12
May
Posted by Derek Hildreth in Programming » 29 Comments »
Grab Raw Keyboard Input from Event Device Node (/dev/input/event)
The following is a quick c program that will capture raw keyboard data from the event device node such as /dev/input/event1. Simply compile and run with the specific device node as an argument. ie. ./keyboard_key_capture /dev/input/event1.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <termios.h>
#include <signal.h>
void handler (int sig)
{
printf ("nexiting...(%d)n", sig);
exit (0);
}
void perror_exit (char *error)
{
perror (error);
handler (9);
}
int main (int argc, char *argv[])
{
struct input_event ev[64];
int fd, rd, value, size = sizeof (struct input_event);
char name[256] = "Unknown";
char *device = NULL;
//Setup check
if (argv[1] == NULL){
printf("Please specify (on the command line) the path to the dev event interface devicen");
exit (0);
}
if ((getuid ()) != 0)
printf ("You are not root! This may not work...n");
if (argc > 1)
device = argv[1];
//Open Device
if ((fd = open (device, O_RDONLY)) == -1)
printf ("%s is not a vaild device.n", device);
//Print Device Name
ioctl (fd, EVIOCGNAME (sizeof (name)), name);
printf ("Reading From : %s (%s)n", device, name);
while (1){
if ((rd = read (fd, ev, size * 64)) < size)
perror_exit ("read()");
value = ev[0].value;
if (value != ' ' && ev[1].value == 1 && ev[1].type == 1){ // Only read the key press event
printf ("Code[%d]n", (ev[1].code));
}
}
return 0;
}
Here is an example output from running the above command. Notice that Code[] is printed before the key that was pressed.
# ./keyb_key_cap_x86 /dev/input/by-id/usb-Dell_Dell_USB_Keyboard-event-kbd Reading From : /dev/input/by-id/usb-Dell_Dell_USB_Keyboard-event-kbd (Dell Dell USB Keyboard) Code[30] aCode[48] bCode[46] cCode[32] dCode[18] eCode[33] fCode[34] gCode[35] hCode[23] iCode[36] jCode[37] kCode[38] lCode[50] mCode[49] nCode[24] oCode[25] pCode[16] qCode[19] rCode[31] sCode[20] tCode[22] uCode[47] vCode[17] wCode[45] xCode[21] yCode[44] zCode[2] 1Code[3] 2Code[4] 3Code[5] 4Code[6] 5Code[7] 6Code[8] 7Code[9] 8Code[10] 9Code[11] 0
This is only an example program that I picked up from work. I hope it will be of use to somebody out there so it can quickly help you get started with your project.
Feel free to donate if this post prevented any headaches! Another way to show your appreciation is to take a gander at these relative ads that you may be interested in:
Here are some similar posts that you may be interested in:
There's 29 Comments So Far
August 12th, 2010 at 9:54 am
What license are you posting this under?
I’m including it in an keyboard monitoring app I wrote (nealy verbatim), and you
never specified a license.
August 12th, 2010 at 10:57 am
Good question. Anything I post on this site is open game to everybody. I wouldn’t say there is any license, but if I were to give it one I suppose it would fall under the BSD License which allows everyone to use and redistribute the program as they wish.
Just don’t use it for evil. π
August 12th, 2010 at 2:29 pm
“Just donβt use it for evil. ;-)”
Decide yourself π
The project is at http://github.com/adamnew123456/kbmon
It is (in it’s slightly modified form) in “src/kbd-demo.c”
December 22nd, 2010 at 4:25 am
Hi, thank you very much for this program! I just wonder why did you skip ev[0]? it was not working for me. I have modified it in a such way:
instead of this code:
if (value != ‘ ‘ && ev[1].value == 1 && ev[1].type == 1){ // Only read the key press event
printf (“Code[%d]n”, (ev[1].code));
}
i used this:
if (ev[0].value == 1 && ev[0].type == EV_KEY) // Only read the key press event
printf (“Code[%d]n”, (ev[0].code));
December 22nd, 2010 at 8:05 am
It was more of a throw-it-together program for testing purposes. I’m happy to hear that 1) you’ve found it useful and 2) you have brought an improvement to the table! Thank you!
December 27th, 2010 at 3:37 am
Thank you for posting this. I’ve been working on the same thing for about a day now and while I can read the output from event(x) I was having a difficult time figuring out its format, especially since I haven’t had much practice with UTF. After digging through the Linux kernel device drivers I got lucky finding your included headers and got pointed in the right direction. Thanks a ton!
February 9th, 2011 at 1:22 pm
is it possible to have the ((rd = read (fd, ev, size * 64)) < size) non blocking (if no key is pressed) ?
February 9th, 2011 at 1:53 pm
hum found π sorry π
O_RDONLY | O_NONBLOCK
February 15th, 2011 at 5:03 am
Thank you for this good example!
July 18th, 2011 at 6:27 am
Hi all,
I have a problem with reading USB keyboard event file. I can read this file using this program but the problem is that some characters that I type are read multiple times(2 or 3 times). Like I type on my keyboard some number, for example code(73) and my application reads this thing often 2 times, or 3 times. I’ve been looking for this all over the Internet and I didn’t find anything useable to solve this problem yet. Could anyone help me with this?
Or could anyone explain me if the keyboard event file is somehow buffered and if there is any way to clean this file after every reading from this file? Maybe this could solve my problem that some characters are read multiple – 2 or 3 times.
October 24th, 2011 at 6:40 am
Thanks man. It was really helpful π
March 10th, 2012 at 9:44 am
Does not work for me? I gets stuck on the first message and then do not show any key pressed π Still works on Linux 3.x versions? Thank you π
September 27th, 2012 at 8:28 am
Good, worked for me.
Note only that the \n became escaped ( “Code[%d]n” instead of “Code[%d]\n” ) on this post, and due to terminals buffering, the pressed key may be printed only after several keys are pressed (using fflush() on stdout would be safer).
December 18th, 2012 at 8:01 am
Thanks for the code. I played with it on Raspberry Pi (simple cross-compiling) and it works fine :-).
February 6th, 2013 at 10:00 am
Using this as a base for getting a cuecat working on a raspberry pi. thanks!
https://github.com/sixty4k/cuepie
February 9th, 2013 at 6:44 pm
Thanks for the nice example! Was struggling to get it working on the raspberry pi – I kept getting the message “device temporary unavailable”. This error was triggered by the read() function and causes the program to exit. Seems this is not a fatal error, so I removed the perror_exit so the code now reads:
while (1){
rd = read (fd, ev, size * 64);
value = ev[0].value;
……
It now ignores errors on read() – maybe not the best way to do it – but will continue testing the device for the event. That seems to work fine and does what I want! Thanks a lot!
Rob
March 27th, 2013 at 4:36 pm
Your code reads up to 64 events at a time, but you only ever look at the first event. Why?
May 12th, 2013 at 9:36 am
Unfortunately, the /dev/input directory is full of at least 12 files matching your filespec (ubuntu 12.04):
[email protected]:~$ ls -la /dev/input
total 0
drwxr-xr-x 4 root root 380 May 11 21:18 .
drwxr-xr-x 18 root root 4300 May 11 21:36 ..
drwxr-xr-x 2 root root 100 May 11 21:18 by-id
drwxr-xr-x 2 root root 140 May 11 21:18 by-path
crw-r—– 1 root root 13, 64 May 11 21:18 event0
crw-r—– 1 root root 13, 65 May 11 21:18 event1
crw-r—– 1 root root 13, 74 May 11 21:18 event10
crw-r—– 1 root root 13, 75 May 11 21:18 event11
crw-r—– 1 root root 13, 66 May 11 21:18 event2
crw-r—– 1 root root 13, 67 May 11 21:18 event3
crw-r—– 1 root root 13, 68 May 11 21:18 event4
crw-r—– 1 root root 13, 69 May 11 21:18 event5
crw-r—– 1 root root 13, 70 May 11 21:18 event6
crw-r—– 1 root root 13, 71 May 11 21:18 event7
crw-r—– 1 root root 13, 72 May 11 21:18 event8
crw-r—– 1 root root 13, 73 May 11 21:18 event9
crw-r–r– 1 root root 13, 0 May 11 21:18 js0
crw-r—– 1 root root 13, 63 May 11 21:18 mice
crw-r—– 1 root root 13, 32 May 11 21:18 mouse0
So, I guess the better question would be how to determine which event device is theone that controls the active keyboard (there is usually only going to be one). Otherwise, this program is useful, but in a very restrictive, unportable way.
July 14th, 2016 at 5:45 pm
Probably waay late for Jamie above but if you look in /dev/input/by-id you’ll see links from the name of the device (my keyboard ends in -kbd) to the /dev/input/event? device file. You can probably control this with udev rules if you need to go that far…
January 18th, 2017 at 1:56 pm
I wrote a simple game in ncurses/c++ and I want to improve the input. Right now the program accepts input from only one key at a time, so it will only detect either up, down, left, or right, so the character will only move north, south, west, or east. I want it to detect when 2 arrow keys are pressed simultaneously so that the character will also know when to move north-west, north-east, south-west, and south-east. Can you help?
January 19th, 2017 at 9:44 am
Sounds like fun! Unfortunately, it’s been so long I wouldn’t be much help here. Maybe bring it over to stackoverflow? Or possibly another reader will be able to answer your question. Good luck!
January 19th, 2017 at 2:06 pm
I tried. So far no luck in getting answers.
Also I tried running your code from the above post and it fails to read any of the inputs.
October 13th, 2017 at 4:21 am
Hi,
The code above did not work for me initially (it never wrote anything to the screen), and as it turns out, the problem was that the \n (escape n) new line feed was missing all the backslashes
for example:
printf (“nexiting…(%d)n”, sig);
changing this to printf (“\nexiting…(%d)\n”, sig);
– and all the subsequent n-s to \n solved the problem.
November 10th, 2017 at 1:53 pm
Hi guys, the above comment is right. This code does not work. The only input I was able to get was: sudo cat /dev/input/mouse0 Three days nothing from keyboard and now nobody knows why but keyboard gives output. Strange behaviour of computers these days… Ubuntu Linux
Who Linked To This Post?
Share your thoughts, leave a comment!