Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Send -[NSTextInputClient doCommandBySelector:] selectors to the framework #30272

Conversation

LongCatIsLooong
Copy link
Contributor

Framework pull request: flutter/flutter#94961

Related issues:

I just found out that when I press ⌘-A I get a noop: in doCommandbySelector: 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

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See testing the engine for instructions on
    writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@@ -283,19 +413,6 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
} else if ([method isEqualToString:kSetEditingStateMethod]) {
NSDictionary* state = call.arguments;
[self setEditingState:state];

Copy link
Contributor Author

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.

Copy link
Contributor

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.

@gspencergoog
Copy link
Contributor

gspencergoog commented Dec 10, 2021

Do you think it would be possible to remove all the framework-defined keys when the macOS menu is implemented @gspencergoog ?

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.

@LongCatIsLooong
Copy link
Contributor Author

@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.

@LongCatIsLooong
Copy link
Contributor Author

Turning this back to a draft pull request. Need to figure out how I can properly enable select all and other key equivalents

@LongCatIsLooong LongCatIsLooong marked this pull request as draft December 10, 2021 23:43
Copy link
Contributor

@justinmc justinmc left a 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];

Copy link
Contributor

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.
Copy link
Contributor

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.

Copy link
Contributor Author

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) {
Copy link
Contributor

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?

Copy link
Contributor Author

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).

Comment on lines +728 to +730
/// 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When would this happen?

Copy link
Contributor Author

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 = @[
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. But selectAll seems to be dispatched by the application menu:

Screen Shot 2021-12-13 at 10 07 23 AM

Copy link
Contributor Author

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).

@justinmc
Copy link
Contributor

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.

@LongCatIsLooong
Copy link
Contributor Author

It seems doCommandBySelector: are not receiving selectAll:. To make cmd-A work I had to:

  1. add the macOS text input plugin to the responder chain and view hierarchy and make it the first responder when there's a focused flutter text field.
  2. implement -[FlutterTextInputPlugin selectAll:] so the target-action gets dispatched to the text input plugin.

I'll add those shortcuts back in the framework pull request for now.

@LongCatIsLooong LongCatIsLooong marked this pull request as ready for review December 13, 2021 18:52
@chinmaygarde
Copy link
Member

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.

@LongCatIsLooong
Copy link
Contributor Author

@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 performSelector if this is what you meant?

@flutter-dashboard
Copy link

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.

@LongCatIsLooong
Copy link
Contributor Author

@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 NSResponder which does the wrong thing (propagate the event up the responder chain). See the discussion section in https://developer.apple.com/documentation/appkit/nstextinputclient/1438256-docommandbyselector?language=objc

Copy link
Contributor

@justinmc justinmc left a 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):

  1. 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.
  2. 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?

Comment on lines +99 to +100
[SelectorIntent intentWith:@selector(deleteBackward:)
methodCall:@[ kDeleteCharacterIntent, @(false) ]],
Copy link
Contributor

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.

Copy link
Contributor Author

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.

@zanderso
Copy link
Member

What is the status of this PR? Is it still waiting on feedback from @chinmaygarde?

@LongCatIsLooong
Copy link
Contributor Author

@zanderso I'm not actively working on it but I plan to get back to this soon. I'll close it for now.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants