The automation tool for Windows that knows autocomplete from typing
Every listicle ranks automation tools for Windows by price, licensing, and drag-and-drop feel. Those rankings skip the one question that decides whether a recording replays next Tuesday: does the recorder know the user picked “New York” from an autocomplete list, or does it think the user typed N, e, w, down-arrow, down-arrow, enter? Terminator’s workflow recorder makes that call with a 5000ms timer and emits a typed event called TextInputCompleted instead of a keystroke stream.
The silent-miss bug in most Windows recorders
A user records a workflow in Chrome. They click the City field, type N-e-w, wait for the autocomplete list to open, press Down twice, hit Enter, and the field ends up with “New York”. A traditional keystroke recorder saves six events: N, e, w, Down, Down, Enter. The raw log is faithful to the user’s fingers but lies about the user’s intent.
On replay, the automation runs on a cold browser session. Chrome has no autocomplete history for this origin. The bot types N-e-w, sends two Down keys into an empty list, presses Enter, and submits the form with “New”. The test passed on the author’s laptop and silently ships the wrong city to a production ledger.
The fix is to have the recorder notice that the Enter was pressed while the user was navigating a suggestion list, and to save the final value of the field instead of the keystrokes. That is exactly what Terminator’s workflow recorder does, in one function, with a 5000-millisecond window.
The five input-method classes
One enum, five variants, in crates/terminator-workflow-recorder/src/events.rs. Every text field a recording touches ends up tagged with one of these. The replay layer uses the tag to decide how to put the same value into the same field on a different machine.
Typed
Keys land one by one with no paste, no autocomplete navigation, no auto-fill trigger. The default when no other signal fires. Replays by sending the final text_value into the field.
Pasted
A large block of characters arrives within a single event window. The recorder will mark this in later classifier passes. Replays by writing the string directly instead of simulating keys.
AutoFilled
Browser or OS populates the field without a user keystroke — saved credentials, address fill, form memory. The replay layer knows to expect this and does not type over it.
Suggestion
The user navigated a dropdown with arrow keys and pressed Enter inside the 5000ms window in structs.rs line 125. The final field value comes from the list, not from the typed prefix.
Mixed
Multiple methods inside one field-edit session. The replay layer falls back to setting the final text_value verbatim.
The enum, verbatim
The whole taxonomy is thirteen lines of Rust. No external library owns the classification; it is a data type Terminator defines and every SDK binding re-exports.
“if time_since_nav < std::time::Duration::from_millis(5000) { return true; }”
crates/terminator-workflow-recorder/src/recorder/windows/structs.rs line 125. The single comparison that promotes a plain Enter into a TextInputMethod::Suggestion event.
The state machine inside the tracker
Every focused text field gets a TextInputTracker struct. The interesting fields are in_autocomplete_navigation and last_autocomplete_activity. Here is how the state transitions.
Keystroke to TextInputCompleted, Windows path
Typing key
0x30..0x39, 0x41..0x5A, space, punctuation. Increments keystroke_count, sets has_typing_activity=true.
Arrow or Escape
0x26, 0x28, 0x25, 0x27, 0x1B. Flips in_autocomplete_navigation to true and stamps last_autocomplete_activity.
Enter within 5000ms
handle_enter_key returns true. Completion reason becomes suggestion_enter.
Emit
WorkflowEvent::TextInputCompleted with input_method = TextInputMethod::Suggestion.
add_keystroke: the routing function
Each key event goes through one place. Arrows and Escape flip the flag. Typing keys advance the counter. Modifiers and navigation keys are ignored. This is the whole routing.
handle_enter_key: the 5-second decision
This is the only function in the Terminator codebase that turns a plain Enter into a Suggestion event. Fifteen lines. One comparison against Duration::from_millis(5000).
Where the tag gets stamped
The emission point lives in the input-processing loop inside mod.rs. Key code 0x0D asks the tracker whether we are mid-suggestion. If yes, the event is sent with TextInputMethod::Suggestion. If no, the tracker falls through to Typed.
Five-frame walkthrough of a real interaction
A user types “New” in a City field, navigates a Chrome autocomplete with the Down arrow, and hits Enter. Here is what the tracker observes, millisecond by millisecond.
New York from a Chrome autocomplete list
t=0ms
Field gets focus. A TextInputTracker is created and initial_text is captured.
Same field, different tags
Two sample events from the same City field on the same form. The only difference in the user’s behavior is whether the autocomplete list opened. The event shape is identical; only input_method and text_value change.
Typed
Suggestion
Replay with and without the tag
Toggle the two views. The top tab is what a traditional Windows automation tool captures and plays back. The bottom tab is what Terminator captures and plays back. Same user behavior, different outcome on replay.
'New York' autocomplete pick, replayed on a cold session
Recorded events for a 'New York' autocomplete pick in Chrome: KEY N (0x4E) KEY e (0x45) KEY w (0x57) KEY DOWN (0x28) KEY DOWN (0x28) KEY ENTER (0x0D) Replay on a clean machine where the autocomplete list does not appear (cache cleared, different browser profile, different user session).
- N, e, w are typed
- Down arrow twice hits nothing because no suggestion list opened
- Enter submits the form with 'New' in the City field
- Replay silently produces the wrong data
Numbers from the source
The literal argument to Duration::from_millis on line 125 of structs.rs. Long enough that a user who pauses to read the suggestion list still lands inside the window, short enough that a later typing session does not get mis-classified.
Virtual-key codes that set in_autocomplete_navigation to true: 0x26, 0x28, 0x25, 0x27, 0x1B. Arrows in four directions plus Escape for explicit cancel.
Keystrokes the replay layer has to simulate when the recording saw a Suggestion event. The bot writes the final text_value directly into the field, which is why it works even when the autocomplete popup never appears.
Inputs, classifier, outputs
One tracker reads typing keys, arrows, Escape, and Enter from the Windows low-level input hook. One helper makes the Suggestion decision. Five output labels land on the completion event.
TextInputTracker routes raw input into one of five labels
Automation tools for Windows that leave this bug in the recording
Every tool in the row below either saves raw input or stores only the final string with no provenance. None of them tag the completion event with a Suggestion marker so the replay layer can route around the dropdown.
Feature-by-feature
| Feature | Other Windows recorders | Terminator |
|---|---|---|
| Emits a per-field completion event, not a keystroke stream | Mostly no (raw input logs) | WorkflowEvent::TextInputCompleted in events.rs line 495 |
| Classifies input as Typed / Pasted / AutoFilled / Suggestion / Mixed | No differentiation | TextInputMethod enum in events.rs lines 946-958 |
| Detects 'picked from dropdown' via arrow-key plus Enter timing | Records arrows and Enter as keystrokes | 5000ms rule in structs.rs line 125 |
| Records the final text_value of the field | Some do, some store only the keystrokes | element.text(0) with retry in structs.rs line 171 |
| Captures focus method (click, Tab, programmatic) | Rare | FieldFocusMethod enum in events.rs lines 962-973 |
| Escape cancels autocomplete-nav state for the next Enter | Not tracked as a state change | 0x1B in is_autocomplete_navigation_key, structs.rs line 96 |
Verify in the repo
Three grep lines against the public mediar-ai/terminator repo. The enum, the 5000ms literal, and both emission sites all sit under the workflow-recorder crate.
Curious whether this would catch the silent-miss bugs in your current recordings?
Book 20 minutes and bring a flaky recording. We will run it through the workflow recorder and show you exactly which events come back as Typed, Suggestion, or Mixed.
Frequently asked questions
Why does an automation tool for Windows need to know whether the user typed or picked from autocomplete?
Because typing and picking look identical in a raw keystroke log but mean different things on replay. If the user types 'New' and selects 'New York' from a city autocomplete, a recorder that saves the keystrokes will replay N E W on a machine where the dropdown does not open, and the field ends up with 'New' instead of 'New York'. A recorder that marks the finished field as Suggestion remembers the final value and the interaction shape, so the replay restores 'New York' even when no suggestion popup appears.
Where in Terminator's source is this classification done?
Three files in the terminator-workflow-recorder crate. The enum TextInputMethod lives at crates/terminator-workflow-recorder/src/events.rs lines 946 to 958 with variants Typed, Pasted, AutoFilled, Suggestion, and Mixed. The 5000ms decision rule is in handle_enter_key at src/recorder/windows/structs.rs lines 121 to 135. The emission site for the suggestion case is in src/recorder/windows/mod.rs lines 3262 to 3285, where key_code 0x0D triggers the branch that sets input_method to TextInputMethod::Suggestion before sending WorkflowEvent::TextInputCompleted.
Which specific keys put the tracker into autocomplete navigation mode?
Five virtual-key codes from add_keystroke in structs.rs line 68. 0x26 is Up arrow. 0x28 is Down arrow. 0x25 is Left arrow. 0x27 is Right arrow. 0x1B is Escape. When any of these fire, in_autocomplete_navigation is set to true and last_autocomplete_activity is reset to Instant::now(). Escape is included because it cancels a suggestion list without selecting anything, which the replay layer needs to know about.
Why 5000 milliseconds specifically?
It is the literal argument in structs.rs line 125: time_since_nav < std::time::Duration::from_millis(5000). Five seconds is long enough that a human who paused to read the autocomplete list before hitting Enter is still inside the window, and short enough that a separate typing session a minute later does not get mis-classified as a suggestion pick. This is a soft heuristic, tuned to real recordings. The code is in plain view if you want to tune it for your domain.
What does the emitted event actually contain?
A TextInputCompletedEvent struct from events.rs lines 977 to 999. Ten fields. text_value is the final contents of the field. field_name and field_type are the label and role. input_method is one of the five enum variants. focus_method is how the field got focus (MouseClick, KeyboardNav, Programmatic, Unknown). typing_duration_ms is the wall-clock elapsed from first keystroke to completion. keystroke_count is only the typing keys, not arrow keys or modifiers. process_name is the .exe of the host. metadata carries the full UI element reference. This is a replayable representation, not a keystroke log.
What other Windows automation tools differentiate the five input methods?
None that I have found. Power Automate Desktop records the final text value of a field but does not mark how the text arrived; a paste and a type look identical in the flow graph. UiPath Studio's Type Into activity stores a string, with no field for whether the recorder saw it typed or pasted. AutoHotkey has no recorder. WinAppDriver is a driver, not a recorder. TinyTask saves raw input events with no classification. Terminator's workflow-recorder crate is the only Windows automation tool I have read the source of that emits an input_method tag on the completion event.
Does this make the recorded JSON bigger?
Smaller on average. A field where the user typed twelve characters and then picked a suggestion generates one TextInputCompleted event with input_method=Suggestion and the final text_value, not twelve keystroke events plus an arrow-key trail plus an Enter. The SerializableTextInputCompletedEvent type at events.rs line 1524 is the on-disk shape, and it skips empty fields via serde's skip_serializing_if. A recording of a typical form fill is noticeably shorter than the equivalent raw keystroke dump.
How do I turn this on?
It is on by default in terminator-workflow-recorder when record_text_input_completion is true. The Balanced performance mode keeps it on; LowEnergy turns it off because the UIA probes for text value add measurable overhead on weak machines. See WorkflowRecorderConfig::default() in src/recorder.rs and PerformanceMode::low_energy_config() at src/recorder.rs line 46. If you want just this event and nothing else, set record_mouse=false, record_keyboard=false, record_text_input_completion=true, and you will see only the high-level completion events.