Plover: teck.py

File teck.py, 4.8 KB (added by anonym, 7 years ago)

geänderte sidewinder.py

Line 
1# Copyright (c) 2010 Joshua Harlan Lifton.
2# See LICENSE.txt for details.
3
4# TODO: add options to remap keys
5# TODO: look into programmatically pasting into other applications
6
7"For use with a Microsoft Sidewinder X4 keyboard used as stenotype machine."
8
9# TODO: Change name to NKRO Keyboard.
10
11from plover.machine.base import StenotypeBase
12from plover.oslayer import keyboardcontrol
13
14KEYSTRING_TO_STENO_KEY = {"a": "S-",
15 "q": "S-",
16 "w": "T-",
17 "s": "K-",
18 "e": "P-",
19 "d": "W-",
20 "r": "H-",
21 "f": "R-",
22 "c": "A-",
23 "v": "O-",
24 "t": "#",
25 "g": "*",
26 "y": "-F",
27 "h": "-R",
28 "m": "-E",
29 ",": "-U",
30 "u": "-P",
31 "j": "-B",
32 "i": "-L",
33 "k": "-G",
34 "o": "-T",
35 "l": "-S",
36 "p": "-D",
37 ";": "-Z",
38 "1": "#",
39 "2": "#",
40 "3": "#",
41 "4": "#",
42 "5": "#",
43 "6": "#",
44 "7": "#",
45 "8": "#",
46 "9": "#",
47 "0": "#",
48 "-": "#",
49 "=": "#",
50 }
51
52
53class Stenotype(StenotypeBase):
54 """Standard stenotype interface for a Microsoft Sidewinder X4 keyboard.
55
56 This class implements the three methods necessary for a standard
57 stenotype interface: start_capture, stop_capture, and
58 add_callback.
59
60 """
61
62 def __init__(self, params):
63 """Monitor a Microsoft Sidewinder X4 keyboard via X events."""
64 StenotypeBase.__init__(self)
65 self._keyboard_emulation = keyboardcontrol.KeyboardEmulation()
66 self._keyboard_capture = keyboardcontrol.KeyboardCapture()
67 self._keyboard_capture.key_down = self._key_down
68 self._keyboard_capture.key_up = self._key_up
69 self.suppress_keyboard(True)
70 self._down_keys = set()
71 self._released_keys = set()
72 self.arpeggiate = params['arpeggiate']
73
74 def start_capture(self):
75 """Begin listening for output from the stenotype machine."""
76 self._keyboard_capture.start()
77 self._ready()
78
79 def stop_capture(self):
80 """Stop listening for output from the stenotype machine."""
81 self._keyboard_capture.cancel()
82 self._stopped()
83
84 def suppress_keyboard(self, suppress):
85 self._is_keyboard_suppressed = suppress
86 self._keyboard_capture.suppress_keyboard(suppress)
87
88 def _key_down(self, event):
89 """Called when a key is pressed."""
90 if (self._is_keyboard_suppressed
91 and event.keystring is not None
92 and not self._keyboard_capture.is_keyboard_suppressed()):
93 self._keyboard_emulation.send_backspaces(1)
94 if event.keystring in KEYSTRING_TO_STENO_KEY:
95 self._down_keys.add(event.keystring)
96
97 def _post_suppress(self, suppress, steno_keys):
98 """Backspace the last stroke since it matched a command.
99
100 The suppress function is passed in to prevent threading issues with the
101 gui.
102 """
103 n = len(steno_keys)
104 if self.arpeggiate:
105 n += 1
106 suppress(n)
107
108 def _key_up(self, event):
109 """Called when a key is released."""
110 if event.keystring in KEYSTRING_TO_STENO_KEY:
111 # Process the newly released key.
112 self._released_keys.add(event.keystring)
113 # Remove invalid released keys.
114 self._released_keys = self._released_keys.intersection(self._down_keys)
115
116 # A stroke is complete if all pressed keys have been released.
117 # If we are in arpeggiate mode then only send stroke when spacebar is pressed.
118 send_strokes = bool(self._down_keys and
119 self._down_keys == self._released_keys)
120 if self.arpeggiate:
121 send_strokes &= event.keystring == ' '
122 if send_strokes:
123 steno_keys = [KEYSTRING_TO_STENO_KEY[k] for k in self._down_keys
124 if k in KEYSTRING_TO_STENO_KEY]
125 if steno_keys:
126 self._down_keys.clear()
127 self._released_keys.clear()
128 self._notify(steno_keys)
129
130 @staticmethod
131 def get_option_info():
132 bool_converter = lambda s: s == 'True'
133 return {
134 'arpeggiate': (False, bool_converter),
135 }