Skip to content
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

#459 IME UI does not follow the cursor in Windows Terminal #1919

Merged
merged 33 commits into from
Nov 22, 2019

Conversation

philnach
Copy link
Member

@philnach philnach commented Jul 10, 2019

Summary of the Pull Request

TerminalControl doesn't use any of the built in text input and edit controls provided by XAML
for text input, which means TermianlControl needs to communicate with the Text Services Framework (TSF)
in order to provide Input Method Editor (IME) support. Just like the rest of Terminal we get
to take advantage of newer APIs (Windows.UI.Text.Core namespace) to provide support vs. the old TSF 1.0.

Windows.UI.Text.Core handles communication between a text edit control and the text services primarily
through a CoretextEditContext object.

This change introduces a new UserControl TSFInputControl which is a custom EditControl similar to the CustomEditControl sample

TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo).

References

PR Checklist

Detailed Description of the Pull Request / Additional comments

TSFInputControl is a Windows.UI.Xaml.Controls.UserControl

TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within it's containing control (TerminalControl).

The TextBlock control is used for displaying candidate text from the IME. When the user makes a choice in the IME the TextBlock is cleared and the text is written to the Terminal buffer like normal text.

TSFInputControl creates an instance of the CoreTextEditContext and attaches appropriate event handlers to CoreTextEditContext in order to interact with the IME.

A good write-up on how to interact with CoreTextEditContext can be found here: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input

Text Updates:
Text updates from the IME come in on the TextUpdating event handler, text updates are stored in an internal buffer (_inputBuffer).

Completed Text:
Once a user selects a text in the IME, the CompositionCompleted handler is invoked. The input buffer (_inputBuffer) is written to the Terminal buffer, _inputBuffer is cleared and Canvas and TextBlock controls are hidden until the user starts a composition session again.

Positioning:
Telling the IME where to properly position itself was the hardest part of this change. The IME expects to know it's location in screen coordinates as supposed to client coordinates. This is pretty easy if you are a pure UWP, but since we are hosted inside a XAMLIsland the client to screen coordinate translation is a little harder.

How screen coordinate is calculated is by:

  1. Obtaining the Window position in Screen coordinates.
  2. Determining the Client coordinate of the cursor.
  3. Converting the Client coordinate of the cursor to Screen coordinates.
  4. Offsetting the X and Y coordinate of the cursor by the position of the TerminalControl within the window (tabs if present, margins, etc..).
  5. Applying any scale factor of the display.

Once we have the right position in screen coordinates, this is supplied in the LayoutBounds of the CoreTextLayoutRequestedEventArgs which let's the IME know where to position itself on the Screen.

Font Information/Cursor/Writing to Terminal:
3 events were added to the TSFInputControl to create a loosely coupled implementation between the TerminalControl and the TSFInputControl. These events are used for obtaining Font information from the TerminalControl, getting the Cursor position and writing to the terminal buffer.

Known issues with this change:

  • Width of TextBlock is hardcoded to 200 pixels and most likely should adjust to the available width of the current input line on the console.
  • Entering text in the middle of an existing set of text has TextBlock render under existing text. Current Console behavior here isn't good experience either (writes over text)
  • Text input at edges of window is clipped versus wrapping around to next line. This isn't any worse than the original command line, but Terminal should be better.

Future considerations:
Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types.

Validation Steps Performed

General steps to try functionality

  • Open Console
  • Switch to Simplified Chinese (Shortcut: Windows+Spacebar)
  • Switch to Chinese mode on language bar

Scenarios validated:

  • As user types unformatted candidates appear on command line and IME renders in correct position under unformatted characters.
  • User can dismiss IME and text doesn't appear on command line
  • Switch back to English mode, functions like normal
  • New tab has proper behavior
  • Switching between tabs has proper behavior
  • Switching away from Terminal Window with IME present causes IME to disappear

@DHowett-MSFT
Copy link
Contributor

This is so cool. How did you resolve the bug where switching away while the IME was open would tank all input?

@philnach
Copy link
Member Author

Good question, it was due to calling NotifyFocusLeave. Apparently pulling the rug out from under the IME didn't leave it in a good state. I need to follow-up on how Focus is handled with the Terminal Control and Tabs, but for now not calling NotifyFocusLeave leaves the IME in a good state. I want to get this code out there to start to gather feedback. We can tweak Focus along the way.

originally I planned on setting them from the TerminalControl, however,
this wasn't a good idea because it would put too much TSFInputControl code
into the TerminalControl.

Also, removed some commented out code and increased the TAB_OFFSET to 38 vs 34
amount.
Copy link
Member

@miniksa miniksa left a comment

Choose a reason for hiding this comment

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

I know you're still Draft/WIP, but I gave it a quick once-over.

src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TermControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TermControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TermControl.cpp Outdated Show resolved Hide resolved
@philnach philnach marked this pull request as ready for review November 21, 2019 00:05
@DHowett-MSFT
Copy link
Contributor

We now have that WinRT Utils library Michael mentioned that might be good for ColorRefToColor! 😄

Copy link
Contributor

@DHowett-MSFT DHowett-MSFT left a comment

Choose a reason for hiding this comment

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

(partway through)

src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@DHowett-MSFT DHowett-MSFT left a comment

Choose a reason for hiding this comment

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

I honestly? don't have any problem with this, but I'd like to see a bit of macro cleanup. I'm still going to approve it, because dang, it's way way way better than what we have.

src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.h Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TermControl.cpp Outdated Show resolved Hide resolved
_tsfInputControl.CompositionCompleted({ this, &TermControl::_CompositionCompleted });
_tsfInputControl.CurrentCursorPosition({ this, &TermControl::_CurrentCursorPositionHandler });
_tsfInputControl.CurrentFontInfo({ this, &TermControl::_FontInfoHandler });
container.Children().Append(_tsfInputControl);
Copy link
Contributor

Choose a reason for hiding this comment

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

we may need to tell the accessibility subsystem something about this, but I am not sure what. @carlos-zamora?

@DHowett-MSFT
Copy link
Contributor

To the actual person who does the merge here: please copy Phil's excellent description into the commit message and get rid of the other cruft github puts in there!

@DHowett-MSFT
Copy link
Contributor

@philnach, I've got it! TextBlock's font size is in pixels. I cannot fathom why. It doesn't even take a unit. I'm just out of words.

Anyway, it's actually in device-independent pixels...

So, to go from a point size to a DIP size, you need to

auto points = /* ... */;
auto dips = 96.0*(points/72.0);

then pass dips along to the TextBlock 😁

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.

Largely I'm happy with this, but there's a bunch of nits commented throughout, so I want to give you a chance to clean those up. I'll come back and signoff near 3pm PST regardless, because this looks so SO much better than having nothing.

Thanks!

src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
src/cascadia/TerminalControl/TSFInputControl.cpp Outdated Show resolved Hide resolved
@zadjii-msft zadjii-msft added Area-Input Related to input processing (key presses, mouse, etc.) Area-TerminalControl Issues pertaining to the terminal control (input, selection, keybindings, mouse interaction, etc.) Product-Terminal The new Windows Terminal. labels Nov 21, 2019
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.

😀

double TermControl::_GetAutoScrollSpeed(double cursorDistanceFromBorder) const
{
// The numbers below just feel well, feel free to change.
// TODO: Maybe account for space beyond border that user has available
Copy link
Member

Choose a reason for hiding this comment

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

bare todo

@miniksa
Copy link
Member

miniksa commented Nov 21, 2019

Glad to have this. We're not perfect yet, but at least we now have a foundation to work from when it comes to IME.

@ghost ghost added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Nov 21, 2019
@ghost ghost removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Nov 21, 2019
Copy link
Contributor

@DHowett-MSFT DHowett-MSFT left a comment

Choose a reason for hiding this comment

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

It works, I'm shipping it.

@DHowett-MSFT
Copy link
Contributor

BATON: I am making the commit here.

@DHowett-MSFT DHowett-MSFT merged commit 62d7f11 into microsoft:master Nov 22, 2019
@philnach philnach deleted the dev/philnach/459-TSF30-IME_2 branch November 22, 2019 19:01
@ghost
Copy link

ghost commented Nov 26, 2019

🎉Windows Terminal Preview v0.7.3291.0 has been released which incorporates this pull request.:tada:

Handy links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Input Related to input processing (key presses, mouse, etc.) Area-TerminalControl Issues pertaining to the terminal control (input, selection, keybindings, mouse interaction, etc.) Product-Terminal The new Windows Terminal.
Projects
None yet
5 participants