@@ -32,6 +32,7 @@ def _parse_args():
3232 parser .add_argument ('--port' , type = str , default = SUPERKEY_DEFAULT_PORT , help = 'Serial port to connect to.' )
3333 parser .add_argument ('--baudrate' , type = int , default = SUPERKEY_DEFAULT_BAUDRATE , help = 'Serial port baud rate.' )
3434 parser .add_argument ('--timeout' , type = float , default = SUPERKEY_DEFAULT_TIMEOUT , help = 'Serial port timeout (s).' )
35+ parser .add_argument ('--immediate' , action = argparse .BooleanOptionalAction , help = 'Use immediate mode?' )
3536 parser .add_argument ('--silent' , action = argparse .BooleanOptionalAction , help = 'Disable output to console?' )
3637 return parser .parse_args ()
3738
@@ -57,6 +58,124 @@ def _should_autokey(code: int) -> bool:
5758 (code >= 0x61 and code <= 0x7A )) # lower case letter
5859
5960
61+ def _buffered_mode (port : str = SUPERKEY_DEFAULT_PORT ,
62+ baudrate : int = SUPERKEY_DEFAULT_BAUDRATE ,
63+ timeout : float = SUPERKEY_DEFAULT_TIMEOUT ):
64+ """
65+ Runs the autokeyer in buffered mode.
66+ """
67+ with Interface (port = port , baudrate = baudrate , timeout = timeout ) as intf :
68+ while True :
69+
70+ # Get next input from user
71+ line = input ('> ' )
72+
73+ # Check for special commands
74+ if line == ':q' or line == ':quit' :
75+ # Exit program
76+ break
77+
78+ elif line == ':!' or line == ':panic' :
79+ # Panic
80+ intf .panic ()
81+ continue
82+
83+ elif line == ':wpm' :
84+ # Print WPM status
85+ print (f'WPM: { intf .get_wpm ():.1f} ' )
86+ continue
87+
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
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
100+
101+ elif line == ':buzzer off' :
102+ # Turn buzzer off
103+ intf .set_buzzer_enabled (False )
104+ continue
105+
106+ elif line == ':buzzer on' :
107+ # Turn buzzer on
108+ intf .set_buzzer_enabled (True )
109+ continue
110+
111+ elif line [:12 ] == ':buzzer frequency' :
112+ # Set buzzer frequency
113+ try :
114+ intf .set_buzzer_frequency (int (line [12 :]))
115+ except ValueError :
116+ print ('Invalid frequency?' )
117+ continue
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
131+
132+ elif line == ':paddle iambic' :
133+ # Set paddles to iambic mode
134+ intf .set_paddle_mode (PaddleMode .IAMBIC )
135+ continue
136+
137+ elif line == ':paddle ultimatic' :
138+ # Set paddles to ultimatic mode
139+ intf .set_paddle_mode (PaddleMode .ULTIMATIC )
140+ continue
141+
142+ elif line == ':paddle ultimatic_alternate' :
143+ # Set paddles to ultimatic alternate mode
144+ intf .set_paddle_mode (PaddleMode .ULTIMATIC_ALTERNATE )
145+ continue
146+
147+ elif line == ':trainer' :
148+ # Print trainer mode status
149+ print (f'Trainer mode: { 'On' if intf .get_trainer_mode () else 'Off' } ' )
150+ continue
151+
152+ elif line == ':trainer on' :
153+ # Enable trainer mode
154+ intf .set_trainer_mode (True )
155+ continue
156+
157+ elif line == ':trainer off' :
158+ # Disable trainer mode
159+ intf .set_trainer_mode (False )
160+ continue
161+
162+ elif line [0 ] == ':' :
163+ # Unknown command?
164+ print ('Unknown command?' )
165+ continue
166+
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
177+
178+
60179def _immediate_mode (port : str = SUPERKEY_DEFAULT_PORT ,
61180 baudrate : int = SUPERKEY_DEFAULT_BAUDRATE ,
62181 timeout : float = SUPERKEY_DEFAULT_TIMEOUT ,
@@ -75,8 +194,7 @@ def _immediate_mode(port: str = SUPERKEY_DEFAULT_PORT,
75194 with Interface (port = port , baudrate = baudrate , timeout = timeout ) as intf :
76195
77196 # Tracking variables
78- last_char_was_backslash = False
79- prosign_count = 0
197+ prosign_active = False
80198 prosign_string = ''
81199
82200 # Loop until commanded to quit
@@ -94,60 +212,41 @@ def _immediate_mode(port: str = SUPERKEY_DEFAULT_PORT,
94212 # Panic if the user pressed backspace key
95213 if code == _ASCII_BACKSPACE :
96214 intf .panic ()
97- prosign_count = 0
98- prosign_string = ''
99- last_char_was_backslash = False
100215 continue
101216
102217 # Start a prosign if the user pressed backslash key
103218 if code == _ASCII_BACKSLASH :
104219 print (chr (_ASCII_BACKSLASH ), end = '' , flush = True )
105- prosign_count = 2
106- prosign_string = ''
107- last_char_was_backslash = True
108- continue
109-
110- # If the last character was a backslash, and the next character is a digit from 2 to 9, then change the
111- # number of characters we're expecting for the prosign
112- if last_char_was_backslash and code >= 0x32 and code <= 0x39 :
113- print (chr (code ), end = '' , flush = True )
114- prosign_count = code - 0x30
115- last_char_was_backslash = False
116- continue
117-
118- # Unconditionally clear flag
119- last_char_was_backslash = False
220+ prosign_active = not prosign_active
221+ if prosign_active :
222+ prosign_string = ''
223+ continue
120224
121225 # Ignore unknown characters, but allow newlines to print
122226 should_autokey = _should_autokey (code )
123227 should_print = should_autokey or code == _ASCII_NEWLINE
124228
125- # Bail if there's nothing to do
126- if not should_autokey and not should_print :
127- continue
128-
129229 # Convert character code to string, fixing newlines
130230 if code != _ASCII_NEWLINE :
131231 char = chr (code )
132232 else :
133233 char = '\r \n '
134234
135- # Send character to keyer
136- if should_autokey :
137-
138- # Handle prosigns
139- if prosign_count != 0 :
140- if len (prosign_string ) < prosign_count :
141- prosign_string += char
142- if len (prosign_string ) == prosign_count :
143- intf .autokey (prosign_string [:- 1 ], [AutokeyFlag .NO_LETTER_SPACE ])
144- intf .autokey (prosign_string [- 1 ])
145- prosign_count = 0
146- prosign_string = ''
147-
148- # Otherwise, key normally
235+ # Handle prosigns
236+ if prosign_active and should_autokey :
237+ prosign_string += char
238+ elif not prosign_active and len (prosign_string ) != 0 :
239+ assert code == _ASCII_BACKSLASH , 'Logic error!'
240+ if len (prosign_string ) > 1 :
241+ intf .autokey (prosign_string [:- 1 ], [AutokeyFlag .NO_LETTER_SPACE ])
242+ intf .autokey (prosign_string [- 1 ])
149243 else :
150- intf .autokey (char )
244+ intf .autokey (prosign_string )
245+ prosign_string = ''
246+
247+ # Send character to keyer
248+ elif should_autokey :
249+ intf .autokey (char )
151250
152251 # Send character to console
153252 if echo and should_print :
@@ -159,8 +258,13 @@ def _immediate_mode(port: str = SUPERKEY_DEFAULT_PORT,
159258
160259 # Read arguments
161260 args = _parse_args ()
162- _immediate_mode (port = args .port ,
163- baudrate = args .baudrate ,
164- timeout = args .timeout ,
165- echo = not args .silent ,
166- print_help = not args .silent )
261+ if args .immediate :
262+ _immediate_mode (port = args .port ,
263+ baudrate = args .baudrate ,
264+ timeout = args .timeout ,
265+ echo = not args .silent ,
266+ print_help = not args .silent )
267+ else :
268+ _buffered_mode (port = args .port ,
269+ baudrate = args .baudrate ,
270+ timeout = args .timeout )
0 commit comments