Skip to content

Auto-focus terminal when selecting a session #13

Closed

Description

@mortenaslo

Problem

When clicking a session in the left sidebar, keyboard focus stays on the WPF sidebar item that was clicked — it does not "jump into" the selected CLI. The user has to click into the terminal area before they can start typing.

The root cause is in TerminalBridge.FocusTerminal(): it only posts a JS focus message to xterm.js inside the WebView2. That focuses the inner xterm textarea at the DOM level but does nothing at the WPF level, so the WebView2 host never actually gains keyboard focus when another WPF control (the clicked sidebar Border) currently holds it.

The same flow runs from Ctrl+Tab cycling and from the OnWindowActivated Alt+Tab refocus — the latter happens to work because focus was already on the WebView2 before the window deactivated, but a fresh sidebar click breaks the assumption.

Solution

  1. Make TerminalBridge.FocusTerminal() call _webView.Focus() in addition to posting the JS focus message, so WPF keyboard focus actually moves onto the WebView2 host.
  2. Add a new AppSettings.AutoFocusTerminalOnSelect setting (default true) that gates the focus call inside MainViewModel.FocusSession.
  3. Surface the setting in the Settings window under "SESSION SETTINGS" as "Auto-focus terminal when selecting a session".

This means:

  • Default behaviour: clicking a sidebar session (or Ctrl+Tab cycling) immediately moves focus into that session's terminal — no extra click needed.
  • Users who prefer the old behaviour can disable the setting; selection still updates ActiveSession and the active-terminal highlight, but focus is left where it was.

Files affected

  • src/CodeShellManager/Models/AppState.cs — new AutoFocusTerminalOnSelect property on AppSettings.
  • src/CodeShellManager/Terminal/TerminalBridge.cs — FocusTerminal() now also calls _webView.Focus().
  • src/CodeShellManager/ViewModels/MainViewModel.cs — FocusSession gates the focus call on the setting.
  • src/CodeShellManager/Views/SettingsWindow.xaml + .xaml.cs — new checkbox with clone/populate/save wiring.
  • src/CodeShellManager/MainWindow.xaml.cs — copy edited value back into _vm.Settings.

Activity

  1. mortenaslo commented on May 9, 2026

    @mortenaslo
    ContributorAuthor

    Implementation in progress:

    Will auto-close on merge via the Closes #13 reference in the PR body.

  2. m13v commented on May 9, 2026

    @m13v

    the WPF-vs-WebView2 focus split is the obvious fix but there's a second trap waiting. _webView.Focus() moves logical focus onto the host but xterm.js inside CoreWebView2 has its own focus model, and on a cold WebView2 (first activation after process start) the JS focus message can race the WPF focus call and land before the iframe is actually ready to accept keystrokes. result: focus looks correct in spy++ but the first 1-2 chars get eaten. cheap mitigation is to await CoreWebView2InitializationCompleted before wiring FocusTerminal, and on Ctrl+Tab cycling debounce the focus call until WebMessageReceived confirms xterm acked. otherwise the setting works 95% of the time and you ship a heisenbug for the other 5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions