Skip to content

Conversation

@gmegidish
Copy link
Member

@gmegidish gmegidish commented Dec 1, 2025

Summary by CodeRabbit

New Features

  • Improved text input support for non-ASCII characters on Android devices with optimized ASCII handling and clipboard-based input when available.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 1, 2025

Walkthrough

Modified the SendKeys method in devices/android.go to handle non-ASCII text input through DeviceKit using base64 encoding and clipboard operations. ASCII text is escaped and sent directly via adb shell. Added helper methods to detect DeviceKit installation, validate ASCII text, and escape shell characters. Added encoding/base64 import.

Changes

Cohort / File(s) Summary
Android device input handling
devices/android.go
Enhanced SendKeys method with ASCII and non-ASCII text handling paths; non-ASCII text now uses base64 encoding and DeviceKit clipboard operations when available; added isDeviceKitInstalled, isAscii, and escapeShellText helper methods; added encoding/base64 import

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: support non-ascii characters in io text' directly and clearly summarizes the main change: adding support for non-ASCII characters in text input operations.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-support-non-ascii-characters-in-io-text

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
devices/android.go (1)

657-687: ASCII vs DeviceKit paths look solid; consider richer errors and always-clearing clipboard

The overall control flow (ASCII via input text + escaping, non-ASCII via DeviceKit clipboard + paste, explicit error otherwise) aligns well with the PR goal. A couple of small, non-blocking improvements:

  1. Include adb output in new error paths
    For set clipboard and paste, you currently drop the command output, which can make debugging hard compared to other methods in this file that include it.

    For example:

-		_, err := d.runAdbCommand("shell", "am", "broadcast", "-a", "devicekit.clipboard.set", "-e", "encoding", "base64", "-e", "text", base64Text, "-n", "com.mobilenext.devicekit/.ClipboardBroadcastReceiver")
-		if err != nil {
-			return fmt.Errorf("failed to set clipboard: %w", err)
-		}
+		output, err := d.runAdbCommand("shell", "am", "broadcast", "-a", "devicekit.clipboard.set", "-e", "encoding", "base64", "-e", "text", base64Text, "-n", "com.mobilenext.devicekit/.ClipboardBroadcastReceiver")
+		if err != nil {
+			return fmt.Errorf("failed to set clipboard: %v\nOutput: %s", err, string(output))
+		}

And similarly for the KEYCODE_PASTE call.

  1. Always attempt to clear the clipboard (even on paste failures)
    Right now, if KEYCODE_PASTE fails, the function returns without attempting the clear broadcast, potentially leaving sensitive text on the clipboard. You could make the clear a defer so it always runs best-effort:
-	// try sending over clipboard if DeviceKit is installed
-	if d.isDeviceKitInstalled() {
+	// try sending over clipboard if DeviceKit is installed
+	if d.isDeviceKitInstalled() {
+		defer func() {
+			_, _ = d.runAdbCommand("shell", "am", "broadcast", "-a", "devicekit.clipboard.clear", "-n", "com.mobilenext.devicekit/.ClipboardBroadcastReceiver")
+		}()
@@
-		// clear clipboard when we're done
-		_, _ = d.runAdbCommand("shell", "am", "broadcast", "-a", "devicekit.clipboard.clear", "-n", "com.mobilenext.devicekit/.ClipboardBroadcastReceiver")
-
-		return nil
+		return nil
 	}

These changes are optional, but they improve debuggability and make the clipboard behavior more robust.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09a027e and 9a4fac9.

📒 Files selected for processing (1)
  • devices/android.go (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: lint
🔇 Additional comments (3)
devices/android.go (3)

5-5: Base64 import fits the new clipboard flow

Importing encoding/base64 is appropriate for the DeviceKit clipboard path and looks correct.


612-641: Tighten helpers: simplify DeviceKit check and improve shell-escaping helper

Two small cleanups here:

  1. isDeviceKitInstalled:
    • Given GetAppPath currently never surfaces an error (it returns ("", nil) on failure), the err == nil part is effectively redundant.
    • You can simplify without behavior change:
-func (d *AndroidDevice) isDeviceKitInstalled() bool {
-	appPath, err := d.GetAppPath("com.mobilenext.devicekit")
-	return err == nil && appPath != ""
-}
+func (d *AndroidDevice) isDeviceKitInstalled() bool {
+	appPath, _ := d.GetAppPath("com.mobilenext.devicekit")
+	return appPath != ""
+}
  1. escapeShellText:
    • The current specialChars construction is a bit hard to read and introduces an extra newline into the set.
    • Repeated string concatenation inside the loop is O(n²) in the worst case.
    • A small refactor with a named const and strings.Builder keeps it clearer and linear:
-// escapeShellText escapes shell special characters
-func escapeShellText(text string) string {
-	// escape all shell special characters that could be used for injection
-	specialChars := `\'"`+ "`" + `
-|&;()<>{}[]$*?`
-	result := ""
-	for _, char := range text {
-		if strings.ContainsRune(specialChars, char) {
-			result += "\\"
-		}
-		result += string(char)
-	}
-	return result
-}
+const shellSpecialChars = "\\'\"`|&;()<>{}[]$*?"
+
+// escapeShellText escapes shell special characters
+func escapeShellText(text string) string {
+	var b strings.Builder
+	b.Grow(len(text) * 2) // worst case: every char escaped
+	for _, char := range text {
+		if strings.ContainsRune(shellSpecialChars, char) {
+			b.WriteByte('\\')
+		}
+		b.WriteRune(char)
+	}
+	return b.String()
+}

[ suggest_optional_refactor ]


644-648: Early return on empty text is a good guard

Short-circuiting on text == "" avoids invoking adb shell input with an empty payload and matches the “simple submit” comment; no issues here.

@gmegidish gmegidish merged commit b6dc9f0 into main Dec 1, 2025
6 checks passed
@gmegidish gmegidish deleted the feat-support-non-ascii-characters-in-io-text branch December 14, 2025 19:31
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.

2 participants