-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Copy pathAndroidKeyboardEventsHelper.cs
159 lines (133 loc) · 5.54 KB
/
AndroidKeyboardEventsHelper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
using System;
using System.Runtime.Versioning;
using Android.Views;
using Avalonia.Android.Platform.Input;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Input;
using Avalonia.Input.Raw;
namespace Avalonia.Android.Platform.Specific.Helpers
{
internal class AndroidKeyboardEventsHelper<TView> : IDisposable where TView : TopLevelImpl, IAndroidView
{
private readonly TView _view;
public bool HandleEvents { get; set; }
public AndroidKeyboardEventsHelper(TView view)
{
_view = view;
HandleEvents = true;
}
public bool? DispatchKeyEvent(KeyEvent? e, out bool callBase)
{
if (!HandleEvents || e is null)
{
callBase = true;
return null;
}
return DispatchKeyEventInternal(e, out callBase);
}
[ObsoletedOSPlatform("android29.0")]
static string? UnicodeTextInput(KeyEvent keyEvent)
{
return keyEvent.Action == KeyEventActions.Multiple
&& keyEvent.RepeatCount == 0
&& !string.IsNullOrEmpty(keyEvent.Characters)
? keyEvent.Characters
: null;
}
private bool? DispatchKeyEventInternal(KeyEvent e, out bool callBase)
{
var unicodeTextInput = OperatingSystem.IsAndroidVersionAtLeast(29) ? null : UnicodeTextInput(e);
var inputRoot = _view.InputRoot;
if ((e.Action == KeyEventActions.Multiple && unicodeTextInput == null)
|| inputRoot is null)
{
callBase = true;
return null;
}
var physicalKey = AndroidKeyInterop.PhysicalKeyFromScanCode(e.ScanCode);
var keySymbol = GetKeySymbol(e.UnicodeChar, physicalKey);
var keyDeviceType = GetKeyDeviceType(e);
var rawKeyEvent = new RawKeyEventArgs(
AndroidKeyboardDevice.Instance!,
Convert.ToUInt64(e.EventTime),
inputRoot,
e.Action == KeyEventActions.Down ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
AndroidKeyboardDevice.ConvertKey(e.KeyCode),
GetModifierKeys(e),
physicalKey,
keyDeviceType,
keySymbol);
_view.Input?.Invoke(rawKeyEvent);
bool handled = rawKeyEvent.Handled;
if ((e.Action == KeyEventActions.Down && e.UnicodeChar >= 32)
|| unicodeTextInput != null)
{
var rawTextEvent = new RawTextInputEventArgs(
AndroidKeyboardDevice.Instance!,
Convert.ToUInt64(e.EventTime),
inputRoot,
unicodeTextInput ?? Convert.ToChar(e.UnicodeChar).ToString()
);
_view.Input?.Invoke(rawTextEvent);
handled = handled || rawTextEvent.Handled;
}
if (e.Action == KeyEventActions.Up)
{
//nothing to do here more call base no need of more events
callBase = true;
return null;
}
callBase = false;
return handled;
}
private static RawInputModifiers GetModifierKeys(KeyEvent e)
{
var rv = RawInputModifiers.None;
if (e.IsCtrlPressed) rv |= RawInputModifiers.Control;
if (e.IsShiftPressed) rv |= RawInputModifiers.Shift;
return rv;
}
private static string? GetKeySymbol(int unicodeChar, PhysicalKey physicalKey)
{
// Handle a very limited set of control characters so that we're consistent with other platforms
// (matches KeySymbolHelper.IsAllowedAsciiKeySymbol)
switch (physicalKey)
{
case PhysicalKey.Backspace:
return "\b";
case PhysicalKey.Tab:
return "\t";
case PhysicalKey.Enter:
case PhysicalKey.NumPadEnter:
return "\r";
case PhysicalKey.Escape:
return "\u001B";
default:
if (unicodeChar <= 0x7F)
{
var asciiChar = (char)unicodeChar;
return KeySymbolHelper.IsAllowedAsciiKeySymbol(asciiChar) ? asciiChar.ToString() : null;
}
return char.ConvertFromUtf32(unicodeChar);
}
}
private KeyDeviceType GetKeyDeviceType(KeyEvent e)
{
var source = e.Device?.Sources ?? InputSourceType.Unknown;
// Remote controller reports itself as "DPad | Keyboard", which is confusing,
// so we need to double-check KeyboardType as well.
if (source.HasAnyFlag(InputSourceType.Dpad)
&& e.Device?.KeyboardType == InputKeyboardType.NonAlphabetic)
return KeyDeviceType.Remote;
// ReSharper disable BitwiseOperatorOnEnumWithoutFlags - it IS flags enum under the hood.
if (source.HasAnyFlag(InputSourceType.Joystick | InputSourceType.Gamepad))
return KeyDeviceType.Gamepad;
// ReSharper restore BitwiseOperatorOnEnumWithoutFlags
return KeyDeviceType.Keyboard; // fallback to the keyboard, if unknown.
}
public void Dispose()
{
HandleEvents = false;
}
}
}