终端截获ctrl+c,非阻塞获取按键事件

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);这句屏蔽整行缓存

按键之后直接返回,不用等待输入回车

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值