11// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
22// See the LICENCE file in the repository root for full licence text.
33
4+ using System . Collections . Generic ;
5+ using System . Runtime . CompilerServices ;
46using Android . Views ;
57using osu . Framework . Input . Handlers ;
68using osu . Framework . Input . StateChanges ;
@@ -14,6 +16,42 @@ public class AndroidKeyboardHandler : InputHandler
1416 public override string Description => "Keyboard (Low Latency)" ;
1517 public override bool IsActive => Enabled . Value ;
1618
19+ // Static dictionary for O(1) key mapping instead of 80+ case switch.
20+ private static readonly Dictionary < Keycode , Key > key_map = new Dictionary < Keycode , Key >
21+ {
22+ { Keycode . A , Key . A } , { Keycode . B , Key . B } , { Keycode . C , Key . C } , { Keycode . D , Key . D } ,
23+ { Keycode . E , Key . E } , { Keycode . F , Key . F } , { Keycode . G , Key . G } , { Keycode . H , Key . H } ,
24+ { Keycode . I , Key . I } , { Keycode . J , Key . J } , { Keycode . K , Key . K } , { Keycode . L , Key . L } ,
25+ { Keycode . M , Key . M } , { Keycode . N , Key . N } , { Keycode . O , Key . O } , { Keycode . P , Key . P } ,
26+ { Keycode . Q , Key . Q } , { Keycode . R , Key . R } , { Keycode . S , Key . S } , { Keycode . T , Key . T } ,
27+ { Keycode . U , Key . U } , { Keycode . V , Key . V } , { Keycode . W , Key . W } , { Keycode . X , Key . X } ,
28+ { Keycode . Y , Key . Y } , { Keycode . Z , Key . Z } ,
29+ { Keycode . Num0 , Key . Number0 } , { Keycode . Num1 , Key . Number1 } , { Keycode . Num2 , Key . Number2 } ,
30+ { Keycode . Num3 , Key . Number3 } , { Keycode . Num4 , Key . Number4 } , { Keycode . Num5 , Key . Number5 } ,
31+ { Keycode . Num6 , Key . Number6 } , { Keycode . Num7 , Key . Number7 } , { Keycode . Num8 , Key . Number8 } ,
32+ { Keycode . Num9 , Key . Number9 } ,
33+ { Keycode . DpadUp , Key . Up } , { Keycode . DpadDown , Key . Down } ,
34+ { Keycode . DpadLeft , Key . Left } , { Keycode . DpadRight , Key . Right } ,
35+ { Keycode . Enter , Key . Enter } , { Keycode . Escape , Key . Escape } ,
36+ { Keycode . Space , Key . Space } , { Keycode . Tab , Key . Tab } ,
37+ { Keycode . Del , Key . BackSpace } , { Keycode . ForwardDel , Key . Delete } ,
38+ { Keycode . MoveHome , Key . Home } , { Keycode . MoveEnd , Key . End } ,
39+ { Keycode . PageUp , Key . PageUp } , { Keycode . PageDown , Key . PageDown } ,
40+ { Keycode . ShiftLeft , Key . ShiftLeft } , { Keycode . ShiftRight , Key . ShiftRight } ,
41+ { Keycode . CtrlLeft , Key . ControlLeft } , { Keycode . CtrlRight , Key . ControlRight } ,
42+ { Keycode . AltLeft , Key . AltLeft } , { Keycode . AltRight , Key . AltRight } ,
43+ { Keycode . CapsLock , Key . CapsLock } ,
44+ { Keycode . F1 , Key . F1 } , { Keycode . F2 , Key . F2 } , { Keycode . F3 , Key . F3 } ,
45+ { Keycode . F4 , Key . F4 } , { Keycode . F5 , Key . F5 } , { Keycode . F6 , Key . F6 } ,
46+ { Keycode . F7 , Key . F7 } , { Keycode . F8 , Key . F8 } , { Keycode . F9 , Key . F9 } ,
47+ { Keycode . F10 , Key . F10 } , { Keycode . F11 , Key . F11 } , { Keycode . F12 , Key . F12 } ,
48+ { Keycode . Grave , Key . Tilde } , { Keycode . Minus , Key . Minus } , { Keycode . Equals , Key . Plus } ,
49+ { Keycode . LeftBracket , Key . BracketLeft } , { Keycode . RightBracket , Key . BracketRight } ,
50+ { Keycode . Backslash , Key . BackSlash } , { Keycode . Semicolon , Key . Semicolon } ,
51+ { Keycode . Apostrophe , Key . Quote } , { Keycode . Comma , Key . Comma } ,
52+ { Keycode . Period , Key . Period } , { Keycode . Slash , Key . Slash } ,
53+ } ;
54+
1755 public AndroidKeyboardHandler ( )
1856 {
1957 Enabled . Default = true ;
@@ -22,124 +60,32 @@ public AndroidKeyboardHandler()
2260
2361 public override bool Initialize ( GameHost host ) => true ;
2462
63+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
2564 public bool HandleKeyEvent ( KeyEvent e )
2665 {
2766 if ( ! Enabled . Value ) return false ;
2867
29- // System keys should ALWAYS fall through to the OS
3068 if ( e . KeyCode == Keycode . Back || e . KeyCode == Keycode . Home || e . KeyCode == Keycode . Menu ||
3169 e . KeyCode == Keycode . VolumeUp || e . KeyCode == Keycode . VolumeDown || e . KeyCode == Keycode . VolumeMute ||
3270 e . KeyCode == Keycode . AppSwitch )
3371 return false ;
3472
35- // In DeX, source might include other flags (like Mouse or Stylus).
36- // We should allow anything that is clearly a keyboard or has a valid keycode.
3773 if ( ! e . Source . HasFlag ( InputSourceType . Keyboard ) && ! e . Source . HasFlag ( InputSourceType . Mouse ) && ! e . Source . HasFlag ( InputSourceType . Stylus ) && e . Source != InputSourceType . Unknown )
3874 {
39- // If it's not a keyboard source, only allow if it's from a device that HAS a keyboard
40- var device = e . Device ;
41- if ( device == null || device . KeyboardType == global ::Android . Views . InputKeyboardType . None )
42- return false ;
75+ var device = e . Device ;
76+ if ( device == null || device . KeyboardType == global ::Android . Views . InputKeyboardType . None )
77+ return false ;
4378 }
4479
45- var key = mapKey ( e . KeyCode ) ;
46- if ( key == Key . Unknown ) return false ;
80+ if ( ! key_map . TryGetValue ( e . KeyCode , out var key ) )
81+ return false ;
4782
4883 bool isDown = e . Action == KeyEventActions . Down ;
4984
50- // We want to handle the first press, but skip OS-level repeats to avoid input lag/buffer bloat
5185 if ( e . RepeatCount > 0 && isDown ) return true ;
5286
5387 PendingInputs . Enqueue ( new KeyboardKeyInput ( key , isDown ) ) ;
5488 return true ;
5589 }
56-
57- private Key mapKey ( Keycode code )
58- {
59- switch ( code )
60- {
61- case Keycode . A : return Key . A ;
62- case Keycode . B : return Key . B ;
63- case Keycode . C : return Key . C ;
64- case Keycode . D : return Key . D ;
65- case Keycode . E : return Key . E ;
66- case Keycode . F : return Key . F ;
67- case Keycode . G : return Key . G ;
68- case Keycode . H : return Key . H ;
69- case Keycode . I : return Key . I ;
70- case Keycode . J : return Key . J ;
71- case Keycode . K : return Key . K ;
72- case Keycode . L : return Key . L ;
73- case Keycode . M : return Key . M ;
74- case Keycode . N : return Key . N ;
75- case Keycode . O : return Key . O ;
76- case Keycode . P : return Key . P ;
77- case Keycode . Q : return Key . Q ;
78- case Keycode . R : return Key . R ;
79- case Keycode . S : return Key . S ;
80- case Keycode . T : return Key . T ;
81- case Keycode . U : return Key . U ;
82- case Keycode . V : return Key . V ;
83- case Keycode . W : return Key . W ;
84- case Keycode . X : return Key . X ;
85- case Keycode . Y : return Key . Y ;
86- case Keycode . Z : return Key . Z ;
87- case Keycode . Num0 : return Key . Number0 ;
88- case Keycode . Num1 : return Key . Number1 ;
89- case Keycode . Num2 : return Key . Number2 ;
90- case Keycode . Num3 : return Key . Number3 ;
91- case Keycode . Num4 : return Key . Number4 ;
92- case Keycode . Num5 : return Key . Number5 ;
93- case Keycode . Num6 : return Key . Number6 ;
94- case Keycode . Num7 : return Key . Number7 ;
95- case Keycode . Num8 : return Key . Number8 ;
96- case Keycode . Num9 : return Key . Number9 ;
97- case Keycode . DpadUp : return Key . Up ;
98- case Keycode . DpadDown : return Key . Down ;
99- case Keycode . DpadLeft : return Key . Left ;
100- case Keycode . DpadRight : return Key . Right ;
101- case Keycode . Enter : return Key . Enter ;
102- case Keycode . Escape : return Key . Escape ;
103- case Keycode . Space : return Key . Space ;
104- case Keycode . Tab : return Key . Tab ;
105- case Keycode . Del : return Key . BackSpace ;
106- case Keycode . ForwardDel : return Key . Delete ;
107- case Keycode . MoveHome : return Key . Home ;
108- case Keycode . MoveEnd : return Key . End ;
109- case Keycode . PageUp : return Key . PageUp ;
110- case Keycode . PageDown : return Key . PageDown ;
111- case Keycode . ShiftLeft : return Key . ShiftLeft ;
112- case Keycode . ShiftRight : return Key . ShiftRight ;
113- case Keycode . CtrlLeft : return Key . ControlLeft ;
114- case Keycode . CtrlRight : return Key . ControlRight ;
115- case Keycode . AltLeft : return Key . AltLeft ;
116- case Keycode . AltRight : return Key . AltRight ;
117- case Keycode . CapsLock : return Key . CapsLock ;
118- case Keycode . F1 : return Key . F1 ;
119- case Keycode . F2 : return Key . F2 ;
120- case Keycode . F3 : return Key . F3 ;
121- case Keycode . F4 : return Key . F4 ;
122- case Keycode . F5 : return Key . F5 ;
123- case Keycode . F6 : return Key . F6 ;
124- case Keycode . F7 : return Key . F7 ;
125- case Keycode . F8 : return Key . F8 ;
126- case Keycode . F9 : return Key . F9 ;
127- case Keycode . F10 : return Key . F10 ;
128- case Keycode . F11 : return Key . F11 ;
129- case Keycode . F12 : return Key . F12 ;
130- case Keycode . Grave : return Key . Tilde ;
131- case Keycode . Minus : return Key . Minus ;
132- case Keycode . Equals : return Key . Plus ;
133- case Keycode . LeftBracket : return Key . BracketLeft ;
134- case Keycode . RightBracket : return Key . BracketRight ;
135- case Keycode . Backslash : return Key . BackSlash ;
136- case Keycode . Semicolon : return Key . Semicolon ;
137- case Keycode . Apostrophe : return Key . Quote ;
138- case Keycode . Comma : return Key . Comma ;
139- case Keycode . Period : return Key . Period ;
140- case Keycode . Slash : return Key . Slash ;
141- default : return Key . Unknown ;
142- }
143- }
14490 }
14591}
0 commit comments