hedgehog/software/ RawLinuxEventsToOsc001


Trackball/Mouse

This needs to be run as root. Arguments are of the form t:/dev/input/eventXX where t is either k for keyboard or m for mouse. e.g.

sudo ./input_to_osc.py m:/dev/input/event16

The code

#!/usr/bin/env python
import struct
import time
import sys
import os
from glob import glob
from threading import Thread
from pythonosc import udp_client # python -m pip install python-osc

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)

class InputToOsc:
  def __init__(self,host,port,inputdev):
    self.host = host
    self.port = port
    self.inputdev = inputdev
    self.client = udp_client.SimpleUDPClient(host,port)
    self.thread = None
  def start(self):
    self.thread = Thread(target=self.listen0,args=())
    self.thread.start()
  def listen0(self):
    try:
      self.listen1()
    except KeyboardInterrupt:
      print("Ctrl-C")
      exit(0)
  def listen1(self):
    FORMAT = 'llHHI'
    EVENT_SIZE = struct.calcsize(FORMAT)

    #open file in binary mode
    try:
      in_file = open(self.inputdev, "rb")
    except PermissionError:
      print(f"Permission error with: {self.inputdev} (do we need to run as root?)")
      exit(1)

    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:
        self.handle(ty,code,value,tv_sec,tv_usec)
      else:
        self.sep()

      event = in_file.read(EVENT_SIZE)

    in_file.close()
  def sep(self):
    print("===========================================")
  def send(self,addr,args):
    self.client.send_message(addr,args)
  def handle(self,ty,code,value,tv_sec,tv_usec):
    print(f"Input event from {self.inputdev}: type={ty} {code=} {value=} {tv_sec=} {tv_usec=}")

class KeyboardToOsc(InputToOsc):
  def handle(self,ty,code,value,tv_sec,tv_usec):
    print(f"Keyboard input event from {self.inputdev}: type={ty} {code=} {value=} {tv_sec=} {tv_usec=}")

class MouseToOsc(InputToOsc):
  def handle(self,ty,code,value,tv_sec,tv_usec):
    print(f"Mouse input event from {self.inputdev}: type={ty} {code=} {value=} {tv_sec=} {tv_usec=}")
    if ty == 2:
      if value >= 2**31:
        value -= 2**32 # uint to int
      self.send(f"/hh/a/mouse/0/axis/{code}/dx",(value,))

type_to_class = {
  "k": KeyboardToOsc,
  "m": MouseToOsc
}

def main():
  listeners = {}
  host = os.getenv('host','turnipland')
  port = int(os.getenv('port',9999))
  args = sys.argv[1:]
  nodes = {}
  for arg in args:
    t,n = arg.split(":",1)
    nodes[n] = t
  for n,t in nodes.items():
    if not t in type_to_class:
      print(f"Unknown input type: {t}")
      exit(1)
    c = type_to_class[t]
    x = c(host,port,n)
    listeners[n] = x
    x.start()

if __name__ == "__main__":
  main()