Terminal-based typing trainer (Python 3.14, curses) similar to keybr.com.
Author: johnvexcoder (https://github.com/johnvexcoder)
Main file: Keybr.py
Stats file: ~/.keybr_stats.json
- Common Words — 365 words, random 20 per session, 45s timer
- Hard Words — 159 words, random 15 per session, 60s timer
- Sentences — 25 long sentences, random pick, 45s timer
- Symbols & Punctuation — 20 sentences with !, ?, ", etc., 40s timer
- Capital Letters — 20 properly capitalized sentences, 50s timer
- Keybr Offline — Adaptive learning with dictionary words, 45s timer
- Statistics — Per-letter accuracy, session history, best WPM per category
- Centered everything (header, stats, text area, progress bar, instructions, stats screen)
- Word wrapping — words never split across lines
- Color-coded feedback: green=correct, red=wrong, yellow underline=current char
- Per-letter accuracy tracking with persistent stats
- Ctrl+C exit confirmation dialog (red-bordered box, Y/N)
- Per-category best WPM box on menu (properly aligned)
- Overall stats box on menu (Best WPM, Sessions, Accuracy, Practice time)
- Auto-start next round after completing a test
- Countdown timer — shows below WPM, green >10s / red <=10s, auto-finishes session at 0:00
- Progressive letter unlocking (starts with 9 most frequent: e t a o i n s r h)
- Per-letter confidence scoring (accuracy 70% + speed 30%)
- Bigram tracking for combo weaknesses
- Weak letter detection — ranks unlocked letters by confidence
- Dictionary-based text generation (~1500 real English words, 3-5 letters)
- Words containing weak letters are weighted 2-5x more heavily
- Key map visualization after sessions (green/yellow/red/gray)
- Shows weak bigrams and recent sessions
.gitignore— excludes pycache, .keybr_stats.json, venvs, IDE filesLICENSE— MIT License credited to johnvexcoderREADME.md— Full documentation with all modes, screenshots section, credits
- Real words, not Markov chains — Markov chain pseudo-words ("hrrs, hrss, hars") were unusable. Replaced with dictionary-based generation filtered by weak letters.
- Timer per category — Hard words get 60s, symbols get 40s, etc. based on difficulty.
- No adaptive learning in other modes — Only Keybr Offline tracks per-letter progress. Other modes are fixed random selection.
- Laptop: Lenovo ThinkPad X280 20KESBQG00
- CPU: Intel Core i5-8250U (4C/8T, 1.6GHz base, 3.4GHz turbo)
- RAM: 7.5GB
- Storage: NVMe 238GB (OS) + SATA HDD 116GB + 7.5GB zram swap
- GPU: Intel UHD 620 (integrated only)
- WiFi: Intel wireless (iwlwifi)
- Battery: 48.1Wh design, 36.8Wh current (76% health, 788 cycles)
- Installed: TLP 1.10.1 (replaced tuned/tuned-ppd which conflicted)
- Status: enabled, active,
balanced/BATprofile on battery - tlp-rdw: enabled
- tlp-pd: enabled (TLP profiles daemon)
- Config:
/etc/tlp.conf
START_CHARGE_THRESH_BAT0=80 # NEEDS FIX → should be 40
STOP_CHARGE_THRESH_BAT0=90 # NEEDS FIX → should be 80
CPU_SCALING_GOVERNOR_ON_AC=performance
CPU_SCALING_GOVERNOR_ON_BAT=powersave
CPU_ENERGY_PERF_POLICY_ON_AC=performance
CPU_ENERGY_PERF_POLICY_ON_BAT=balance_power
CPU_BOOST_ON_AC=1
CPU_BOOST_ON_BAT=0 # Disables turbo on battery = 800MHz
DISK_APM_LEVEL_ON_AC="255 255"
DISK_APM_LEVEL_ON_BAT="128 128"
DISK_SPINDOWN_TIMEOUT_ON_AC="0"
DISK_SPINDOWN_TIMEOUT_ON_BAT="12"
WIFI_PWR_ON_AC=off
WIFI_PWR_ON_BAT=on
SOUND_POWER_SAVE_ON_AC=0
SOUND_POWER_SAVE_ON_BAT=1
PCIE_ASPM_ON_AC=default
PCIE_ASPM_ON_BAT=powersupersave
RUNTIME_PM_ON_AC=auto
RUNTIME_PM_ON_BAT=auto
- File:
/etc/sysctl.d/99-swappiness.conf - Value:
vm.swappiness=10(less swap usage, better battery)
- read_ahead_kb: 2048 (increased from 128)
- udev rule:
/etc/udev/rules.d/60-nvme.rulesACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/read_ahead_kb}="2048" - scheduler:
none(correct for NVMe)
- scheduler:
bfq(good for rotational) - ** rotational:** 1 (confirmed HDD)
abrtd+abrt-journal-core+abrt-oops+abrt-xorg(crash reporting)avahi-daemon+avahi-daemon.socket(mDNS, not needed)ModemManager(no mobile broadband)
- tlp, tlp-pd, thermald, irqbalance, smartd, fwupd, chronyd
- gdm, cups, colord, rtkit-daemon, udisks2, upower
- wpa_supplicant, bluetooth (if not used, can disable)
- Status: running (FedoraWorkstation zone)
- Interfaces: wlp59s0
- Ports open: 1025-65535/tcp and /udp (VERY wide — potential security concern)
- Services: dhcpv6-client, samba-client
- TCP congestion: cubic
- tcp_fastopen: 1 (could enable to 3)
- tcp_window_scaling: 1 (good)
- somaxconn: 4096
- Version: 150.1.92.144 (RPM install, not flatpak)
- Extensions: 10 installed (disabled unused ones, kept enabled ones)
- Performance flags applied:
#enable-gpu-rasterization→ Enabled#enable-zero-copy→ Enabled#smooth-scrolling→ Enabled
- Settings: Hardware acceleration enabled, Memory Saver enabled
- CPU cores: 41-44°C (healthy, no throttling)
- NVMe: 29-37°C
- Fan: 0 RPM (passive cooling, no thermal issues)
- Consider adding adaptive learning to other modes
- Could add difficulty levels within modes
- Could add a "custom text" mode where user pastes their own text
- Could export statistics to CSV
- Fix charge thresholds: START=40, STOP=80 (788 cycles, battery degrading)
- Enable CPU boost on battery:
CPU_BOOST_ON_BAT=1(currently 800MHz, 4x slower) - Tighten firewall ports (1025-65535 is too wide)
- Disable Bluetooth if not used
- Install dnf-automatic for security updates
- Consider disabling swap partition (zram handles it)
python3 Keybr.py- User is on Fedora 44 Workstation with Python 3.14
- ThinkPad X280 with i5-8250U, 8GB RAM, NVMe + HDD
- Repo pushed to https://github.com/johnvexcoder/Python-Keybr (branch: master)
- Stats persist in
~/.keybr_stats.json - User runs opencode, Brave, VSCode, Firefox concurrently (high RAM usage)