-
Notifications
You must be signed in to change notification settings - Fork 6k
Send -[NSTextInputClient doCommandBySelector:] selectors to the framework #30272
Send -[NSTextInputClient doCommandBySelector:] selectors to the framework #30272
Conversation
@@ -283,19 +413,6 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { | |||
} else if ([method isEqualToString:kSetEditingStateMethod]) { | |||
NSDictionary* state = call.arguments; | |||
[self setEditingState:state]; | |||
|
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.
Removed these because typing too quickly may cause an endless loop between the framework and the text input plugin.
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've run into this infinite loop before. I think the race condition almost never actually happens in reality, so really I think it's a net win to remove this code. It is concerning that we have no real way to handle the race condition though.
What exactly do you mean? Remove framework-defined keys from the default menus? In the new system as I'm currently seeing it, the Flutter developer will define what goes into the menus, and there will be a default set for macOS including the system defaults that they can edit. But they'll have full control over the keys that are bound to the entries, and we'd have full control over the default set. |
@gspencergoog never mind that commend, I was able to get select all to work when I add the text input plugin to the view hierarchy and make it the first responder when it has the framework focus. I thought select all needed the main menu to work but that doesn't seem to be the case. |
Turning this back to a draft pull request. Need to figure out how I can properly enable select all and other key equivalents |
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.
This looks really straightforward and nice, but I left a few comments around to make sure that I understand everything since this is the first PR from this project that I'm reviewing.
Also one more high level question: What if a Flutter developer wants to remap some shortcut like ctrl/cmd + A to do something else on all platforms? Will Mac never trigger the cmd+A shortcut in the framework because it will be seen as a selector in kIntentLookUp here in the engine first?
@@ -283,19 +413,6 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { | |||
} else if ([method isEqualToString:kSetEditingStateMethod]) { | |||
NSDictionary* state = call.arguments; | |||
[self setEditingState:state]; | |||
|
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've run into this infinite loop before. I think the race condition almost never actually happens in reality, so really I think it's a net win to remove this code. It is concerning that we have no real way to handle the race condition though.
[SelectorIntent intentWith:@selector(moveToRightEndOfLineAndModifySelection:) | ||
methodCall:@[ kExtendSelectionToLineBreakIntent, @(true), @(false) ]] | ||
|
||
// TODO: implement paragrah boundary intents in the framework. |
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.
Heads up that this TODO is still here.
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.
We don't have paragraph boundary defined in the framework right now. I'll create an issue for that.
} | ||
#pragma clang diagnostic pop | ||
|
||
for (SelectorIntent* intent in kIntentLookUp) { |
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.
Could you make kIntentLookup an NSSet to make this lookup faster?
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.
selectors are not hashable and need a special global function to compare equality (sel_isEqual
).
/// If the selector is not in the selector lookup table, and it's not | ||
/// implementd by this class, send the selector as a private command to the | ||
/// framework. |
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.
When would this happen?
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.
basically this describes what the doCommandBySelector
implementation does, first check the LUT, then try to call the selector on this class. If both fail then send the selector name as a private command.
|
||
@end | ||
|
||
static NSArray<SelectorIntent*>* const kIntentLookUp = @[ |
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.
Are these basically all of the Mac keybinding responses that Flutter also supports?
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.
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 except a few that are currently don't have a framework counterpart, or it not getting dispatched via doCommandBySelector
(e.g., selectAll).
Sorry I didn't realize this got turned back into a draft, feel free to ignore my comments that won't be relevant after any changes. |
It seems
I'll add those shortcuts back in the framework pull request for now. |
…ector-selectors-to-framework
Drive by comment from triage: This form of Objective-C runtime wrangling is problematic and known to cause issues in the other instances where we have resorted to it. We would like to understand why this was necessary in the first place (I realize this patch is not the one to introduce this pattern) to see if there are alternatives. |
@chinmaygarde thanks for the info! Is there a place that I can find out more about the the potential problems this could cause? Here's the documentation: https://developer.apple.com/documentation/appkit/nstextinputclient/1438256-docommandbyselector?language=objc. Also I'm not using |
This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold. |
@chinmaygarde gentle ping, what should be done to address your concerns? According to the documentation, this method should be overridden, the default implementation is inherited from |
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.
About your comment #30272 (comment):
- It seems like the framework PR (Use [Intent]s to send text input plugin commands to text fields flutter#94961) hasn't been updated to support the changes mentioned in that comment, is that right? No rush, just making sure I understand how this will be used in the framework.
- If the MacOS TextInputPlugin is the first responder, does that mean that Flutter developers can't override shortcuts that it handles on Mac, like cmd+A? Or maybe I misunderstand what you meant there, I didn't notice any change to the responder order in this PR. I was thinking of the keyboard responders. Or is there another PR?
[SelectorIntent intentWith:@selector(deleteBackward:) | ||
methodCall:@[ kDeleteCharacterIntent, @(false) ]], |
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.
At first blush it strikes me as awkward that we're sort of remotely calling these intents like this, passing parameters without compile time error checking like we would have in the framework. I can't think of a better way though. We shouldn't send deleteBackward etc. to the framework because then we're mixing MacOS concerns with the framework.
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.
Yeah I think I was originally straight up sending the selector names as strings to the framework then the framework would have to translate macOS selector names to intents. So following our convention I'm doing the translation in the text input plugin and the framework just have to "reify" the intent. The platform messages are sent in json anyway so I feel there isn't much we can get by leveraging dart's type system.
What is the status of this PR? Is it still waiting on feedback from @chinmaygarde? |
@zanderso I'm not actively working on it but I plan to get back to this soon. I'll close it for now. |
Framework pull request: flutter/flutter#94961
Related issues:
I just found out that when I press ⌘-A I get a
noop:
indoCommandbySelector:
because these commands need to be defined in the main menu (according to https://forums.macrumors.com/threads/nstextfield-cmd-a-select-all.937808/). I'll add those keys back in my framework pull request for now. Do you think it would be possible to remove all the framework-defined keys when the macOS menu is implemented @gspencergoog ?Pre-launch Checklist
writing and running engine tests.
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.