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)

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:

There's 29 Comments So Far

  • Adam Marchetti
    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.

  • [email protected]
    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. πŸ˜‰

  • Adam Marchetti
    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”

  • Helmik
    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));

  • [email protected]
    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!

  • Michael Gardner
    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!

  • matt
    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) ?

  • matt
    February 9th, 2011 at 1:53 pm

    hum found πŸ™‚ sorry πŸ™‚

  • dima
    February 15th, 2011 at 5:03 am

    Thank you for this good example!

  • mathio
    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.

  • Devesh Yamparala
    October 24th, 2011 at 6:40 am

    Thanks man. It was really helpful πŸ™‚

  • Gabriel Duarte
    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 πŸ™‚

  • ribamar
    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).

  • Darmawan
    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 :-).

  • Mike Robinson
    February 6th, 2013 at 10:00 am

    Using this as a base for getting a cuecat working on a raspberry pi. thanks!


  • Rob
    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!


  • Matthew
    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?

  • jamie
    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.

  • ivan
    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…

  • Lestibournes
    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?

  • Derek Hildreth
    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!

  • Lestibournes
    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.

  • Winger
    October 13th, 2017 at 4:21 am


    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.

  • lesna.vevericka
    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?

  1. keypad interfacing
  2. DD WRT Asus WL500gp v1 USB keyboard | Y12 Studio
  3. Note: QuickLaunch/User defined button for Android « 鑘~~
  4. http www thelinuxdaily com 2010 05 grab raw… « μ•ˆλ“œλ‘œμ΄λ“œ ν”„λ ˆμž„μ›Œν¬ 뢄석
  5. Keyloggers, showkey e Capturando Eventos do Teclado via /dev/input/eventX | Daemonio Labs

Share your thoughts, leave a comment!