Skip to content

Android TV: open the keyboard on OK, not when the D-pad reaches a field - #107

Merged
keyldev merged 1 commit into
mainfrom
fix/tv-keyboard-on-ok
Nov 3, 2026
Merged

keyldev merged 1 commit into
mainfrom
fix/tv-keyboard-on-ok

Conversation

@compot-dev

Copy link
Copy Markdown
Collaborator

On a TV (UiModeManager reports Television), a text field that gets the focus no longer keeps the soft keyboard Avalonia opens for it; OK (D-pad centre / Enter) on the field opens it, Back closes it, and the D-pad moves on. Phones and tablets are not affected. New Platform/TvSoftKeyboard.cs, installed from MainActivity.OnCreate.

Checked on an Android TV 16 emulator: the Library search box is passed through without a keyboard, OK opens it, typing works, Back closes it.

Fixes #103

Avalonia.Android shows the soft keyboard as soon as a TextBox gets the
focus (AndroidInputMethod.SetClient -> ShowSoftInput). On a touch screen
that is a tap on the field; with a TV remote it fires whenever the D-pad
merely passes through one. The Library search box sits between the
toolbar and the filters, so moving down the page opened a keyboard over
half the screen, and the keyboard then took the D-pad.

On a TV (UiModeManager reports Television) a TextBox that gets the focus
now has the keyboard hidden again right after Avalonia opens it, and OK
(D-pad centre, which Avalonia maps to Key.Space, or Enter) on the field
opens it; that key does nothing else. Back closes it as before, and the
D-pad then moves on. Phones and tablets are not affected.

Checked on an Android TV 16 emulator with D-pad input only: Down from the
toolbar focuses the search box without a keyboard, OK opens it, typed
text lands in the box, Back closes it, Down moves on to the group filter
with no keyboard.

Fixes #103
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Android TV: open text-field keyboard on OK instead of D-pad focus

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Prevent D-pad focus from opening the soft keyboard over Android TV text fields.
• Open the keyboard on OK or Enter, while preserving phone and tablet behavior.
Diagram

graph TD
  A["MainActivity"] --> B{"TV mode?"}
  B -- "TV" --> C["TextBox focus"] --> D["Hide IME"] --> E{"OK or Enter?"}
  E -- "Yes" --> F["Show IME"]
  B -- "No" --> G["Normal behavior"]
  E -- "No" --> H["D-pad navigation"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Customize Avalonia's Android input-method integration
  • ➕ Could prevent the initial keyboard show rather than hiding it afterward.
  • ➖ Requires a broader, more framework-coupled change for a TV-only behavior.

Recommendation: The TV-gated handler is proportionate and keeps phone and tablet behavior intact. Prefer it over changing Avalonia's input-method integration, while verifying that the deferred hide remains reliable across focus transitions.

Files changed (2) +77 / -0

Bug fix (2) +77 / -0
MainActivity.csInstall TV keyboard handling at activity startup +3/-0

Install TV keyboard handling at activity startup

• Calls the new TV keyboard installer after the Android activity is created. The installer itself decides whether television-specific handling applies.

src/OpenIPC.Viewer.Android/MainActivity.cs

TvSoftKeyboard.csGate soft-keyboard opening on TV text-field activation +74/-0

Gate soft-keyboard opening on TV text-field activation

• Registers TV-only TextBox focus and key handlers that hide the keyboard after focus, then show it on Space or Enter without passing that key to the field. Clears the pending activation state when focus leaves the field.

src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. OK can insert a space after Back 🐞 Bug ≡ Correctness
Description
OnKeyDown clears _waitingForOk when it first opens the keyboard, but nothing restores that
marker when Back dismisses the keyboard without moving focus. On the next D-pad OK in the same text
box, the handler returns and Avalonia receives the key as Space instead of reopening the keyboard.
Code

src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[R55-58]

+        if (e.Handled || !ReferenceEquals(_waitingForOk, box)) return;
+        if (e.Key is not (Key.Space or Key.Enter)) return;
+        _waitingForOk = null;
+        SetKeyboard(show: true);
Evidence
The marker is assigned only on focus, cleared on the first OK, and checked before the key is
consumed. The existing terminal implementation documents that Android can dismiss the keyboard while
its text box remains focused, so dismissal does not necessarily produce another focus event.

src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[42-60]
src/OpenIPC.Viewer.App/Views/Dialogs/SshTerminalContent.axaml.cs[229-248]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
After Back dismisses the IME, the focused text box is no longer marked as waiting for OK, so another OK can edit the text instead of reopening the keyboard.
## Fix Focus Areas
- src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[42-61]
## Recommended Fix
Track whether the keyboard is open independently of the focused text box, and update that state when the input pane closes. Make a subsequent OK on a still-focused field reopen the keyboard and consume the key.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. The terminal keyboard button stays closed 🐞 Bug ≡ Correctness
Description
OnGotFocus posts an unconditional keyboard hide for the terminal’s ImeProxy text box. When the
terminal’s keyboard button bounces focus back to that proxy to reopen a dismissed keyboard, the
posted hide counteracts the explicit request.
Code

src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[R47-50]

+        Dispatcher.UIThread.Post(() =>
+        {
+            if (ReferenceEquals(_waitingForOk, box)) SetKeyboard(show: false);
+        }, DispatcherPriority.Background);
Evidence
The terminal button calls FocusInput, which moves focus away from and then back to its proxy after
dismissal. That proxy is a TextBox, so its refocus triggers the new class handler and scheduled
hide.

src/OpenIPC.Viewer.App/Views/Dialogs/SshTerminalContent.axaml.cs[67-84]
src/OpenIPC.Viewer.App/Views/Dialogs/SshTerminalContent.axaml.cs[229-257]
src/OpenIPC.Viewer.App/Views/Dialogs/SshTerminalContent.axaml[127-145]
src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[34-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The global focus handler hides the keyboard when the terminal’s keyboard button explicitly refocuses its IME proxy.
## Fix Focus Areas
- src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[42-50]
- src/OpenIPC.Viewer.App/Views/Dialogs/SshTerminalContent.axaml.cs[229-257]
## Recommended Fix
Distinguish an explicit keyboard request from D-pad traversal before scheduling the hide, or provide an opt-out for the terminal’s proxy. Preserve the terminal button’s ability to reopen the keyboard after Back.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Keyboard control can target an old window 🐞 Bug ☼ Reliability
Description
Install retains the first Activity in a static field and returns without updating it on later
calls. If Android recreates MainActivity in the same process, the registered text-box handlers
still run, but SetKeyboard obtains the focused view and window token from the previous activity.
Code

src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[R27-32]

+    public static void Install(Activity activity)
+    {
+        if (_activity is not null) return;
+        var uiMode = activity.GetSystemService(Context.UiModeService) as UiModeManager;
+        if (uiMode?.CurrentModeType != UiMode.TypeTelevision) return;
+        _activity = activity;
Evidence
Every activity instance calls Install, but the first installation prevents subsequent instances
from replacing _activity. All show and hide operations then use that cached instance; the activity
declaration handles only a subset of configuration changes.

src/OpenIPC.Viewer.Android/MainActivity.cs[21-36]
src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[23-40]
src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[63-72]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Activity recreation leaves the global keyboard handlers pointing at the original activity and its obsolete window.
## Fix Focus Areas
- src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[23-40]
- src/OpenIPC.Viewer.Android/Platform/TvSoftKeyboard.cs[63-72]
## Recommended Fix
Register the class handlers only once, but refresh the active activity on each installation. Clear the reference when its activity is destroyed and avoid retaining a text box from the old window.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can tweak Display settings with a live preview to see your comment before it ships

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@keyldev
keyldev merged commit b5e1193 into main Nov 3, 2026
6 checks passed
@compot-dev
compot-dev deleted the fix/tv-keyboard-on-ok branch November 4, 2026 10:10
keyldev added a commit that referenced this pull request Nov 4, 2026
Follow-ups to #104, #106 and #107: CI test order, dialog focus, TV keyboard
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.

Android TV: a text field opens the keyboard as soon as the D-pad passes over it

2 participants