Determine Linux keyboard events device
This other question, Accessing Keys from Linux Input Device provided working C code on how to recognize a modifier key press in the Linux text console when no other keys are being pressed. However, to apply the trick you have to know the specific file /dev/input/event* that logs keyboard events. How do I determine the name of that file?
2 Answers 2
I prefer next solution because it parses devices file internally.
If we check contents of /proc/bus/input/devices we can found something like this:
# cat /proc/bus/input/devices I: Bus=0019 Vendor=0002 Product=0001 Version=0100 N: Name="vmouse" P: Phys=vmouse/input0 S: Sysfs=/devices/virtual/input/input0 U: Uniq= H: Handlers=mouse0 event0 B: PROP=0 B: EV=7 B: KEY=70400 0 0 0 0 0 0 0 0 B: REL=143 I: Bus=0019 Vendor=0001 Product=0001 Version=0100 N: Name="sunxi-ths" P: Phys=sunxiths/input0 S: Sysfs=/devices/virtual/input/input3 U: Uniq= H: Handlers=event3 B: PROP=0 B: EV=9 B: ABS=100 0 I: Bus=0003 Vendor=1220 Product=0008 Version=0100 N: Name="HID 1220:0008" P: Phys=usb-sunxi-ohci-1/input0 S: Sysfs=/devices/platform/sunxi-ohci.3/usb7/7-1/7-1:1.0/input/input6 U: Uniq= H: Handlers=sysrq kbd event1 B: PROP=0 B: EV=120013 B: KEY=10000 7 ff9f207a c14057ff febeffdf ffefffff ffffffff fffffffe B: MSC=10 B: LED=1f I: Bus=0003 Vendor=1220 Product=0008 Version=0100 N: Name="HID 1220:0008" P: Phys=usb-sunxi-ohci-1/input1 S: Sysfs=/devices/platform/sunxi-ohci.3/usb7/7-1/7-1:1.1/input/input7 U: Uniq= H: Handlers=kbd mouse1 event2 B: PROP=0 B: EV=1f B: KEY=4837fff 72ff32d bf544446 0 0 1f0001 20f90 8b17c000 677bfa d941dfed 9ed680 4400 0 10000002 B: REL=143 B: ABS=1 0 B: MSC=10
So the only thing we need is to find event device number in block where «EV=120013» string appeared:
#include #include #include #include #include using namespace std; string getInputDeviceName() < int rd; std::string devName; const char* pdevsName = "/proc/bus/input/devices"; int devsFile = open(pdevsName, O_RDONLY); if (devsFile == -1) < printf("[ERR] Open input devices file: '%s' is FAILED\n", pdevsName); >else < char devs[2048]; if ((rd = read(devsFile, devs, sizeof(devs) - 1)) < 6) < printf("[ERR] Wrong size was read from devs file\n"); >else < devs[rd] = 0; char *pHandlers, *pEV = devs; do < pHandlers = strstr(pEV, "Handlers="); pEV = strstr(pHandlers, "EV="); >while (pHandlers && pEV && 0 != strncmp(pEV + 3, "120013", 6)); if (pHandlers && pEV) < char* pevent = strstr(pHandlers, "event"); if (pevent) < devName = string("/dev/input/event"); devName.push_back(pevent[5]); >else < printf("[ERR] Abnormal keyboard event device\n"); >> else < printf("[ERR] Keyboard event device not found\n"); >> > return devName; >
NOTE1: This code works on event devices with numbers less than 10.
NOTE2: Please check «devs» buffer size, on your system 2048 bytes may be not enough.
Ubuntu: show what keys are pressed in real-time [duplicate]
I am looking for a tool that tells what keys (including Alt, Shift, Ctrl, etc) are pressed now. Need it to do a health-check on a possibly faulty keyboard.
4 Answers 4
Install keymon . It’s in the Universe repository and run it using key-mon (not keymon !).
Keymon — Keyboard and mouse monitor window for GTK.
Do read man keymon for all the options available.
You should also right-click on it to check that the settings are appropriate for you.
And if you don’t like the default location, drag it to a more suitable position on your screen.
An alternative is screenkey , also in the Universe repository. A feature of screenkey is that it’s interface only when you type something and disappears after a few seconds if the keyboard is inactive. However, unlike keymon, screenkey doesn’t register mouse clicks.
There’s a YouTube video on both keymon and screenkey . The video’s in German but still is easy to follow.
A search for keymon of key-mon currently returns no results from the Universe. You might need to expand your answer.
To test a possibly faulty keyboard it’s best to go as low-level as possible. One of the easiest ways to do this without diving into kernel space is to work almost directly with /dev/input/event* device files. Namely, you can use evtest to see all the keyboard input. If you run it in grabbing mode, this will let you intercept everything—even Magic SysRq combos (funnily, even SAK)!
Here’s how I’d go about it. First, get a list of input devices by running sudo evtest :
$ sudo evtest No device specified, trying to scan all of /dev/input/event* Available devices: /dev/input/event0: Power Button /dev/input/event1: Power Button /dev/input/event2: PC Speaker /dev/input/event3: Video Bus /dev/input/event4: HDA Intel HDMI HDMI/DP,pcm=3 /dev/input/event5: HDA Intel HDMI HDMI/DP,pcm=7 /dev/input/event6: HDA Intel HDMI HDMI/DP,pcm=8 /dev/input/event7: HDA Intel HDMI HDMI/DP,pcm=9 /dev/input/event8: HDA Intel HDMI HDMI/DP,pcm=10 /dev/input/event9: HDA Intel PCH Front Mic /dev/input/event10: HDA Intel PCH Rear Mic /dev/input/event11: HDA Intel PCH Line /dev/input/event12: HDA Intel PCH Line Out /dev/input/event13: HDA Intel PCH Front Headphone /dev/input/event14: HDA NVidia HDMI/DP,pcm=3 /dev/input/event15: HDA NVidia HDMI/DP,pcm=7 /dev/input/event16: HDA NVidia HDMI/DP,pcm=8 /dev/input/event17: ImExPS/2 Generic Explorer Mouse /dev/input/event18: AT Translated Set 2 keyboard Select the device event number 4:
Don’t choose anything here yet: just press Ctrl + C . This run of evtest was in a simple non-grabbing mode, which won’t let you intercept everything. But you now know the device file you need (in my case given above, it’s /dev/input/event18 ).
Now you can actually run evtest in grabbing mode, using the —grab option, so that it intercepts all events from the keyboard—including the release of Return after you submit your command to the shell, subsequent Ctrl + C , Magic SysRq, VT switch shortcuts etc.. To avoid being locked out of the system, we’ll set up a timeout for evtest .
sudo su -c 'sleep 1; timeout -k5 10 evtest --grab /dev/input/event18'
This command does the following:
- Waits 1 second so that you can release Return before the keyboard is grabbed (otherwise you’ll get autorepeats rapidly scrolling the console)
- Starts evtest in grabbing mode on my keyboard’s device file (replace it with yours).
- evtest is run with a timeout of 10 seconds, and additional grace period of 5 seconds in (unlikely) case it hangs, after which it’s killed by SIGKILL , hopefully returning keyboard control to you.
- sudo is wrapped around the whole command instead of only evtest to make sure that you enter the password (if needed) before sleep 1 , otherwise this sleep will be useless
During the timeout of 10 seconds (which you can, of course, change to something that suits you better) you can press anything on your keyboard—aside maybe from Fn -driven keys, which might work in a nonstandard way—and see what it inputs.
How can I get the keyboard state in Linux?
I want to check if the user pressed down the Shift key when the program starts. (That means, press down the Shift key before the program is started) It’s a simple console program, nothing related to X. This maybe similar to the Win32 GetKeyboardState() function. I want to know whether I can do this and how, but not any pros and cons with accessing the terminal directly.
4 Answers 4
I think there would be a way to do this. The thing is that you would have to read directly from the keyboard device. You would not be getting input from the terminal. I have the same problem. I have a program that runs (in the background) and I want to know if the user is holding down the shift key.
I believe this is possible and a place to start might be /dev/input/by-path/*-kbd .
This file does give input every time a key is pressed or reptadly if it is held down so it might be worth a look. (Try cat /dev/input/by-path/*-kbd )
If you do figure this out I would love to hear how you did it.
EDIT: I have found the solution
I have figured out how do do this. My program is as follows:
#include #include #include void usage ( int argc, char *argv[] ) < printf("Usage:\n\t%s key\n\nvalid keys are:\n\tlshift\t- Left Shift key\n" , argv[0]); exit(EXIT_FAILURE); >int main ( int argc, char *argv[], char *env[] ) < if ( argc != 2 ) usage(argc, argv); int key; if ( strcmp(argv[1], "lshift") == 0 ) key = KEY_LEFTSHIFT; else if ( strcmp(argv[1], "rshift") == 0 ) key = KEY_RIGHTSHIFT; else if ( strcmp(argv[1], "lalt") == 0 ) key = KEY_LEFTALT; else if ( strcmp(argv[1], "ralt") == 0 ) key = KEY_RIGHTALT; else if ( strcmp(argv[1], "lctrl") == 0 ) key = KEY_LEFTCTRL; else if ( strcmp(argv[1], "rctrl") == 0 ) key = KEY_RIGHTCTRL; FILE *kbd = fopen("/dev/input/by-path/platform-i8042-serio-0-event-kbd", "r"); char key_map[KEY_MAX/8 + 1]; // Create a byte array the size of the number of keys memset(key_map, 0, sizeof(key_map)); // Initate the array to zero's ioctl(fileno(kbd), EVIOCGKEY(sizeof(key_map)), key_map); // Fill the keymap with the current keyboard state int keyb = key_mapLinux get keyboard events; // The key we want (and the seven others arround it) int mask = 1
The info message is lacking (I'm too lazy). But essentially the first argument is compared to a list of keys and the appropriate key identifier is used. It returns true if the key is pressed and false if not.
Please Note
You will need to change the name of they keyboard device. I do not know of a way to find the default keyboard device. (if you know I would love to hear 😉 )
This works beautifully: I use it to start the autostart of Xorg if I hold down the shift key.
This program needs root privileges, otherwise it segfaults on my machine. This is because of permissions for the keyboard device file (BTW, it's the same platform-i8042-serio-0-event-kbd here, so maybe at least every PC has it?). By running sudo xxd /dev/input/by-path/platform-i8042-serio-0-event-kbd I saw that the file "grows" by another sizeof(keymap) every time the keyboard state changes.
AFAIK this cannot be done without Xlib (aka. X) with no root level permissions. Using XQueryKeymap() will do what you want. however you pointed out that X cannot be used. Regardless, opening display connection will also be required.
#include #include #include #include int main() < Display* dpy = XOpenDisplay(NULL); char keys_return[32]; XQueryKeymap( dpy, keys_return ); KeyCode kc2 = XKeysymToKeycode( dpy, XK_Shift_L ); bool bShiftPressed = !!( keys_return[ kc2>>3 ] & ( 1
I have found a very simple way through gtk/gdk.
int main ( int argc, char *argv[], char *env[] ) < gtk_init(&argc, &argv); GdkModifierType button_state; gdk_window_get_pointer(NULL, NULL, NULL, &button_state); if(button_state & GDK_CONTROL_MASK) < printf("ctrl key is pressed"); >>
The Shift key isn't considered as a character key, so even if you access the terminal directly, you won't be able to detect this key.
Maybe you shouldn't have to. Imagine for example that you are using a US keyboard where numbers are accessible on the top row without modifiers, and also checking for the Shift key. People with other keyboard layout may have to use Shift modifiers to access the numbers. If your program react to this Shift press, then your program is basically unusable. The same thing applies for other modifier keys : you may detect some of them only after a normal character key is pressed. Or worse, they may need to use the Shift key to use 'enter' to run your program.
Also, what Shift key do you want to monitor? the one on the local machine, or the one where the user is? remember that SSH exists and is commonly used to access a pseudoterminal remotely.
If you are root and want to monitor the Shift key on the local machine, you can read the evdev devices for events about the Shift key. But this is only possible because of automatic key repeating, so you won't detect a Shift key that is pressed right before running your program, but only a few second before.
Of course you can't do that on the remote machine, that would be a security flaw.
And anyway, why would you want to do that? Wouldn't an X application be the right thing to do in your case?
jtyr / README.md
Instructions how to capture keyboard and mouse events and turn them into human readable output.
- Run evtest without any argments and see which event device you need to use.
- Run the following command for the keyboard events:
evtest /dev/input/event5 | grep --line-buffered 'EV_KEY' | sed -r -e 's/.*\(KEY_/Keyboard: /' -e 's/\), value 0/ - UP/' -e 's/\), value 1/ - DOWN/' -e 's/\), value 2/ - HOLD/'
Keyboard: Z - DOWN Keyboard: Z - UP Keyboard: SPACE - DOWN Keyboard: SPACE - HOLD Keyboard: SPACE - HOLD Keyboard: SPACE - HOLD Keyboard: SPACE - UP Keyboard: LEFTCTRL - DOWN Keyboard: LEFTCTRL - HOLD Keyboard: LEFTCTRL - HOLD Keyboard: LEFTCTRL - HOLD Keyboard: LEFTCTRL - UP
evtest /dev/input/event7 | egrep --line-buffered '(EV_KEY|REL_WHEEL_HI_RES)' | sed -r -e 's/.*\((BTN_|REL_WHEEL_HI_RES)/Mouse: /' -e 's/\), value -120/WHEEL - DOWN/' -e 's/\), value 120/WHEEL - UP/' -e 's/\), value 0/ - UP/' -e 's/\), value 1/ - DOWN/' -e 's/\), value 2/ - HOLD/'
Mouse: WHEEL - UP Mouse: WHEEL - UP Mouse: WHEEL - UP Mouse: LEFT - DOWN Mouse: LEFT - UP Mouse: MIDDLE - DOWN Mouse: MIDDLE - UP Mouse: RIGHT - DOWN Mouse: RIGHT - UP Mouse: WHEEL - DOWN Mouse: WHEEL - DOWN Mouse: WHEEL - DOWN