or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

hotkeys.mdindex.mdinteractive-input.mdkey-simulation.mdkeyboard-events.mdrecording-playback.mdtext-processing.md

text-processing.mddocs/

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.