huion-keys/huion_keys.py
2020-10-29 15:22:59 -07:00

138 lines
4.2 KiB
Python

import os
from _xdo_cffi import ffi, lib
BUTTON_BINDINGS = [
# left side, top to bottom
None,
None,
None,
None,
None,
None,
None,
None,
# right side, top to bottom
None,
None,
None,
None,
None,
None,
None,
None,
# scroll strip, up/down
# even though the Kamvas 22 (2019) has two scroll strips, they both send
# the same button codes
None,
None,
]
def main():
xdo = lib.xdo_new(ffi.NULL)
hidraw_path = get_tablet_hidraw('256c', '006e')
if hidraw_path is None:
print("Could not find tablet hidraw device")
print("Found tablet at " + hidraw_path)
read_config(os.path.expanduser('~/.config/huion_keys.conf'))
hidraw = open(hidraw_path, 'rb')
while True:
btn = get_button_press(hidraw)
print("Got button %d" % (btn,))
if BUTTON_BINDINGS[btn]:
print("Sending %s" % (BUTTON_BINDINGS[btn],))
lib.xdo_send_keysequence_window(
xdo, lib.CURRENTWINDOW, BUTTON_BINDINGS[btn], 10)
def get_tablet_hidraw(vendor_id, product_id):
"""Finds the /dev/hidrawX file that belongs to the given vendor and product ID."""
# TODO: is this too fragile?
hidraws = os.listdir('/sys/class/hidraw')
for h in hidraws:
device_path = os.readlink(os.path.join('/sys/class/hidraw', h, 'device'))
if ("%s:%s" % (vendor_id.upper(), product_id.upper())) in device_path:
# need to confirm that there's "input" because there are two hidraw
# files listed for the tablet, but only one of them carries the
# mouse/keyboard input
if os.path.exists(os.path.join('/sys/class/hidraw', h, 'device/input')):
return os.path.join('/dev', os.path.basename(h))
return None
def read_config(config_file):
with open(config_file, 'r') as config:
for line in config.readlines():
# strip out any comment
if line.find('#') > -1:
line = line[:line.find('#')]
if line.find('='):
setting = line[:line.find('=')].strip()
value = line[line.find('=')+1:].strip()
if setting.isdigit():
# button bindings are 0-indexed so need to subtract one
BUTTON_BINDINGS[int(setting)-1] = value.encode('utf-8')
elif setting == 'scroll_up':
BUTTON_BINDINGS[16] = value.encode('utf-8')
elif setting == 'scroll_down':
BUTTON_BINDINGS[17] = value.encode('utf-8')
else:
print("[WARN] unrecognized setting '%s'" % (setting,))
BUTTON_BITS = {
0x01: 0,
0x02: 1,
0x04: 2,
0x08: 3,
0x10: 4,
0x20: 5,
0x40: 6,
0x80: 7,
}
SCROLL_STATE=None
def get_button_press(hidraw):
global SCROLL_STATE
while True:
sequence = hidraw.read(12)
# don't think there's anything we care about that doesn't start with 0xf7
if sequence[0] != 0xf7:
pass
if sequence[1] == 0xe0: # buttons
# doesn't seem like the tablet will let you push two buttons at once
if sequence[4] > 0:
return BUTTON_BITS[sequence[4]]
elif sequence[5] > 0:
# right-side buttons are 8-15, so add 8
return BUTTON_BITS[sequence[5]] + 8
else:
# must be button release (all zeros)
continue
elif sequence[1] == 0xf0: # scroll strip
scroll_pos = sequence[5]
if scroll_pos == 0:
# reset scroll state after lifting finger off scroll strip
SCROLL_STATE = None
elif SCROLL_STATE is not None:
# scroll strip is numbered from top to bottom so a greater new
# value means they scrolled down
if scroll_pos > SCROLL_STATE:
SCROLL_STATE = scroll_pos
return 17 # scroll down
elif scroll_pos < SCROLL_STATE:
SCROLL_STATE = scroll_pos
return 16
else:
SCROLL_STATE = scroll_pos
continue
if __name__ == "__main__":
main()