Reputation: 12412
Is there a way to catch the KEY PRESSED and KEY RELEASED events in while (1)
loop in simple C program on Linux running from a terminal window.
kbhit()
will return true
if a key was pressed, getch()
returns the character that was pressed.
How do I catch the RELEASE event?
Upvotes: 1
Views: 3482
Reputation: 6239
This works for me with xterm
and the openbox
window manager:
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}'
Outputs something like:
(KeyRelease) 36
(KeyPress) 38
a(KeyRelease) 38
s(KeyPress) 39
d(KeyPress) 40
(KeyRelease) 39
(KeyRelease) 40
(those a
, s
, d
are the local echo for the characters that xterm
wrote to the master side of the pseudo-terminal upon handling those KeyPress events and are not part of the output).
xinput test-xi2 --root
will report every X Window event for the current $DISPLAY
including but not limited to keypress and keyrelease events in a format similar to:
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
From my limited testing, I find that the child
field in there seems to match the id of the parent of the terminal emulator main window (which most terminal emulators make available in the $WINDOWID
environment variable) which receives those events. I suspect that window id is somewhat belongs to the window manager.
So, here, we retrieve that id from the xwininfo -children
command output, and use that to filter the events reported by xinput
.
To translate those key codes to key labels, check this other answer.
Now, you'll want to check the source code of xinput
or play with ltrace
(if on Linux) to do the same thing directly in C without the help of those utilities.
Upvotes: 1
Reputation: 54505
You cannot do this in a portable manner. Terminals (and emulators of those such as xterm) give you only the key that was pressed, not the release events. Graphical user interfaces often provide the ability to receive separate press- and release-events.
Terminal emulators running in a graphical environment compose those events into individual characters. As read in the graphical environment, those are key symbols, which may contain characters. In addition to the press- and release-events for the key events themselves, you can have modifiers such as shift-, control- and meta-modifiers which are separate events. If you run xev
, you can see these separate events.
After composing these events into a character, the terminal emulator may send it to your application as a series of data bytes, e.g., in UTF-8 encoding. When you use getch()
, the ncurses library reads those bytes, and puts it together again into a character. In between those two (the terminal emulator and application) are the pseudo-terminal and its translation, which both terminal emulator and application must manipulate.
If you are not running in a graphical environment, there are (not always) other ways than graphical applications such as xev
which can read directly the key press/release events. The Linux console supports that. See for example the links cited in Receiving key press and key release events in Linux terminal applications?
Upvotes: 3