Skip to content

Instantly share code, notes, and snippets.

@HeroBrine1st
Last active April 7, 2021 00:08
Show Gist options
  • Save HeroBrine1st/bfbb4d6ff3300ffe727418080f07663b to your computer and use it in GitHub Desktop.
Save HeroBrine1st/bfbb4d6ff3300ffe727418080f07663b to your computer and use it in GitHub Desktop.
Python script for pretending your tablet as wacom tablet on linux (because all distros can handle any tablet, but instead they handle only wacom)
from errno import ENODEV
from typing import Optional
import evdev
# Сокрытие в питоне..
# noinspection PyProtectedMember
from evdev import InputDevice, UInput, _uinput, ecodes, _input
from evdev.ecodes import EV_ABS
from pyudev import Monitor, Context
# Классы сука с большой буквы нахуй ВСЕГДА
# (кроме примитивов, но те не классы)
from select import epoll as Epoll, EPOLLIN
#### DON'T FORGET TO CHANGE IT ####
vendor_id = 0x28bd
product_id = 0x0094
name = "XP-PEN STAR G640 Pen"
###################################
target_vendor_id = 0x056a
target_product_id = 0x00D4
epoll = Epoll()
monitor: Monitor = Monitor.from_netlink(Context())
device: Optional[InputDevice] = None
device_fd: Optional[int] = None
uinput: Optional[UInput] = None
uinput_fd: Optional[int] = None
monitor.filter_by("input")
epoll.register(monitor, EPOLLIN)
def register_device(path: str):
global device, uinput, device_fd, uinput_fd
if device is not None: return
candidate = InputDevice(path)
caps = candidate.capabilities()
if candidate.info.vendor == vendor_id and candidate.info.product == product_id and candidate.name == name\
and EV_ABS in caps and len(caps[EV_ABS]) >= 3:
print(f"Connected {candidate.name} ({candidate.path})")
device = candidate
device.grab()
uinput = UInput.from_device(device, vendor=target_vendor_id, product=target_product_id)
device_fd = device.fileno()
uinput_fd = uinput.fileno()
epoll.register(device.fileno(), EPOLLIN)
return True
def main():
global device, uinput, uinput_fd, device_fd
monitor.start()
for path in evdev.list_devices():
if register_device(path): break
while True:
events = epoll.poll()
for (fd, _) in events:
# print(fd, monitor.fileno(), device and device.fd)
if device is not None and fd is device_fd:
# Используем процедурщину для максимальной производительности
try:
# event = device.read_one()
event = _input.device_read(device_fd)
# print(event)
_uinput.write(uinput_fd, event[2], event[3], event[4])
# _uinput.write(uinput_fd, ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
except OSError as e:
if e.errno == ENODEV:
# Device disconnected, signal dispatched - monitor will close device
pass
else:
raise
elif fd is monitor.fileno():
source = monitor.poll()
action = source.action
if action == "add" and device is None:
if source.device_node and source.device_node.startswith("/dev/input/event"):
register_device(source.device_node)
elif action == "remove" and device is not None:
if source.device_node == device.path:
print("Device disconnected")
# Мне блять 4 проверки писать?
# noinspection PyTypeChecker
epoll.unregister(device_fd)
device.close()
# И тут тоже, видите ли uinput = None значит код выше не будет работать
# noinspection PyUnresolvedReferences
uinput.close()
device = None
uinput = None
uinput_fd = None
device_fd = None
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print("Exit")
finally:
if device is not None: device.close()
if uinput is not None: uinput.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment