5#import <objc/message.h>
10#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterCodecs.h"
11#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
12#import "flutter/shell/platform/embedder/embedder.h"
27 return bitmask & -bitmask;
34 return (character <= 0x1f && character >= 0x00) || (
character >= 0x7f &&
character <= 0x9f);
54static uint64_t
KeyOfPlane(uint64_t baseKey, uint64_t plane) {
63 if (physicalKey == nil) {
66 return physicalKey.unsignedLongLongValue;
74 if (fromKeyCode != nil) {
75 return fromKeyCode.unsignedLongLongValue;
86static uint64_t
toLower(uint64_t n) {
87 constexpr uint64_t lowerA = 0x61;
88 constexpr uint64_t upperA = 0x41;
89 constexpr uint64_t upperZ = 0x5a;
91 constexpr uint64_t lowerAGrave = 0xe0;
92 constexpr uint64_t upperAGrave = 0xc0;
93 constexpr uint64_t upperThorn = 0xde;
94 constexpr uint64_t division = 0xf7;
97 if (n >= upperA && n <= upperZ) {
98 return n - upperA + lowerA;
102 if (n >= upperAGrave && n <= upperThorn && n != division) {
103 return n - upperAGrave + lowerAGrave;
118static uint32_t* DecodeUtf16(NSString*
target,
size_t* out_length) {
120 size_t result_pos = 0;
122 uint16_t high_surrogate = 0;
123 for (NSUInteger target_pos = 0; target_pos <
target.length; target_pos += 1) {
124 uint16_t codeUnit = [
target characterAtIndex:target_pos];
126 if (codeUnit <= 0xD7FF || codeUnit >= 0xE000) {
127 result[result_pos] = codeUnit;
130 }
else if (codeUnit <= 0xDBFF) {
131 high_surrogate = codeUnit - 0xD800;
134 uint16_t low_surrogate = codeUnit - 0xDC00;
135 result[result_pos] = (high_surrogate << 10) + low_surrogate + 0x10000;
139 *out_length = result_pos;
151 if (fromKeyCode != nil) {
152 return fromKeyCode.unsignedLongLongValue;
156 NSString* keyLabelUtf16 =
event.charactersIgnoringModifiers;
165 if (keyLabelUtf16.length != 0) {
166 size_t keyLabelLength;
167 uint32_t* keyLabel = DecodeUtf16(keyLabelUtf16, &keyLabelLength);
168 if (keyLabelLength == 1) {
169 uint32_t keyLabelChar = *keyLabel;
171 <<
"Unexpected control or unprintable keylabel 0x" << std::hex << keyLabelChar;
173 <<
"Out of range keylabel 0x" << std::hex << keyLabelChar;
192 return timestamp * 1000000.0;
202 __block NSUInteger modifierFlagOfInterestMask = NSEventModifierFlagCapsLock;
204 enumerateKeysAndObjectsUsingBlock:^(NSNumber* keyCode, NSNumber*
flag,
BOOL* stop) {
205 modifierFlagOfInterestMask = modifierFlagOfInterestMask | [
flag unsignedLongValue];
207 return modifierFlagOfInterestMask;
221const char* getEventString(NSString* characters) {
222 if ([characters
length] == 0) {
225 unichar utf16Code = [characters characterAtIndex:0];
226 if (utf16Code >= 0xf700 && utf16Code <= 0xf7ff) {
246 return [characters UTF8String];
274 withId:(uint64_t)responseId;
279- (void)resolveTo:(
BOOL)handled;
302 _sentAnyEvents =
FALSE;
308 withId:(uint64_t)responseId {
309 NSAssert(!_handled,
@"This callback has been handled by %@.", _debugHandleSource);
313 pendingResponses[@(responseId)] = _callback;
316 ((_debugHandleSource = [NSString stringWithFormat:
@"pending event %llu", responseId]),
TRUE),
320- (void)resolveTo:(
BOOL)handled {
321 NSAssert(!_handled,
@"This callback has been handled by %@.", _debugHandleSource);
327 NSAssert(((_debugHandleSource = [NSString stringWithFormat:
@"resolved with %d", _handled]),
TRUE),
347@property(nonatomic) NSMutableDictionary<NSNumber*, NSNumber*>*
pressingRecords;
386@property(nonatomic) NSMutableDictionary<NSNumber*, FlutterAsyncKeyCallback>*
pendingResponses;
398- (void)synchronizeModifiers:(NSUInteger)currentFlags
399 ignoringFlags:(NSUInteger)ignoringFlags
400 timestamp:(NSTimeInterval)timestamp
409- (void)updateKey:(uint64_t)physicalKey asPressed:(uint64_t)logicalKey;
433- (void)sendCapsLockTapWithTimestamp:(NSTimeInterval)timestamp
434 synthesizeDown:(
bool)synthesizeDown
440- (void)sendModifierEventOfType:(
BOOL)isDownEvent
441 timestamp:(NSTimeInterval)timestamp
442 keyCode:(
unsigned short)keyCode
443 synthesized:(
bool)synthesized
459- (void)handleCapsLockEvent:(nonnull NSEvent*)event
470- (void)handleResponse:(
BOOL)handled forId:(uint64_t)responseId;
482 _pressingRecords = [NSMutableDictionary dictionary];
483 _pendingResponses = [NSMutableDictionary dictionary];
485 _lastModifierFlagsOfInterest = 0;
494 NSAssert(
callback != nil,
@"The callback must not be nil.");
497 switch (
event.type) {
498 case NSEventTypeKeyDown:
499 [
self handleDownEvent:event callback:guardedCallback];
501 case NSEventTypeKeyUp:
502 [
self handleUpEvent:event callback:guardedCallback];
504 case NSEventTypeFlagsChanged:
505 [
self handleFlagEvent:event callback:guardedCallback];
508 NSAssert(
false,
@"Unexpected key event type: |%@|.", @(
event.type));
510 NSAssert(guardedCallback.
handled,
@"The callback is returned without being handled.");
519 .synthesized =
false,
521 _sendEvent(flutterEvent,
nullptr,
nullptr);
523 NSAssert(_lastModifierFlagsOfInterest == (
event.modifierFlags & _modifierFlagOfInterestMask),
524 @"The modifier flags are not properly updated: recorded 0x%lx, event with mask 0x%lx",
525 _lastModifierFlagsOfInterest,
event.modifierFlags & _modifierFlagOfInterestMask);
528#pragma mark - Private
530- (void)synchronizeModifiers:(NSUInteger)currentFlags
531 ignoringFlags:(NSUInteger)ignoringFlags
532 timestamp:(NSTimeInterval)timestamp
534 const NSUInteger updatingMask = _modifierFlagOfInterestMask & ~ignoringFlags;
535 const NSUInteger currentFlagsOfInterest = currentFlags & updatingMask;
536 const NSUInteger lastFlagsOfInterest = _lastModifierFlagsOfInterest & updatingMask;
537 NSUInteger flagDifference = currentFlagsOfInterest ^ lastFlagsOfInterest;
538 if (flagDifference & NSEventModifierFlagCapsLock) {
539 [
self sendCapsLockTapWithTimestamp:timestamp synthesizeDown:true callback:guard];
540 flagDifference = flagDifference & ~NSEventModifierFlagCapsLock;
543 const NSUInteger currentFlag =
lowestSetBit(flagDifference);
544 if (currentFlag == 0) {
547 flagDifference = flagDifference & ~currentFlag;
548 NSNumber* keyCode = [flutter::modifierFlagToKeyCode objectForKey:@(currentFlag)];
549 NSAssert(keyCode != nil,
@"Invalid modifier flag 0x%lx", currentFlag);
550 if (keyCode == nil) {
553 BOOL isDownEvent = (currentFlagsOfInterest & currentFlag) != 0;
554 [
self sendModifierEventOfType:isDownEvent
556 keyCode:[keyCode unsignedShortValue]
560 _lastModifierFlagsOfInterest =
561 (_lastModifierFlagsOfInterest & ~updatingMask) | currentFlagsOfInterest;
564- (void)updateKey:(uint64_t)physicalKey asPressed:(uint64_t)logicalKey {
565 if (logicalKey == 0) {
566 [_pressingRecords removeObjectForKey:@(physicalKey)];
568 _pressingRecords[@(physicalKey)] = @(logicalKey);
585 _sendEvent(
event,
nullptr,
nullptr);
589- (void)sendCapsLockTapWithTimestamp:(NSTimeInterval)timestamp
590 synthesizeDown:(
bool)synthesizeDown
604 .synthesized = synthesizeDown,
606 if (!synthesizeDown) {
607 [
self sendPrimaryFlutterEvent:flutterEvent callback:callback];
609 [
self sendSynthesizedFlutterEvent:flutterEvent guard:callback];
614 [
self sendSynthesizedFlutterEvent:flutterEvent guard:callback];
617- (void)sendModifierEventOfType:(
BOOL)isDownEvent
618 timestamp:(NSTimeInterval)timestamp
619 keyCode:(
unsigned short)keyCode
620 synthesized:(
bool)synthesized
624 if (physicalKey == 0 || logicalKey == 0) {
625 NSLog(
@"Unrecognized modifier key: keyCode 0x%hx, physical key 0x%llx", keyCode, physicalKey);
633 .physical = physicalKey,
634 .logical = logicalKey,
636 .synthesized = synthesized,
638 [
self updateKey:physicalKey asPressed:isDownEvent ? logicalKey : 0];
640 [
self sendPrimaryFlutterEvent:flutterEvent callback:callback];
642 [
self sendSynthesizedFlutterEvent:flutterEvent guard:callback];
648 NSNumber* logicalKeyFromMap =
self.layoutMap[@(event.keyCode)];
649 uint64_t logicalKey = logicalKeyFromMap != nil ? [logicalKeyFromMap unsignedLongLongValue]
651 [
self synchronizeModifiers:event.modifierFlags
653 timestamp:event.timestamp
656 bool isARepeat =
event.isARepeat;
657 NSNumber* pressedLogicalKey = _pressingRecords[@(physicalKey)];
658 if (pressedLogicalKey != nil && !isARepeat) {
669 .physical = physicalKey,
670 .logical = [pressedLogicalKey unsignedLongLongValue],
674 [
self sendSynthesizedFlutterEvent:flutterEvent guard:callback];
675 pressedLogicalKey = nil;
678 if (pressedLogicalKey == nil) {
679 [
self updateKey:physicalKey asPressed:logicalKey];
686 .physical = physicalKey,
687 .logical = pressedLogicalKey == nil ? logicalKey : [pressedLogicalKey unsignedLongLongValue],
688 .character = getEventString(
event.characters),
689 .synthesized =
false,
691 [
self sendPrimaryFlutterEvent:flutterEvent callback:callback];
695 NSAssert(!
event.isARepeat,
@"Unexpected repeated Up event: keyCode %d, char %@, charIM %@",
697 [
self synchronizeModifiers:event.modifierFlags
699 timestamp:event.timestamp
703 NSNumber* pressedLogicalKey = _pressingRecords[@(physicalKey)];
704 if (pressedLogicalKey == nil) {
712 [
self updateKey:physicalKey asPressed:0];
718 .physical = physicalKey,
719 .logical = [pressedLogicalKey unsignedLongLongValue],
721 .synthesized =
false,
723 [
self sendPrimaryFlutterEvent:flutterEvent callback:callback];
727 [
self synchronizeModifiers:event.modifierFlags
728 ignoringFlags:NSEventModifierFlagCapsLock
729 timestamp:event.timestamp
731 if ((_lastModifierFlagsOfInterest & NSEventModifierFlagCapsLock) !=
732 (
event.modifierFlags & NSEventModifierFlagCapsLock)) {
733 [
self sendCapsLockTapWithTimestamp:event.timestamp synthesizeDown:false callback:callback];
734 _lastModifierFlagsOfInterest = _lastModifierFlagsOfInterest ^ NSEventModifierFlagCapsLock;
742 NSUInteger targetModifierFlag =
743 targetModifierFlagObj == nil ? 0 : [targetModifierFlagObj unsignedLongValue];
746 return [
self handleCapsLockEvent:event callback:callback];
749 [
self synchronizeModifiers:event.modifierFlags
750 ignoringFlags:targetModifierFlag
751 timestamp:event.timestamp
754 NSNumber* pressedLogicalKey = [_pressingRecords objectForKey:@(targetKey)];
755 BOOL lastTargetPressed = pressedLogicalKey != nil;
756 NSAssert(targetModifierFlagObj == nil ||
757 (_lastModifierFlagsOfInterest & targetModifierFlag) != 0 == lastTargetPressed,
758 @"Desynchronized state between lastModifierFlagsOfInterest (0x%lx) on bit 0x%lx "
759 @"for keyCode 0x%hx, whose pressing state is %@.",
760 _lastModifierFlagsOfInterest, targetModifierFlag,
event.keyCode,
762 ? [NSString stringWithFormat:
@"0x%llx", [pressedLogicalKey unsignedLongLongValue]]
765 BOOL shouldBePressed = (
event.modifierFlags & targetModifierFlag) != 0;
766 if (lastTargetPressed == shouldBePressed) {
770 _lastModifierFlagsOfInterest = _lastModifierFlagsOfInterest ^ targetModifierFlag;
771 [
self sendModifierEventOfType:shouldBePressed
772 timestamp:event.timestamp
773 keyCode:event.keyCode
778- (void)handleResponse:(
BOOL)handled forId:(uint64_t)responseId {
781 [_pendingResponses removeObjectForKey:@(responseId)];
784- (void)syncModifiersIfNeeded:(NSEventModifierFlags)modifierFlags
785 timestamp:(NSTimeInterval)timestamp {
791 [
self synchronizeModifiers:modifierFlags
794 guard:guardedCallback];
798 return [NSDictionary dictionaryWithDictionary:_pressingRecords];
805 auto pending = std::unique_ptr<FlutterKeyPendingResponse>(
807 [pending->responder handleResponse:handled forId:pending->responseId];
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
FlutterSendKeyEvent sendEvent
@ kFlutterKeyEventTypeDown
@ kFlutterKeyEventTypeRepeat
FlutterSemanticsFlag flag
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
#define FML_DCHECK(condition)
nonnull NSDictionary * getPressedState()
NSUInteger lastModifierFlagsOfInterest
NSMutableDictionary< NSNumber *, NSNumber * > * pressingRecords
NSUInteger modifierFlagOfInterestMask
NSMutableDictionary< NSNumber *, FlutterAsyncKeyCallback > * pendingResponses
NSString * debugHandleSource
void resolveTo:(BOOL handled)
void pendTo:withId:(nonnull NSMutableDictionary< NSNumber *, FlutterAsyncKeyCallback > *pendingResponses,[withId] uint64_t responseId)
FlutterEmbedderKeyResponder * responder
void(^ FlutterAsyncKeyCallback)(BOOL handled)
void(^ FlutterSendEmbedderKeyEvent)(const FlutterKeyEvent &, _Nullable FlutterKeyEventCallback, void *_Nullable)
static uint64_t KeyOfPlane(uint64_t baseKey, uint64_t plane)
static uint64_t toLower(uint64_t n)
static double GetFlutterTimestampFrom(NSTimeInterval timestamp)
static NSUInteger lowestSetBit(NSUInteger bitmask)
static NSUInteger computeModifierFlagOfInterestMask()
static uint64_t GetPhysicalKeyForKeyCode(UInt32 keyCode)
static bool IsControlCharacter(NSUInteger length, NSString *label)
void HandleResponse(bool handled, void *user_data)
static uint64_t GetLogicalKeyForEvent(FlutterUIPressProxy *press, NSNumber *maybeSpecialKey) API_AVAILABLE(ios(13.4))
static uint64_t GetLogicalKeyForModifier(UInt32 keyCode, uint64_t hidCode)
static bool IsUnprintableKey(NSUInteger length, NSString *label)
const NSDictionary * keyCodeToLogicalKey
const uint64_t kUnicodePlane
const NSDictionary * keyCodeToPhysicalKey
const NSDictionary * keyCodeToModifierFlag
const uint64_t kValueMask
const uint64_t kCapsLockLogicalKey
const uint64_t kMacosPlane
const uint64_t kCapsLockPhysicalKey
NSMutableDictionary< NSNumber *, NSNumber * > * layoutMap
size_t struct_size
The size of this struct. Must be sizeof(FlutterKeyEvent).
FlutterKeyEventType type
The event kind.