vial/src/main/python/macro_recorder_linux.py

175 lines
4.5 KiB
Python
Raw Normal View History

# SPDX-License-Identifier: GPL-2.0-or-later
import sys
from PyQt5 import QtCore
from PyQt5.QtCore import pyqtSignal, QProcess
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QApplication
from fbs_runtime.application_context import is_frozen
from keycodes import KEYCODES_BASIC
from macro_key import KeyUp, KeyDown
from util import tr
class LinuxRecorder(QWidget):
keystroke = pyqtSignal(object)
stopped = pyqtSignal()
mapping_qmk_id = {
"esc": "KC_ESCAPE",
"1": "KC_1",
"2": "KC_2",
"3": "KC_3",
"4": "KC_4",
"5": "KC_5",
"6": "KC_6",
"7": "KC_7",
"8": "KC_8",
"9": "KC_9",
"0": "KC_0",
"-": "KC_MINUS",
"=": "KC_EQUAL",
"backspace": "KC_BSPACE",
"tab": "KC_TAB",
"q": "KC_Q",
"w": "KC_W",
"e": "KC_E",
"r": "KC_R",
"t": "KC_T",
"y": "KC_Y",
"u": "KC_U",
"i": "KC_I",
"o": "KC_O",
"p": "KC_P",
"[": "KC_LBRACKET",
"]": "KC_RBRACKET",
"enter": "KC_ENTER",
"ctrl": "KC_LCTRL",
"a": "KC_A",
"s": "KC_S",
"d": "KC_D",
"f": "KC_F",
"g": "KC_G",
"h": "KC_H",
"j": "KC_J",
"k": "KC_K",
"l": "KC_L",
";": "KC_SCOLON",
"'": "KC_QUOTE",
"`": "KC_GRAVE",
"shift": "KC_LSHIFT",
"\\": "KC_BSLASH",
"z": "KC_Z",
"x": "KC_X",
"c": "KC_C",
"v": "KC_V",
"b": "KC_B",
"n": "KC_N",
"m": "KC_M",
",": "KC_COMMA",
".": "KC_DOT",
"/": "KC_SLASH",
"alt": "KC_LALT",
"space": "KC_SPACE",
"caps lock": "KC_CAPSLOCK",
"f1": "KC_F1",
"f2": "KC_F2",
"f3": "KC_F3",
"f4": "KC_F4",
"f5": "KC_F5",
"f6": "KC_F6",
"f7": "KC_F7",
"f8": "KC_F8",
"f9": "KC_F9",
"f10": "KC_F10",
"f11": "KC_F11",
"f12": "KC_F12",
"num lock": "KC_NUMLOCK",
"scroll lock": "KC_SCROLLLOCK",
"break": "KC_PAUSE",
"home": "KC_HOME",
"up": "KC_UP",
"page up": "KC_PGUP",
"left": "KC_LEFT",
"right": "KC_RIGHT",
"end": "KC_END",
"down": "KC_DOWN",
"page down": "KC_PGDOWN",
"insert": "KC_INSERT",
"delete": "KC_DELETE",
"pause": "KC_PAUSE",
"windows": "KC_LGUI",
"menu": "KC_APPLICATION",
}
mapping = dict()
def __init__(self):
super().__init__()
self.process = QProcess()
self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.X11BypassWindowManagerHint)
layout = QVBoxLayout()
btn = QPushButton(tr("MacroRecorder", "Stop recording"))
btn.clicked.connect(self.on_stop)
layout.addWidget(btn)
self.setLayout(layout)
def start(self):
self.show()
center = QApplication.desktop().availableGeometry(self).center()
self.move(center.x() - self.width() * 0.5, 0)
args = [sys.executable]
if is_frozen():
args += sys.argv[1:]
else:
args += sys.argv
args += ["--linux-recorder"]
self.process.readyReadStandardOutput.connect(self.on_output)
self.process.start("pkexec", args, QProcess.Unbuffered | QProcess.ReadWrite)
def on_stop(self):
2020-12-24 09:48:11 -05:00
self.stop()
def stop(self):
self.process.write(b"q")
self.process.waitForFinished()
self.process.close()
self.hide()
self.stopped.emit()
def action2cls(self, action):
if action == "up":
return KeyUp
elif action == "down":
return KeyDown
else:
raise RuntimeError("unexpected action={}".format(action))
def key2code(self, key):
return self.mapping.get(key, None)
def on_output(self):
if self.process.canReadLine():
line = bytes(self.process.readLine()).decode("utf-8")
action, key = line.strip().split(":")
code = self.key2code(key)
if code is not None:
self.keystroke.emit(self.action2cls(action)(code))
for linux, qmk in LinuxRecorder.mapping_qmk_id.items():
for k in KEYCODES_BASIC:
if k.qmk_id == qmk:
LinuxRecorder.mapping[linux] = k
break
if linux not in LinuxRecorder.mapping:
raise RuntimeError("Misconfigured - cannot determine QMK keycode value for {}:{} pair".format(linux, qmk))