From 46632f9edcee541b96bb15833932ffa58c94cb60 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Mon, 25 Nov 2019 17:06:16 -0800 Subject: [PATCH] Handle bare modifier flags on macOS (#45438) This fixes an unreported bug in the macOS key handling where for some remote access situations, the modifier mask is set to the "any modifier" mask without any side specified (e.g. modifierShift bit is specified and not modifierLeftShift bit). --- .../lib/src/services/raw_keyboard_macos.dart | 49 +++++++++++++------ .../test/services/raw_keyboard_test.dart | 4 ++ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/packages/flutter/lib/src/services/raw_keyboard_macos.dart b/packages/flutter/lib/src/services/raw_keyboard_macos.dart index 7473839a73..8937403037 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_macos.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_macos.dart @@ -127,15 +127,21 @@ class RawKeyEventDataMacOs extends RawKeyEventData { if (modifiers & anyMask == 0) { return false; } + // If only the "anyMask" bit is set, then we respond true for requests of + // whether either left or right is pressed. + // Handles the case where macOS supplies just the "either" modifier flag, + // but not the left/right flag. (e.g. modifierShift but not + // modifierLeftShift). + final bool anyOnly = modifiers & (leftMask | rightMask | anyMask) == anyMask; switch (side) { case KeyboardSide.any: return true; case KeyboardSide.all: - return modifiers & leftMask != 0 && modifiers & rightMask != 0; + return modifiers & leftMask != 0 && modifiers & rightMask != 0 || anyOnly; case KeyboardSide.left: - return modifiers & leftMask != 0; + return modifiers & leftMask != 0 || anyOnly; case KeyboardSide.right: - return modifiers & rightMask != 0; + return modifiers & rightMask != 0 || anyOnly; } return false; } @@ -143,17 +149,23 @@ class RawKeyEventDataMacOs extends RawKeyEventData { @override bool isModifierPressed(ModifierKey key, {KeyboardSide side = KeyboardSide.any}) { final int independentModifier = modifiers & deviceIndependentMask; + bool result; switch (key) { case ModifierKey.controlModifier: - return _isLeftRightModifierPressed(side, independentModifier & modifierControl, modifierLeftControl, modifierRightControl); + result = _isLeftRightModifierPressed(side, independentModifier & modifierControl, modifierLeftControl, modifierRightControl); + break; case ModifierKey.shiftModifier: - return _isLeftRightModifierPressed(side, independentModifier & modifierShift, modifierLeftShift, modifierRightShift); + result = _isLeftRightModifierPressed(side, independentModifier & modifierShift, modifierLeftShift, modifierRightShift); + break; case ModifierKey.altModifier: - return _isLeftRightModifierPressed(side, independentModifier & modifierOption, modifierLeftOption, modifierRightOption); + result = _isLeftRightModifierPressed(side, independentModifier & modifierOption, modifierLeftOption, modifierRightOption); + break; case ModifierKey.metaModifier: - return _isLeftRightModifierPressed(side, independentModifier & modifierCommand, modifierLeftCommand, modifierRightCommand); + result = _isLeftRightModifierPressed(side, independentModifier & modifierCommand, modifierLeftCommand, modifierRightCommand); + break; case ModifierKey.capsLockModifier: - return independentModifier & modifierCapsLock != 0; + result = independentModifier & modifierCapsLock != 0; + break; // On macOS, the function modifier bit is set for any function key, like F1, // F2, etc., but the meaning of ModifierKey.modifierFunction in Flutter is // that of the Fn modifier key, so there's no good way to emulate that on @@ -163,21 +175,26 @@ class RawKeyEventDataMacOs extends RawKeyEventData { case ModifierKey.symbolModifier: case ModifierKey.scrollLockModifier: // These modifier masks are not used in macOS keyboards. - return false; + result = false; + break; } - return false; + assert(!result || getModifierSide(key) != null, "$runtimeType thinks that a modifier is pressed, but can't figure out what side it's on."); + return result; } @override KeyboardSide getModifierSide(ModifierKey key) { - KeyboardSide findSide(int leftMask, int rightMask) { + KeyboardSide findSide(int leftMask, int rightMask, int anyMask) { final int combinedMask = leftMask | rightMask; final int combined = modifiers & combinedMask; if (combined == leftMask) { return KeyboardSide.left; } else if (combined == rightMask) { return KeyboardSide.right; - } else if (combined == combinedMask) { + } else if (combined == combinedMask || modifiers & (combinedMask | anyMask) == anyMask) { + // Handles the case where macOS supplies just the "either" modifier + // flag, but not the left/right flag. (e.g. modifierShift but not + // modifierLeftShift). return KeyboardSide.all; } return null; @@ -185,13 +202,13 @@ class RawKeyEventDataMacOs extends RawKeyEventData { switch (key) { case ModifierKey.controlModifier: - return findSide(modifierLeftControl, modifierRightControl); + return findSide(modifierLeftControl, modifierRightControl, modifierControl); case ModifierKey.shiftModifier: - return findSide(modifierLeftShift, modifierRightShift); + return findSide(modifierLeftShift, modifierRightShift, modifierShift); case ModifierKey.altModifier: - return findSide(modifierLeftOption, modifierRightOption); + return findSide(modifierLeftOption, modifierRightOption, modifierOption); case ModifierKey.metaModifier: - return findSide(modifierLeftCommand, modifierRightCommand); + return findSide(modifierLeftCommand, modifierRightCommand, modifierCommand); case ModifierKey.capsLockModifier: case ModifierKey.numLockModifier: case ModifierKey.scrollLockModifier: diff --git a/packages/flutter/test/services/raw_keyboard_test.dart b/packages/flutter/test/services/raw_keyboard_test.dart index 612c1e2a2a..3069fadb92 100644 --- a/packages/flutter/test/services/raw_keyboard_test.dart +++ b/packages/flutter/test/services/raw_keyboard_test.dart @@ -563,6 +563,10 @@ void main() { RawKeyEventDataMacOs.modifierControl | RawKeyEventDataMacOs.modifierRightControl: _ModifierCheck(ModifierKey.controlModifier, KeyboardSide.right), RawKeyEventDataMacOs.modifierCommand | RawKeyEventDataMacOs.modifierLeftCommand: _ModifierCheck(ModifierKey.metaModifier, KeyboardSide.left), RawKeyEventDataMacOs.modifierCommand | RawKeyEventDataMacOs.modifierRightCommand: _ModifierCheck(ModifierKey.metaModifier, KeyboardSide.right), + RawKeyEventDataMacOs.modifierOption: _ModifierCheck(ModifierKey.altModifier, KeyboardSide.all), + RawKeyEventDataMacOs.modifierShift: _ModifierCheck(ModifierKey.shiftModifier, KeyboardSide.all), + RawKeyEventDataMacOs.modifierControl: _ModifierCheck(ModifierKey.controlModifier, KeyboardSide.all), + RawKeyEventDataMacOs.modifierCommand: _ModifierCheck(ModifierKey.metaModifier, KeyboardSide.all), RawKeyEventDataMacOs.modifierCapsLock: _ModifierCheck(ModifierKey.capsLockModifier, KeyboardSide.all), };