dokumentation/docs/Hardware/teck.py

136 lines
4.8 KiB
Python

# Copyright (c) 2010 Joshua Harlan Lifton.
# See LICENSE.txt for details.
# TODO: add options to remap keys
# TODO: look into programmatically pasting into other applications
"For use with a Microsoft Sidewinder X4 keyboard used as stenotype machine."
# TODO: Change name to NKRO Keyboard.
from plover.machine.base import StenotypeBase
from plover.oslayer import keyboardcontrol
KEYSTRING_TO_STENO_KEY = {"a": "S-",
"q": "S-",
"w": "T-",
"s": "K-",
"e": "P-",
"d": "W-",
"r": "H-",
"f": "R-",
"c": "A-",
"v": "O-",
"t": "#",
"g": "*",
"y": "-F",
"h": "-R",
"m": "-E",
",": "-U",
"u": "-P",
"j": "-B",
"i": "-L",
"k": "-G",
"o": "-T",
"l": "-S",
"p": "-D",
";": "-Z",
"1": "#",
"2": "#",
"3": "#",
"4": "#",
"5": "#",
"6": "#",
"7": "#",
"8": "#",
"9": "#",
"0": "#",
"-": "#",
"=": "#",
}
class Stenotype(StenotypeBase):
"""Standard stenotype interface for a Microsoft Sidewinder X4 keyboard.
This class implements the three methods necessary for a standard
stenotype interface: start_capture, stop_capture, and
add_callback.
"""
def __init__(self, params):
"""Monitor a Microsoft Sidewinder X4 keyboard via X events."""
StenotypeBase.__init__(self)
self._keyboard_emulation = keyboardcontrol.KeyboardEmulation()
self._keyboard_capture = keyboardcontrol.KeyboardCapture()
self._keyboard_capture.key_down = self._key_down
self._keyboard_capture.key_up = self._key_up
self.suppress_keyboard(True)
self._down_keys = set()
self._released_keys = set()
self.arpeggiate = params['arpeggiate']
def start_capture(self):
"""Begin listening for output from the stenotype machine."""
self._keyboard_capture.start()
self._ready()
def stop_capture(self):
"""Stop listening for output from the stenotype machine."""
self._keyboard_capture.cancel()
self._stopped()
def suppress_keyboard(self, suppress):
self._is_keyboard_suppressed = suppress
self._keyboard_capture.suppress_keyboard(suppress)
def _key_down(self, event):
"""Called when a key is pressed."""
if (self._is_keyboard_suppressed
and event.keystring is not None
and not self._keyboard_capture.is_keyboard_suppressed()):
self._keyboard_emulation.send_backspaces(1)
if event.keystring in KEYSTRING_TO_STENO_KEY:
self._down_keys.add(event.keystring)
def _post_suppress(self, suppress, steno_keys):
"""Backspace the last stroke since it matched a command.
The suppress function is passed in to prevent threading issues with the
gui.
"""
n = len(steno_keys)
if self.arpeggiate:
n += 1
suppress(n)
def _key_up(self, event):
"""Called when a key is released."""
if event.keystring in KEYSTRING_TO_STENO_KEY:
# Process the newly released key.
self._released_keys.add(event.keystring)
# Remove invalid released keys.
self._released_keys = self._released_keys.intersection(self._down_keys)
# A stroke is complete if all pressed keys have been released.
# If we are in arpeggiate mode then only send stroke when spacebar is pressed.
send_strokes = bool(self._down_keys and
self._down_keys == self._released_keys)
if self.arpeggiate:
send_strokes &= event.keystring == ' '
if send_strokes:
steno_keys = [KEYSTRING_TO_STENO_KEY[k] for k in self._down_keys
if k in KEYSTRING_TO_STENO_KEY]
if steno_keys:
self._down_keys.clear()
self._released_keys.clear()
self._notify(steno_keys)
@staticmethod
def get_option_info():
bool_converter = lambda s: s == 'True'
return {
'arpeggiate': (False, bool_converter),
}