Browse Source

Add GUI to position target range, and stretch mode (#55)

* Add stretch mode

* Update readme with stretch mode

* Add rect gui

* readme update

* shuffle some code around, rename to --region

Co-authored-by: evan <evan@evanw.org>
master
Daniel Melcer 3 years ago committed by GitHub
parent
commit
24ca4f6fc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      README.md
  2. 67
      remarkable_mouse/common.py
  3. 22
      remarkable_mouse/pynput.py
  4. 11
      remarkable_mouse/remarkable_mouse.py

20
README.md

@ -15,7 +15,9 @@ pip install remarkable-mouse
remouse remouse
``` ```
By default, `10.11.99.1` is used as the address. Seems to work pretty well wirelessly, too. By default ssh-agent is used to authenticate if it is available, otherwise you are asked for your password. Find your password in the reMarkable's [settings menu](https://remarkablewiki.com/tech/ssh). By default, `10.11.99.1` is used as the address. Find your password in the reMarkable's [settings menu](https://remarkablewiki.com/tech/ssh). If you are on Linux using X11, you can use the `--evdev` option for pressure support.
To use the `--region` flag, you may need to install the `python3-tk` or `python3-tkinter` package with your package manager.
# Examples # Examples
@ -34,10 +36,9 @@ remouse --key ~/.ssh/remarkable
# Usage # Usage
usage: remouse [-h] [--debug] [--key PATH] [--password PASSWORD] ```
[--address ADDRESS] [--mode {fit,fill}] usage: remouse [-h] [--debug] [--key PATH] [--password PASSWORD] [--address ADDRESS] [--mode {fit,fill,stretch}] [--orientation {top,left,right,bottom}] [--monitor NUM] [--region] [--threshold THRESH]
[--orientation {top,left,right,bottom}] [--monitor NUM] [--evdev]
[--threshold THRESH] [--evdev]
use reMarkable tablet as a mouse input use reMarkable tablet as a mouse input
@ -47,10 +48,13 @@ remouse --key ~/.ssh/remarkable
--key PATH ssh private key --key PATH ssh private key
--password PASSWORD ssh password --password PASSWORD ssh password
--address ADDRESS device address --address ADDRESS device address
--mode {fit,fill} scale setting --mode {fit,fill,stretch}
Scale setting. Fit (default): take up the entire tablet, but not necessarily the entire monitor. Fill: take up the entire monitor, but not necessarily the entire tablet. Stretch:
take up both the entire tablet and monitor, but don't maintain aspect ratio.
--orientation {top,left,right,bottom} --orientation {top,left,right,bottom}
position of tablet buttons position of tablet buttons
--monitor NUM monitor to output to --monitor NUM monitor to output to
--region Use a GUI to position the output area. Overrides --monitor
--threshold THRESH stylus pressure threshold (default 600) --threshold THRESH stylus pressure threshold (default 600)
--evdev use evdev to support pen pressure (requires root, --evdev use evdev to support pen pressure (requires root, Linux only)
Linux only) ```

67
remarkable_mouse/common.py

@ -0,0 +1,67 @@
#!/usr/bin/env python
import logging
import sys
from screeninfo import get_monitors, Monitor
logging.basicConfig(format='%(message)s')
log = logging.getLogger('remouse')
# get info of where we want to map the tablet to
def get_monitor(region, monitor_num, orientation):
if region is not None:
monitor = get_region(orientation)
else:
monitor = get_monitors()[monitor_num]
return monitor
# Pop up a window, ask the user to move the window, and then get the position of the window's contents
def get_region(orientation):
try:
import tkinter as tk
from tkinter import ttk
except ImportError:
print(
"Unable to import tkinter; please follow the instructions at https://tkdocs.com/tutorial/install.html to install it")
sys.exit(1)
window = tk.Tk()
# A bit of an ugly hack to get this function to run synchronously
# Ideally would use full async support, but this solution required minimal changes to rest of code
selected_pos = None
def on_click():
nonlocal selected_pos
selected_pos = Monitor(
window.winfo_x(),
window.winfo_y(),
window.winfo_width(),
window.winfo_height(),
name="Fake monitor from region selection"
)
window.destroy()
confirm = ttk.Button(window, text="Drag and resize this button to the desired mouse range, then click",
command=on_click)
confirm.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
window.columnconfigure(0, weight=1)
window.rowconfigure(0, weight=1)
window.attributes('-alpha', 0.5)
window.title("Remarkable Mouse")
if orientation == 'bottom' or orientation == 'top':
window.geometry("702x936")
else:
window.geometry("936x702")
window.mainloop()
if selected_pos is None:
log.debug("Window closed without giving mouse range")
sys.exit(1)
return selected_pos

22
remarkable_mouse/pynput.py

@ -2,6 +2,8 @@ import logging
import struct import struct
from screeninfo import get_monitors from screeninfo import get_monitors
from .common import get_monitor
logging.basicConfig(format='%(message)s') logging.basicConfig(format='%(message)s')
log = logging.getLogger('remouse') log = logging.getLogger('remouse')
@ -45,26 +47,32 @@ def remap(x, y, wacom_width, wacom_height, monitor_width,
ratio_width, ratio_height = monitor_width / wacom_width, monitor_height / wacom_height ratio_width, ratio_height = monitor_width / wacom_width, monitor_height / wacom_height
if mode == 'fill': if mode == 'fill':
scaling = max(ratio_width, ratio_height) scaling_x = max(ratio_width, ratio_height)
scaling_y = scaling_x
elif mode == 'fit': elif mode == 'fit':
scaling = min(ratio_width, ratio_height) scaling_x = min(ratio_width, ratio_height)
scaling_y = scaling_x
elif mode == 'stretch':
scaling_x = ratio_width
scaling_y = ratio_height
else: else:
raise NotImplementedError raise NotImplementedError
return ( return (
scaling * (x - (wacom_width - monitor_width / scaling) / 2), scaling_x * (x - (wacom_width - monitor_width / scaling_x) / 2),
scaling * (y - (wacom_height - monitor_height / scaling) / 2) scaling_y * (y - (wacom_height - monitor_height / scaling_y) / 2)
) )
def read_tablet(rm_inputs, *, orientation, monitor, threshold, mode): def read_tablet(rm_inputs, *, orientation, monitor_num, region, threshold, mode):
"""Loop forever and map evdev events to mouse """Loop forever and map evdev events to mouse
Args: Args:
rm_inputs (dictionary of paramiko.ChannelFile): dict of pen, button rm_inputs (dictionary of paramiko.ChannelFile): dict of pen, button
and touch input streams and touch input streams
orientation (str): tablet orientation orientation (str): tablet orientation
monitor (int): monitor number to map to monitor_num (int): monitor number to map to
region (boolean): whether to selection mapping region with region tool
threshold (int): pressure threshold threshold (int): pressure threshold
mode (str): mapping mode mode (str): mapping mode
""" """
@ -76,7 +84,7 @@ def read_tablet(rm_inputs, *, orientation, monitor, threshold, mode):
mouse = Controller() mouse = Controller()
monitor = get_monitors()[monitor] monitor = get_monitor(monitor_num, region, orientation)
log.debug('Chose monitor: {}'.format(monitor)) log.debug('Chose monitor: {}'.format(monitor))
while True: while True:

11
remarkable_mouse/remarkable_mouse.py

@ -112,9 +112,13 @@ def main():
parser.add_argument('--key', type=str, metavar='PATH', help="ssh private key") 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('--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('--address', default='10.11.99.1', type=str, help="device address")
parser.add_argument('--mode', default='fill', choices=['fit', 'fill'], help="scale setting") parser.add_argument('--mode', default='fill', choices=['fit', 'fill', 'stretch'], help="""Scale setting.
parser.add_argument('--orientation', default='right', choices=['top', 'left', 'right', 'bottom'], help="position of charging port") Fit (default): take up the entire tablet, but not necessarily the entire monitor.
Fill: take up the entire monitor, but not necessarily the entire tablet.
Stretch: take up both the entire tablet and monitor, but don't maintain aspect ratio.""")
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 output to") parser.add_argument('--monitor', default=0, type=int, metavar='NUM', help="monitor to output to")
parser.add_argument('--region', action='store_true', default=False, help="Use a GUI to position the output area. Overrides --monitor")
parser.add_argument('--threshold', metavar='THRESH', default=600, type=int, help="stylus pressure threshold (default 600)") 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)") parser.add_argument('--evdev', action='store_true', default=False, help="use evdev to support pen pressure (requires root, Linux only)")
@ -146,7 +150,8 @@ def main():
read_tablet( read_tablet(
rm_inputs, rm_inputs,
orientation=args.orientation, orientation=args.orientation,
monitor=args.monitor, monitor_num=args.monitor,
region=args.region,
threshold=args.threshold, threshold=args.threshold,
mode=args.mode, mode=args.mode,
) )

Loading…
Cancel
Save