[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) {
|
||||
return numPadKey;
|
||||
}
|
||||
|
||||
// Look to see if the keyCode is one we know about and have a mapping for.
|
||||
// If this key is printable, generate the LogicalKeyboardKey from its Unicode value.
|
||||
// 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 &&
|
||||
!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);
|
||||
int codeUnit = charactersIgnoringModifiers.codeUnitAt(0);
|
||||
if (charactersIgnoringModifiers.length == 2) {
|
||||
// Not covering length > 2 case since > 1 is already unlikely.
|
||||
final int secondCode = charactersIgnoringModifiers.codeUnitAt(1);
|
||||
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
|
||||
// code with the autogenerated bit set.
|
||||
const int macOsKeyIdPlane = 0x00500000000;
|
||||
|
||||
// Keys like "backspace" won't have a character, but it's known by the physical keyboard.
|
||||
// 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.
|
||||
// Control keys like "backspace" and movement keys like arrow keys don't have a printable representation,
|
||||
// but are present on the physical keyboard. 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 duplicating the physical
|
||||
// key map.
|
||||
if (physicalKey != PhysicalKeyboardKey.none) {
|
||||
final int keyId = physicalKey.usbHidUsage | LogicalKeyboardKey.hidPlane;
|
||||
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(
|
||||
macOsKeyIdPlane | keyCode | LogicalKeyboardKey.autogeneratedMask,
|
||||
debugName: kReleaseMode ? null : 'Unknown macOS key code $keyCode',
|
||||
@ -197,6 +202,23 @@ class RawKeyEventDataMacOs extends RawKeyEventData {
|
||||
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
|
||||
// https://developer.apple.com/documentation/appkit/nseventmodifierflags?language=objc
|
||||
// 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.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', () {
|
||||
const Map<int, _ModifierCheck> modifierTests = <int, _ModifierCheck>{
|
||||
|
Loading…
x
Reference in New Issue
Block a user