如何在C 语言中监听CTRL键?

编程语言 2026-07-10

我正在用C 编写一个程序,禁用了canonical模式和回显模式,使用 termios.h
我在想,怎样才能监听CTRL快捷键(在我的情况下,是 CTRL + Q):

  1. 我尝试查找CTRL快捷键的按键码,但没有找到任何东西。
  2. 然后再深入一点,发现了 signal.h,但我想监听 CTRL + Q,不是一个宏。
  3. 我一直在搜索,但其实没找到什么,只有在《用C 构建文本编辑器》中的一段内容:
#define CTRL_KEY(k) ((k) & 0x1f)

除了当我尝试监听 CTRL + Q 时:

case CTRL_KEY('q'):
    cin_ignore();
    clear_screen();
    reset_termios();
    main_menu();
    break;

它并不工作,因为我期望在同时按下 CTRLQ 时会调用相应的函数。

顺便说一下,我尝试读取按键的方式如下:

当调用函数 "write_screen" 时:

                init_termios(); // disable echo and canonical mode

        global_signal = 0; // ignore

        while (1)
        {
            write_check(content); // check what user input is , for example if it is CTRL + Q, then quit the program

            if (read(STDIN_FILENO, &content, 1) == -1 && errno != EAGAIN)
            {
                error_handle("read"); // perror() function
            }

            type_check(content); // check if the character is printable, if it is arrows keys etc , if it is printable then print the content
        }

那么,我到底哪里出错了?如果不能那样实现,还有其他方法吗?

规格:

  • 操作系统:Linux
  • 解释器:Visual Studio Code

下面是一段最小的代码:

#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <errno.h>
#include <type.h>

char c;
int global_signal = 0;

static struct termios old, new1;

#define CTRL_KEY(k) ((k) & 0x1f)

void init_termios()
{
    tcgetattr(0, &old);

    new1 = old;

    new1.c_lflag &= ~ICANON;
    new1.c_lflag &= ~ECHO;
    new1.c_lflag &= ~IGNBRK;

    tcsetattr(0, TCSANOW, &new1);
}

void reset_termios()
{
    tcsetattr(0, TCSANOW, &old);
}


void type_check(char content)
{
     if (isprint(content))
    {
          // print ..
    }
}

void write_check(char content)
{
    switch (content)
    {
    case CTRL_KEY('q'):
        printf("CTRL + Q pressed\n");
        break;
    }
}

void write_screen(int global_signal, char content)
{
    if (global_signal == 0)
    {
        init_termios();

        global_signal = 0;

        while (1)
        {
            write_check(content);

            if (read(STDIN_FILENO, &content, 1) == -1 && errno != EAGAIN)
            {
                // error function..
            }

            type_check(content);
        }
    }
}

int main()
{
 write_screen(0, c);
}

那么,是我这边的问题吗?我是不是在不应该运行它的地方运行了它?就这种情况而言?

解决方案

你的代码在标准终端的MATE(mate-terminal)和 WezTerm 下对我来说工作正常,但在 xtermAlacritty 时会有问题。

问题可能是因为某些终端为了自身使用会拦截 Ctrl+Q(以及 Ctrl+S)。

如果我设置

    new1.c_iflag &= ~IXON;

那么它对我就起作用。


通常它会与 IXOFF 一起出现

    new1.c_iflag &= ~(IXON|IXOFF);

pty - IXON与 IXOFF tty属性有什么区别? - Unix & Linux Stack Exchange


对 [termios] 的手册:

IXON   Enable XON/XOFF flow control on output.

IXOFF  Enable XON/XOFF flow control on input.

还有一些关于 Ctrl+QCtrl+S 的信息

VSTART (021, DC1, Ctrl-Q) Start character (START).  Restarts
       output stopped by the Stop character.  Recognized when IXON
       is set, and then not passed as input.

VSTOP  (023, DC3, Ctrl-S) Stop character (STOP).  Stop output
       until Start character typed.  Recognized when IXON is set,
       and then not passed as input.
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章