|
11 | 11 |
|
12 | 12 | import argparse |
13 | 13 | from msvcrt import getch |
| 14 | +import re |
14 | 15 |
|
15 | 16 | from superkey import * |
16 | 17 |
|
@@ -66,114 +67,150 @@ def _buffered_mode(port: str = SUPERKEY_DEFAULT_PORT, |
66 | 67 | """ |
67 | 68 | with Interface(port=port, baudrate=baudrate, timeout=timeout) as intf: |
68 | 69 | while True: |
| 70 | + try: |
69 | 71 |
|
70 | | - # Get next input from user |
71 | | - line = input('> ') |
| 72 | + # Get next input from user |
| 73 | + line = input('> ') |
72 | 74 |
|
73 | | - # Check for special commands |
74 | | - if line == ':q' or line == ':quit' or line == ':exit': |
75 | | - # Exit program |
76 | | - break |
| 75 | + # Helper functions |
| 76 | + def line_equals(x: str) -> bool: |
| 77 | + return line.casefold() == x.casefold() |
| 78 | + def line_starts_with(x: str) -> bool: |
| 79 | + return line.casefold().startswith(x.casefold()) |
77 | 80 |
|
78 | | - elif line == ':!' or line == ':panic': |
79 | | - # Panic |
80 | | - intf.panic() |
81 | | - continue |
| 81 | + # Check for special commands |
| 82 | + if line_equals(':q') or line_equals(':quit') or line_equals(':exit'): |
| 83 | + # Exit program |
| 84 | + break |
82 | 85 |
|
83 | | - elif line == ':wpm': |
84 | | - # Print WPM status |
85 | | - print(f'WPM: {intf.get_wpm():.1f}') |
86 | | - continue |
| 86 | + elif line_equals(':!') or line_equals(':panic'): |
| 87 | + # Panic |
| 88 | + intf.panic() |
| 89 | + continue |
87 | 90 |
|
88 | | - elif line[:5] == ':wpm ': |
89 | | - # Set WPM |
90 | | - try: |
91 | | - intf.set_wpm(float(line[5:])) |
92 | | - except ValueError: |
93 | | - print('Invalid WPM?') |
94 | | - continue |
| 91 | + elif line_equals(':wpm'): |
| 92 | + # Print WPM status |
| 93 | + print(f'WPM: {intf.get_wpm():.1f}') |
| 94 | + continue |
95 | 95 |
|
96 | | - elif line == ':buzzer': |
97 | | - # Print buzzer status |
98 | | - print(f'Buzzer: {'On' if intf.get_buzzer_enabled() else 'Off'} ({intf.get_buzzer_frequency()} Hz)') |
99 | | - continue |
| 96 | + elif line_starts_with(':wpm '): |
| 97 | + # Set WPM |
| 98 | + try: |
| 99 | + intf.set_wpm(float(line[5:])) |
| 100 | + except ValueError: |
| 101 | + print('Invalid WPM?') |
| 102 | + continue |
100 | 103 |
|
101 | | - elif line == ':buzzer off': |
102 | | - # Turn buzzer off |
103 | | - intf.set_buzzer_enabled(False) |
104 | | - continue |
| 104 | + elif line_equals(':buzzer'): |
| 105 | + # Print buzzer status |
| 106 | + print(f'Buzzer: {'On' if intf.get_buzzer_enabled() else 'Off'} ({intf.get_buzzer_frequency()} Hz)') |
| 107 | + continue |
105 | 108 |
|
106 | | - elif line == ':buzzer on': |
107 | | - # Turn buzzer on |
108 | | - intf.set_buzzer_enabled(True) |
109 | | - continue |
| 109 | + elif line_equals(':buzzer off'): |
| 110 | + # Turn buzzer off |
| 111 | + intf.set_buzzer_enabled(False) |
| 112 | + continue |
110 | 113 |
|
111 | | - elif line[:18] == ':buzzer frequency ': |
112 | | - # Set buzzer frequency |
113 | | - try: |
114 | | - intf.set_buzzer_frequency(int(line[18:])) |
115 | | - except ValueError: |
116 | | - print('Invalid frequency?') |
117 | | - continue |
| 114 | + elif line_equals(':buzzer on'): |
| 115 | + # Turn buzzer on |
| 116 | + intf.set_buzzer_enabled(True) |
| 117 | + continue |
118 | 118 |
|
119 | | - elif line == ':paddle': |
120 | | - # Print paddle mode |
121 | | - mode = intf.get_paddle_mode() |
122 | | - if mode == PaddleMode.IAMBIC: |
123 | | - print('Paddle mode: IAMBIC') |
124 | | - elif mode == PaddleMode.ULTIMATIC: |
125 | | - print('Paddle mode: ULTIMATIC') |
126 | | - elif mode == PaddleMode.ULTIMATIC_ALTERNATE: |
127 | | - print('Paddle mode: ULTIMATIC_ALTERNATE') |
128 | | - else: |
129 | | - print('Paddle mode: unknown?') |
130 | | - continue |
| 119 | + elif line_starts_with(':buzzer frequency '): |
| 120 | + # Set buzzer frequency |
| 121 | + try: |
| 122 | + intf.set_buzzer_frequency(int(line[18:])) |
| 123 | + except ValueError: |
| 124 | + print('Invalid frequency?') |
| 125 | + continue |
131 | 126 |
|
132 | | - elif line == ':paddle iambic': |
133 | | - # Set paddles to iambic mode |
134 | | - intf.set_paddle_mode(PaddleMode.IAMBIC) |
135 | | - continue |
| 127 | + elif line_equals(':paddle'): |
| 128 | + # Print paddle mode |
| 129 | + mode = intf.get_paddle_mode() |
| 130 | + if mode == PaddleMode.IAMBIC: |
| 131 | + print('Paddle mode: Iambic') |
| 132 | + elif mode == PaddleMode.ULTIMATIC: |
| 133 | + print('Paddle mode: Ultimatic') |
| 134 | + elif mode == PaddleMode.ULTIMATIC_ALTERNATE: |
| 135 | + print('Paddle mode: Ultimatic Alternate') |
| 136 | + else: |
| 137 | + print('Paddle mode: unknown?') |
| 138 | + continue |
136 | 139 |
|
137 | | - elif line == ':paddle ultimatic': |
138 | | - # Set paddles to ultimatic mode |
139 | | - intf.set_paddle_mode(PaddleMode.ULTIMATIC) |
140 | | - continue |
| 140 | + elif line_equals(':paddle iambic'): |
| 141 | + # Set paddles to iambic mode |
| 142 | + intf.set_paddle_mode(PaddleMode.IAMBIC) |
| 143 | + continue |
141 | 144 |
|
142 | | - elif line == ':paddle ultimatic_alternate': |
143 | | - # Set paddles to ultimatic alternate mode |
144 | | - intf.set_paddle_mode(PaddleMode.ULTIMATIC_ALTERNATE) |
145 | | - continue |
| 145 | + elif line_equals(':paddle ultimatic'): |
| 146 | + # Set paddles to ultimatic mode |
| 147 | + intf.set_paddle_mode(PaddleMode.ULTIMATIC) |
| 148 | + continue |
146 | 149 |
|
147 | | - elif line == ':trainer': |
148 | | - # Print trainer mode status |
149 | | - print(f'Trainer mode: {'On' if intf.get_trainer_mode() else 'Off'}') |
150 | | - continue |
| 150 | + elif line_equals(':paddle ultimatic_alternate'): |
| 151 | + # Set paddles to ultimatic alternate mode |
| 152 | + intf.set_paddle_mode(PaddleMode.ULTIMATIC_ALTERNATE) |
| 153 | + continue |
151 | 154 |
|
152 | | - elif line == ':trainer on': |
153 | | - # Enable trainer mode |
154 | | - intf.set_trainer_mode(True) |
155 | | - continue |
| 155 | + elif line_equals(':trainer'): |
| 156 | + # Print trainer mode status |
| 157 | + print(f'Trainer mode: {'On' if intf.get_trainer_mode() else 'Off'}') |
| 158 | + continue |
156 | 159 |
|
157 | | - elif line == ':trainer off': |
158 | | - # Disable trainer mode |
159 | | - intf.set_trainer_mode(False) |
160 | | - continue |
| 160 | + elif line_equals(':trainer on'): |
| 161 | + # Enable trainer mode |
| 162 | + intf.set_trainer_mode(True) |
| 163 | + continue |
161 | 164 |
|
162 | | - elif line[0] == ':': |
163 | | - # Unknown command? |
164 | | - print('Unknown command?') |
165 | | - continue |
| 165 | + elif line_equals(':trainer off'): |
| 166 | + # Disable trainer mode |
| 167 | + intf.set_trainer_mode(False) |
| 168 | + continue |
| 169 | + |
| 170 | + elif line_starts_with(':qm'): |
| 171 | + # Handle this with regex for easier processing |
| 172 | + if match := re.match(r'^:qm get (\d+)$', line, re.IGNORECASE): |
| 173 | + print(intf.get_quick_msg(int(match.group(1)))) |
| 174 | + continue |
| 175 | + elif match := re.match(r'^:qm set (\d+) (.+)$', line, re.IGNORECASE): |
| 176 | + intf.set_quick_msg(int(match.group(1)), match.group(2)) |
| 177 | + continue |
| 178 | + elif match := re.match(r'^:qm del (\d+)$', line, re.IGNORECASE): |
| 179 | + intf.invalidate_quick_msg(int(match.group(1))) |
| 180 | + continue |
| 181 | + elif match := re.match(r'^:qm (\d+)$', line, re.IGNORECASE): |
| 182 | + intf.autokey_quick_msg(int(match.group(1))) |
| 183 | + continue |
| 184 | + |
| 185 | + elif line_starts_with(':'): |
| 186 | + # Unknown command? |
| 187 | + print('Unknown command?') |
| 188 | + continue |
166 | 189 |
|
167 | | - # Split line into tokens and send in either normal or prosign mode |
168 | | - tokens = line.split('\\') |
169 | | - prosign = False |
170 | | - for token in tokens: |
171 | | - if prosign and len(token) > 1: |
172 | | - intf.autokey(token[:-1], flags=[AutokeyFlag.NO_LETTER_SPACE]) |
173 | | - intf.autokey(token[-1]) |
174 | | - elif len(token) != 0: |
175 | | - intf.autokey(token) |
176 | | - prosign = not prosign |
| 190 | + # Split line into tokens and send in either normal or prosign mode |
| 191 | + tokens = line.split('\\') |
| 192 | + prosign = False |
| 193 | + for token in tokens: |
| 194 | + if prosign and len(token) > 1: |
| 195 | + intf.autokey(token[:-1], flags=[AutokeyFlag.NO_LETTER_SPACE]) |
| 196 | + intf.autokey(token[-1]) |
| 197 | + elif len(token) != 0: |
| 198 | + intf.autokey(token) |
| 199 | + prosign = not prosign |
| 200 | + |
| 201 | + # Ultra-graceful error handling |
| 202 | + except InvalidMessageError: |
| 203 | + print('SuperKey responds: invalid message!') |
| 204 | + except InvalidSizeError: |
| 205 | + print('SuperKey responds: invalid size!') |
| 206 | + except InvalidCRCError: |
| 207 | + print('SuperKey responds: invalid CRC!') |
| 208 | + except InvalidPayloadError: |
| 209 | + print('SuperKey responds: invalid payload!') |
| 210 | + except InvalidValueError: |
| 211 | + print('SuperKey responds: invalid value!') |
| 212 | + except InterfaceError: |
| 213 | + print('SuperKey responds: unknown error!') |
177 | 214 |
|
178 | 215 |
|
179 | 216 | def _immediate_mode(port: str = SUPERKEY_DEFAULT_PORT, |
|
0 commit comments