[macos] Check for special keys before creating a logical key (#37901)
This commit is contained in:
parent
c8af729d1c
commit
deb155e89a
@ -75,14 +75,18 @@ class RawKeyEventDataMacOs extends RawKeyEventData {
|
|||||||
if (numPadKey != null) {
|
if (numPadKey != null) {
|
||||||
return numPadKey;
|
return numPadKey;
|
||||||
}
|
}
|
||||||
|
// If this key is printable, generate the LogicalKeyboardKey from its Unicode value.
|
||||||
// Look to see if the keyCode is one we know about and have a mapping for.
|
// Control keys such as ESC, CRTL, and SHIFT are not printable. HOME, DEL, arrow keys, and function
|
||||||
|
// keys are considered modifier function keys, which generate invalid Unicode scalar values.
|
||||||
if (keyLabel != null &&
|
if (keyLabel != null &&
|
||||||
!LogicalKeyboardKey.isControlCharacter(keyLabel)) {
|
!LogicalKeyboardKey.isControlCharacter(keyLabel) &&
|
||||||
|
!_isUnprintableKey(keyLabel)) {
|
||||||
|
// Given that charactersIgnoringModifiers can contain a String of arbitrary length,
|
||||||
|
// limit to a maximum of two Unicode scalar values. It is unlikely that a keyboard would produce a code point
|
||||||
|
// bigger than 32 bits, but it is still worth defending against this case.
|
||||||
assert(charactersIgnoringModifiers.length <= 2);
|
assert(charactersIgnoringModifiers.length <= 2);
|
||||||
int codeUnit = charactersIgnoringModifiers.codeUnitAt(0);
|
int codeUnit = charactersIgnoringModifiers.codeUnitAt(0);
|
||||||
if (charactersIgnoringModifiers.length == 2) {
|
if (charactersIgnoringModifiers.length == 2) {
|
||||||
// Not covering length > 2 case since > 1 is already unlikely.
|
|
||||||
final int secondCode = charactersIgnoringModifiers.codeUnitAt(1);
|
final int secondCode = charactersIgnoringModifiers.codeUnitAt(1);
|
||||||
codeUnit = (codeUnit << 16) | secondCode;
|
codeUnit = (codeUnit << 16) | secondCode;
|
||||||
}
|
}
|
||||||
@ -95,14 +99,11 @@ class RawKeyEventDataMacOs extends RawKeyEventData {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a non-printable key that we don't know about, so we mint a new
|
// Control keys like "backspace" and movement keys like arrow keys don't have a printable representation,
|
||||||
// code with the autogenerated bit set.
|
// but are present on the physical keyboard. Since there is no logical keycode map for macOS
|
||||||
const int macOsKeyIdPlane = 0x00500000000;
|
// (macOS uses the keycode to reference physical keys), a LogicalKeyboardKey is created with
|
||||||
|
// the physical key's HID usage and debugName. This avoids duplicating the physical
|
||||||
// Keys like "backspace" won't have a character, but it's known by the physical keyboard.
|
// key map.
|
||||||
// Since there is no logical keycode map for macOS (macOS uses the keycode to reference
|
|
||||||
// physical keys), a LogicalKeyboardKey is created with the physical key's HID usage and
|
|
||||||
// debugName. This avoids the need for duplicating the physical key map.
|
|
||||||
if (physicalKey != PhysicalKeyboardKey.none) {
|
if (physicalKey != PhysicalKeyboardKey.none) {
|
||||||
final int keyId = physicalKey.usbHidUsage | LogicalKeyboardKey.hidPlane;
|
final int keyId = physicalKey.usbHidUsage | LogicalKeyboardKey.hidPlane;
|
||||||
return LogicalKeyboardKey.findKeyByKeyId(keyId) ?? LogicalKeyboardKey(
|
return LogicalKeyboardKey.findKeyByKeyId(keyId) ?? LogicalKeyboardKey(
|
||||||
@ -112,6 +113,10 @@ class RawKeyEventDataMacOs extends RawKeyEventData {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a non-printable key that we don't know about, so we mint a new
|
||||||
|
// code with the autogenerated bit set.
|
||||||
|
const int macOsKeyIdPlane = 0x00500000000;
|
||||||
|
|
||||||
return LogicalKeyboardKey(
|
return LogicalKeyboardKey(
|
||||||
macOsKeyIdPlane | keyCode | LogicalKeyboardKey.autogeneratedMask,
|
macOsKeyIdPlane | keyCode | LogicalKeyboardKey.autogeneratedMask,
|
||||||
debugName: kReleaseMode ? null : 'Unknown macOS key code $keyCode',
|
debugName: kReleaseMode ? null : 'Unknown macOS key code $keyCode',
|
||||||
@ -197,6 +202,23 @@ class RawKeyEventDataMacOs extends RawKeyEventData {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the given label represents an unprintable key.
|
||||||
|
///
|
||||||
|
/// Examples of unprintable keys are "NSUpArrowFunctionKey = 0xF700"
|
||||||
|
/// or "NSHomeFunctionKey = 0xF729".
|
||||||
|
///
|
||||||
|
/// See <https://developer.apple.com/documentation/appkit/1535851-function-key_unicodes?language=objc> for more
|
||||||
|
/// information.
|
||||||
|
///
|
||||||
|
/// Used by [RawKeyEvent] subclasses to help construct IDs.
|
||||||
|
static bool _isUnprintableKey(String label) {
|
||||||
|
if (label.length > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final int codeUnit = label.codeUnitAt(0);
|
||||||
|
return codeUnit >= 0xF700 && codeUnit <= 0xF8FF;
|
||||||
|
}
|
||||||
|
|
||||||
// Modifier key masks. See Apple's NSEvent documentation
|
// Modifier key masks. See Apple's NSEvent documentation
|
||||||
// https://developer.apple.com/documentation/appkit/nseventmodifierflags?language=objc
|
// https://developer.apple.com/documentation/appkit/nseventmodifierflags?language=objc
|
||||||
// https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-86/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h.auto.html
|
// https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-86/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h.auto.html
|
||||||
|
@ -450,6 +450,22 @@ void main() {
|
|||||||
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
|
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
|
||||||
expect(data.keyLabel, isNull);
|
expect(data.keyLabel, isNull);
|
||||||
});
|
});
|
||||||
|
test('Unprintable keyboard keys are correctly translated', () {
|
||||||
|
final RawKeyEvent leftArrowKey = RawKeyEvent.fromMessage(const <String, dynamic>{
|
||||||
|
'type': 'keydown',
|
||||||
|
'keymap': 'macos',
|
||||||
|
'keyCode': 0x0000007B,
|
||||||
|
'characters': '',
|
||||||
|
'charactersIgnoringModifiers': '', // NSLeftArrowFunctionKey = 0xF702
|
||||||
|
'character': null,
|
||||||
|
'modifiers': RawKeyEventDataMacOs.modifierFunction,
|
||||||
|
});
|
||||||
|
final RawKeyEventDataMacOs data = leftArrowKey.data;
|
||||||
|
expect(data.physicalKey, equals(PhysicalKeyboardKey.arrowLeft));
|
||||||
|
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowLeft));
|
||||||
|
expect(data.logicalKey.keyLabel, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
group('RawKeyEventDataLinux-GFLW', () {
|
group('RawKeyEventDataLinux-GFLW', () {
|
||||||
const Map<int, _ModifierCheck> modifierTests = <int, _ModifierCheck>{
|
const Map<int, _ModifierCheck> modifierTests = <int, _ModifierCheck>{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user