Самодельный «драйвер» для графического планшета GAOMON M106K для Linux на Python

Для графического планшета GAOMON M106K пару лет назад драйвера для Linux не было. Скорее всего, до сих пор нет. Поэтому пару лет назад написал для себя скрипт на Python, с помощью которого планшет у меня заработал в Ubuntu и Raspbian.

Сначала про подготовку к запуску скрипта. Нужно будет кое-что установить (под root`ом):

# apt-get install python3-pip && \
pip3 install --upgrade pip && \
pip3 install setuptools && \
pip3 install Xlib && \
pip3 install pyautogui

Библиотека pyautogui по умолчанию работает не очень (перемещение курсора дёрганое), поэтому нужно поправить в ней один файл (версия питона может отличаться):

# cp __init__.py /usr/local/lib/python3.4/dist-packages/pyautogui/__init__.py

После этого нужно проверить в скрипте planshet.py имя файла устройства (у меня он подключался под именем /dev/hidraw2) и запустить его под root`ом (иначе не будет прав на чтение из файла устройства).

Сам «драйвер» planshet.py:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# "driver" for GAOMON M106K by Maxim Kuznetsov http://kmsvsr.ru
# To install needed packages and modules run "install.sh" as superuser
# Don`t forget to replace or edit /usr/local/lib/python.../dist-packages/pyautogui/__init__.py before use
# "sudo ./planshet.py" to run. Sudo is for access to read from device /dev/hidraw0
# Works in Linux Mint 18

import time
import struct
import pyautogui   	#https://pyautogui.readthedocs.io/en/latest/mouse.html#the-mousedown-and-mouseup-functions

#init
f = open("/dev/hidraw2", "rb")
lm_pressed = False
rm_pressed = False
mm_pressed = False
last_move_time = int(round(time.time() * 1000))	

#endless cycle of reading data from device
while (True):
	data = f.read(8) # 8 is for my GAOMON M106K
	a = struct.unpack('HHHH',data)
	print("Buttons: " + hex(a[0]) + \
		"; X: " + hex(a[1]) +\
		"; Y: " + hex(a[2]) +\
		"; Press: " + hex(a[3]) 
		)
	#https://stackoverflow.com/questions/1181464/controlling-mouse-with-python
	current_time = int(round(time.time() * 1000))
	deadline_time = last_move_time + 15	
	if(deadline_time < current_time):
		x = a[1] * 1400 / 0x7fff
		y = a[2] * 1050 / 0x7fff
		buttons = a[0]
		press = a[3]
		pyautogui.moveTo(x, y)
		last_move_time = current_time
		
		#Left mouse button is touch by pen
		if(press > 0):
			if(not lm_pressed):
				pyautogui.mouseDown(button='left')
				lm_pressed = True
		else:
			if(lm_pressed):	
				pyautogui.mouseUp(button='left')
				lm_pressed = False

		#Right mouse button is touch by pen with bottom button on it
		if(buttons == 0xc20a):
			if(not rm_pressed):
				pyautogui.mouseDown(button='right')
				rm_pressed = True
		else:
			if(rm_pressed):	
				pyautogui.mouseUp(button='right')
				rm_pressed = False

		#Middle mouse button is touch by pen with top button on it
		if(buttons == 0xc40a):
			if(not mm_pressed):
				pyautogui.mouseDown(button='middle')
				mm_pressed = True
		else:
			if(mm_pressed):	
				pyautogui.mouseUp(button='middle')
				mm_pressed = False

f.close()

Весь «драйвер» получился чуть больше 50 строчек кода. Может быть кому-нибудь пригодится подключить так же другую модель планшета или ещё какое-нибудь необычное устройство ввода, для которого нет нормального драйвера под Linux.

Из недоделок: не работают кнопки на планшете, либо они подключаются другим устройством, либо через /dev вообще не доступны, лишку не разбирался.

Python: шапка скрипта для быстрой отладки и профилирования

# -*- coding: utf-8 -*-
import datetime
import sys

TIME_START = datetime.datetime.now()

def my_debug(txt):
    #print('%s - %s' % (datetime.datetime.now() - TIME_START, txt))
    pass
        
def my_info(txt):
    print('%s - %s' % (datetime.datetime.now() - TIME_START, txt))
    pass
        
        
my_info("Python")        
my_info("Начали") 

Python: цветной текст в консоли

Здесь предлагают импользовать 2 варианта.

Первый — использовать ansi. Здесь будет нужен какой-то справочник, чтобы с ними разобраться:

print('\033[96mКак поменять цвет?\033[0m')
print('Как поменять цвет ' + '\033[96mодного\033[0m' + ' слова?')

Второй способ — импортировать библиотеку colorama:

Type "help", "copyright", "credits" or "license" for more information.
>>> import colorama
>>> from colorama import Fore, Back
>>> colorama.init()
>>> print(Back.BLUE + Fore.GREEN + "text")
text
>>> quit()  

Попробовал — библиотеку в ubuntu отдельно устанавливать не пришлось, уже была в наличии. В использовании проще первого варианта.

Прохождение квеста по запуску OpenGL для Python3

Оказалось, что если просто взять и открыть первый попавшийся урок по OpenGL на Python, то скорее всего ничего не получится. Всё пробовал на Python 3.6.5 под Windows x64. Для начала. пробуем установать пакеты, которые используются в скриптах:

\Python36\python.exe -m pip install PyOpenGL
Collecting PyOpenGL
  Using cached PyOpenGL-3.1.5-py3-none-any.whl (2.4 MB)
Installing collected packages: PyOpenGL
Successfully installed PyOpenGL-3.1.5
\Python36\python.exe -m pip install PyOpenGL-accelerate
Collecting PyOpenGL-accelerate
  Using cached PyOpenGL_accelerate-3.1.5-cp36-cp36m-win_amd64.whl (329 kB)
Installing collected packages: PyOpenGL-accelerate
Successfully installed PyOpenGL-accelerate-3.1.5

Теперь попробуем выполнить скрипт из примеров примерно с таким содержимым:

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
...
glutInit()
...

Результат получится примерно такой:

\Python36\python.exe testopengl.py
Traceback (most recent call last):
  File "testopengl.py", line 30, in <module>
    glutInit()
  File "Python\Python36\lib\site-pac
kages\OpenGL\GLUT\special.py", line 333, in glutInit
    _base_glutInit( ctypes.byref(count), holder )
  File "Python\Python36\lib\site-pac
kages\OpenGL\platform\baseplatform.py", line 425, in __call__
    self.__name__, self.__name__,
OpenGL.error.NullFunctionError: Attempt to call an undefined function glutInit,
check for bool(glutInit) before calling

По советам из интернета скачиваем freeglut (качал отсюда https://www.transmissionzero.co.uk/files/software/development/GLUT/freeglut-MSVC-3.0.0-2.mp.zip), извлекаем оттуда и ложим рядом со скриптом файл freeglut.dll. Пробуем запустить скрипт снова — получаем ту же самую ошибку. В интернете пишут, что в стандартных пакетах питона какой-то касяк, поэтому их нужно удалить:

\Python36\python.exe -m pip uninstall pyopengl
Found existing installation: PyOpenGL 3.1.5
Uninstalling PyOpenGL-3.1.5:
  Would remove:
    python\python36\lib\site-package
s\opengl\*
    python\python36\lib\site-package
s\pyopengl-3.1.5.dist-info\*
Proceed (y/n)? y
  Successfully uninstalled PyOpenGL-3.1.5

\Python36\python.exe -m pip uninstall pyopengl-accelerate
Found existing installation: PyOpenGL-accelerate 3.1.5
Uninstalling PyOpenGL-accelerate-3.1.5:
  Would remove:
    python\python36\lib\site-package
s\opengl_accelerate\*
    python\python36\lib\site-package
s\pyopengl_accelerate-3.1.5.dist-info\*
Proceed (y/n)? y
  Successfully uninstalled PyOpenGL-accelerate-3.1.5

А теперь, говорят, надо скачивать альтернативные пакеты вот отсюда: https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopengl. Я схватился за самый свежий пакет PyOpenGL‑3.1.5‑cp39‑cp39‑win_amd64.whl, и он мне не подошёл:

\Python36\python.exe -m pip install PyOpenGL-3.1.5-cp39-cp39-win_amd64.whl
ERROR: PyOpenGL-3.1.5-cp39-cp39-win_amd64.whl is not a supported wheel on this p
latform.

Как я понял, в названии пакета 39 — это версия питона, для которого предназначен пакет, то есть мне для 3.6.5 нужны пакеты с цифрой 36:

\Python36\python.exe -m pip install PyOpenGL-3.1.5-cp36-cp36m-win_amd64.whl
Processing pyopengl-3.1.5-cp36-cp36m-win_amd64.whl
Installing collected packages: PyOpenGL
Successfully installed PyOpenGL-3.1.5

\Python36\python.exe -m pip install PyOpenGL_accelerate-3.1.5-cp36-cp36m-win_am
d64.whl
Processing pyopengl_accelerate-3.1.5-cp36-cp36m-win_amd64.whl
Installing collected packages: PyOpenGL-accelerate
Successfully installed PyOpenGL-accelerate-3.1.5

Ну и теперь пробуем запустить скрипт:

python.exe testopengl.py
Python OpenGL
Python OpenGL

Короче победа. Все загрузки (пакеты для питона и freeglut) проверялись антивирусом, но если будете повторять — качайте на свой страх и риск.

auto-py-to-exe — компилятор питоновских скриптов для windows

Проверено на Python 3 — работает

Установка:

>c:\users\user\AppData\Local\Programs\Python\Python36\python.exe -m pip install auto-py-to-exe
Collecting auto-py-to-exe
  Downloading auto_py_to_exe-2.7.4-py2.py3-none-any.whl (74 kB)
     |████████████████████████████████| 74 kB 84 kB/s
....
Successfully installed Eel-0.11.0 altgraph-0.17 auto-py-to-exe-2.7.4 bottle-0.12
.18 bottle-websocket-0.2.9 cffi-1.14.0 future-0.18.2 gevent-20.6.0 gevent-websoc
ket-0.10.1 greenlet-0.4.16 pefile-2019.4.18 pycparser-2.20 pyinstaller-3.6 pywin
32-ctypes-0.2.0 whichcraft-0.6.1 zope.event-4.4 zope.interface-5.1.0

После успешной установки в папке Python36\Scripts\ появится auto-py-to-exe.exe, запускаем его

auto-py-to-exe
auto-py-to-exe

Выбираем скрипт, выставляем нужные настройки и жмём снизу «CONVERT .PY TO .EXE«. Появляется папка output с откомпилированным скриптом program.exe