-
Notifications
You must be signed in to change notification settings - Fork 8.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make command palette ephemeral #8377
Conversation
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 got a couple questions and spelling nits. I've checked out the branch and played with it and it feels fine to me, so I'm okay with this. I just want to make sure the TODOs shouldn't be "TODONEs"
} | ||
|
||
// Method Description: | ||
// - The purpose of this event handler is to hind the palette if it loses focus. |
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 purpose of this event handler is to hind the palette if it loses focus. | |
// - The purpose of this event handler is to hide the palette if it loses focus. |
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 guess I was drunk or something 😕
// We cannot do it on closing because if the window loses focus (alt+tab) | ||
// the closing event is not fired. | ||
// It is important to set the focus on the tab | ||
// Sine the previous focus location might be discarded in the background, |
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.
// Sine the previous focus location might be discarded in the background, | |
// Since the previous focus location might be discarded in the background, |
// Return focus to the active control | ||
if (auto index{ _GetFocusedTabIndex() }) | ||
// We don't want to set focus on the tab if fly-out is open as it will be closed | ||
// TODO: consider checking we are not in the opening state, by hooking both Opening and Open events |
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.
Do we want to address this TODO during this review?
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.
@zadjii-msft - don't think so - its highly theoretical.
// Since the focus might move within the palette we need to register this handler for all focusable children | ||
// Right now this is achieved by explicitly registering on the root on the highlighted text controls. | ||
// Few notes: | ||
// - found no way to entires disable focus on list-view elements in single-item-selection mode without breaking list behavior |
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.
// - found no way to entires disable focus on list-view elements in single-item-selection mode without breaking list behavior | |
// - found no way to entirely disable focus on list-view elements in single-item-selection mode without breaking list behavior |
(I think?)
// Right now this is achieved by explicitly registering on the root on the highlighted text controls. | ||
// Few notes: | ||
// - found no way to entires disable focus on list-view elements in single-item-selection mode without breaking list behavior | ||
// - TODO: the explicit implementation can be generalized by checking if the focused element is a descendant of palette |
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.
Do we want to address this TODO? Are there any drawbacks from the current approach? Like, will he manually have to add this _lostFocusHandler
to all the focusable UI elements in the cmdpal?
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.
As you said, the only drawback of the current approach is that we add another field (that might get focus) we need to remember to add it here. On the other hand this solution is simple (funny stuff is that Xaml UI guys have implemented similar function but do not export it - seen it occasionally, trying to understand if we can bind the tabview in any case).
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.
Okay. That's definitely annoying to remember, but hopefully we'll remember to do this.
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.
Okay. That's definitely annoying to remember, but hopefully we'll remember to do this.
IT IS NOW FIXED HA HA HA
@zadjii-msft - thanks for the review! And sorry for all misspellings (I guess it is an hour of the day.. or of the night.. that I start to err the way that even spellchecker cannot stop me). I am not sure if we need to implement TODOs now.. as both are somewhat hypothetical.. I can absolutely work on them if you find it is a correct timing 😊 |
@zadjii-msft - a week has passed, so bumping 😄 |
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'm okay with this, mostly on the premise that it works well when I played with it. I really don't love having to remember to add that event handler each time manually, but we can live with it. And If we can't live with ti, then we've at least got a plan.
My only real nit is that we don't usually allow bare TODOs in the code, so I'm suggesting that we just link these to the bullet points I added in #5400. They don't really deserve a whole issue, but best to have them enumerated somewhere.
// Right now this is achieved by explicitly registering on the root on the highlighted text controls. | ||
// Few notes: | ||
// - found no way to entires disable focus on list-view elements in single-item-selection mode without breaking list behavior | ||
// - TODO: the explicit implementation can be generalized by checking if the focused element is a descendant of palette |
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.
Okay. That's definitely annoying to remember, but hopefully we'll remember to do this.
(I'm throwing Needs-Second on this, but I'd bet that @DHowett would want to take a look) |
void CommandPalette::_lostFocusHandler(Windows::Foundation::IInspectable const& /* sender*/, | ||
Windows::UI::Xaml::RoutedEventArgs const& /*args*/) | ||
{ | ||
auto focusedElement = Input::FocusManager::GetFocusedElement(this->XamlRoot()).try_as<FrameworkElement>(); | ||
if (focusedElement && focusedElement != *this && focusedElement.Name() != L"_highlightedTextControl" && Visibility() != Visibility::Collapsed) | ||
{ | ||
_dismissPalette(); | ||
} |
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 seen some strange things with the Focus event that make me feel like this should be easier.
If you add a LostFocus handler on the root control, and check the sender
parameter instead of GetFocusedElement
, you might find that you're getting LostFocus event fired for all contained controls. (I am not certain about this, but it is a routed event!) That would make this easier: use VisualTreeHelper
to walk the control's parent to see if it is us or is within us.
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.
@DHowett - Yeah.. I have a code with VisualTreeHelper
iterating the parents. This is how I started, but putting the lost focus on the root of the palette was not sufficient. Are you suggesting to put in on TerminalPage
?
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.
Also from the documentation of Lost Focus Event:
Specific Windows Runtime controls may have class-based handling for the LostFocus event. If so, the control probably has an override for the method OnLostFocus. Typically the event is marked handled by the class handler, and the LostFocus event is not raised for handling by any user code handlers on that control. Controls might handle the event in order to unload a visual state that displayed a focus rectangle in response to OnGotFocus.
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 can check if we can do something with LosingFocus event that won't probably get swallowed the way LostFocus does
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.
Blocking to have out the discussion about LostFocus -- not totally sure -- otherwise I like this! 😄
Ah. Don't do any work to investigate that -- I don't want you to waste your effort. After we get through this spec review meeting I'll come back to tap this PR. 😄 |
Too late - already playing with this 😄 |
So.. LosingFocus seems to catch everything:
The problem I believe is that _dismissPalette, changes the visibility of the palette, that invokes a property changed handler in terminal page, that sets focus, that causes corruption 😄 |
So it seems that lostFocusHandler does capture all events (I cannot reproduce why it didn't work for me earlier), but sender is not good enough, it is always ourselves. So i am submitting something in between:
|
while (focusedElement) | ||
{ | ||
if (focusedElement == *this) | ||
{ | ||
return; | ||
} | ||
|
||
focusedElement = winrt::Windows::UI::Xaml::Media::VisualTreeHelper::GetParent(focusedElement); |
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.
k so just so I understand: If the thing losing focus is inside us or is us, we will return here and keep the palette open.
I don't totally understand why this works as described 😄 because if we aren't reacting to the command palette itself or any of its descendants losing focus and dismissing, when ARE we dismissing?
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.
@DHowett - I mean you were right, the lost focus event is getting routed to us if we or one of our children loses focus. We only need to distinguish if it loses the focus in favor of some other our child or some external element.
We cannot achieve this with the sender
, because it is always the element that loses focus, while we are interested in element that gets focus.
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 guess I will issue another commit explaining this 😊
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.
Oh, of course, it makes sense. Not sender
. "Is the thing that now has focus inside us".
Thanks!
Hello @DHowett! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
🎉 Handy links: |
So the implementation is somewhat dirty. The ideas was nice - add lostFocusHandler However it broke few things: * In the TabSwitcher the ListItem must be focusable since otherwise the SingleSelectionMode behavior breaks. To address this I had to put the lostFocusHandler on the items as well * When you click the flyout, the palette loses focus, which makes the terminal page to set the focus on the tab, closing the flyout. To address this I had to ensure the tab won't get focused once the flyout is open. In addition, flyout should fix the focus before opening, otherwise alt+tab will put a focus on a tab row rather than on tab * I also had to close the palette if the tab order changes. To prevent inconsistencies. Closes microsoft#8355
Fixes a regression of command palette accessibility. The regression was introduced in #8377 by setting `IsTabStop` to false. Though the commands would light up, the focus didn't technically get on the command, so the screen reader would just read the text box. ## Validation Steps Performed Opened the command palette while NVDA is active. It now reads the commands as focus moves on them.
Fixes a regression of command palette accessibility. The regression was introduced in #8377 by setting `IsTabStop` to false. Though the commands would light up, the focus didn't technically get on the command, so the screen reader would just read the text box. Opened the command palette while NVDA is active. It now reads the commands as focus moves on them. (cherry picked from commit ac3e4bf)
So the implementation is somewhat dirty.
The ideas was nice - add lostFocusHandler
However it broke few things:
In the TabSwitcher the ListItem must be focusable since otherwise
the SingleSelectionMode behavior breaks.
To address this I had to put the lostFocusHandler on the items as well
When you click the flyout, the palette loses focus,
which makes the terminal page to set the focus on the tab, closing the flyout.
To address this I had to ensure the tab won't get focused once the flyout is open.
In addition, flyout should fix the focus before opening,
otherwise alt+tab will put a focus on a tab row rather than on tab
I also had to close the palette if the tab order changes.
To prevent inconsistencies.
Closes #8355