[英]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,因為我錯誤地標記了它。
由於您使用的是 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.