Unverified Commit f0978c22 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Game controller button support (#33868)

This adds support for game controller buttons. It adds some supplemental USB HID codes that aren't available from the Chromium source code, and maps those on Android to the game pad buttons that Android supports. Other platforms are not supported yet.
parent 4e4d3a5d
......@@ -36,10 +36,11 @@ class _HardwareKeyDemoState extends State<RawKeyboardDemo> {
super.dispose();
}
void _handleKeyEvent(RawKeyEvent event) {
bool _handleKeyEvent(FocusNode node, RawKeyEvent event) {
setState(() {
_event = event;
});
return false;
}
String _asHex(int value) => value != null ? '0x${value.toRadixString(16)}' : 'null';
......@@ -53,9 +54,10 @@ class _HardwareKeyDemoState extends State<RawKeyboardDemo> {
@override
Widget build(BuildContext context) {
final TextTheme textTheme = Theme.of(context).textTheme;
return RawKeyboardListener(
return Focus(
focusNode: _focusNode,
onKey: _handleKeyEvent,
autofocus: true,
child: AnimatedBuilder(
animation: _focusNode,
builder: (BuildContext context, Widget child) {
......@@ -87,6 +89,9 @@ class _HardwareKeyDemoState extends State<RawKeyboardDemo> {
dataText.add(Text('keyCode: ${data.keyCode} (${_asHex(data.keyCode)})'));
dataText.add(Text('scanCode: ${data.scanCode} (${_asHex(data.scanCode)})'));
dataText.add(Text('metaState: ${data.metaState} (${_asHex(data.metaState)})'));
dataText.add(Text('source: ${data.eventSource} (${_asHex(data.eventSource)})'));
dataText.add(Text('vendorId: ${data.vendorId} (${_asHex(data.vendorId)})'));
dataText.add(Text('productId: ${data.productId} (${_asHex(data.productId)})'));
dataText.add(Text('flags: ${data.flags} (${_asHex(data.flags)})'));
} else if (data is RawKeyEventDataFuchsia) {
dataText.add(Text('codePoint: ${data.codePoint} (${_asHex(data.codePoint)})'));
......@@ -118,7 +123,7 @@ class _HardwareKeyDemoState extends State<RawKeyboardDemo> {
}
}
return DefaultTextStyle(
style: textTheme.headline,
style: textTheme.subhead,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: dataText,
......
......@@ -52,6 +52,12 @@ Future<void> main(List<String> rawArguments) async {
'read. If --chromium-hid-codes is not specified, the input will be read '
'from the correct file in the Chromium repository.',
);
argParser.addOption(
'supplemental-hid-codes',
defaultsTo: path.join(flutterRoot.path, 'dev', 'tools', 'gen_keycodes', 'data', 'supplemental_hid_codes.inc'),
help: "The path to where the supplemental HID codes that don't appear in the "
'Chromium map should be read.',
);
argParser.addOption(
'android-keycodes',
defaultsTo: null,
......@@ -140,6 +146,9 @@ Future<void> main(List<String> rawArguments) async {
hidCodes = File(parsedArguments['chromium-hid-codes']).readAsStringSync();
}
final String supplementalHidCodes = File(parsedArguments['supplemental-hid-codes']).readAsStringSync();
hidCodes = '$hidCodes\n$supplementalHidCodes';
String androidKeyCodes;
if (parsedArguments['android-keycodes'] == null) {
androidKeyCodes = await getAndroidKeyCodes();
......
This diff is collapsed.
......@@ -90,6 +90,37 @@
"f24": ["F24"],
"find": ["FIND"],
"fn": ["FUNCTION"],
"gameButton1": ["BUTTON_1"],
"gameButton2": ["BUTTON_2"],
"gameButton3": ["BUTTON_3"],
"gameButton4": ["BUTTON_4"],
"gameButton5": ["BUTTON_5"],
"gameButton6": ["BUTTON_6"],
"gameButton7": ["BUTTON_7"],
"gameButton8": ["BUTTON_8"],
"gameButton9": ["BUTTON_9"],
"gameButton10": ["BUTTON_10"],
"gameButton11": ["BUTTON_11"],
"gameButton12": ["BUTTON_12"],
"gameButton13": ["BUTTON_13"],
"gameButton14": ["BUTTON_14"],
"gameButton15": ["BUTTON_15"],
"gameButton16": ["BUTTON_16"],
"gameButtonA": ["BUTTON_A"],
"gameButtonB": ["BUTTON_B"],
"gameButtonC": ["BUTTON_C"],
"gameButtonLeft1": ["BUTTON_L1"],
"gameButtonLeft2": ["BUTTON_L2"],
"gameButtonMode": ["BUTTON_MODE"],
"gameButtonRight1": ["BUTTON_R1"],
"gameButtonRight2": ["BUTTON_R2"],
"gameButtonSelect": ["BUTTON_SELECT"],
"gameButtonStart": ["BUTTON_START"],
"gameButtonThumbLeft": ["BUTTON_THUMBL"],
"gameButtonThumbRight": ["BUTTON_THUMBR"],
"gameButtonX": ["BUTTON_X"],
"gameButtonY": ["BUTTON_Y"],
"gameButtonZ": ["BUTTON_Z"],
"goBack": ["BACK"],
"goHome": ["HOME"],
"groupNext": ["LANGUAGE_SWITCH"],
......@@ -200,6 +231,7 @@
"quote": ["APOSTROPHE"],
"redo": ["REDO"],
"scrollLock": ["SCROLL_LOCK"],
"select": ["DPAD_CENTER"],
"semicolon": ["SEMICOLON"],
"settings": ["SETTINGS"],
"shiftLeft": ["SHIFT_LEFT"],
......
// These are supplemental key codes to be added to those that Chromium
// defines. Since the web doesn't have game controller buttons defined in the
// same way, these map USB HID codes for game controller buttons to
// Android/Linux button names.
//
// The HID codes here are not real USB HID codes, because the USB HID standard
// doesn't define game controller buttons in this way. It defines only two
// button "collections" (fire/jump and trigger), with the button number for
// each collection sent as extra data. Since we're just using USB HID as a
// convenient namespace, and not using these HID codes for interfacing with a
// USB protocol, we can define new ones to enumerate the buttons. These don't
// collide with any currently defined HID codes.
//
// USB HID evdev XKB Win Mac DOMKey Code
USB_KEYMAP(0x05ff01, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton1", BUTTON_1),
USB_KEYMAP(0x05ff02, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton2", BUTTON_2),
USB_KEYMAP(0x05ff03, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton3", BUTTON_3),
USB_KEYMAP(0x05ff04, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton4", BUTTON_4),
USB_KEYMAP(0x05ff05, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton5", BUTTON_5),
USB_KEYMAP(0x05ff06, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton6", BUTTON_6),
USB_KEYMAP(0x05ff07, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton7", BUTTON_7),
USB_KEYMAP(0x05ff08, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton8", BUTTON_8),
USB_KEYMAP(0x05ff09, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton9", BUTTON_9),
USB_KEYMAP(0x05ff0a, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton10", BUTTON_10),
USB_KEYMAP(0x05ff0b, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton11", BUTTON_11),
USB_KEYMAP(0x05ff0c, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton12", BUTTON_12),
USB_KEYMAP(0x05ff0d, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton13", BUTTON_13),
USB_KEYMAP(0x05ff0e, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton14", BUTTON_14),
USB_KEYMAP(0x05ff0f, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton15", BUTTON_15),
USB_KEYMAP(0x05ff10, 0x0000, 0x0000, 0x0000, 0xffff, "GameButton16", BUTTON_16),
USB_KEYMAP(0x05ff11, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonA", BUTTON_A),
USB_KEYMAP(0x05ff12, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonB", BUTTON_B),
USB_KEYMAP(0x05ff13, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonC", BUTTON_C),
USB_KEYMAP(0x05ff14, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonLeft1", BUTTON_L1),
USB_KEYMAP(0x05ff15, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonLeft2", BUTTON_L2),
USB_KEYMAP(0x05ff16, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonMode", BUTTON_MODE),
USB_KEYMAP(0x05ff17, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonRight1", BUTTON_R1),
USB_KEYMAP(0x05ff18, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonRight2", BUTTON_R2),
USB_KEYMAP(0x05ff19, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonSelect", BUTTON_SELECT),
USB_KEYMAP(0x05ff1a, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonStart", BUTTON_START),
USB_KEYMAP(0x05ff1b, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonThumbLeft", BUTTON_THUMBL),
USB_KEYMAP(0x05ff1c, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonThumbRight", BUTTON_THUMBR),
USB_KEYMAP(0x05ff1d, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonX", BUTTON_X),
USB_KEYMAP(0x05ff1e, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonY", BUTTON_Y),
USB_KEYMAP(0x05ff1f, 0x0000, 0x0000, 0x0000, 0xffff, "GameButtonZ", BUTTON_Z),
......@@ -375,7 +375,7 @@ class Key {
static String getCommentName(String constantName) {
String upperCamel = lowerCamelToUpperCamel(constantName);
upperCamel = upperCamel.replaceAllMapped(RegExp(r'(Digit|Numpad|Lang)([0-9]+)'), (Match match) => '${match.group(1)} ${match.group(2)}');
upperCamel = upperCamel.replaceAllMapped(RegExp(r'(Digit|Numpad|Lang|Button|Left|Right)([0-9]+)'), (Match match) => '${match.group(1)} ${match.group(2)}');
return upperCamel.replaceAllMapped(RegExp(r'([A-Z])'), (Match match) => ' ${match.group(1)}').trim();
}
......
......@@ -116,6 +116,7 @@ const Map<int, LogicalKeyboardKey> kAndroidToLogicalKey = <int, LogicalKeyboardK
26: LogicalKeyboardKey.power,
161: LogicalKeyboardKey.numpadEqual,
259: LogicalKeyboardKey.help,
23: LogicalKeyboardKey.select,
277: LogicalKeyboardKey.cut,
278: LogicalKeyboardKey.copy,
279: LogicalKeyboardKey.paste,
......@@ -162,6 +163,37 @@ const Map<int, LogicalKeyboardKey> kAndroidToLogicalKey = <int, LogicalKeyboardK
168: LogicalKeyboardKey.zoomIn,
169: LogicalKeyboardKey.zoomOut,
255: LogicalKeyboardKey.zoomToggle,
188: LogicalKeyboardKey.gameButton1,
189: LogicalKeyboardKey.gameButton2,
190: LogicalKeyboardKey.gameButton3,
191: LogicalKeyboardKey.gameButton4,
192: LogicalKeyboardKey.gameButton5,
193: LogicalKeyboardKey.gameButton6,
194: LogicalKeyboardKey.gameButton7,
195: LogicalKeyboardKey.gameButton8,
196: LogicalKeyboardKey.gameButton9,
197: LogicalKeyboardKey.gameButton10,
198: LogicalKeyboardKey.gameButton11,
199: LogicalKeyboardKey.gameButton12,
200: LogicalKeyboardKey.gameButton13,
201: LogicalKeyboardKey.gameButton14,
202: LogicalKeyboardKey.gameButton15,
203: LogicalKeyboardKey.gameButton16,
96: LogicalKeyboardKey.gameButtonA,
97: LogicalKeyboardKey.gameButtonB,
98: LogicalKeyboardKey.gameButtonC,
102: LogicalKeyboardKey.gameButtonLeft1,
104: LogicalKeyboardKey.gameButtonLeft2,
110: LogicalKeyboardKey.gameButtonMode,
103: LogicalKeyboardKey.gameButtonRight1,
105: LogicalKeyboardKey.gameButtonRight2,
109: LogicalKeyboardKey.gameButtonSelect,
108: LogicalKeyboardKey.gameButtonStart,
106: LogicalKeyboardKey.gameButtonThumbLeft,
107: LogicalKeyboardKey.gameButtonThumbRight,
99: LogicalKeyboardKey.gameButtonX,
100: LogicalKeyboardKey.gameButtonY,
101: LogicalKeyboardKey.gameButtonZ,
};
/// Maps Android-specific scan codes to the matching [PhysicalKeyboardKey].
......@@ -288,6 +320,7 @@ const Map<int, PhysicalKeyboardKey> kAndroidToPhysicalKey = <int, PhysicalKeyboa
194: PhysicalKeyboardKey.f24,
134: PhysicalKeyboardKey.open,
138: PhysicalKeyboardKey.help,
353: PhysicalKeyboardKey.select,
129: PhysicalKeyboardKey.again,
131: PhysicalKeyboardKey.undo,
137: PhysicalKeyboardKey.cut,
......@@ -345,6 +378,53 @@ const Map<int, PhysicalKeyboardKey> kAndroidToPhysicalKey = <int, PhysicalKeyboa
159: PhysicalKeyboardKey.browserForward,
156: PhysicalKeyboardKey.browserFavorites,
182: PhysicalKeyboardKey.redo,
256: PhysicalKeyboardKey.gameButton1,
288: PhysicalKeyboardKey.gameButton1,
257: PhysicalKeyboardKey.gameButton2,
289: PhysicalKeyboardKey.gameButton2,
258: PhysicalKeyboardKey.gameButton3,
290: PhysicalKeyboardKey.gameButton3,
259: PhysicalKeyboardKey.gameButton4,
291: PhysicalKeyboardKey.gameButton4,
260: PhysicalKeyboardKey.gameButton5,
292: PhysicalKeyboardKey.gameButton5,
261: PhysicalKeyboardKey.gameButton6,
293: PhysicalKeyboardKey.gameButton6,
262: PhysicalKeyboardKey.gameButton7,
294: PhysicalKeyboardKey.gameButton7,
263: PhysicalKeyboardKey.gameButton8,
295: PhysicalKeyboardKey.gameButton8,
264: PhysicalKeyboardKey.gameButton9,
296: PhysicalKeyboardKey.gameButton9,
265: PhysicalKeyboardKey.gameButton10,
297: PhysicalKeyboardKey.gameButton10,
266: PhysicalKeyboardKey.gameButton11,
298: PhysicalKeyboardKey.gameButton11,
267: PhysicalKeyboardKey.gameButton12,
299: PhysicalKeyboardKey.gameButton12,
268: PhysicalKeyboardKey.gameButton13,
300: PhysicalKeyboardKey.gameButton13,
269: PhysicalKeyboardKey.gameButton14,
301: PhysicalKeyboardKey.gameButton14,
270: PhysicalKeyboardKey.gameButton15,
302: PhysicalKeyboardKey.gameButton15,
271: PhysicalKeyboardKey.gameButton16,
303: PhysicalKeyboardKey.gameButton16,
304: PhysicalKeyboardKey.gameButtonA,
305: PhysicalKeyboardKey.gameButtonB,
306: PhysicalKeyboardKey.gameButtonC,
310: PhysicalKeyboardKey.gameButtonLeft1,
312: PhysicalKeyboardKey.gameButtonLeft2,
316: PhysicalKeyboardKey.gameButtonMode,
311: PhysicalKeyboardKey.gameButtonRight1,
313: PhysicalKeyboardKey.gameButtonRight2,
314: PhysicalKeyboardKey.gameButtonSelect,
315: PhysicalKeyboardKey.gameButtonStart,
317: PhysicalKeyboardKey.gameButtonThumbLeft,
318: PhysicalKeyboardKey.gameButtonThumbRight,
307: PhysicalKeyboardKey.gameButtonX,
308: PhysicalKeyboardKey.gameButtonY,
309: PhysicalKeyboardKey.gameButtonZ,
};
/// A map of Android key codes which have printable representations, but appear
......@@ -608,6 +688,37 @@ const Map<int, LogicalKeyboardKey> kFuchsiaToLogicalKey = <int, LogicalKeyboardK
0x1000c028c: LogicalKeyboardKey.mailSend,
0x1000c029d: LogicalKeyboardKey.keyboardLayoutSelect,
0x1000c029f: LogicalKeyboardKey.showAllWindows,
0x100053701: LogicalKeyboardKey.gameButton1,
0x100053702: LogicalKeyboardKey.gameButton2,
0x100053703: LogicalKeyboardKey.gameButton3,
0x100053704: LogicalKeyboardKey.gameButton4,
0x100053705: LogicalKeyboardKey.gameButton5,
0x100053706: LogicalKeyboardKey.gameButton6,
0x100053707: LogicalKeyboardKey.gameButton7,
0x100053708: LogicalKeyboardKey.gameButton8,
0x100053709: LogicalKeyboardKey.gameButton9,
0x10005370a: LogicalKeyboardKey.gameButton10,
0x10005370b: LogicalKeyboardKey.gameButton11,
0x10005370c: LogicalKeyboardKey.gameButton12,
0x10005370d: LogicalKeyboardKey.gameButton13,
0x10005370e: LogicalKeyboardKey.gameButton14,
0x10005370f: LogicalKeyboardKey.gameButton15,
0x100053710: LogicalKeyboardKey.gameButton16,
0x100053711: LogicalKeyboardKey.gameButtonA,
0x100053712: LogicalKeyboardKey.gameButtonB,
0x100053713: LogicalKeyboardKey.gameButtonC,
0x100053714: LogicalKeyboardKey.gameButtonLeft1,
0x100053715: LogicalKeyboardKey.gameButtonLeft2,
0x100053716: LogicalKeyboardKey.gameButtonMode,
0x100053717: LogicalKeyboardKey.gameButtonRight1,
0x100053718: LogicalKeyboardKey.gameButtonRight2,
0x100053719: LogicalKeyboardKey.gameButtonSelect,
0x10005371a: LogicalKeyboardKey.gameButtonStart,
0x10005371b: LogicalKeyboardKey.gameButtonThumbLeft,
0x10005371c: LogicalKeyboardKey.gameButtonThumbRight,
0x10005371d: LogicalKeyboardKey.gameButtonX,
0x10005371e: LogicalKeyboardKey.gameButtonY,
0x10005371f: LogicalKeyboardKey.gameButtonZ,
};
/// Maps Fuchsia-specific USB HID Usage IDs to the matching
......@@ -847,6 +958,37 @@ const Map<int, PhysicalKeyboardKey> kFuchsiaToPhysicalKey = <int, PhysicalKeyboa
0x000c028c: PhysicalKeyboardKey.mailSend,
0x000c029d: PhysicalKeyboardKey.keyboardLayoutSelect,
0x000c029f: PhysicalKeyboardKey.showAllWindows,
0x00053701: PhysicalKeyboardKey.gameButton1,
0x00053702: PhysicalKeyboardKey.gameButton2,
0x00053703: PhysicalKeyboardKey.gameButton3,
0x00053704: PhysicalKeyboardKey.gameButton4,
0x00053705: PhysicalKeyboardKey.gameButton5,
0x00053706: PhysicalKeyboardKey.gameButton6,
0x00053707: PhysicalKeyboardKey.gameButton7,
0x00053708: PhysicalKeyboardKey.gameButton8,
0x00053709: PhysicalKeyboardKey.gameButton9,
0x0005370a: PhysicalKeyboardKey.gameButton10,
0x0005370b: PhysicalKeyboardKey.gameButton11,
0x0005370c: PhysicalKeyboardKey.gameButton12,
0x0005370d: PhysicalKeyboardKey.gameButton13,
0x0005370e: PhysicalKeyboardKey.gameButton14,
0x0005370f: PhysicalKeyboardKey.gameButton15,
0x00053710: PhysicalKeyboardKey.gameButton16,
0x00053711: PhysicalKeyboardKey.gameButtonA,
0x00053712: PhysicalKeyboardKey.gameButtonB,
0x00053713: PhysicalKeyboardKey.gameButtonC,
0x00053714: PhysicalKeyboardKey.gameButtonLeft1,
0x00053715: PhysicalKeyboardKey.gameButtonLeft2,
0x00053716: PhysicalKeyboardKey.gameButtonMode,
0x00053717: PhysicalKeyboardKey.gameButtonRight1,
0x00053718: PhysicalKeyboardKey.gameButtonRight2,
0x00053719: PhysicalKeyboardKey.gameButtonSelect,
0x0005371a: PhysicalKeyboardKey.gameButtonStart,
0x0005371b: PhysicalKeyboardKey.gameButtonThumbLeft,
0x0005371c: PhysicalKeyboardKey.gameButtonThumbRight,
0x0005371d: PhysicalKeyboardKey.gameButtonX,
0x0005371e: PhysicalKeyboardKey.gameButtonY,
0x0005371f: PhysicalKeyboardKey.gameButtonZ,
};
/// Maps macOS-specific key code values representing [PhysicalKeyboardKey].
......
......@@ -256,6 +256,9 @@ abstract class RawKeyEvent extends Diagnosticable {
plainCodePoint: message['plainCodePoint'] ?? 0,
scanCode: message['scanCode'] ?? 0,
metaState: message['metaState'] ?? 0,
eventSource: message['source'] ?? 0,
vendorId: message['vendorId'] ?? 0,
productId: message['productId'] ?? 0,
);
break;
case 'fuchsia':
......
......@@ -33,6 +33,9 @@ class RawKeyEventDataAndroid extends RawKeyEventData {
this.keyCode = 0,
this.scanCode = 0,
this.metaState = 0,
this.eventSource = 0,
this.vendorId = 0,
this.productId = 0,
}) : assert(flags != null),
assert(codePoint != null),
assert(keyCode != null),
......@@ -105,12 +108,60 @@ class RawKeyEventDataAndroid extends RawKeyEventData {
/// * [isMetaPressed], to see if a META key is pressed.
final int metaState;
/// The source of the event.
///
/// See <https://developer.android.com/reference/android/view/KeyEvent.html#getSource()>
/// for the numerical values of the `source`. Many of these constants are also
/// replicated as static constants in this class.
final int eventSource;
/// The vendor ID of the device that produced the event.
///
/// See <https://developer.android.com/reference/android/view/InputDevice.html#getVendorId()>
/// for the numerical values of the `vendorId`.
final int vendorId;
/// The product ID of the device that produced the event.
///
/// See <https://developer.android.com/reference/android/view/InputDevice.html#getProductId()>
/// for the numerical values of the `productId`.
final int productId;
// The source code that indicates that an event came from a joystick.
// from https://developer.android.com/reference/android/view/InputDevice.html#SOURCE_JOYSTICK
static const int _sourceJoystick = 0x01000010;
// Android only reports a single code point for the key label.
@override
String get keyLabel => plainCodePoint == 0 ? null : String.fromCharCode(plainCodePoint & _kCombiningCharacterMask);
@override
PhysicalKeyboardKey get physicalKey => kAndroidToPhysicalKey[scanCode] ?? PhysicalKeyboardKey.none;
PhysicalKeyboardKey get physicalKey {
if (kAndroidToPhysicalKey.containsKey(scanCode)) {
return kAndroidToPhysicalKey[scanCode] ?? PhysicalKeyboardKey.none;
}
// Android sends DPAD_UP, etc. as the keyCode for joystick DPAD events, but
// it doesn't set the scanCode for those, so we have to detect this, and set
// our own DPAD physical keys. The logical key will still match "arrowUp",
// etc.
if (eventSource & _sourceJoystick == _sourceJoystick) {
final LogicalKeyboardKey foundKey = kAndroidToLogicalKey[keyCode];
if (foundKey == LogicalKeyboardKey.arrowUp) {
return PhysicalKeyboardKey.arrowUp;
}
if (foundKey == LogicalKeyboardKey.arrowDown) {
return PhysicalKeyboardKey.arrowDown;
}
if (foundKey == LogicalKeyboardKey.arrowLeft) {
return PhysicalKeyboardKey.arrowLeft;
}
if (foundKey == LogicalKeyboardKey.arrowRight) {
return PhysicalKeyboardKey.arrowRight;
}
}
return PhysicalKeyboardKey.none;
}
@override
LogicalKeyboardKey get logicalKey {
......
......@@ -39,6 +39,7 @@ void main() {
'codePoint': 0x44,
'scanCode': 0x20,
'metaState': modifier,
'source': 0x101, // Keyboard source.
});
final RawKeyEventDataAndroid data = event.data;
for (ModifierKey key in ModifierKey.values) {
......@@ -73,6 +74,7 @@ void main() {
'codePoint': 0x44,
'scanCode': 0x20,
'metaState': modifier | RawKeyEventDataAndroid.modifierFunction,
'source': 0x101, // Keyboard source.
});
final RawKeyEventDataAndroid data = event.data;
for (ModifierKey key in ModifierKey.values) {
......@@ -109,6 +111,7 @@ void main() {
'character': 'A',
'scanCode': 30,
'metaState': 0x0,
'source': 0x101, // Keyboard source.
});
final RawKeyEventDataAndroid data = keyAEvent.data;
expect(data.physicalKey, equals(PhysicalKeyboardKey.keyA));
......@@ -124,6 +127,7 @@ void main() {
'character': null,
'scanCode': 1,
'metaState': 0x0,
'source': 0x101, // Keyboard source.
});
final RawKeyEventDataAndroid data = escapeKeyEvent.data;
expect(data.physicalKey, equals(PhysicalKeyboardKey.escape));
......@@ -140,12 +144,64 @@ void main() {
'character': null,
'scanCode': 42,
'metaState': RawKeyEventDataAndroid.modifierLeftShift,
'source': 0x101, // Keyboard source.
});
final RawKeyEventDataAndroid data = shiftLeftKeyEvent.data;
expect(data.physicalKey, equals(PhysicalKeyboardKey.shiftLeft));
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
expect(data.keyLabel, isNull);
});
test('DPAD keys from a joystick give physical key mappings', () {
final RawKeyEvent joystickDpadDown = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
'keymap': 'android',
'keyCode': 20,
'plainCodePoint': 0,
'codePoint': 0,
'character': null,
'scanCode': 0,
'metaState': 0,
'source': 0x1000010, // Joystick source.
});
final RawKeyEventDataAndroid data = joystickDpadDown.data;
expect(data.physicalKey, equals(PhysicalKeyboardKey.arrowDown));
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown));
expect(data.keyLabel, isNull);
});
test('Arrow keys from a keyboard give correct physical key mappings', () {
final RawKeyEvent joystickDpadDown = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
'keymap': 'android',
'keyCode': 20,
'plainCodePoint': 0,
'codePoint': 0,
'character': null,
'scanCode': 108,
'metaState': 0,
'source': 0x101, // Keyboard source.
});
final RawKeyEventDataAndroid data = joystickDpadDown.data;
expect(data.physicalKey, equals(PhysicalKeyboardKey.arrowDown));
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown));
expect(data.keyLabel, isNull);
});
test('DPAD center from a game pad gives physical key mappings', () {
final RawKeyEvent joystickDpadCenter = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
'keymap': 'android',
'keyCode': 23, // DPAD_CENTER code.
'plainCodePoint': 0,
'codePoint': 0,
'character': null,
'scanCode': 317, // Left side thumb joystick center click button.
'metaState': 0,
'source': 0x501, // Gamepad and keyboard source.
});
final RawKeyEventDataAndroid data = joystickDpadCenter.data;
expect(data.physicalKey, equals(PhysicalKeyboardKey.gameButtonThumbLeft));
expect(data.logicalKey, equals(LogicalKeyboardKey.select));
expect(data.keyLabel, isNull);
});
});
group('RawKeyEventDataFuchsia', () {
const Map<int, _ModifierCheck> modifierTests = <int, _ModifierCheck>{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment