How to Create a Command-Line Typing Test Script

Key Points
  • A CLI typing test in 50 lines or fewer is a realistic and useful project for developers.
  • The key challenge is entering raw terminal mode — bypassing the OS's line buffering.
  • Python, Rust, Go, and C all have raw terminal APIs that solve this differently.
  • The scoring formula is the same regardless of platform: (correct_chars / 5) / elapsed_minutes.
  • The best CLI typing tests (like TTYPER) add word highlighting and per-word timing to the basics.

The Core Problem: Raw Terminal Input

In a normal terminal program, input is line-buffered: the OS holds your keystrokes until you press Enter, then sends the whole line to your program. A typing test needs to see each keystroke immediately, character by character, without waiting for Enter. This requires switching the terminal into "raw mode."

Every major language has a way to do this, but the APIs look different:

LanguageRaw mode approachLibrary / built-in
Pythontty.setraw(sys.stdin.fileno())Built-in tty module
Python (easier)readchar.readkey()readchar package
Rustcrossterm or termion crateThird-party
Gogolang.org/x/term packageExtended library
Ctcgetattr() + cfmakeraw()termios.h

A 50-Line Python Script

The structure of a minimal CLI typing test:

  1. Setup: Choose a sentence from a word list.
  2. Display: Print the sentence. Move cursor to start.
  3. Input loop: Enter raw mode. Read characters one at a time.
  4. Comparison: Compare each character to the expected character at the current position.
  5. State tracking: Keep a list of correct/incorrect results per position.
  6. Timer: Record start on first keystroke, end on last correct character.
  7. Scoring: Calculate WPM and accuracy from the state list and elapsed time.
  8. Cleanup: Restore normal terminal mode and display results.

Important: Restore Terminal Mode

The most common mistake in raw terminal programs is forgetting to restore normal mode when the program exits. If your script crashes or you interrupt it with Ctrl+C while in raw mode, the terminal stays in raw mode and becomes unusable — echo is off, Enter doesn't work as expected. Always use a try/finally block to restore the original terminal settings:

import tty, termios, sys

fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
    tty.setraw(fd)
    # ... your input loop here ...
finally:
    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

Adding Visual Feedback

A minimal script can display the target text and overwrite characters in green (correct) or red (incorrect) as you type them. This requires ANSI escape codes for colors and cursor positioning. For example:  starts green text,  starts red,  resets. This is available natively in any Unix-like terminal.

For more features — word-by-word progress, per-second WPM tracking, multiple passages — look at the ready-made TTYPER tool, explained in TTYPER explained for developers. For a browser-based approach with the same architecture concepts, see how to build a typing test website from scratch. For the WPM formula details, read how WPM and accuracy are calculated.

Ready to put it into practice?

Take a free typing test and start tracking your progress.

Free Typing Test →