簡體   English   中英

在 C 程序中捕獲一個字符但顯示其他內容

[英]Capture one character but display something else in C program

是否甚至可以編寫一個等待用戶輸入的 C 程序(如 C++ 中的cin ),當用戶只敲擊一個鍵(不輸入)時,假設鍵盤上的“a”字符終端將顯示“b "(仍然等待輸入)? 如果是這樣 - 我怎樣才能做到這一點?

這是可能的,但這不是“標准” C 處理的。 您需要額外的庫來實現這一點。

您需要意識到標准 C(或 C++)函數不適用於“鍵”、“屏幕”或“終端”。 他們唯一能做的就是所謂的“標准輸入輸出”,僅限於在某處寫入字符,從某處讀取字符。 字符的源和目標沒有嚴格定義,並且取決於附加到 IO 流的內容。

當您考慮按鍵、屏幕和終端時,您會考慮更具體的事情。 您對在某些未指定的地方之間發送和接收字符不感興趣。 您希望它們完全來自按鍵,並最終出現在屏幕上。 為此,您需要一個知道如何使用鍵和屏幕的庫。 例如,其中一個庫是ncurses ,但可能還有其他選擇。

有一些與使用附加庫相關的潛在問題:可用性、可移植性、可維護性等。當您決定使用什么庫時,您需要考慮這些因素,因為最終選擇取決於您的要求:您正在使用什么平台? 你希望你的代碼是可移植的嗎?

對於Windows ,使用conio.h庫 function getch() ,與Linux相同,但以curses.h為例:

#include <stdio.h>
#include <conio.h> /* or curses if you are on linux*/


int main(void)
{
  int c = 0;

  c = getch();

  if (c == 'a')
  {
    putchar('b');
    getchar(); /* waiting for a newline */
  }

  return 0;
}

注意getch()不是標准的 C function。

編輯:正如 Lundin 在評論中指出的那樣,這是一個 MS DOS 實現,而不是 Windows,因為我錯誤地標記了它。

更多關於 curses heregetch() here

由於您使用的是 Linux 並且您不需要存儲真實輸入,您可以嘗試使用termios.h

#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#define KEY_ENTER   0x000a
#define KEY_ESCAPE  0x001b

static struct termios term, oterm;

static int getch(void);
static int kbhit(void);
static int kbesc(void);
static int kbget(void);

static int getch(void)
{
    int c = 0;

    tcgetattr(0, &oterm);
    memcpy(&term, &oterm, sizeof(term));
    term.c_lflag &= ~(ICANON | ECHO);
    term.c_cc[VMIN] = 1;
    term.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &term);
    c = getchar();
    tcsetattr(0, TCSANOW, &oterm);
    return c;
}

static int kbhit(void)
{
    int c = 0;

    tcgetattr(0, &oterm);
    memcpy(&term, &oterm, sizeof(term));
    term.c_lflag &= ~(ICANON | ECHO);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;
    tcsetattr(0, TCSANOW, &term);
    c = getchar();
    tcsetattr(0, TCSANOW, &oterm);
    if (c != -1) ungetc(c, stdin);
    return ((c != -1) ? 1 : 0);
}

static int kbesc(void)
{
    int c;
    
    while (kbhit())
    {
        c = getch();
    }
    return c;
}

static int kbget(void)
{
    int c;

    c = getch();
    return (c == KEY_ESCAPE) ? kbesc() : c;
}

int main(void)
{
    int c;

    while (1)
    {
        c = kbget();
        if (c == KEY_ENTER)
        {
            break;
        }
        putchar('b');
    }
    printf("\n");
    return 0;
}

對於更復雜的事情,請考慮ncurses

如果您在用戶按下回車鍵之前嘗試更改用戶的輸入,則需要更改終端的一些配置。 下面的代碼將逐個字符地讀取用戶輸入的字符並將任何 a 更改為 b。 按下回車后停止。

#include <termios.h>
#include <unistd.h>

int main(void) {
  struct termios oldterm, newterm;
  tcgetattr(STDIN_FILENO, &oldterm); // save current config
  // set new config
  newterm = oldterm;
  newterm.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
  tcsetattr(STDIN_FILENO, TCSAFLUSH, &newterm);

  char ch = 0;
  while (read(STDIN_FILENO, &ch, 1) && ch != '\n') {
    if (ch == 'a') // show a's as b's
      write(STDOUT_FILENO, "b", 1);
    else if (ch == 127) // allows deleting chars
      write(STDOUT_FILENO, "\b \b", 3);
    else // other chars
      write(STDOUT_FILENO, &ch, 1);
  }

  // return to old config
  tcsetattr(STDIN_FILENO, TCSANOW, &oldterm);

  return 0;
}

您可以通過將讀取的字符ch存儲在數組中來保存實際輸入。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM