10aab84
Pinchord · pinchord.git · Tickets · Changelog
Branches > serial-mods > 10aab84 > files
Add copy of Plover HID plugin
Commit: 10aab84c5a18cd2c0c64e362cf59026079daa81c
Parent: cc501de
7 changed files:
MANIFEST.in view file
@@ -1 +1,2 @@ include plover_pinchord_31/dictionaries/*+include plover_pinchord_machine_hid/LICENSEplover_pinchord_31/system.py view file
@@ -99,5 +99,31 @@ "-*": ("-S"), "-e": ("-D", "-Z"), "-s": ("X1")+ },+ "Pinchord Plover HID": {+ "#-": ("S1-"),+ "+-": ("S2-"),+ "T-": ("T-"),+ "S-": ("K-"),+ "P-": ("P-"),+ "W-": ("W-"),+ "H-": ("H-"),+ "R-": ("R-"),+ "&-": ("*1", "*2"),+ "A": ("A-"),+ "O": ("O-"),+ "I": ("-E"),+ "U": ("-U"),+ "^": ("*3", "*4"),+ "-L": ("-F"),+ "-R": ("-R"),+ "-P": ("-P"),+ "-K": ("-B"),+ "-F": ("-L"),+ "-S": ("-G"),+ "-T": ("-T"),+ "-*": ("-S"),+ "-e": ("-D", "-Z"),+ "-s": ("X1") } }plover_pinchord_machine_hid/LICENSE view file
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2021 dnaq++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.plover_pinchord_machine_hid/__init__.py view file
plover_pinchord_machine_hid/hid_option.py view file
@@ -0,0 +1,93 @@+# Taken from https://github.com/dnaq/plover-machine-hid/blob/main/hid_option.py+# Copyright dnaq, see ./LICENSE++from copy import copy++from PySide6.QtCore import Signal+from PySide6.QtGui import QIntValidator+from PySide6.QtWidgets import (+ QGroupBox,+ QHBoxLayout,+ QVBoxLayout,+ QCheckBox,+ QLabel,+ QLineEdit,+)+++class HidOption(QGroupBox):++ valueChanged = Signal('QVariant')++ def checkbox(self, name, label, tooltip):+ checkbox = QCheckBox(label)+ checkbox.setToolTip(tooltip)++ def on_changed(value):+ self._value[name] = value+ self.valueChanged.emit(self._value)++ checkbox.stateChanged.connect(on_changed)+ self.setters.append(lambda value: checkbox.setChecked(value[name]))+ return checkbox++ def number(self, name, label, tooltip, minimum, maximum):+ edit = QLineEdit("")+ edit.setToolTip(tooltip)+ edit.setValidator(QIntValidator(minimum, maximum, edit))++ def on_changed(value):+ self._value[name] = int(value)+ self.valueChanged.emit(self._value)++ edit.textChanged.connect(on_changed)+ row = QHBoxLayout()+ row.addWidget(QLabel(label))+ row.addWidget(edit)+ self.setters.append(lambda value: edit.setText(str(value[name])))+ return row++ def __init__(self):+ super().__init__()+ self.setters = []+ self._value = {}+ vbox = QVBoxLayout()+ vbox.addWidget(+ self.checkbox(+ name="first_up_chord_send",+ label="Send chord on first key release",+ tooltip="When the first key in a chord is released, the chord is sent.\n"+ "If the key is pressed and released again, another chord is sent.",+ )+ )+ vbox.addWidget(+ self.checkbox(+ name="double_tap_repeat",+ label="Double tap to repeat",+ tooltip="Tap and then hold a chord to send it repeatedly.",+ )+ )+ vbox.addLayout(+ self.number(+ name="repeat_delay_ms",+ label="Repeat delay (ms)",+ tooltip="Delay before chord starts repeating.",+ minimum=10,+ maximum=10000,+ )+ )+ vbox.addLayout(+ self.number(+ name="repeat_interval_ms",+ label="Repeat interval (ms)",+ tooltip="Interval between chord repetitions.",+ minimum=10,+ maximum=10000,+ )+ )+ self.setLayout(vbox)++ def setValue(self, value):+ self._value = copy(value)+ for setter in self.setters:+ setter(value)plover_pinchord_machine_hid/plover_pinchord_machine_hid.py view file
@@ -0,0 +1,174 @@+'''+A plover machine plugin for supporting the Plover HID protocol.++This protocol is a simple HID-based protocol that sends the current state+of the steno machine every time that state changes.++See the README for more details on the protocol.++The order of the buttons (from left to right) is the same as in `KEYS_LAYOUT`.+Most buttons have the same names as in GeminiPR, except for the extra buttons+which are called X1-X26.+'''++# Taken from https://github.com/dnaq/plover-machine-hid/blob/main/plover_machine_hid.py+# Copyright dnaq, see ./LICENSE++from plover.machine.base import ThreadedStenotypeBase+from plover import log+from plover.misc import boolean++import hid+import platform+import time++# This is a hack to not open the hid device in exclusive mode on+# darwin, if the version of hidapi installed is current enough+if platform.system() == "Darwin":+ import ctypes+ try:+ hid.hidapi.hid_darwin_set_open_exclusive.argtypes = (ctypes.c_int, )+ hid.hidapi.hid_darwin_set_open_exclusive.restype = None+ hid.hidapi.hid_darwin_set_open_exclusive(0)+ except AttributeError as e:+ log.error("hidapi < 0.12 in use, plover-pinchord-hid will not work correctly")++USAGE_PAGE: int = 0xFF50+USAGE: int = 0x4C56++N_LEVERS: int = 64++# A simple report contains the report id 1 and one bit+# for each of the 64 buttons in the report.+SIMPLE_REPORT_TYPE: int = 0x01+SIMPLE_REPORT_LEN: int = N_LEVERS // 8++class InvalidReport(Exception):+ pass++STENO_KEY_CHART = ("S1-", "T-", "K-", "P-", "W-", "H-",+ "R-", "A-", "O-", "*1", "-E", "-U",+ "-F", "-R", "-P", "-B", "-L", "-G",+ "-T", "-S", "-D", "-Z", "#1",+ "S2-", "*2", "*3", "*4", "#2", "#3",+ "#4", "#5", "#6", "#7", "#8", "#9",+ "#A", "#B", "#C", "X1", "X2", "X3",+ "X4", "X5", "X6", "X7", "X8", "X9",+ "X10", "X11", "X12", "X13", "X14", "X15",+ "X16", "X17", "X18", "X19", "X20", "X21",+ "X22", "X23", "X24", "X25", "X26")++class HidMachine(ThreadedStenotypeBase):+ KEYS_LAYOUT: str = '''+ #1 #2 #3 #4 #5 #6 #7 #8 #9 #A #B #C+ S1- T- P- H- *1 *3 -F -P -L -T -D+ S2- K- W- R- *2 *4 -R -B -G -S -Z+ A- O- -E -U+ X1 X2 X3 X4 X5 X6 X7 X8 X9 X10+ X11 X12 X13 X14 X15 X16 X17 X18 X19 X20+ X21 X22 X23 X24 X25 X26+ '''+ def __init__(self, params):+ super().__init__()+ self._params = params+ self._hid = None++ def _parse(self, report):+ # The first byte is the report id, and due to idiosynchrasies+ # in how HID-apis work on different operating system we can't+ # map the report id to the contents in a good way, so we force+ # compliant devices to always use a report id of 0x50 ('P').+ if len(report) > SIMPLE_REPORT_LEN and report[0] == 0x50:+ return int.from_bytes(report[1:SIMPLE_REPORT_LEN+1], 'big')+ else:+ raise InvalidReport()++ def send(self, keystate):+ steno_actions = self.keymap.keys_to_actions(+ [key for i, key in enumerate(STENO_KEY_CHART) if keystate >> (63 - i) & 1]+ )+ if steno_actions:+ self._notify(steno_actions)++ def run(self):+ self._ready()+ keystate = 0+ current = 0+ last_sent = 0+ press_started = time.time()+ sent_first_up = Falsesetup.cfg view file
@@ -19,9 +19,11 @@ install_requires = plover>=4.0.0 plover-python-dictionary+ hid include_package_data = True packages = plover_pinchord_31+ plover_pinchord_machine_hid # 'Pinchord' is the latest version for compatibility [options.entry_points]@@ -29,3 +31,7 @@ Pinchord = plover_pinchord_31.system plover.extension = Pinchord = plover_pinchord_31.extension:Extension+plover.machine =+ Pinchord Plover HID = plover_pinchord_machine_hid.plover_pinchord_machine_hid:HidMachine+plover.gui.qt.machine_option =+ plover_pinchord_machine_hid.plover_pinchord_machine_hid:HidMachine = plover_pinchord_machine_hid.hid_option:HidOption