Provide caret rect to text input plugin#77608
Provide caret rect to text input plugin#77608fluttergithubbot merged 5 commits intoflutter:masterfrom
Conversation
There was a problem hiding this comment.
selection can be null or !isValid, in either case there's no caret.
There was a problem hiding this comment.
You may also want to make sure selection.isCollapsed is true, because the caret doesn't show up (in addition to the 2 aforementioned cases) if there's an actual non-empty selection.
There was a problem hiding this comment.
Looks like we are skipping reporting the caret rect to the engine when there's no caret. Does the engine need to know that the caret is gone (instead of using the out-of-date caret rect that was previously sent to it)?
There was a problem hiding this comment.
The purpose of caret rect is to position the IME candidate popup. The popup is displayed after long pressing a key (or possibly while typing with some languages). So if there is any selection it will be replaced by a character before the popup is displayed. I'm not aware of a way to get the IME popup visible without caret present. And should that ever happen, last caret position seems to me like a good enough fallback.
There was a problem hiding this comment.
Wouldn't the accent popup show up at the wrong location if you:
- change the selection to somewhere in the document that's far away from the current caret location (the framework won't send anything in this case because it's a non-collapsed selection).
- long press a key to trigger the popup
There was a problem hiding this comment.
Long pressing key first clears the selection replacing it with pressed character, moving caret to new position. I don't think this would cause any issues. The way this works is that the popup shows the moment character would normally start repeating (after a long key press).
There was a problem hiding this comment.
The communication between the text input plugin and the framework is asynchronous. When the software keyboard clears the selection and changes the caret's position, the text input plugin needs to query the new caret coordinates from the framework. There seems to be a chance that the framework can't respond in time, resulting in the outdated caret coordinates being reported in the firstRect method?
There was a problem hiding this comment.
I'm not entirely sure what do you mean by software keyboard? if you mean mean the selection popup, that is shown as response to previous keypress (that would clear the selection). The time between the initial key press and showing popup (when long pressing the key) is about a second, plenty of time for framework to notify plugin of cursor location.
There was a problem hiding this comment.
ah sorry forgot this is macOS & hardware keyboard, I meant the key event. Sounds good.
There was a problem hiding this comment.
nit: is this CGRectNull? Could you put a code comment that explains why this invalid rect is specifically chosen?
There was a problem hiding this comment.
I wasn't trying to match CGRectNull (i think that's [inf, inf, 0, 0]), just to be consistent with setComposingRect.
|
Looks like @cbracken is about to land a patch that addresses something similar. Maybe we should wait for that patch to land? I'm not familiar with how accents work on macos. Does long-pressing a key initiate a composing region (that highlights the base character) on macos? |
Sure. I wasn't aware @cbracken was working on this when I opened the PR. Don't mean to step on anyone's toes :)
Not necessarily. The text input controller suppresses normal key-repeat behavior, showing selection popup on first key repeat instead. However it only enters compositing mode after you change the character selection within the popup. Which currently doesn't work in flutter due to way caret movement and arrow events are handled (but you can still pick up option directly by pressing a number, which works). In which case it generates text |
cbracken
left a comment
There was a problem hiding this comment.
Can you provide a bit more context on why this is required? TextInput.setMarkedTextRect should provide the caret position when not composing.
flutter/packages/flutter/lib/src/widgets/editable_text.dart
Lines 2442 to 2463 in 48f5674
I'm not aware of any cases where both an IME candidate menu and the accent pop-up are in use at the same time -- in local testing with Japanese and Korean text, I get direct input of the vowel in question (e.g. あ) and no accent menu.
Ah no worries at all! Thanks so much for sending these patches! I was working on landing Did you try with just the handlers for the above two messages, and if so, what was the result? As noted, despite its unfortunate name, the |
|
@cbracken, I did try |
Ah interesting; yep looking at this line, @LongCatIsLooong any concerns with the general approach? From my point of view this seems like a reasonable message to add, and I think this actually solves an additional issue with CJK candidate menu positioning. On some platforms, the candidate dropdown movies with the caret, on others it remains positioned at the bottom left corner of the composing rect. Currently on platforms that track the caret, we track the bottom-right corner of the composing rect as a proxy for that. An alternative would be to have the |
justinmc
left a comment
There was a problem hiding this comment.
I'll defer to @LongCatIsLooong on this, but it seems to make sense to me.
There was a problem hiding this comment.
This makes me worry about an infinite loop (well at least doing this unnecessarily once every frame). Are we sure that can never happen? Like for example if the selection is (-1,-1).
There was a problem hiding this comment.
TextInputConnection checks if the rect is same, and so skips the message.
I'm not quite sure how infinite loop could happen, it is started in _openInputConnection and repeated every frame for as long as there is input connection. It is exactly the same behavior as _updateComposingRectIfNeeded, so if that doesn't cause infinite loops neither should this.
There was a problem hiding this comment.
You're right, _updateComposingRectIfNeeded does seem to do the same thing so I think it's ok 👍
There was a problem hiding this comment.
Could we test that the Rect that gets passed is the right one somewhere?
LongCatIsLooong
left a comment
There was a problem hiding this comment.
LGTM modulo comments from other reviewers
There was a problem hiding this comment.
nit: s/only used/used/ just in case we do start using it in another embedder at some point. IIRC we have similar wording about iOS somewhere that is now out-of-date.
Also super-pedantic nit, but add a period at the end.
|
(PR triage) @LongCatIsLooong @justinmc @knopp What's the status of this PR? |
e3a1965 to
a499cc9
Compare
|
I rebased the PR and added unit tests (as requested by @justinmc). Anything else needed here? |
justinmc
left a comment
There was a problem hiding this comment.
LGTM 👍
The build is currently broken, but this can be merged when it's green.

#77545
Adds required code to provide current caret rectangle to text input plugin. This rect, with addition to current editable transform can be used to position the accent selection menu on macOS similarly to how IME popup is positioned on iOS.
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.