mirror of
https://github.com/rfc2822/GfxTablet
synced 2025-10-03 17:49:17 +02:00
initial python app version
This commit is contained in:
parent
54140b9e10
commit
d77d486dd8
3 changed files with 122 additions and 0 deletions
118
python-app/main.py
Executable file
118
python-app/main.py
Executable file
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/env python3
|
||||
import subprocess
|
||||
import pyautogui
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
INTMAX = 65536
|
||||
WIDTH, HEIGHT = pyautogui.size()
|
||||
ASPECT_RATIOS = defaultdict(lambda: (16, 9))
|
||||
default_ratios = [
|
||||
("Galaxy Note 4", (16, 9)),
|
||||
]
|
||||
|
||||
|
||||
class Event:
|
||||
|
||||
def __str__(self):
|
||||
return "{}({})".format(
|
||||
self.__class__.__name__,
|
||||
', '.join(
|
||||
["{}={}".format(k, v) for k, v in self.__dict__.items()]))
|
||||
|
||||
|
||||
class PositionEvent(Event):
|
||||
"""Model of position events."""
|
||||
|
||||
def __init__(self, x, y, pressure):
|
||||
super().__init__()
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.pressure = pressure
|
||||
|
||||
|
||||
class ButtonEvent(Event):
|
||||
"""Model of button events."""
|
||||
|
||||
def __init__(self, button_id, button_status):
|
||||
super().__init__()
|
||||
self.id = button_id
|
||||
self.status = button_status
|
||||
|
||||
|
||||
class PositionManager:
|
||||
"""Model for handling relative vs. absolute movement and track button states."""
|
||||
|
||||
def __init__(self, device, aspect_ratio=None):
|
||||
if aspect_ratio is None:
|
||||
try:
|
||||
r = ASPECT_RATIOS[device]
|
||||
self.xscale = r[0] / r[1]
|
||||
except KeyError:
|
||||
raise ValueError("Sorry, that is an unsupported device.")
|
||||
self.last_pos_event = None
|
||||
self._deltas = [0, 0]
|
||||
# only track movement delta when btn id -1 state is 1
|
||||
self.button_states = defaultdict(lambda: 0)
|
||||
|
||||
def consume(self, event):
|
||||
if isinstance(event, PositionEvent):
|
||||
if self.last_pos_event is not None:
|
||||
# skip non-relative movement events
|
||||
if self.button_states.get(-1, None) == 1:
|
||||
self._deltas[0] = (
|
||||
event.x - self.last_pos_event.x) * self.xscale * HEIGHT / INTMAX
|
||||
self._deltas[1] = (
|
||||
event.y - self.last_pos_event.y) * HEIGHT / INTMAX
|
||||
self.last_pos_event = event
|
||||
elif isinstance(event, ButtonEvent):
|
||||
self.button_states[event.id] = event.status
|
||||
return tuple(self._deltas)
|
||||
|
||||
@property
|
||||
def deltas(self):
|
||||
return tuple(self._deltas)
|
||||
|
||||
|
||||
def process_line(l):
|
||||
if l.startswith("."):
|
||||
return PositionEvent(*[int(i.split(":")[1].strip()) for i in l.split(",")])
|
||||
elif l.startswith("sent button"):
|
||||
ss = l.split(":")[1].strip()
|
||||
return ButtonEvent(*[int(i.strip()) for i in ss.split(",")])
|
||||
else:
|
||||
raise ValueError("Invalid command string: {}".format(l))
|
||||
|
||||
|
||||
def main():
|
||||
# necessary to prevent pyautogui calls from causing unnecessary delays
|
||||
pyautogui.PAUSE = 0
|
||||
cmd = ["../driver-uinput/networktablet"]
|
||||
try:
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
except FileNotFoundError:
|
||||
print("ERROR: Did you build the binary?")
|
||||
quit()
|
||||
|
||||
movement_manager = PositionManager("Galaxy Note 4")
|
||||
while True:
|
||||
line = p.stdout.readline().decode("utf-8")
|
||||
if not line:
|
||||
break
|
||||
try:
|
||||
e = process_line(line)
|
||||
print(e)
|
||||
movement_manager.consume(e)
|
||||
dx, dy = movement_manager.deltas
|
||||
pyautogui.moveRel(dx, dy, 0)
|
||||
|
||||
if movement_manager.button_states.get(0, None) == 1:
|
||||
pyautogui.mouseDown(button="left")
|
||||
else:
|
||||
pyautogui.mouseUp(button="left")
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue