Skip to content

Tesseract setup helpers, multi-click, drag pacing and Windows key names for Jeffrey_RPA - #491

Merged
JE-Chen merged 7 commits into
devfrom
feat/jeffrey-rpa-gui-apis
Oct 8, 2026
Merged

JE-Chen merged 7 commits into
devfrom
feat/jeffrey-rpa-gui-apis

Conversation

@JE-Chen

@JE-Chen JE-Chen commented Oct 1, 2026

Copy link
Copy Markdown
Member

Four groups of public API so Jeffrey_RPA can drop the desktop-automation code it hand-rolls in JeffreyRPA/_gui_control.py. One commit per group, plus a refactor commit that comes before the drag change and a typing fix for the click change.

1. Tesseract setup helpers (utils/ocr/tesseract_setup.py, exported from the facade)

  • find_tesseract_cmd() -> Optional[str]: looks in $TESSERACT_CMD, then PATH, then the installers' default folders. It only looks.
  • set_tessdata_dir(path) -> Optional[str]: resolves the path, requires a directory and sets TESSDATA_PREFIX. None clears it.
  • ocr_languages() -> Optional[List[str]]: the sorted language codes. [] means the engine answered and has no language data; None means the engine could not be asked. It is never cached.
  • ocr_status() -> OCRStatus(ok, reason): reason is one of ready, missing_package, missing_engine, engine_unusable or no_language_data.
  • TesseractBackend.cmd, version() and languages(). version() catches the SystemExit that pytesseract raises for a version string it cannot parse.
  • Jeffrey_RPA no longer has to write pytesseract.pytesseract.tesseract_cmd itself, so TesseractBackend.set_cmd stays the only writer.
  • Also exposed as AC_ocr_status / AC_ocr_languages, as MCP tools and in the Script Builder.

2. Multi-click

  • click_mouse(mouse_keycode, x=None, y=None, clicks=1, interval=0.0): every click lands on the same point, interval seconds apart.
  • The defaults keep the old single click, and a single click records the same action as before.
  • Invalid values are refused before any click: a bool or float for clicks, or a NaN, infinite or negative interval.
  • On macOS the clicks still arrive as separate single clicks. This is documented and recorded in Progress.md.

3. Drag pacing

  • tween_drag and drag_path gain step_delay_s and settle_s, both 0 by default, which leaves the event sequence unchanged.
  • Behaviour change on failure: when a step raises, the button is now released in a finally at the last point the pointer reached. It used to be released at the end of the path. A cleanup release that fails is logged instead of raised over the original error, the same pattern hotkey and type_keyboard use.
  • The shared loop is extracted first, in a refactor commit with no behaviour change.

4. Windows key table

  • New keys: the OEM keys, browser_home, a lower-case launch_app2 (LAUNCH_APP2 stays) and the common aliases.
  • The aliases live in one keyboard_key_aliases map, which every platform publishes; it is empty off Windows.
  • keyboard_key_name(keycode) returns the canonical name and never an alias. For every code the old table named, it returns the name a shortest-lower-case lookup gave before any alias existed. This is pinned for every code in the table.

Checks run locally

  • ruff (package and new tests), bandit, radon and pylint on the changed modules.
  • The typing contract: the only failure is utils/ci_annotations, which this branch does not touch; it fails the same way with the local mypy 2.1.
  • The new tests (27 + 22 + 25 + 68) and the related existing suites: doc counts and line counts, the stub generator, the adapter registry sweep, the cross-project contracts, the file-length and complexity budgets, and the OCR, drag, key and wrapper tests.
  • The full suite was not run on this machine, because it shares the desktop with an unattended job.

Notes

  • No version bump.
  • Jeffrey_RPA loads the library from its own working tree, so nothing here reaches it until that tree moves.

…ing pytesseract

Jeffrey_RPA imported pytesseract itself to list languages and probe the
engine, and wrote pytesseract's tesseract_cmd global directly, giving that
global a second writer outside this package. find_tesseract_cmd,
set_tessdata_dir, ocr_languages and ocr_status answer those questions here,
with ocr_languages keeping "no language data" ([]) apart from "cannot ask"
(None), and TesseractBackend.set_cmd stays the only writer.

AC_ocr_status / AC_ocr_languages and the matching MCP tools and Script
Builder entries expose the same checks to action files.
Jeffrey_RPA built a double-click from two click_mouse calls and its own
sleep. click_mouse(clicks=, interval=) resolves the point once, clicks it
clicks times with interval seconds between, and refuses a bool, float or
non-finite value before any click. The defaults are the old single click
and record the same action as before.

AC_click_mouse, the ac_click_mouse MCP tool, the MCP fake backend and the
Script Builder take both parameters. macOS apps read a click count the osx
backend never sets, so there the clicks stay separate single clicks; that
is documented and recorded in Progress.md.
…d drag_path

The two drags carried identical copies of the same loop. Both now call
tween_drag._drag_through; behaviour is unchanged, which the existing drag
tests confirm, so the pacing and release changes that follow touch one
place.
Apps that judge a drag by the pointer's motion read the library's drags,
which moved as fast as events could be sent, as clicks, so Jeffrey_RPA
kept its own loop. The shared drag sequence now takes step_delay_s (after
each move) and settle_s (on the start before the press, after it and
before the release); both default to 0 and leave the event sequence as it
was.

When a step raised, the button used to be released at the end of the
path, completing a drop the drag never reached. The release now runs in
a finally at the last point the pointer reached, and a failing cleanup
release is logged rather than raised over the original error, the same
pattern hotkey and type_keyboard use.
… interval keys

The typing contract checks the whole package; the dict literal was
inferred as holding only the keycode and coordinate types, so adding
clicks and interval to it failed there on every target platform.
…ey aliases, and look keys up by canonical name

Jeffrey_RPA kept its own alias table and a table of keys the library
could not name (the OEM keys, browser_home, and launch_app2, which only
existed upper-case), converting names to codes before every call. The
Windows table now has those keys under the same names and codes, plus
the aliases (ctrl, alt, enter, esc, win, pgup, numpad0, plus, ...), kept
in one keyboard_key_aliases map that every platform publishes.

keyboard_key_name(keycode) answers with the canonical name and never an
alias, so adding an alias cannot change the key names a recorder writes;
for every code the old table named it returns what a shortest-lower-case
lookup returned before any alias existed.
@codacy-production

Copy link
Copy Markdown

Not up to standards ⛔

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

One condition per assert and bare fixture decorators in the new tests, a
single exception-raising call inside pytest.raises, one extend for the two
new Script Builder entries, PEP 604 unions on the changed signatures, and
a justified NOSONAR where TesseractBackend.version() deliberately turns
pytesseract's SystemExit into OCRBackendNotAvailableError.
@sonarqubecloud

sonarqubecloud Bot commented Oct 1, 2026

Copy link
Copy Markdown

@JE-Chen

JE-Chen commented Oct 8, 2026

Copy link
Copy Markdown
Member Author

Merged into main through #501 and released in 0.0.226. This pull request targets dev, so it stays open until dev is fast-forwarded to main (dev is an ancestor of main, nothing to resolve); it then closes as merged on its own.

@JE-Chen
JE-Chen merged commit 2dcca67 into dev Oct 8, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant