hedgehog/software/ RawLinuxEvents001


See here.

Floating XInputs

So that devices intended to be used as Hedgehogs don't generate normal input (i.e. if we want to use a trackball as a Hedgehog, we don't want it to also move the mouse pointer), we can float them. With X11 this is achieved using the xinput command. How this is done with Windows, Macos or Wayland is something I don't know at present.

To list devices

$ xinput
⎡ Virtual core pointer                          id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad                id=11   [slave  pointer  (2)]
⎜   ↳ TPPS/2 IBM TrackPoint                     id=12   [slave  pointer  (2)]
⎜   ↳ Kensington USB/PS2 Orbit                  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=9    [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard              id=10   [slave  keyboard (3)]
    ↳ ThinkPad Extra Buttons                    id=13   [slave  keyboard (3)]

To float e.g. the KensingtonOrbit with the above, note the line

⎜   ↳ Kensington USB/PS2 Orbit                  id=14   [slave  pointer  (2)]

from which we get the id=14 and use float via

xinput float 14

and to undo this we note id=2 from the xinput list the following

 Virtual core pointer                          id=2    [master pointer  (3)]

so to reattach we do

xinput reattach 14 2

Simple event listener

#!/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 = args
  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)
  try:
    for t in threads.values():
      t.join()
  except KeyboardInterrupt:
    print("Ctrl-C")
    exit(0)

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()