【问题标题】:Key pressed and key released interrupts in CC中的按键按下和按键释放中断
【发布时间】:2016-02-08 10:34:21
【问题描述】:

有没有办法在 Linux 上从终端窗口运行的简单 C 程序中捕获 while (1) 循环中的 KEY PRESSED 和 KEY RELEASED 事件。

kbhit() 将返回true,如果一个键被按下,getch() 返回被按下的字符。

如何捕捉 RELEASE 事件?

【问题讨论】:

    标签: keyboard c interrupt events


    【解决方案1】:

    您不能以可移植的方式执行此操作。终端(以及诸如xterm 之类的模拟器)只为您提供按下的键,而不是释放事件。图形用户界面通常提供接收单独的新闻和发布事件的能力。

    在图形环境中运行的终端模拟器将这些事件组合成单个字符。如在图形环境中所读,这些是键符号,其中可能包含字符。除了按键事件本身的按下和释放事件之外,您还可以拥有 修饰符,例如 shift-、control- 和 meta-modifiers,它们是单独的事件。如果你运行xev,你可以看到这些单独的事件。

    在将这些事件组合成一个字符后,终端仿真器可能会将其作为一系列数据字节(例如 UTF-8 编码)发送到您的应用程序。当您使用getch() 时,ncurses 库会读取这些字节,并将它们再次组合成一个字符。在这两者之间(终端仿真器和应用程序)是伪终端和它的翻译,终端仿真器和应用程序都必须操作它们。

    如果您不在图形环境中运行,则(并非总是)有除图形应用程序之外的其他方式,例如 xev 可以直接读取按键/释放事件。 Linux 控制台支持这一点。例如,请参阅 Receiving key press and key release events in Linux terminal applications?

    中引用的链接

    【讨论】:

    • 不能在$WINDOWID 上使用XISelectEvents()(对于X11 模拟器)?就像xinput test-xi2 --root 在根窗口上所做的那样?
    • 你当然可以写一个图形应用程序。
    • 我的问题更多的是关于 XISelectEvents() API 是否可以查询任意目标窗口接收到的 X 事件。从快速测试(但可能不是决定性的)来看,它似乎不适用于除根窗口之外的任何窗口。
    【解决方案2】:

    这适用于 xterm 和 openbox 窗口管理器:

    xinput test-xi2 --root |
      awk -v id="$(
         xwininfo -children -id "$WINDOWID" |
           awk '$1 == "Parent" {print $4}'
         )" '
      $1 == "EVENT"{e = $NF}
      $1 == "detail:" {k = $2}
      $6 == "child" && $7 == id && e ~ /Key/ {print e, k}'
    

    输出类似:

    (KeyRelease) 36
    (KeyPress) 38
    a(KeyRelease) 38
    s(KeyPress) 39
    d(KeyPress) 40
    (KeyRelease) 39
    (KeyRelease) 40
    

    (那些a、s、d 是xterm 在处理这些 KeyPress 事件时写入伪终端的主端的字符的本地回显,而不是输出的一部分) .

    xinput test-xi2 --root 将报告当前$DISPLAY 的每个 X Window 事件,包括但不限于 keypress 和 keyrelease 事件,格式类似于:

    EVENT type 2 (KeyPress)
        device: 14 (14)
        detail: 54
        flags:
        root: 795.06/645.66
        event: 795.06/645.66
        buttons:
        modifiers: locked 0 latched 0 base 0x4 effective: 0x4
        group: locked 0 latched 0 base 0 effective: 0
        valuators:
        windows: root 0x252 event 0x252 child 0x1c0015b
    

    从我有限的测试中,我发现那里的 child 字段似乎与接收那些事件。我怀疑窗口 id 有点属于窗口管理器。

    因此,在这里,我们从 xwininfo -children 命令输出中检索该 id,并使用它来过滤 xinput 报告的事件。

    要将这些关键代码转换为关键标签,请查看this other answer。

    现在,您需要检查 xinput 的源代码或使用 ltrace(如果在 Linux 上)直接在 C 中执行相同的操作,而无需这些实用程序的帮助。

    【讨论】:

      猜你喜欢
      • 2011-10-14
      • 2021-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      相关资源
      最近更新 更多