Skip to content

Conversation

@haefele
Copy link
Owner

@haefele haefele commented Jan 20, 2026

No description provided.

haefele and others added 2 commits January 20, 2026 20:46
When viewer and presenter have different keyboard layouts (e.g., QWERTZ vs QWERTY),
typed characters now appear correctly. The implementation uses a hybrid approach:

- TextInput event captures actual Unicode characters for regular typing
- KeyDown/KeyUp events still used for shortcuts (Ctrl+X, Alt+X) and special keys

This ensures special characters like ö, ä, ü, ß, é work correctly regardless
of keyboard layout differences between viewer and presenter.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace IsCharacterProducingKey and HasShortcutModifier with single
ShouldDeferToTextInput check that relies on KeySymbol for printable
character detection. Add text length validation to prevent DoS.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@haefele
Copy link
Owner Author

haefele commented Jan 20, 2026

@greptile

@greptile-apps
Copy link

greptile-apps bot commented Jan 20, 2026

Greptile Summary

This PR adds Unicode text input support to enable cross-layout keyboard compatibility by introducing a separate text input path that handles printable characters using Avalonia's TextInput event and KeySymbol property, while special keys continue through the existing key event system.

  • Added TextInputMessage protocol message and full end-to-end routing from viewer to presenter
  • Simplified key detection using ShouldDeferToTextInput() helper that checks KeySymbol for printable characters
  • Implemented DoS protection with 100-char limit on viewer side and 1000-char limit on presenter side
  • Text injection uses Keyboard.TextEntry() API which properly handles Unicode characters
  • All changes follow existing patterns: error handling, input suppression checks, and session recorder integration

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation follows established patterns throughout the codebase, includes appropriate validation and DoS protection at multiple layers, and cleanly separates text input from special key handling. The changes are well-structured across the protocol, service, and UI layers without introducing breaking changes.
  • No files require special attention

Important Files Changed

Filename Overview
src/RemoteViewer.Shared/Protocol/KeyMessage.cs Added TextInputMessage record to carry Unicode text strings between viewer and presenter
src/RemoteViewer.Client/Views/Viewer/ViewerView.axaml.cs Simplified key detection using KeySymbol, added TextInput handler with DoS protection (100 char limit)
src/RemoteViewer.Client/Services/HubClient/PresenterConnectionService.cs Implemented text input handler with validation (1000 char limit), input suppression checks, and injection
src/RemoteViewer.Client/Services/InputInjection/WindowsInputInjectionService.cs Implemented text injection using TextEntry API with stuck modifier check and action queue

Sequence Diagram

sequenceDiagram
    participant User
    participant ViewerView as ViewerView.axaml.cs
    participant ViewerService as ViewerConnectionService
    participant SignalR as SignalR Hub
    participant Connection as Connection (Presenter)
    participant PresenterService as PresenterConnectionService
    participant InputInjection as WindowsInputInjectionService
    participant OS as Windows OS

    User->>ViewerView: Type character (e.g., "é")
    
    alt Printable character (KeySymbol check)
        ViewerView->>ViewerView: KeyDown event → ShouldDeferToTextInput() = true
        ViewerView->>ViewerView: Defer to TextInput event
        ViewerView->>ViewerView: TextInput event fires
        ViewerView->>ViewerView: Validate: IsInputEnabled && length ≤ 100
        ViewerView->>ViewerService: SendTextInputAsync(text)
        ViewerService->>ViewerService: Serialize TextInputMessage
        ViewerService->>SignalR: Send message (MessageTypes.Input.TextInput)
        SignalR->>Connection: Route input message
        Connection->>Connection: Deserialize TextInputMessage
        Connection->>PresenterService: HandleTextInput(senderClientId, text)
        PresenterService->>PresenterService: Validate: length ≤ 1000, check input blocking
        PresenterService->>InputInjection: InjectText(text, connectionId, ct)
        InputInjection->>InputInjection: CheckAndReleaseStuckModifiers()
        InputInjection->>OS: Keyboard.TextEntry(text)
        OS->>OS: Unicode text injected
    else Special key (Escape, F11, Arrow, etc.)
        ViewerView->>ViewerView: KeyDown event → ShouldDeferToTextInput() = false
        ViewerView->>ViewerService: SendKeyDownAsync(keyCode, modifiers)
        Note over ViewerService,OS: Traditional key event flow (existing)
    end
Loading

@greptile-apps
Copy link

greptile-apps bot commented Jan 20, 2026

Greptile found no issues!

From now on, if a review finishes and we haven't found any issues, we will not post anything, but you can confirm that we reviewed your changes in the status check section.

This feature can be toggled off in your Code Review Settings by deselecting "Create a status check for each PR".

@haefele haefele merged commit ec54768 into main Jan 20, 2026
2 checks passed
@haefele haefele deleted the feature/unicode-text-input branch January 20, 2026 20:40
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