windows
截获ctrl+c,通过api SetConsoleCtrlHandler监听部分事件,除了ctrl+c还有关机和账户退出事件。
#include <stdio.h>
#include <windows.h>
bool g_exit = false;
const char* GetEventMessage(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_C_EVENT:
return "CTRL_C_EVENT";
case CTRL_BREAK_EVENT:
return "CTRL_BREAK_EVENT";
case CTRL_CLOSE_EVENT:
return "CTRL_CLOSE_EVENT";
case CTRL_LOGOFF_EVENT:
return "CTRL_LOGOFF_EVENT";
case CTRL_SHUTDOWN_EVENT:
return "CTRL_SHUTDOWN_EVENT";
}
return "Unknown";
}
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
printf("%s event received\n", GetEventMessage(dwCtrlType));
g_exit = true;
return TRUE;
}
// int main()
int holdCtrlC()
{
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
while (!g_exit)
{
printf("main\n");
Sleep(5000);
}
printf("exit\n");
Sleep(5000);
return 0;
}
linux
ctrl+c通过api signal注册回调事件SIGINT,也就是结束事件
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <stdbool.h>
bool g_bExit = false;
void Ctrl_c(int _)
{
printf("Ctrl + c detected!\n");
g_bExit = true;
}
int main(){
signal(SIGINT, &Ctrl_c);
while(!g_bExit){
printf("wait for ctrl_c\n");
sleep(3);
}
printf("out while\n");
return 0;
}
signal支持的回调有如下:
SIGHUP 1 /* Hangup (POSIX). */ 终止进程 终端线路挂断
SIGINT 2 /* Interrupt (ANSI). */ 终止进程 中断进程 Ctrl+C
SIGQUIT 3 /* Quit (POSIX). */ 建立CORE文件终止进程,并且生成core文件 Ctrl+\
SIGILL 4 /* Illegal instruction (ANSI). */ 建立CORE文件,非法指令
SIGTRAP 5 /* Trace trap (POSIX). */ 建立CORE文件,跟踪自陷
SIGABRT 6 /* Abort (ANSI). */
SIGIOT 6 /* IOT trap (4.2 BSD). */ 建立CORE文件,执行I/O自陷
SIGBUS 7 /* BUS error (4.2 BSD). */ 建立CORE文件,总线错误
SIGFPE 8 /* Floating-point exception (ANSI). */ 建立CORE文件,浮点异常
SIGKILL 9 /* Kill, unblockable (POSIX). */ 终止进程 杀死进程
SIGUSR1 10 /* User-defined signal 1 (POSIX). */ 终止进程 用户定义信号1
SIGSEGV 11 /* Segmentation violation (ANSI). */ 建立CORE文件,段非法错误
SIGUSR2 12 /* User-defined signal 2 (POSIX). */ 终止进程 用户定义信号2
SIGPIPE 13 /* Broken pipe (POSIX). */ 终止进程 向一个没有读进程的管道写数据
SIGALARM 14 /* Alarm clock (POSIX). */ 终止进程 计时器到时
SIGTERM 15 /* Termination (ANSI). */ 终止进程 软件终止信号
SIGSTKFLT 16 /* Stack fault. */
SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
SIGCHLD 17 /* Child status has changed (POSIX). */ 忽略信号 当子进程停止或退出时通知父进程
SIGCONT 18 /* Continue (POSIX). */ 忽略信号 继续执行一个停止的进程
SIGSTOP 19 /* Stop, unblockable (POSIX). */ 停止进程 非终端来的停止信号
SIGTSTP 20 /* Keyboard stop (POSIX). */ 停止进程 终端来的停止信号 Ctrl+Z
SIGTTIN 21 /* Background read from tty (POSIX). */ 停止进程 后台进程读终端
SIGTTOU 22 /* Background write to tty (POSIX). */ 停止进程 后台进程写终端
SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ 忽略信号 I/O紧急信号
SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ 终止进程 CPU时限超时
SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ 终止进程 文件长度过长
SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ 终止进程 虚拟计时器到时
SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ 终止进程 统计分布图用计时器到时
SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ 忽略信号 窗口大小发生变化
SIGPOLL SIGIO /* Pollable event occurred (System V). */
SIGIO 29 /* I/O now possible (4.2 BSD). */ 忽略信号 描述符上可以进行I/O
SIGPWR 30 /* Power failure restart (System V). */
SIGSYS 31 /* Bad system call. */
SIGUNUSED 31
windows非阻塞监听按键
#include<stdio.h>
#include<windows.h>
#include<conio.h>
void onKeyDown(char c)
{
printf("pressedkey=%d\n", c);
if (c == 'x') exit(0);
}
void onKeyUp(char c)
{
printf("releasedkey=%d\n", c);
}
// int mian()
int unblockWaitKey()
{
char key = 0;
while (1)
{
printf("wait key\n");
if (_kbhit())
{
key = _getch();
onKeyDown(key);
}
else if (key)
{
onKeyUp(key);
key = 0;
}
else {
printf("no key\n");
}
Sleep(100);
}
return 0;
}
kbhit判断当前是否已经有按键按下,如果有,就调用getch
linux非阻塞监听按键事件
#include <stdio.h>
#include <termios.h>
#include <string.h>
#include <sys/time.h>
struct termios orig_termios;
void reset_terminal_mode()
{
printf("reset_terminal_mode happen\n");
tcsetattr(0, TCSANOW, &orig_termios);
}
void set_conio_terminal_mode()
{
struct termios new_settings;
/* take two copies - one for now, one for later */
tcgetattr(0, &orig_termios);
memcpy(&new_settings, &orig_termios, sizeof(new_settings));
/* register cleanup handler, and set the new terminal mode */
atexit(reset_terminal_mode);
new_settings.c_lflag &= (~ICANON);
new_settings.c_lflag |= ECHO;
new_settings.c_lflag |= ISIG;
new_settings.c_cc[VMIN] = 1;
new_settings.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &new_settings);
}
int kbhit()
{
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds);
FD_SET(0, &fds);
return select(1, &fds, NULL, NULL, &tv);
}
int getch()
{
int r;
unsigned char c;
if ((r = read(0, &c, sizeof(c))) < 0) {
return r;
} else {
return c;
}
}
int main(int argc, char *argv[])
{
int ch = 0;
set_conio_terminal_mode();
while (1) {
if(kbhit()){
ch = getch(); /* consume the character */
printf("get char 0x%x\n", ch);
}
/* do some work */
printf("wait in while \n");
sleep(3);
if('x' == ch){
break;
}
}
printf("out while\n");
return 0;
}
默认getchar,fgetc需要敲回车后才会返回,
new_settings.c_lflag &= (~ICANON);这句屏蔽整行缓存
按键之后直接返回,不用等待输入回车