#include <termios.h>
struct termios info;
tcgetattr(0, &info); /* get current terminal attirbutes; 0 is the file descriptor for stdin */
info.c_lflag &= ~ICANON; /* disable canonical mode */
info.c_cc[VMIN] = 1; /* wait until at least one keystroke available */
info.c_cc[VTIME] = 0; /* no timeout */
tcsetattr(0, TCSANOW, &info); /* set immediately */
int ch;
while((ch = getchar()) != 27 /* ascii ESC */) {
if (ch < 0) {
if (ferror(stdin)) { /* there was an error... */ }
clearerr(stdin);
/* do other stuff */
} else {
/* some key OTHER than ESC was hit, do something about it? */
}
}
#include <pthread.h> // Multithreading
#include <stdio.h>
#include <stdlib.h> // for atexit()
#include <termios.h> // For changing terminal mode
#include <unistd.h> // For changing terminal mode
struct termios original; // A struct to save the original state of terminal
int ESCPressed = 0; // For thread communication
void disableRAWMode();
void enableRAWMode();
void *asciRead();
void *print();
int main() {
// Start Multithreading
pthread_t id_print, id_read;
pthread_create(&id_print, NULL, print, NULL);
pthread_create(&id_read, NULL, asciRead, NULL);
pthread_join(id_print, NULL);
pthread_join(id_read, NULL);
return 0;
}
/// Reads keyboard input
void *asciRead() {
enableRAWMode(); // local function: Enable Raw Mode
char ch;
while ((ch = getchar()) != 27)
; // ASCI code for ESC is 27
ESCPressed = 1;
printf("ESC Pressed!\n");
}
/// Doing Stuff while listening to keyboard
void *print() {
while (!ESCPressed) { // When ESC is not pressed
sleep(1);
printf("I am Printing!\n");
}
printf("Printing Thread Finished!\n");
}
/// This function enables RAW mode for terminal.
void enableRAWMode() {
struct termios raw;
tcgetattr(STDIN_FILENO, &raw); // Save the state of the terminal to struct raw
// STDIN_FILENO is from <stdlib.h>
// tcgetattr() from <termios.h>
tcgetattr(STDIN_FILENO, &original);
atexit(&disableRAWMode); // Revert to canonical mode when exiting the program
// atext() from <stdlib.h>
raw.c_lflag &=
~(ECHO | ICANON); // Turn off canonical mode
// Turn off ECHO mode so that keyboard is not
// printing to terminal
// ICANON and ECHO is bitflag. ~ is binary NOT operator
tcsetattr(STDIN_FILENO, TCSAFLUSH,
&raw); // Set the terminal to be in raw mode
// tcsetattr() from <termios.h>
}
void disableRAWMode() {
tcsetattr(STDIN_FILENO, TCSAFLUSH,
&original); // Set terminal to original state
}
4条答案
按热度按时间9rbhqvlz1#
这严重依赖于系统。在Unix/Linux系统中,默认的终端处理程序收集行,并且只在完整的行可用时通知程序(在按下Enter之后)。)如果您想立即按键,则需要将终端置于非规范模式:
一旦你完成了这一步,你就可以使用任何从stdin读取的调用,它们将返回键,而不需要等待行尾。您还可以设置
c_cc[VMIN] = 0
,使其在从stdin读取时根本不等待击键。然而,如果你正在阅读stdin与stdio FILE相关的调用(getchar等),设置VMIN = 0将使它认为你已经达到EOF,每当没有可用的键时,所以你必须在这之后调用
clearerr
来尝试读取更多的字符。你可以像这样使用循环:完成后,您可能希望确保将终端设置回规范模式,以免其他程序(例如您的shell)感到困惑:
你还可以用tcsetattr做其他事情--详细信息请参见手册页。有一件事可以满足您的目的,那就是设置一个可选的EOL字符。
nue99wik2#
如果你正在做的主要工作可以放在这个主循环中,你可以在非阻塞模式下使用STDIN。你仍然有一个问题的终端,行缓冲正常。您还应将终端设置为原始模式。
如何使用Ctrl-C(中断)?
非阻塞意味着
read()
系统调用总是立即返回,即使文件中没有新字节。在Linux/Unix上,可以通过以下方式使STDIN非阻塞:2exbekwf3#
这就是你想要的:
xmjla07d4#
要在执行其他命令的同时持续监视键盘,需要使用
termios.h
更改终端模式,并使用pthread.h
进行多线程处理。终端以规范模式启动,这意味着标准输入仅在按下
Enter
后发送到程序。对于按键后的即时响应,我们需要原始模式。当调用C输入函数
getchar()
时,线程停止并等待,直到接收到输入。因此,在监听键盘输入的同时连续执行动作需要多线程。全局变量帮助不同的线程进行通信。
代码如下:
有用的资源:
Terminal Raw Mode
Multithreading