title: Accessing Keys from Linux Input Device
body: <h2>What I am trying to do</h2>
  
  <p>So, I have been trying to access keyboard input in Linux. Specifically, I need to be able to access modifier key presses <strong>without</strong> other keys being pressed. Furthermore, I want to be able to do this <strong>without</strong> an X system running.</p>
  
  <p>So, in short, my requirements are these:</p>
  
  <ul>
  <li>Works on Linux</li>
  <li>Does not need X11</li>
  <li>Can retrieve modifier key press <strong>without</strong> any other keys being pressed
  
  <ul>
  <li>This includes the following keys:
  
  <ul>
  <li>Shift</li>
  <li>Control</li>
  <li>Alt</li>
  </ul></li>
  <li>All I need is a simple <code>0 = not pressed</code>, <code>1 = currently pressed</code> to let me know if
  the key is being held down when the keyboard is checked</li>
  </ul></li>
  </ul>
  
  <h2>My computer setup</h2>
  
  <p>My normal Linux machine is on a truck towards my new apartment; so, I only have a Macbook Air to work with right now. Therefore, I am running Linux in a VM to test this out.</p>
  
  <p><strong>Virtual Machine in VirtualBox</strong></p>
  
  <ul>
  <li>OS: Linux Mint 16</li>
  <li>Desktop Environment: XFCE</li>
  </ul>
  
  <p>Everything below was done in this environment. I've tried both with X running and in one of the other ttys.</p>
  
  <h2>My Thoughts</h2>
  
  <p>I'll alter this if someone can correct me.</p>
  
  <p>I've done a fair bit of reading to realize that higher-level libraries do not provide this kind of functionality. Modifier keys are used with other keys to provide an alternate key code. Accessing the modifier keys themselves through a high-level library in Linux isn't as easy. Or, rather, I haven't found a high-level API for this on Linux. </p>
  
  <p>I thought <a href="http://www.leonerd.org.uk/code/libtermkey/" rel="noreferrer" title="Link to the library">libtermkey</a> would be the answer, but it doesn't seem to support the Shift modifier key any better than normal keystroke retrieval. I'm also not sure if it works without X.</p>
  
  <p>While working with libtermkey (before I realized it didn't get shift in cases like Shift-Return), I was planning to write a daemon that would run to gather keyboard events. Running copies of the daemon program would simply pipe requests for keyboard data and receive keyboard data in response. I could use this setup to have something always running in the background, in case I cannot check key code statuses at specific times (have to be receive key codes as they happen).</p>
  
  <p>Below are my two attempts to write a program that can read from the Linux keyboard device. I've also included my small check to make sure I had the right device.</p>
  
  <h2>Attempt #1</h2>
  
  <p>I have tried to access the keyboard device directly, but am encountering issues. I have tried the suggestion <a href="https://stackoverflow.com/a/4225290" title="Stack Overflow suggestion">here</a> that is in another Stack Overflow thread. It gave me a segmentation fault; so, I changed it from fopen to open:</p>
  
  <pre><code>// ...
  
  int fd;
  fd = open("/dev/input/by-path/platform-i8042-serio-0-event-kbd", O_RDONLY);
  
  char key_map[KEY_MAX/8 + 1];
  
  memset(key_map, 0, sizeof(key_map));
  ioctl(fd, EVIOCGKEY(sizeof key_map), key_map);
  
  // ...
  </code></pre>
  
  <p>While there was no segmentation fault, there was no indicator of any key press (not just modifier keys). I tested this using:</p>
  
  <pre><code>./foo &amp;&amp; echo "TRUE" || echo "FALSE"
  </code></pre>
  
  <p>I've used that to test for successful return codes from commands quite a lot; so, I know that's fine. I've also outputted the key (always 0) and mask (0100) to check. It just doesn't seem to detect anything.</p>
  
  <h2>Attempt #2</h2>
  
  <p>From here, I thought I'd try a slightly different approach. I wanted to figure out what I was doing wrong. Following <a href="http://baruch.siach.name/blog/posts/linux_input_keys_status/" rel="noreferrer" title="Linux Input Key Status">this</a> page providing a snippet demonstrating printing out key codes, I bundled that into a program:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;string.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;linux/input.h&gt;
  
  int main(int argc, char** argv) {
      uint8_t keys[128];
      int fd;
  
      fd = open("/dev/input/by-path/platform-i8042-serio-event-kbd", O_RDONLY);
      for (;;) {
          memset(keys, 0, 128);
          ioctl (fd, EVIOCGKEY(sizeof keys), keys);
  
          int i, j;
          for (i = 0; i &lt; sizeof keys; i++)
              for (j = 0; j &lt; 8; j++)
                  if (keys[i] &amp; (1 &lt;&lt; j))
                      printf ("key code %d\n", (i*8) + j);
      }
  
      return 0;
  }
  </code></pre>
  
  <p>Previously, I had the size to 16 bytes instead of 128 bytes. I should honestly spend a bit more time understanding ioctl and EVIOCGKEY. I just know that it supposedly maps bits to specific keys to indicate presses, or something like that (<strong>correct me if I'm wrong, please!</strong>).</p>
  
  <p>I also didn't have a loop initially and would just hold down various keys to see if a key code appeared. I received nothing; so, I thought a loop might make the check easier to test in case a missed something.</p>
  
  <h2>How I know the input device is the right one</h2>
  
  <p>I tested it by running <code>cat</code> on the input device. Specifically:</p>
  
  <pre><code>$ sudo cat /dev/input/by-path/platform-i8042-serio-0-event-kbd
  </code></pre>
  
  <p>Garbage ASCII was sent to my terminal on key press and release events starting with the return (enter) key when I began the output using cat. I also know that this seems to work fine with modifier keys like shift, control, function, and even Apple's command key on my Macbook running a Linux VM. Output appeared when a key was pressed, began to appear rapidly from subsequent signals sent by holding the key down, and outputted more data when a key was released.</p>
  
  <p>So, while my approach may not be the right one (I'm willing to hear <strong>any</strong> alternative), the device seems to provide what I need.</p>
  
  <p>Furthermore, I know that this device is just a link pointing to /dev/input/event2 from running:</p>
  
  <pre><code>$ ls -l /dev/input/by-path/platform-i8042-serio-0-event-kbd
  </code></pre>
  
  <p>I've tried both programs above with /dev/input/event2 and received no data. Running cat on /dev/input/event2 provided the same output as with the link.</p>