0
# Text Processing and Abbreviations
1
2
Advanced text input processing including word detection, automatic text replacement, typed string extraction, and abbreviation expansion. The keyboard package provides sophisticated text processing capabilities for creating text automation tools and improving typing efficiency.
3
4
## Capabilities
5
6
### Word Listening
7
8
Monitor typed words and trigger callbacks when specific words are detected.
9
10
```python { .api }
11
def add_word_listener(word, callback, triggers=['space'], match_suffix=False, timeout=2):
12
"""
13
Invokes a callback every time a sequence of characters is typed (e.g. 'pet')
14
and followed by a trigger key (e.g. space). Modifiers are ignored.
15
16
Parameters:
17
- word: The typed text to be matched (case sensitive)
18
- callback: Function to call when word is detected (no arguments)
19
- triggers: List of keys that trigger word matching (default: ['space'])
20
- match_suffix: If True, match word endings rather than whole words
21
- timeout: Maximum seconds between characters before discarding current word
22
23
Returns:
24
Function to remove the word listener
25
26
Examples:
27
- add_word_listener('hello', greet_user)
28
- add_word_listener('help', show_help, triggers=['space', 'enter'])
29
- add_word_listener('pet', handle_pet, match_suffix=True) # matches 'carpet'
30
"""
31
32
def register_word_listener(word, callback, triggers=['space'], match_suffix=False, timeout=2):
33
"""Alias for add_word_listener()."""
34
35
def remove_word_listener(word_or_handler):
36
"""
37
Removes a previously registered word listener. Accepts either the word used
38
during registration (exact string) or the event handler returned by
39
add_word_listener().
40
41
Parameters:
42
- word_or_handler: Word string or handler function to remove
43
"""
44
```
45
46
### Text Abbreviation and Replacement
47
48
Automatically replace typed abbreviations with expanded text.
49
50
```python { .api }
51
def add_abbreviation(source_text, replacement_text, match_suffix=False, timeout=2):
52
"""
53
Registers a hotkey that replaces one typed text with another. The
54
replacement is done by sending backspace events to delete the source
55
text, then typing the replacement.
56
57
Parameters:
58
- source_text: Text to be replaced when typed
59
- replacement_text: Text to replace it with
60
- match_suffix: If True, match endings of words instead of whole words
61
- timeout: Maximum seconds between characters before discarding current word
62
63
Returns:
64
Function to remove the abbreviation
65
66
Examples:
67
- add_abbreviation('tm', '™')
68
- add_abbreviation('addr', '123 Main St, City, State 12345')
69
- add_abbreviation('email', 'user@example.com')
70
"""
71
72
def register_abbreviation(source_text, replacement_text, match_suffix=False, timeout=2):
73
"""Alias for add_abbreviation()."""
74
75
def remove_abbreviation(word_or_handler):
76
"""Alias for remove_word_listener()."""
77
```
78
79
### Typed String Extraction
80
81
Extract meaningful text strings from keyboard event sequences.
82
83
```python { .api }
84
def get_typed_strings(events, allow_backspace=True):
85
"""
86
Given a sequence of events, tries to deduce what strings were typed.
87
Strings are separated when a non-textual key is pressed (such as tab or
88
enter). Characters are converted to uppercase according to shift and
89
capslock status.
90
91
Parameters:
92
- events: Sequence of KeyboardEvent objects
93
- allow_backspace: If True, backspaces remove the last character typed
94
95
Yields:
96
str: Extracted text strings
97
98
Note: This function is a generator, so you can pass an infinite stream of
99
events and convert them to strings in real time. This is merely a heuristic
100
as it cannot access per-process keyboard state like actual keyboard layout.
101
102
Example:
103
get_typed_strings(record()) #-> ['This is what', 'I recorded', '']
104
"""
105
```
106
107
## Usage Examples
108
109
### Basic Word Listening
110
111
```python
112
import keyboard
113
114
def greet():
115
print('Hello there!')
116
117
def farewell():
118
print('Goodbye!')
119
120
def help_command():
121
print('Available commands: hello, bye, help')
122
123
# Register word listeners
124
keyboard.add_word_listener('hello', greet)
125
keyboard.add_word_listener('bye', farewell)
126
keyboard.add_word_listener('help', help_command)
127
128
print('Type "hello", "bye", or "help" followed by space.')
129
print('Press ESC to exit.')
130
131
keyboard.wait('esc')
132
keyboard.remove_word_listener('hello')
133
keyboard.remove_word_listener('bye')
134
keyboard.remove_word_listener('help')
135
```
136
137
### Text Abbreviations
138
139
```python
140
import keyboard
141
142
# Common abbreviations
143
keyboard.add_abbreviation('addr', '123 Main Street, Anytown, ST 12345')
144
keyboard.add_abbreviation('phone', '+1 (555) 123-4567')
145
keyboard.add_abbreviation('email', 'john.doe@example.com')
146
keyboard.add_abbreviation('sig', '\n\nBest regards,\nJohn Doe\nSoftware Engineer')
147
148
# Special characters
149
keyboard.add_abbreviation('tm', '™')
150
keyboard.add_abbreviation('copy', '©')
151
keyboard.add_abbreviation('reg', '®')
152
153
# Date/time shortcuts
154
import datetime
155
now = datetime.datetime.now()
156
keyboard.add_abbreviation('date', now.strftime('%Y-%m-%d'))
157
keyboard.add_abbreviation('time', now.strftime('%H:%M:%S'))
158
159
print('Abbreviation system active!')
160
print('Try typing: addr, phone, email, sig, tm, copy, reg, date, time')
161
print('Press ESC to exit.')
162
163
keyboard.wait('esc')
164
```
165
166
### Advanced Text Processing
167
168
```python
169
import keyboard
170
import re
171
172
class SmartTextProcessor:
173
def __init__(self):
174
self.abbreviations = {}
175
self.word_handlers = {}
176
self.setup_default_processing()
177
178
def setup_default_processing(self):
179
# Smart capitalization
180
keyboard.add_word_listener('i', self.capitalize_i, triggers=['space', '.', '!', '?'])
181
182
# Auto-correct common mistakes
183
self.add_smart_abbreviation('teh', 'the')
184
self.add_smart_abbreviation('adn', 'and')
185
self.add_smart_abbreviation('recieve', 'receive')
186
self.add_smart_abbreviation('occured', 'occurred')
187
188
# Smart punctuation
189
keyboard.add_word_listener('--', self.em_dash)
190
keyboard.add_word_listener('...', self.ellipsis)
191
192
def capitalize_i(self):
193
"""Auto-capitalize standalone 'i'."""
194
keyboard.send('backspace')
195
keyboard.write('I')
196
197
def em_dash(self):
198
"""Replace -- with em dash."""
199
keyboard.send('backspace, backspace')
200
keyboard.write('—')
201
202
def ellipsis(self):
203
"""Replace ... with proper ellipsis."""
204
keyboard.send('backspace, backspace, backspace')
205
keyboard.write('…')
206
207
def add_smart_abbreviation(self, wrong, correct):
208
"""Add abbreviation with smart capitalization."""
209
def replace_with_case():
210
# Simple case handling - could be more sophisticated
211
keyboard.send('backspace' * len(wrong))
212
keyboard.write(correct)
213
214
self.abbreviations[wrong] = keyboard.add_abbreviation(wrong, correct)
215
# Also handle capitalized version
216
wrong_cap = wrong.capitalize()
217
correct_cap = correct.capitalize()
218
self.abbreviations[wrong_cap] = keyboard.add_abbreviation(wrong_cap, correct_cap)
219
220
def cleanup(self):
221
"""Remove all text processing."""
222
for remove_func in self.abbreviations.values():
223
remove_func()
224
225
# Usage
226
processor = SmartTextProcessor()
227
print('Smart text processing active!')
228
print('Try typing: i am, teh, adn, recieve, occured, --, ...')
229
print('Press ESC to exit.')
230
231
keyboard.wait('esc')
232
processor.cleanup()
233
```
234
235
### Dynamic Abbreviation System
236
237
```python
238
import keyboard
239
import json
240
import os
241
242
class AbbreviationManager:
243
def __init__(self, config_file='abbreviations.json'):
244
self.config_file = config_file
245
self.active_abbreviations = {}
246
self.load_abbreviations()
247
self.setup_management_hotkeys()
248
249
def load_abbreviations(self):
250
"""Load abbreviations from config file."""
251
if os.path.exists(self.config_file):
252
with open(self.config_file, 'r') as f:
253
abbrevs = json.load(f)
254
for short, full in abbrevs.items():
255
self.add_abbreviation(short, full)
256
print(f'Loaded {len(abbrevs)} abbreviations')
257
258
def save_abbreviations(self):
259
"""Save current abbreviations to config file."""
260
abbrevs = {}
261
# Extract abbreviation data (simplified)
262
with open(self.config_file, 'w') as f:
263
json.dump(abbrevs, f, indent=2)
264
265
def add_abbreviation(self, short, full):
266
"""Add a new abbreviation."""
267
if short in self.active_abbreviations:
268
self.remove_abbreviation(short)
269
270
remove_func = keyboard.add_abbreviation(short, full)
271
self.active_abbreviations[short] = {
272
'full': full,
273
'remove_func': remove_func
274
}
275
print(f'Added abbreviation: {short} -> {full}')
276
277
def remove_abbreviation(self, short):
278
"""Remove an abbreviation."""
279
if short in self.active_abbreviations:
280
self.active_abbreviations[short]['remove_func']()
281
del self.active_abbreviations[short]
282
print(f'Removed abbreviation: {short}')
283
284
def list_abbreviations(self):
285
"""List all active abbreviations."""
286
print('Active abbreviations:')
287
for short, data in self.active_abbreviations.items():
288
print(f' {short} -> {data["full"]}')
289
290
def setup_management_hotkeys(self):
291
"""Set up hotkeys for managing abbreviations."""
292
keyboard.add_hotkey('ctrl+alt+a', self.interactive_add)
293
keyboard.add_hotkey('ctrl+alt+r', self.interactive_remove)
294
keyboard.add_hotkey('ctrl+alt+l', self.list_abbreviations)
295
296
def interactive_add(self):
297
"""Interactively add abbreviation."""
298
print('\n=== Add Abbreviation ===')
299
short = input('Enter abbreviation: ').strip()
300
if not short:
301
return
302
303
full = input('Enter full text: ').strip()
304
if not full:
305
return
306
307
self.add_abbreviation(short, full)
308
309
def interactive_remove(self):
310
"""Interactively remove abbreviation."""
311
print('\n=== Remove Abbreviation ===')
312
self.list_abbreviations()
313
short = input('Enter abbreviation to remove: ').strip()
314
if short:
315
self.remove_abbreviation(short)
316
317
def cleanup(self):
318
"""Clean up all abbreviations."""
319
keyboard.unhook_all_hotkeys()
320
for data in self.active_abbreviations.values():
321
data['remove_func']()
322
323
# Usage
324
manager = AbbreviationManager()
325
326
# Add some default abbreviations
327
manager.add_abbreviation('brb', 'be right back')
328
manager.add_abbreviation('omw', 'on my way')
329
manager.add_abbreviation('lol', 'laugh out loud')
330
331
print('Abbreviation manager active!')
332
print('Ctrl+Alt+A: Add abbreviation')
333
print('Ctrl+Alt+R: Remove abbreviation')
334
print('Ctrl+Alt+L: List abbreviations')
335
print('Press ESC to exit.')
336
337
keyboard.wait('esc')
338
manager.cleanup()
339
```
340
341
### Text Analysis from Recording
342
343
```python
344
import keyboard
345
from collections import Counter
346
import re
347
348
def analyze_typing_patterns():
349
"""Analyze typing patterns from a recording."""
350
351
print('Type some text for analysis. Press ESC when done.')
352
events = keyboard.record()
353
354
# Extract typed strings
355
typed_strings = list(keyboard.get_typed_strings(events))
356
full_text = ' '.join(typed_strings)
357
358
print(f'\n=== Typing Analysis ===')
359
print(f'Full text: "{full_text}"')
360
print(f'Total strings: {len(typed_strings)}')
361
print(f'Total characters: {len(full_text)}')
362
363
# Word frequency analysis
364
words = re.findall(r'\b\w+\b', full_text.lower())
365
word_freq = Counter(words)
366
367
print(f'\nWord frequency:')
368
for word, count in word_freq.most_common(10):
369
print(f' {word}: {count}')
370
371
# Character frequency
372
char_freq = Counter(c.lower() for c in full_text if c.isalpha())
373
print(f'\nCharacter frequency:')
374
for char, count in char_freq.most_common(10):
375
print(f' {char}: {count}')
376
377
# Suggest abbreviations for common phrases
378
print(f'\nSuggested abbreviations:')
379
phrases = re.findall(r'\b\w+\s+\w+\b', full_text.lower())
380
phrase_freq = Counter(phrases)
381
382
for phrase, count in phrase_freq.most_common(5):
383
if count > 1 and len(phrase) > 10:
384
abbrev = ''.join(word[0] for word in phrase.split())
385
print(f' "{phrase}" -> "{abbrev}" (used {count} times)')
386
387
# Run analysis
388
analyze_typing_patterns()
389
```
390
391
### Context-Aware Text Replacement
392
393
```python
394
import keyboard
395
import time
396
397
class ContextualReplacements:
398
def __init__(self):
399
self.contexts = {}
400
self.current_context = 'default'
401
self.setup_contexts()
402
403
def setup_contexts(self):
404
"""Set up different contexts for text replacement."""
405
406
# Programming context
407
self.contexts['programming'] = {
408
'fn': 'function',
409
'ret': 'return',
410
'var': 'variable',
411
'cls': 'class',
412
'imp': 'import',
413
'def': 'definition'
414
}
415
416
# Email context
417
self.contexts['email'] = {
418
'ty': 'Thank you',
419
'br': 'Best regards',
420
'fyi': 'For your information',
421
'asap': 'as soon as possible',
422
'mtg': 'meeting',
423
'fup': 'follow up'
424
}
425
426
# Default context
427
self.contexts['default'] = {
428
'btw': 'by the way',
429
'imo': 'in my opinion',
430
'afaik': 'as far as I know',
431
'tbh': 'to be honest'
432
}
433
434
self.activate_context('default')
435
self.setup_context_switching()
436
437
def activate_context(self, context_name):
438
"""Activate a specific context."""
439
if context_name not in self.contexts:
440
print(f'Unknown context: {context_name}')
441
return
442
443
# Remove current abbreviations
444
if hasattr(self, 'active_abbrevs'):
445
for remove_func in self.active_abbrevs.values():
446
remove_func()
447
448
# Add new context abbreviations
449
self.active_abbrevs = {}
450
self.current_context = context_name
451
452
for abbrev, full in self.contexts[context_name].items():
453
remove_func = keyboard.add_abbreviation(abbrev, full)
454
self.active_abbrevs[abbrev] = remove_func
455
456
print(f'Activated {context_name} context with {len(self.contexts[context_name])} abbreviations')
457
458
def setup_context_switching(self):
459
"""Set up hotkeys for context switching."""
460
keyboard.add_hotkey('ctrl+1', lambda: self.activate_context('default'))
461
keyboard.add_hotkey('ctrl+2', lambda: self.activate_context('programming'))
462
keyboard.add_hotkey('ctrl+3', lambda: self.activate_context('email'))
463
464
def cleanup(self):
465
"""Clean up all abbreviations and hotkeys."""
466
if hasattr(self, 'active_abbrevs'):
467
for remove_func in self.active_abbrevs.values():
468
remove_func()
469
keyboard.unhook_all_hotkeys()
470
471
# Usage
472
contextual = ContextualReplacements()
473
474
print('Contextual text replacement active!')
475
print('Ctrl+1: Default context (btw, imo, afaik, tbh)')
476
print('Ctrl+2: Programming context (fn, ret, var, cls, imp, def)')
477
print('Ctrl+3: Email context (ty, br, fyi, asap, mtg, fup)')
478
print('Press ESC to exit.')
479
480
keyboard.wait('esc')
481
contextual.cleanup()
482
```
483
484
## Text Processing Considerations
485
486
### Performance
487
- Word listening adds overhead to all keyboard input
488
- Large numbers of abbreviations can impact responsiveness
489
- Pattern matching is performed on every keystroke
490
491
### Timing and Reliability
492
- Timeout values affect responsiveness vs accuracy
493
- Fast typing may not trigger word detection properly
494
- System load can affect timing-sensitive operations
495
496
### Language and Layout Support
497
- Text extraction works best with standard Latin keyboards
498
- Special characters and diacritics may not be handled perfectly
499
- Keyboard layout changes can affect character mapping
500
501
### Case Sensitivity
502
- Word matching is case-sensitive by default
503
- Consider both lowercase and capitalized versions for abbreviations
504
- Smart capitalization requires additional logic
505
506
## Error Handling
507
508
Text processing may encounter:
509
- Invalid regular expressions in pattern matching
510
- Timeout issues with fast typing
511
- Platform limitations on text input simulation
512
- Conflicts between multiple word listeners
513
514
The package handles most errors gracefully but may miss text detection in edge cases or high-load situations.