diff --git a/remarkable_mouse/evdev.py b/remarkable_mouse/evdev.py index 5e2c793..24709d3 100644 --- a/remarkable_mouse/evdev.py +++ b/remarkable_mouse/evdev.py @@ -1,5 +1,8 @@ import logging import struct +import subprocess +from screeninfo import get_monitors +import time logging.basicConfig(format='%(message)s') log = logging.getLogger(__name__) @@ -24,6 +27,7 @@ def create_local_device(): # Set device properties to emulate those of Wacom tablets device.name = 'reMarkable tablet' + device.id = { 'bustype': 0x18, # i2c 'vendor': 0x056a, # wacom @@ -85,6 +89,28 @@ def create_local_device(): return device.create_uinput_device() +# remap screen coordinates to wacom coordinates +def remap(x, y, wacom_width, wacom_height, monitor_width, + monitor_height, mode, orientation=None): + + if orientation in ('bottom', 'top'): + x, y = y, x + monitor_width, monitor_height = monitor_height, monitor_width + + ratio_width, ratio_height = wacom_width / monitor_width, wacom_height / monitor_height + + if mode == 'fit': + scaling = max(ratio_width, ratio_height) + elif mode == 'fill': + scaling = min(ratio_width, ratio_height) + else: + raise NotImplementedError + + return ( + scaling * (x - (monitor_width - wacom_width / scaling) / 2), + scaling * (y - (monitor_height - wacom_height / scaling) / 2) + ) + def pipe_device(args, remote_device, local_device): """ Pipe events from a remote device to a local device. @@ -94,7 +120,65 @@ def pipe_device(args, remote_device, local_device): remote_device (paramiko.ChannelFile): read-only stream of input events local_device: local virtual input device to write events to """ + + # give time for virtual device creation before running xinput commands + time.sleep(1) + + # set orientation with xinput + orientation = {'left': 0, 'bottom': 1, 'top': 2, 'right': 3}[args.orientation] + result = subprocess.run( + 'xinput --set-prop "reMarkable tablet stylus" "Wacom Rotation" {}'.format(orientation), + capture_output=True, + shell=True + ) + if result.returncode != 0: + log.warning("Error setting orientation: %s", result.stderr) + + # set monitor to use + monitor = get_monitors()[args.monitor] + log.debug('Chose monitor: {}'.format(monitor)) + result = subprocess.run( + 'xinput --map-to-output "reMarkable tablet stylus" {}'.format(monitor.name), + capture_output=True, + shell=True + ) + if result.returncode != 0: + log.warning("Error setting monitor: %s", result.stderr) + + # set stylus pressure + result = subprocess.run( + 'xinput --set-prop "reMarkable tablet stylus" "Wacom Pressure Threshold" {}'.format(args.threshold), + capture_output=True, + shell=True + ) + if result.returncode != 0: + log.warning("Error setting pressure threshold: %s", result.stderr) + + # set fitting mode + min_x, min_y = remap( + 0, 0, + MAX_ABS_X, MAX_ABS_Y, monitor.width, monitor.height, + args.mode, + args.orientation + ) + max_x, max_y = remap( + monitor.width, monitor.height, + MAX_ABS_X, MAX_ABS_Y, monitor.width, monitor.height, + args.mode, + args.orientation + ) + log.debug("Wacom tablet area: {} {} {} {}".format(min_x, min_y, max_x, max_y)) + result = subprocess.run( + 'xinput --set-prop "reMarkable tablet stylus" "Wacom Tablet Area" \ + {} {} {} {}'.format(min_x, min_y, max_x, max_y), + capture_output=True, + shell=True + ) + if result.returncode != 0: + log.warning("Error setting fit: %s", result.stderr) + import libevdev + # While debug mode is active, we log events grouped together between # SYN_REPORT events. Pending events for the next log are stored here pending_events = [] diff --git a/remarkable_mouse/pynput.py b/remarkable_mouse/pynput.py index 4f300bc..0d91a33 100644 --- a/remarkable_mouse/pynput.py +++ b/remarkable_mouse/pynput.py @@ -27,8 +27,9 @@ wacom_height = 20967 # finger_height = 1023 -# remap wacom coordinates in various orientations -def remap(x, y, wacom_width, wacom_height, monitor_width, monitor_height, mode, orientation=None): +# remap wacom coordinates to screen coordinates +def remap(x, y, wacom_width, wacom_height, monitor_width, + monitor_height, mode, orientation): if orientation == 'bottom': y = wacom_height - y @@ -43,9 +44,9 @@ def remap(x, y, wacom_width, wacom_height, monitor_width, monitor_height, mode, ratio_width, ratio_height = monitor_width / wacom_width, monitor_height / wacom_height - if mode == 'fit': + if mode == 'fill': scaling = max(ratio_width, ratio_height) - elif mode == 'fill': + elif mode == 'fit': scaling = min(ratio_width, ratio_height) else: raise NotImplementedError diff --git a/remarkable_mouse/remarkable_mouse.py b/remarkable_mouse/remarkable_mouse.py index 540f838..f5225d3 100755 --- a/remarkable_mouse/remarkable_mouse.py +++ b/remarkable_mouse/remarkable_mouse.py @@ -84,11 +84,11 @@ def main(): parser.add_argument('--key', type=str, metavar='PATH', help="ssh private key") parser.add_argument('--password', default=None, type=str, help="ssh password") parser.add_argument('--address', default='10.11.99.1', type=str, help="device address") - parser.add_argument('--mode', default='fit', choices=['fit', 'fill']) + parser.add_argument('--mode', default='fit', choices=['fit', 'fill'], help="scale setting") parser.add_argument('--orientation', default='right', choices=['top', 'left', 'right', 'bottom'], help="position of tablet buttons") - parser.add_argument('--monitor', default=0, type=int, metavar='NUM', help="monitor to use") - parser.add_argument('--threshold', default=1000, type=int, help="stylus pressure threshold (default 1000)") - parser.add_argument('--evdev', action='store_true', default=False, help="use evdev to support pen tilt (requires root, no OSX support)") + parser.add_argument('--monitor', default=0, type=int, metavar='NUM', help="monitor to output to") + parser.add_argument('--threshold', metavar='THRESH', default=600, type=int, help="stylus pressure threshold (default 600)") + parser.add_argument('--evdev', action='store_true', default=False, help="use evdev to support pen pressure (requires root, Linux only)") args = parser.parse_args()