os/linux/ RawInput


How to work out which /dev/input is which

make a threaded python program which has one thread per input, and prints out an event along with the /dev/input/ node it came from.

Look in /dev/input/by-path

See stack exchange question So if you are running X11, you can do

$ xinput
⎡ Virtual core pointer                      id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad                id=13   [slave  pointer  (2)]
⎜   ↳ TPPS/2 IBM TrackPoint                     id=14   [slave  pointer  (2)]
⎣ Virtual core keyboard                     id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    ↳ Power Button                              id=6    [slave  keyboard (3)]
    ↳ Video Bus                                 id=7    [slave  keyboard (3)]
    ↳ Sleep Button                              id=8    [slave  keyboard (3)]
    ↳ Integrated Camera: Integrated C           id=11   [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard              id=12   [slave  keyboard (3)]
    ↳ ThinkPad Extra Buttons   
/sys/class/input -- symlinks to folders in /sys/devices, e.g.
/sys/class/input/input32 =>
  /sys/devices/pci0000:00/0000:00:1b.0/sound/card0/input36

See ExampleSysClassInput1

Event Codes

See https://www.kernel.org/doc/html/v4.13/input/event-codes.html

How to parse /dev/input/etc

See stack overflow question

See http://www.kernel.org/doc/Documentation/input/input.txt for documentation on the format.

struct input_event {
    struct timeval time;
    unsigned short type;
    unsigned short code;
    unsigned int value;
};

Python modules

evdev

#!/usr/bin/env python3
from evdev import InputDevice
from select import select
import sys

try:
  dev = InputDevice(sys.argv[1])
except IndexError:
  print(f"{sys.argv[0]} /dev/input/eventX")
  exit(1)

while True:
   r,w,x = select([dev], [], [])
   for event in dev.read():
       print(event)

# event at 1337427573.061822, code 01, type 02, val 01
# event at 1337427573.061846, code 00, type 00, val 00

Code

Sample /dev/input parser in Python

#!/usr/bin/python
import struct
import time
import sys

infile_path = "/dev/input/event" + (sys.argv[1] if len(sys.argv) > 1 else "0")

"""
FORMAT represents the format used by linux kernel input event struct
See https://github.com/torvalds/linux/blob/v5.5-rc5/include/uapi/linux/input.h#L28
Stands for: long int, long int, unsigned short, unsigned short, unsigned int
"""
FORMAT = 'llHHI'
EVENT_SIZE = struct.calcsize(FORMAT)

#open file in binary mode
in_file = open(infile_path, "rb")

event = in_file.read(EVENT_SIZE)

while event:
    (tv_sec, tv_usec, type, code, value) = struct.unpack(FORMAT, event)

    if type != 0 or code != 0 or value != 0:
        print("Event type %u, code %u, value %u at %d.%d" % \
            (type, code, value, tv_sec, tv_usec))
    else:
        # Events with code, type and value == 0 are "separator" events
        print("===========================================")

    event = in_file.read(EVENT_SIZE)

in_file.close()

Threaded Event Listener

See here for more on threading.

#!/usr/bin/python
import struct
import time
import sys
from glob import glob
from threading import Thread

import socket
def send_message(host,port,message):
  with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as s:
    s.connect(("localhost",4005))
    s.send(message)

def main():
  threads = {}
  args = sys.argv[1:]
  if len(args) > 0:
    nodes = []
    for arg in args:
      if arg.isnumeric():
        nodes.append(f"/dev/input/event{arg}")
      elif "/" in arg:
        nodes.append(arg)
      else:
        nodes.append(f"/dev/input/{arg}")
  else:
    nodes = glob("/dev/input/event*")+glob("/dev/input/mouse*")+glob("/dev/input/mice")
  print(nodes)
  for node in nodes:
    print(node)
    threads[node] = start_thread(node)

def start_thread(node):
  print(node)
  thread = Thread(target=listen,args=(node,))
  thread.start()
  return thread

def listen(node):
  try:
    listen1(node)
  except KeyboardInterrupt:
    print("Ctrl-C")
    exit(0)

def listen1(node):
  """
  FORMAT represents the format used by linux kernel input event struct
  See https://github.com/torvalds/linux/blob/v5.5-rc5/include/uapi/linux/input.h#L28
  Stands for: long int, long int, unsigned short, unsigned short, unsigned int
  """
  FORMAT = 'llHHI'
  EVENT_SIZE = struct.calcsize(FORMAT)

  #open file in binary mode
  in_file = open(node, "rb")

  event = in_file.read(EVENT_SIZE)

  while event:
      (tv_sec, tv_usec, ty, code, value) = struct.unpack(FORMAT, event)

      if ty != 0 or code != 0 or value != 0:
          print("%s: Event type %u, code %u, value %u at %d.%d" % \
              (node, ty, code, value, tv_sec, tv_usec))
          msg = "%s,%u,%u,%u@%d.%d" % (node, ty, code, value, tv_sec, tv_usec)
      else:
          # Events with code, type and value == 0 are "separator" events
          print("===========================================")

      event = in_file.read(EVENT_SIZE)

  in_file.close()

if __name__ == "__main__":
  main()