From a30d8ba768a24d2398ec6279e9296aba37548a5c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 16 Nov 2022 17:55:15 +0600 Subject: [PATCH] [X11] Skip TextInput event if KeyDown event was handled --- src/Avalonia.X11/X11Window.Ime.cs | 50 ++++++++++++++++++++----------- src/Avalonia.X11/X11Window.cs | 10 +++++-- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/Avalonia.X11/X11Window.Ime.cs b/src/Avalonia.X11/X11Window.Ime.cs index d68feaca78..ca987d0a07 100644 --- a/src/Avalonia.X11/X11Window.Ime.cs +++ b/src/Avalonia.X11/X11Window.Ime.cs @@ -8,6 +8,7 @@ using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Input.TextInput; using Avalonia.Platform.Interop; +using JetBrains.Annotations; using static Avalonia.X11.XLib; namespace Avalonia.X11 @@ -104,13 +105,18 @@ namespace Avalonia.X11 if (ev.KeyEvent.state.HasAllFlags(XModifierMask.Mod2Mask) && key > X11Key.Num_Lock && key <= X11Key.KP_9) key = (X11Key)XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, index ? 0 : 1).ToInt32(); - - var filtered = ScheduleKeyInput(new RawKeyEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), _inputRoot, - ev.type == XEventName.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, - X11KeyTransform.ConvertKey(key), TranslateModifiers(ev.KeyEvent.state)), ref ev, (int)key, ev.KeyEvent.keycode); - - if (ev.type == XEventName.KeyPress && !filtered) - TriggerClassicTextInputEvent(ref ev); + + var convertedKey = X11KeyTransform.ConvertKey(key); + var modifiers = TranslateModifiers(ev.KeyEvent.state); + var timestamp = (ulong)ev.KeyEvent.time.ToInt64(); + RawKeyEventArgs args = + ev.type == XEventName.KeyPress + ? new RawKeyEventArgsWithText(_keyboard, timestamp, _inputRoot, RawKeyEventType.KeyDown, + convertedKey, modifiers, TranslateEventToString(ref ev)) + : new RawKeyEventArgs(_keyboard, timestamp, _inputRoot, RawKeyEventType.KeyUp, convertedKey, + modifiers); + + ScheduleKeyInput(args, ref ev, (int)key, ev.KeyEvent.keycode); } void TriggerClassicTextInputEvent(ref XEvent ev) @@ -156,16 +162,15 @@ namespace Avalonia.X11 } - bool ScheduleKeyInput(RawKeyEventArgs args, ref XEvent xev, int keyval, int keycode) + void ScheduleKeyInput(RawKeyEventArgs args, ref XEvent xev, int keyval, int keycode) { _x11.LastActivityTimestamp = xev.ButtonEvent.time; - if (_imeControl != null && _imeControl.IsEnabled) - { - if (FilterIme(args, xev, keyval, keycode)) - return true; - } + + if (_imeControl is { IsEnabled: true } + && FilterIme(args, xev, keyval, keycode)) + return; + ScheduleInput(args); - return false; } bool FilterIme(RawKeyEventArgs args, XEvent xev, int keyval, int keycode) @@ -190,11 +195,7 @@ namespace Avalonia.X11 { var ev = _imeQueue.Dequeue(); if (_imeControl == null || !await _imeControl.HandleEventAsync(ev.args, ev.keyval, ev.keycode)) - { ScheduleInput(ev.args); - if (ev.args.Type == RawKeyEventType.KeyDown) - TriggerClassicTextInputEvent(ref ev.xev); - } } } finally @@ -202,5 +203,18 @@ namespace Avalonia.X11 _processingIme = false; } } + + // This class is used to attach the text value of the key to an asynchronously dispatched KeyDown event + class RawKeyEventArgsWithText : RawKeyEventArgs + { + public RawKeyEventArgsWithText([NotNull] IKeyboardDevice device, ulong timestamp, [NotNull] IInputRoot root, + RawKeyEventType type, Key key, RawInputModifiers modifiers, string text) : + base(device, timestamp, root, type, key, modifiers) + { + Text = text; + } + + public string Text { get; } + } } } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 690ac0ebce..0b5ae281f4 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -190,7 +190,7 @@ namespace Avalonia.X11 UpdateMotifHints(); UpdateSizeHints(null); - _rawEventGrouper = new RawEventGrouper(e => Input?.Invoke(e)); + _rawEventGrouper = new RawEventGrouper(DispatchInput); _transparencyHelper = new TransparencyHelper(_x11, _handle, platform.Globals); _transparencyHelper.SetTransparencyRequest(WindowTransparencyLevel.None); @@ -724,7 +724,13 @@ namespace Avalonia.X11 _x11.LastActivityTimestamp = xev.ButtonEvent.time; ScheduleInput(args); } - + + void DispatchInput(RawInputEventArgs args) + { + Input?.Invoke(args); + if (!args.Handled && args is RawKeyEventArgsWithText text && !string.IsNullOrWhiteSpace(text.Text)) + Input?.Invoke(new RawTextInputEventArgs(_keyboard, args.Timestamp, _inputRoot, text.Text)); + } public void ScheduleXI2Input(RawInputEventArgs args) {