-
Notifications
You must be signed in to change notification settings - Fork 6k
[macOS] TextInputPlugin should not consume unhandled key equivalent events #34250
Conversation
@@ -482,7 +512,16 @@ - (BOOL)handleKeyEvent:(NSEvent*)event { | |||
return NO; | |||
} | |||
|
|||
return [_textInputContext handleEvent:event]; | |||
_eventProducedOutput = NO; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the event is a key equivalent, should we let the application route it as a key equivalent first, if it's not handled, then we give the event to the currently focused text field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not familiar with how key handling on macOS works so /cc @dkwingsmt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By application do you mean the framework? Because if so that's already happening. On the other hand If you mean the rest of cocoa responder chain, then I'd say no - this would be completely different behavior that what happens without text input (framework first, cocoa second).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole purpose of this PR is to make sure that TextInputContext doesn't doesn't simply swallow keyEquivalent events that don't produce any text editing action so that they are forwarded to the rest of responder chain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean the cocoa responder chain (potentially by sending it back to the -[FlutterViewController performKeyEquivalent:]
method's super implementation).
-[FlutterTextInputPlugin handleKeyEvent:]
is only called when the framework doesn't consume the key event iirc? So it's already "framework first"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it's already "framework first"?
It is. This is the main keyboard event processing:
engine/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm
Lines 198 to 229 in 0cc828c
- (void)performProcessEvent:(NSEvent*)event onFinish:(VoidBlock)onFinish { | |
if (_viewDelegate.isComposing) { | |
[self dispatchTextEvent:event]; | |
onFinish(); | |
return; | |
} | |
// Having no primary responders require extra logic, but Flutter hard-codes | |
// all primary responders, so this is a situation that Flutter will never | |
// encounter. | |
NSAssert([_primaryResponders count] >= 0, @"At least one primary responder must be added."); | |
__weak __typeof__(self) weakSelf = self; | |
__block int unreplied = [_primaryResponders count]; | |
__block BOOL anyHandled = false; | |
FlutterAsyncKeyCallback replyCallback = ^(BOOL handled) { | |
unreplied -= 1; | |
NSAssert(unreplied >= 0, @"More primary responders replied than possible."); | |
anyHandled = anyHandled || handled; | |
if (unreplied == 0) { | |
if (!anyHandled) { | |
[weakSelf dispatchTextEvent:event]; | |
} | |
onFinish(); | |
} | |
}; | |
for (id<FlutterKeyPrimaryResponder> responder in _primaryResponders) { | |
[responder handleEvent:event callback:replyCallback]; | |
} | |
} |
Primary responders are FlutterEmbedderKeyResponder
and FlutterChannelKeyResponder
(framework). If these don't handle keyboard event, the event is passed to [FlutterKeyboardManager dispatchTextEvent:]
. This will let the TextInputPlugin
process event, and if not handled will forward it to nextResponder
.
The issue this PR fixes is that any event sent to TextInputPlugin (with active context) was marked as handled, even if it was keyboard shortcut that didn't result in any action.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, FlutterTextInputPlugin#handleKeyEvent
is called only when the Framework's keyboard systems choose not to handle the event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few small comments. The approach looks right to me, but curious about @LongCatIsLooong's response to the discussion at https://github.com/flutter/engine/pull/34250/files#r908880528.
shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm
Outdated
Show resolved
Hide resolved
shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm
Outdated
Show resolved
Hide resolved
shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm
Outdated
Show resolved
Hide resolved
@@ -482,7 +512,16 @@ - (BOOL)handleKeyEvent:(NSEvent*)event { | |||
return NO; | |||
} | |||
|
|||
return [_textInputContext handleEvent:event]; | |||
_eventProducedOutput = NO; | |||
BOOL res = [_textInputContext handleEvent:event]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of know what you're changing here in the context of this PR, but if I'm reading the code the following comment confuses me. Can you add more information and describe it in the positive way, like:
NSTextInputContext#handleEvent returns YES if the context handles the event. One of the reasons the event is handled is because it's a key equivalent. But a key equivalent might produce a text command (indicated by calling
doCommandBySelector
) and might not (for example, Cmd+Q). In the latter case, this command somehow has not been executed yet and Flutter must dispatch it to the next responder. See flutter/flutter#106354 .
I'm ok with this PR. I'm still confused by why |
4a16700
to
9aa4a7b
Compare
@dkwingsmt, I've updated the comment according to your suggestion. Is there anything else or is this good to go? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm
Outdated
Show resolved
Hide resolved
shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm
Outdated
Show resolved
Hide resolved
shell/platform/darwin/macos/framework/Source/FlutterTextInputPluginTest.mm
Outdated
Show resolved
Hide resolved
…lugin.mm Co-authored-by: Tong Mu <[email protected]>
…lugin.mm Co-authored-by: Tong Mu <[email protected]>
…lugin.mm Co-authored-by: Tong Mu <[email protected]>
…lugin.mm Co-authored-by: Tong Mu <[email protected]>
46a20ea
to
3079907
Compare
Fixes flutter/flutter#106354
If you had to change anything in the flutter/tests repo, include a link to the migration guide as per the breaking change policy.
Pre-launch Checklist
writing and running engine tests.
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.