Fix the character
field of the RawKeyEvent
to hold correct data on non-Android platforms. (#65667)
This fixes a problem where the character field of the RawKeyEvent was not being set at all for non-Android platforms. I also updated the key maps, and corrected a problem with the Windows key map where the backquote character wasn't correctly mapped.
This commit is contained in:
parent
b8a39c15f8
commit
199a7c1964
@ -79,6 +79,7 @@ class _HardwareKeyDemoState extends State<RawKeyboardDemo> {
|
|||||||
final String modifierList = data.modifiersPressed.keys.map<String>(_getEnumName).join(', ').replaceAll('Modifier', '');
|
final String modifierList = data.modifiersPressed.keys.map<String>(_getEnumName).join(', ').replaceAll('Modifier', '');
|
||||||
final List<Widget> dataText = <Widget>[
|
final List<Widget> dataText = <Widget>[
|
||||||
Text('${_event.runtimeType}'),
|
Text('${_event.runtimeType}'),
|
||||||
|
if (_event.character?.isNotEmpty ?? false) Text('character produced: "${_event.character}"'),
|
||||||
Text('modifiers set: $modifierList'),
|
Text('modifiers set: $modifierList'),
|
||||||
];
|
];
|
||||||
if (data is RawKeyEventDataAndroid) {
|
if (data is RawKeyEventDataAndroid) {
|
||||||
@ -114,6 +115,10 @@ class _HardwareKeyDemoState extends State<RawKeyboardDemo> {
|
|||||||
dataText.add(Text('scanCode: ${data.scanCode}'));
|
dataText.add(Text('scanCode: ${data.scanCode}'));
|
||||||
dataText.add(Text('characterCodePoint: ${data.characterCodePoint}'));
|
dataText.add(Text('characterCodePoint: ${data.characterCodePoint}'));
|
||||||
dataText.add(Text('modifiers: ${data.modifiers} (${_asHex(data.modifiers)})'));
|
dataText.add(Text('modifiers: ${data.modifiers} (${_asHex(data.modifiers)})'));
|
||||||
|
} else if (data is RawKeyEventDataWeb) {
|
||||||
|
dataText.add(Text('key: ${data.key}'));
|
||||||
|
dataText.add(Text('code: ${data.code}'));
|
||||||
|
dataText.add(Text('metaState: ${data.metaState} (${_asHex(data.metaState)})'));
|
||||||
}
|
}
|
||||||
dataText.add(Text('logical: ${_event.logicalKey}'));
|
dataText.add(Text('logical: ${_event.logicalKey}'));
|
||||||
dataText.add(Text('physical: ${_event.physicalKey}'));
|
dataText.add(Text('physical: ${_event.physicalKey}'));
|
||||||
|
@ -2472,7 +2472,9 @@
|
|||||||
"gtk": [
|
"gtk": [
|
||||||
"quoteleft"
|
"quoteleft"
|
||||||
],
|
],
|
||||||
"windows": null
|
"windows": [
|
||||||
|
"OEM_3"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"scanCodes": {
|
"scanCodes": {
|
||||||
"android": [
|
"android": [
|
||||||
@ -2494,7 +2496,9 @@
|
|||||||
"gtk": [
|
"gtk": [
|
||||||
96
|
96
|
||||||
],
|
],
|
||||||
"windows": null
|
"windows": [
|
||||||
|
192
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"comma": {
|
"comma": {
|
||||||
@ -6565,7 +6569,9 @@
|
|||||||
"windows": null
|
"windows": null
|
||||||
},
|
},
|
||||||
"scanCodes": {
|
"scanCodes": {
|
||||||
"android": null,
|
"android": [
|
||||||
|
370
|
||||||
|
],
|
||||||
"usb": 786529,
|
"usb": 786529,
|
||||||
"linux": 370,
|
"linux": 370,
|
||||||
"xkb": 378,
|
"xkb": 378,
|
||||||
@ -6822,7 +6828,9 @@
|
|||||||
"windows": null
|
"windows": null
|
||||||
},
|
},
|
||||||
"scanCodes": {
|
"scanCodes": {
|
||||||
"android": null,
|
"android": [
|
||||||
|
405
|
||||||
|
],
|
||||||
"usb": 786563,
|
"usb": 786563,
|
||||||
"linux": 405,
|
"linux": 405,
|
||||||
"xkb": 413,
|
"xkb": 413,
|
||||||
@ -7891,7 +7899,9 @@
|
|||||||
"windows": null
|
"windows": null
|
||||||
},
|
},
|
||||||
"scanCodes": {
|
"scanCodes": {
|
||||||
"android": null,
|
"android": [
|
||||||
|
583
|
||||||
|
],
|
||||||
"usb": 786891,
|
"usb": 786891,
|
||||||
"linux": 583,
|
"linux": 583,
|
||||||
"xkb": 591,
|
"xkb": 591,
|
||||||
|
@ -132,7 +132,7 @@
|
|||||||
"minus": ["OEM_MINUS"],
|
"minus": ["OEM_MINUS"],
|
||||||
"period": ["OEM_PERIOD"],
|
"period": ["OEM_PERIOD"],
|
||||||
"slash": ["OEM_2"],
|
"slash": ["OEM_2"],
|
||||||
"backQuote": ["OEM_3"],
|
"backquote": ["OEM_3"],
|
||||||
"gamepadA": ["GAMEPAD_A"],
|
"gamepadA": ["GAMEPAD_A"],
|
||||||
"gamepadB": ["GAMEPAD_B"],
|
"gamepadB": ["GAMEPAD_B"],
|
||||||
"gamepadX": ["GAMEPAD_X"],
|
"gamepadX": ["GAMEPAD_X"],
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
|
// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
|
||||||
// This file is generated by dev/tools/gen_keycodes/bin/gen_keycodes.dart and
|
// This file is generated by dev/tools/gen_keycodes/bin/gen_keycodes.dart and
|
||||||
// should not be edited directly.
|
// should not be edited directly.
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
|
||||||
// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
|
// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
|
||||||
// This file is generated by dev/tools/gen_keycodes/bin/gen_keycodes.dart and
|
// This file is generated by dev/tools/gen_keycodes/bin/gen_keycodes.dart and
|
||||||
// should not be edited directly.
|
// should not be edited directly.
|
||||||
@ -349,8 +348,10 @@ const Map<int, PhysicalKeyboardKey> kAndroidToPhysicalKey = <int, PhysicalKeyboa
|
|||||||
100: PhysicalKeyboardKey.altRight,
|
100: PhysicalKeyboardKey.altRight,
|
||||||
126: PhysicalKeyboardKey.metaRight,
|
126: PhysicalKeyboardKey.metaRight,
|
||||||
358: PhysicalKeyboardKey.info,
|
358: PhysicalKeyboardKey.info,
|
||||||
|
370: PhysicalKeyboardKey.closedCaptionToggle,
|
||||||
225: PhysicalKeyboardKey.brightnessUp,
|
225: PhysicalKeyboardKey.brightnessUp,
|
||||||
224: PhysicalKeyboardKey.brightnessDown,
|
224: PhysicalKeyboardKey.brightnessDown,
|
||||||
|
405: PhysicalKeyboardKey.mediaLast,
|
||||||
174: PhysicalKeyboardKey.exit,
|
174: PhysicalKeyboardKey.exit,
|
||||||
402: PhysicalKeyboardKey.channelUp,
|
402: PhysicalKeyboardKey.channelUp,
|
||||||
403: PhysicalKeyboardKey.channelDown,
|
403: PhysicalKeyboardKey.channelDown,
|
||||||
@ -372,6 +373,7 @@ const Map<int, PhysicalKeyboardKey> kAndroidToPhysicalKey = <int, PhysicalKeyboa
|
|||||||
215: PhysicalKeyboardKey.launchMail,
|
215: PhysicalKeyboardKey.launchMail,
|
||||||
429: PhysicalKeyboardKey.launchContacts,
|
429: PhysicalKeyboardKey.launchContacts,
|
||||||
397: PhysicalKeyboardKey.launchCalendar,
|
397: PhysicalKeyboardKey.launchCalendar,
|
||||||
|
583: PhysicalKeyboardKey.launchAssistant,
|
||||||
181: PhysicalKeyboardKey.newKey,
|
181: PhysicalKeyboardKey.newKey,
|
||||||
160: PhysicalKeyboardKey.close,
|
160: PhysicalKeyboardKey.close,
|
||||||
206: PhysicalKeyboardKey.close,
|
206: PhysicalKeyboardKey.close,
|
||||||
@ -2290,6 +2292,7 @@ const Map<int, LogicalKeyboardKey> kWindowsToLogicalKey = <int, LogicalKeyboardK
|
|||||||
220: LogicalKeyboardKey.backslash,
|
220: LogicalKeyboardKey.backslash,
|
||||||
186: LogicalKeyboardKey.semicolon,
|
186: LogicalKeyboardKey.semicolon,
|
||||||
222: LogicalKeyboardKey.quote,
|
222: LogicalKeyboardKey.quote,
|
||||||
|
192: LogicalKeyboardKey.backquote,
|
||||||
188: LogicalKeyboardKey.comma,
|
188: LogicalKeyboardKey.comma,
|
||||||
190: LogicalKeyboardKey.period,
|
190: LogicalKeyboardKey.period,
|
||||||
191: LogicalKeyboardKey.slash,
|
191: LogicalKeyboardKey.slash,
|
||||||
|
@ -267,6 +267,7 @@ abstract class RawKeyEvent with Diagnosticable {
|
|||||||
/// on the [SystemChannels.keyEvent] channel.
|
/// on the [SystemChannels.keyEvent] channel.
|
||||||
factory RawKeyEvent.fromMessage(Map<String, dynamic> message) {
|
factory RawKeyEvent.fromMessage(Map<String, dynamic> message) {
|
||||||
RawKeyEventData data;
|
RawKeyEventData data;
|
||||||
|
String? character;
|
||||||
|
|
||||||
final String keymap = message['keymap'] as String;
|
final String keymap = message['keymap'] as String;
|
||||||
switch (keymap) {
|
switch (keymap) {
|
||||||
@ -284,13 +285,20 @@ abstract class RawKeyEvent with Diagnosticable {
|
|||||||
deviceId: message['deviceId'] as int? ?? 0,
|
deviceId: message['deviceId'] as int? ?? 0,
|
||||||
repeatCount: message['repeatCount'] as int? ?? 0,
|
repeatCount: message['repeatCount'] as int? ?? 0,
|
||||||
);
|
);
|
||||||
|
if (message.containsKey('character')) {
|
||||||
|
character = message['character'] as String?;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'fuchsia':
|
case 'fuchsia':
|
||||||
|
final int codePoint = message['codePoint'] as int? ?? 0;
|
||||||
data = RawKeyEventDataFuchsia(
|
data = RawKeyEventDataFuchsia(
|
||||||
hidUsage: message['hidUsage'] as int? ?? 0,
|
hidUsage: message['hidUsage'] as int? ?? 0,
|
||||||
codePoint: message['codePoint'] as int? ?? 0,
|
codePoint: codePoint,
|
||||||
modifiers: message['modifiers'] as int? ?? 0,
|
modifiers: message['modifiers'] as int? ?? 0,
|
||||||
);
|
);
|
||||||
|
if (codePoint != 0) {
|
||||||
|
character = String.fromCharCode(codePoint);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'macos':
|
case 'macos':
|
||||||
data = RawKeyEventDataMacOs(
|
data = RawKeyEventDataMacOs(
|
||||||
@ -298,15 +306,20 @@ abstract class RawKeyEvent with Diagnosticable {
|
|||||||
charactersIgnoringModifiers: message['charactersIgnoringModifiers'] as String? ?? '',
|
charactersIgnoringModifiers: message['charactersIgnoringModifiers'] as String? ?? '',
|
||||||
keyCode: message['keyCode'] as int? ?? 0,
|
keyCode: message['keyCode'] as int? ?? 0,
|
||||||
modifiers: message['modifiers'] as int? ?? 0);
|
modifiers: message['modifiers'] as int? ?? 0);
|
||||||
|
character = message['characters'] as String?;
|
||||||
break;
|
break;
|
||||||
case 'linux':
|
case 'linux':
|
||||||
|
final int unicodeScalarValues = message['unicodeScalarValues'] as int? ?? 0;
|
||||||
data = RawKeyEventDataLinux(
|
data = RawKeyEventDataLinux(
|
||||||
keyHelper: KeyHelper(message['toolkit'] as String? ?? ''),
|
keyHelper: KeyHelper(message['toolkit'] as String? ?? ''),
|
||||||
unicodeScalarValues: message['unicodeScalarValues'] as int? ?? 0,
|
unicodeScalarValues: unicodeScalarValues,
|
||||||
keyCode: message['keyCode'] as int? ?? 0,
|
keyCode: message['keyCode'] as int? ?? 0,
|
||||||
scanCode: message['scanCode'] as int? ?? 0,
|
scanCode: message['scanCode'] as int? ?? 0,
|
||||||
modifiers: message['modifiers'] as int? ?? 0,
|
modifiers: message['modifiers'] as int? ?? 0,
|
||||||
isDown: message['type'] == 'keydown');
|
isDown: message['type'] == 'keydown');
|
||||||
|
if (unicodeScalarValues != 0) {
|
||||||
|
character = String.fromCharCode(unicodeScalarValues);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'web':
|
case 'web':
|
||||||
data = RawKeyEventDataWeb(
|
data = RawKeyEventDataWeb(
|
||||||
@ -314,14 +327,19 @@ abstract class RawKeyEvent with Diagnosticable {
|
|||||||
key: message['key'] as String? ?? '',
|
key: message['key'] as String? ?? '',
|
||||||
metaState: message['metaState'] as int? ?? 0,
|
metaState: message['metaState'] as int? ?? 0,
|
||||||
);
|
);
|
||||||
|
character = message['key'] as String?;
|
||||||
break;
|
break;
|
||||||
case 'windows':
|
case 'windows':
|
||||||
|
final int characterCodePoint = message['characterCodePoint'] as int? ?? 0;
|
||||||
data = RawKeyEventDataWindows(
|
data = RawKeyEventDataWindows(
|
||||||
keyCode: message['keyCode'] as int? ?? 0,
|
keyCode: message['keyCode'] as int? ?? 0,
|
||||||
scanCode: message['scanCode'] as int? ?? 0,
|
scanCode: message['scanCode'] as int? ?? 0,
|
||||||
characterCodePoint: message['characterCodePoint'] as int? ?? 0,
|
characterCodePoint: characterCodePoint,
|
||||||
modifiers: message['modifiers'] as int? ?? 0,
|
modifiers: message['modifiers'] as int? ?? 0,
|
||||||
);
|
);
|
||||||
|
if (characterCodePoint != 0) {
|
||||||
|
character = String.fromCharCode(characterCodePoint);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Raw key events are not yet implemented on iOS or other platforms,
|
// Raw key events are not yet implemented on iOS or other platforms,
|
||||||
@ -333,7 +351,7 @@ abstract class RawKeyEvent with Diagnosticable {
|
|||||||
final String type = message['type'] as String;
|
final String type = message['type'] as String;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'keydown':
|
case 'keydown':
|
||||||
return RawKeyDownEvent(data: data, character: message['character'] as String);
|
return RawKeyDownEvent(data: data, character: character);
|
||||||
case 'keyup':
|
case 'keyup':
|
||||||
return RawKeyUpEvent(data: data);
|
return RawKeyUpEvent(data: data);
|
||||||
default:
|
default:
|
||||||
|
@ -17,6 +17,30 @@ class _ModifierCheck {
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('RawKeyboard', () {
|
group('RawKeyboard', () {
|
||||||
|
testWidgets('The correct character is produced', (WidgetTester tester) async {
|
||||||
|
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) {
|
||||||
|
String character = '';
|
||||||
|
void handleKey(RawKeyEvent event) {
|
||||||
|
expect(event.character, equals(character), reason: 'on $platform');
|
||||||
|
}
|
||||||
|
RawKeyboard.instance.addListener(handleKey);
|
||||||
|
character = 'a';
|
||||||
|
await simulateKeyDownEvent(LogicalKeyboardKey.keyA, platform: platform);
|
||||||
|
character = '`';
|
||||||
|
await simulateKeyDownEvent(LogicalKeyboardKey.backquote, platform: platform);
|
||||||
|
RawKeyboard.instance.removeListener(handleKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testWidgets('No character is produced for non-printables', (WidgetTester tester) async {
|
||||||
|
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) {
|
||||||
|
void handleKey(RawKeyEvent event) {
|
||||||
|
expect(event.character, isNull, reason: 'on $platform');
|
||||||
|
}
|
||||||
|
RawKeyboard.instance.addListener(handleKey);
|
||||||
|
await simulateKeyDownEvent(LogicalKeyboardKey.shiftLeft, platform: platform);
|
||||||
|
RawKeyboard.instance.removeListener(handleKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
testWidgets('keysPressed is maintained', (WidgetTester tester) async {
|
testWidgets('keysPressed is maintained', (WidgetTester tester) async {
|
||||||
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) {
|
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) {
|
||||||
RawKeyboard.instance.clearKeysPressed();
|
RawKeyboard.instance.clearKeysPressed();
|
||||||
|
@ -174,7 +174,6 @@ class KeyEventSimulator {
|
|||||||
final Map<String, dynamic> result = <String, dynamic>{
|
final Map<String, dynamic> result = <String, dynamic>{
|
||||||
'type': isDown ? 'keydown' : 'keyup',
|
'type': isDown ? 'keydown' : 'keyup',
|
||||||
'keymap': platform,
|
'keymap': platform,
|
||||||
'character': key.keyLabel,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (platform) {
|
switch (platform) {
|
||||||
@ -182,6 +181,7 @@ class KeyEventSimulator {
|
|||||||
result['keyCode'] = keyCode;
|
result['keyCode'] = keyCode;
|
||||||
if (key.keyLabel.isNotEmpty) {
|
if (key.keyLabel.isNotEmpty) {
|
||||||
result['codePoint'] = key.keyLabel.codeUnitAt(0);
|
result['codePoint'] = key.keyLabel.codeUnitAt(0);
|
||||||
|
result['character'] = key.keyLabel;
|
||||||
}
|
}
|
||||||
result['scanCode'] = scanCode;
|
result['scanCode'] = scanCode;
|
||||||
result['metaState'] = _getAndroidModifierFlags(key, isDown);
|
result['metaState'] = _getAndroidModifierFlags(key, isDown);
|
||||||
@ -198,16 +198,19 @@ class KeyEventSimulator {
|
|||||||
result['keyCode'] = keyCode;
|
result['keyCode'] = keyCode;
|
||||||
result['scanCode'] = scanCode;
|
result['scanCode'] = scanCode;
|
||||||
result['modifiers'] = _getGlfwModifierFlags(key, isDown);
|
result['modifiers'] = _getGlfwModifierFlags(key, isDown);
|
||||||
|
result['unicodeScalarValues'] = key.keyLabel.isNotEmpty ? key.keyLabel.codeUnitAt(0) : 0;
|
||||||
break;
|
break;
|
||||||
case 'macos':
|
case 'macos':
|
||||||
result['keyCode'] = scanCode;
|
result['keyCode'] = scanCode;
|
||||||
|
if (key.keyLabel.isNotEmpty) {
|
||||||
result['characters'] = key.keyLabel;
|
result['characters'] = key.keyLabel;
|
||||||
result['charactersIgnoringModifiers'] = key.keyLabel;
|
result['charactersIgnoringModifiers'] = key.keyLabel;
|
||||||
|
}
|
||||||
result['modifiers'] = _getMacOsModifierFlags(key, isDown);
|
result['modifiers'] = _getMacOsModifierFlags(key, isDown);
|
||||||
break;
|
break;
|
||||||
case 'web':
|
case 'web':
|
||||||
result['code'] = _getWebKeyCode(key);
|
result['code'] = _getWebKeyCode(key);
|
||||||
result['key'] = '';
|
result['key'] = key.keyLabel;
|
||||||
result['metaState'] = _getWebModifierFlags(key, isDown);
|
result['metaState'] = _getWebModifierFlags(key, isDown);
|
||||||
break;
|
break;
|
||||||
case 'windows':
|
case 'windows':
|
||||||
|
Loading…
x
Reference in New Issue
Block a user