Skip to content

TermControl: rework input and focus handling#4748

Closed
DHowett-MSFT wants to merge 3 commits intomasterfrom
dev/duhowett/be_my_input_sink
Closed

TermControl: rework input and focus handling#4748
DHowett-MSFT wants to merge 3 commits intomasterfrom
dev/duhowett/be_my_input_sink

Conversation

@DHowett-MSFT
Copy link
Contributor

This commit changes how we handle focus and tabstop-ness in TermControl
and its descendent controls.

The root of the issue that #4031 set out to investigate is that
TermControl hosts a bunch of other controls, but it's using event
tunneling to get first dibs on every bit of keyboard input sent its way
-- even for things that live inside it. This required us to hack around
and detemrine whether the input was intended for someone else before
eventually ignoring it or using it.

I believe the correct thing for us to do is to direct user keyboard
input to a control that lives logically "inside" the terminal surface
and have that control hold focus and process keyboard events.

Herein, we introduce an empty and invisible UserControl to hold focus
inside the terminal surface. Everything I've tested works great here.

It's important to note that the UserControl is invisible. Unfortunately,
this means that it can't receive mouse input. Its parent, the
SwapChainPanel acting as the terminal surface, can.

I've gone through and unmarked things that should not show up in the
tabstop list and changed the focus parameters for things that should.

Doing this lets us kill TermControl's dependency on all private details
in SearchBoxControl, including the bit where we could ask "do you think
you should be focused?", by letting Xaml handle focus. We now listen to
more focus events and funnel focus where we think it belongs. For
SearchBoxControl, that means we focus the text field and continue to
select all the text in it when the SearchBoxControl gets focus.

Fixes #4031.
This is an alternative solution to #4723, so I reverted that fix.

PR Checklist

This commit changes how we handle focus and tabstop-ness in TermControl
and its descendent controls.

The root of the issue that #4031 set out to investigate is that
TermControl hosts a bunch of other controls, but it's using event
tunneling to get first dibs on every bit of keyboard input sent its way
-- even for things that live inside it. This required us to hack around
and detemrine whether the input was intended for someone else before
eventually ignoring it or using it.

I believe the _correct_ thing for us to do is to direct user keyboard
input to a control that lives logically "inside" the terminal surface
and have that control hold focus and process keyboard events.

Herein, we introduce an empty and invisible UserControl to hold focus
inside the terminal surface. Everything I've tested works great here.

It's important to note that the UserControl is invisible. Unfortunately,
this means that it can't receive **mouse** input. Its parent, the
SwapChainPanel acting as the terminal surface, can.

I've gone through and unmarked things that should not show up in the
tabstop list and changed the focus parameters for things that should.

Doing this lets us kill TermControl's dependency on all private details
in SearchBoxControl, including the bit where we could ask "do you think
you should be focused?", by letting Xaml handle focus. We now listen to
more focus events and funnel focus where we think it belongs. For
SearchBoxControl, that means we focus the text field and continue to
select all the text in it when the SearchBoxControl gets focus.

Fixes #4031.
This is an alternative solution to #4723, so I reverted that fix.
@DHowett-MSFT DHowett-MSFT force-pushed the dev/duhowett/be_my_input_sink branch from 650b321 to bfdce8f Compare February 28, 2020 23:52
Copy link
Member

@carlos-zamora carlos-zamora left a comment

Choose a reason for hiding this comment

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

Tab Stop Issues:

  • You changed a few tab stop things. They make sense. You can tab to a SwapChainPanel. But I still can't figure out how to tab to a search box. Honestly, it's ok to just remove the search box as a tab stop because the user can still access it via the search box keybinding.

Accessibility:

  • This introduces a severe regression. For some reason, the TermControlAutomationPeer is no longer being interacted with when the TermControl gets focus. This means that we are completely unable to access our Automation Providers and extract info from the text buffer.
  • What's weird is that the TCAP still appears in the tree. But there's no way to navigate to it...

Comment on lines +99 to +110
// Method Description:
// - Funnels focus from TermControl to its input control
// Arguments:
// - e: the event args for the focus event
void TermControl::OnGotFocus(const RoutedEventArgs& e)
{
if (e.OriginalSource() == *this)
{
// If we're about to get focus, funnel it into our input site.
TerminalInputTarget().Focus(FocusState::Programmatic);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

So, this means that whenever the TermControl is attempted to get focus, we redirect focus to the TerminalInputTarget right? So you can't ever accidentally give focus to the search box?

Copy link
Member

Choose a reason for hiding this comment

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

Also, just to be clear, this is called just before the _GotFocusHandler?

Should we consolidate styles and rename this function to OnGotFocusHandler?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OnGotFocus is a special method name in that the UserControl composition class will call it if it's implemented. It must be named this: it is not a handler, it is not bound to an event.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the TermControl itself attempts to receive focus (not the controls inside it, not the search box, not anything else), we redirect focus to the input target.

@ghost ghost added Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Mar 2, 2020
@DHowett-MSFT
Copy link
Contributor Author

You changed a few tab stop things. They make sense. You can tab to a SwapChainPanel. But I still can't figure out how to tab to a search box. Honestly, it's ok to just remove the search box as a tab stop because the user can still access it via the search box keybinding.

Information in response to first comment.

Copy link
Contributor

@leonMSFT leonMSFT left a comment

Choose a reason for hiding this comment

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

Just a small question around SearchBoxControl::OnGotFocus. Although it seems like Carlos noticed some concerns around accessibility, so I'll hold my approval for now.

void SearchBoxControl::OnGotFocus(/*const IInspectable& sender,*/ Windows::UI::Xaml::RoutedEventArgs const& args)
{
if (TextBox())
if (args.OriginalSource() == *this)
Copy link
Contributor

Choose a reason for hiding this comment

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

Just to see if I'm understanding this correctly, this condition returns true only if the SearchBoxControl directly gained focus (probably from TermControl)? I'm guessing if the user clicked on the SearchBoxControl::TextBox() or its many Toggle-able buttons, the OriginalSource would be the TextBox or the buttons, so it wouldn't satisfy this condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed! I wanted to maintain the behavior that we had, where the searchbox didn't re-select all its text when the textbox was re-focused, but did when we entered the control for the first time. 😄

Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

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

This seems much more manageable than before. I trust Carlos to make sure his concerns about the accessibility actually get sorted out before he signs off

@zadjii-msft zadjii-msft added Area-TerminalControl Issues pertaining to the terminal control (input, selection, keybindings, mouse interaction, etc.) Needs-Second It's a PR that needs another sign-off labels Mar 6, 2020
@ghost ghost requested a review from miniksa March 6, 2020 13:37
@miniksa
Copy link
Member

miniksa commented Mar 6, 2020

This one's a party of Leon, Mike, and Carlos, so I'm skipping this one intentionally.

@zadjii-msft
Copy link
Member

Hey I'm gonna mark this as "needs author feedback" - I'm not sure how to resolve the accessibility concerns Carlos had, or if they're still reproing, but maybe we should loop back on this, esp with #6680

@zadjii-msft zadjii-msft added Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something and removed Needs-Second It's a PR that needs another sign-off labels Jun 26, 2020
@ghost ghost added the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Jul 3, 2020
@ghost
Copy link

ghost commented Jul 3, 2020

This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 7 days. It will be closed if no further activity occurs within 7 days of this comment.

@ghost ghost closed this Jul 10, 2020
@DHowett DHowett deleted the dev/duhowett/be_my_input_sink branch October 26, 2021 16:59
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-TerminalControl Issues pertaining to the terminal control (input, selection, keybindings, mouse interaction, etc.) Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TermControl key down handling investigation and refactoring

6 participants