Skip to content

fix: improve error handling in InputHandler to prevent stuck keys#241

Closed
kunal-bunkar wants to merge 3 commits into
AOSSIE-Org:mainfrom
kunal-bunkar:fix/inputhandler-error-handling
Closed

fix: improve error handling in InputHandler to prevent stuck keys#241
kunal-bunkar wants to merge 3 commits into
AOSSIE-Org:mainfrom
kunal-bunkar:fix/inputhandler-error-handling

Conversation

@kunal-bunkar

@kunal-bunkar kunal-bunkar commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Addressed Issues:

Fixes #202

Description

This PR improves error handling in src/server/InputHandler.ts to prevent stuck keys or mouse state when @nut-tree-fork/nut-js operations fail (e.g., screen lock, permission/accessibility changes, OS-level failures).

Changes made:

  • Added localized try/catch blocks around nut-js keyboard/mouse operations in move, click, scroll, zoom, key, combo, and text handlers so errors don’t propagate out of handleMessage().
  • Ensured key press flows attempt safe cleanup: pressKey() calls are paired with releaseKey() in finally, and release failures are logged (using .catch) instead of throwing.
  • Combo handling now guarantees releasing any successfully pressed keys (reverse order) even if intermediate presses/typing fail.
  • Errors are logged with context (type/keys) without crashing the input flow.

Screen Mirror

  • Screen MIrror works.

Checklist

  • My PR addresses a single issue, fixes a single bug or makes a single improvement.

  • My code follows the project's code style and conventions

  • I have performed a self-review of my own code

  • I have commented my code, particularly in hard-to-understand areas

  • If applicable, I have made corresponding changes or additions to the documentation

  • If applicable, I have made corresponding changes or additions to tests

  • My changes generate no new warnings or errors

  • I have joined the and I will share a link to this PR with the project maintainers there

Summary by CodeRabbit

  • Bug Fixes
    • Hardened error handling across input processing (movement, clicks, scroll, zoom, key presses, combos, and text) to prevent crashes.
    • Added safer release/fallback paths and fallback behaviors for ambiguous inputs.
    • Improved logging for input failures to aid diagnosis and ensure more resilient runtime behavior.

@coderabbitai

coderabbitai Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Added localized try/catch/finally error handling across input processing in InputHandler to catch and log nut-js failures, ensure pressed keys and mouse buttons are released, and prevent uncaught exceptions or stuck input states. Also adjusted concurrent operation error handling and updated package manifest.

Changes

Cohort / File(s) Summary
Input Handler Error Safety
src/server/InputHandler.ts
Inserted try/catch around move, click, scroll, zoom, key, combo, and text branches; ensured press/release pairs run with finally and added error logging for all input operations.
Manifest
package.json
Updated package manifest (lines changed reported in diff).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Suggested labels

Typescript Lang

Poem

🐰 I hopped through keys both bold and small,
Caught every error, freed them all,
With try and finally I tidy the scene,
No stuck key left — the board stays clean! 🥕

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: improve error handling in InputHandler to prevent stuck keys' directly summarizes the main change, which is adding robust error handling to prevent stuck keys when operations fail.
Description check ✅ Passed The PR description covers the addressed issue (#202), explains the key changes made (try/catch blocks, cleanup guarantees, error logging), and includes relevant checklist items, despite some functional verification items being incomplete.
Linked Issues check ✅ Passed The PR successfully addresses all coding objectives from #202: added localized try/catch blocks around nut-js operations in all required handlers (key, combo, move, click, text, scroll, zoom), ensured pressKey/releaseKey pairing with finally blocks, implemented reverse-order key release for combos, and added contextual error logging.
Out of Scope Changes check ✅ Passed All changes are directly related to improving error handling in InputHandler.ts as specified in issue #202; no unrelated modifications detected in the file.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/server/InputHandler.ts (2)

368-373: ⚠️ Potential issue | 🟡 Minor

Avoid success logging after a caught combo failure.

Line 372 logs Combo complete even when Line 368 catches an error, which makes operational logs misleading.

🔧 Proposed fix
-					try {
+					let comboSucceeded = false
+					try {
 						const nutKeys: (Key | string)[] = []
@@
-					} catch (err) {
+						comboSucceeded = true
+					} catch (err) {
 						console.error("Error handling combo input:", err, msg.keys)
 					}
 
-					console.log(`Combo complete: ${msg.keys.join("+")}`)
+					if (comboSucceeded) {
+						console.log(`Combo complete: ${msg.keys.join("+")}`)
+					}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/server/InputHandler.ts` around lines 368 - 373, The success log "Combo
complete: ${msg.keys.join("+")}" is executed even when the preceding try/catch
caught an error; move the success logging so it only runs on successful
completion (e.g., place the console.log inside the try block that wraps the
combo handling logic, or use a local success flag set to true at the end of the
try and log only if the flag is true) and keep the catch block only for
console.error("Error handling combo input:", err, msg.keys) to avoid misleading
logs; update the code around the try/catch that surrounds the combo handling in
InputHandler (referencing msg.keys) accordingly.

241-259: ⚠️ Potential issue | 🔴 Critical

Move zoom modifier press inside the guarded block to prevent uncaught failures.

Line 241 can throw before entering the try/catch, which still allows handleMessage() to reject on zoom failures.

🔧 Proposed fix
-					if (amount !== 0) {
-						await keyboard.pressKey(Key.LeftControl)
-						try {
-							if (amount > 0) {
-								await mouse.scrollDown(amount)
-							} else {
-								await mouse.scrollUp(-amount)
-							}
-						} catch (err) {
-							console.error("Error handling zoom input:", err)
-						} finally {
-							await keyboard
-								.releaseKey(Key.LeftControl)
-								.catch((releaseErr) => {
-									console.error(
-										"Error releasing control key after zoom:",
-										releaseErr,
-									)
-								})
-						}
-					}
+					if (amount !== 0) {
+						let ctrlPressed = false
+						try {
+							await keyboard.pressKey(Key.LeftControl)
+							ctrlPressed = true
+							if (amount > 0) {
+								await mouse.scrollDown(amount)
+							} else {
+								await mouse.scrollUp(-amount)
+							}
+						} catch (err) {
+							console.error("Error handling zoom input:", err)
+						} finally {
+							if (ctrlPressed) {
+								await keyboard
+									.releaseKey(Key.LeftControl)
+									.catch((releaseErr) => {
+										console.error(
+											"Error releasing control key after zoom:",
+											releaseErr,
+										)
+									})
+							}
+						}
+					}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/server/InputHandler.ts` around lines 241 - 259, The zoom modifier key
press (keyboard.pressKey(Key.LeftControl)) must be moved inside the try so
errors from pressing don't escape the guarded block; update the block around
mouse.scrollDown/scrollUp to call keyboard.pressKey(Key.LeftControl) at the
start of the try, maintain a local flag (e.g., controlPressed) set only if
pressKey succeeds, and in finally call keyboard.releaseKey(Key.LeftControl) only
when controlPressed is true (still catching release errors via .catch). Ensure
mouse.scrollDown/scrollUp and keyboard.releaseKey remain in the try/finally
structure so handleMessage won't reject on zoom failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/server/InputHandler.ts`:
- Around line 249-259: The code formatting in the finally block around the zoom
handling (the await keyboard.releaseKey(Key.LeftControl).catch(...) call and its
console.error callback) is incorrect and causing a Biome lint failure; reformat
that block to match project style (consistent indentation, spacing, trailing
commas, and bracket placement) so the finally block looks clean and
single-indented under the try/finally, keeping the same identifiers (keyboard,
releaseKey, Key.LeftControl, releaseErr, console.error) and the existing
.catch(...) error handler intact.

---

Outside diff comments:
In `@src/server/InputHandler.ts`:
- Around line 368-373: The success log "Combo complete: ${msg.keys.join("+")}"
is executed even when the preceding try/catch caught an error; move the success
logging so it only runs on successful completion (e.g., place the console.log
inside the try block that wraps the combo handling logic, or use a local success
flag set to true at the end of the try and log only if the flag is true) and
keep the catch block only for console.error("Error handling combo input:", err,
msg.keys) to avoid misleading logs; update the code around the try/catch that
surrounds the combo handling in InputHandler (referencing msg.keys) accordingly.
- Around line 241-259: The zoom modifier key press
(keyboard.pressKey(Key.LeftControl)) must be moved inside the try so errors from
pressing don't escape the guarded block; update the block around
mouse.scrollDown/scrollUp to call keyboard.pressKey(Key.LeftControl) at the
start of the try, maintain a local flag (e.g., controlPressed) set only if
pressKey succeeds, and in finally call keyboard.releaseKey(Key.LeftControl) only
when controlPressed is true (still catching release errors via .catch). Ensure
mouse.scrollDown/scrollUp and keyboard.releaseKey remain in the try/finally
structure so handleMessage won't reject on zoom failures.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 54842a8 and c4c8405.

📒 Files selected for processing (1)
  • src/server/InputHandler.ts

Comment thread src/server/InputHandler.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/server/InputHandler.ts (1)

241-257: ⚠️ Potential issue | 🔴 Critical

Wrap pressKey inside the zoom try/finally block.

At line 241, await keyboard.pressKey(Key.LeftControl) executes before the try block. If that call rejects, the error propagates without being caught by this zoom block's catch/finally path, and the control key is never released. Move the press into the try block so error handling and key release stay in one containment scope.

🔧 Proposed fix
 if (amount !== 0) {
-	await keyboard.pressKey(Key.LeftControl)
 	try {
+		await keyboard.pressKey(Key.LeftControl)
 		if (amount > 0) {
 			await mouse.scrollDown(amount)
 		} else {
 			await mouse.scrollUp(-amount)
 		}
 	} catch (err) {
 		console.error("Error handling zoom input:", err)
 	} finally {
 		await keyboard.releaseKey(Key.LeftControl).catch((releaseErr) => {
 			console.error(
 				"Error releasing control key after zoom:",
 				releaseErr,
 			)
 		})
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/server/InputHandler.ts` around lines 241 - 257, The call to
keyboard.pressKey(Key.LeftControl) is outside the try/finally so if pressKey
rejects the catch/finally won't run and the control key may never be released;
move the await keyboard.pressKey(Key.LeftControl) inside the same try block that
calls mouse.scrollDown/mouse.scrollUp and ensure
keyboard.releaseKey(Key.LeftControl) remains in the finally (handling release
errors as before) so press, scroll (mouse.scrollDown/mouse.scrollUp), and
release are all within one try/finally scope.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/server/InputHandler.ts`:
- Around line 241-257: The call to keyboard.pressKey(Key.LeftControl) is outside
the try/finally so if pressKey rejects the catch/finally won't run and the
control key may never be released; move the await
keyboard.pressKey(Key.LeftControl) inside the same try block that calls
mouse.scrollDown/mouse.scrollUp and ensure keyboard.releaseKey(Key.LeftControl)
remains in the finally (handling release errors as before) so press, scroll
(mouse.scrollDown/mouse.scrollUp), and release are all within one try/finally
scope.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cb923340-b78a-4c7a-860c-cdc47f70de4d

📥 Commits

Reviewing files that changed from the base of the PR and between c4c8405 and 7d56bd8.

📒 Files selected for processing (1)
  • src/server/InputHandler.ts

@imxade imxade closed this Mar 7, 2026
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.

[Bug]: Improve Error Handling in InputHandler to Prevent Stuck Keys or Mouse State

2 participants