Files
terminal/src/cascadia/TerminalControl/TSFInputControl.cpp

476 lines
20 KiB
C++
Raw Normal View History

// Copyright (c) Microsoft Corporation.
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Licensed under the MIT license.
#include "pch.h"
#include "TSFInputControl.h"
#include "TSFInputControl.g.cpp"
#include <Utils.h>
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Graphics::Display;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Text;
using namespace winrt::Windows::UI::Text::Core;
using namespace winrt::Windows::UI::Xaml;
Rename `Microsoft.Terminal.TerminalControl` to `.Control`; Split into dll & lib (#9472) **BE NOT AFRAID**. I know that there's 107 files in this PR, but almost all of it is just find/replacing `TerminalControl` with `Control`. This is the start of the work to move TermControl into multiple pieces, for #5000. The PR starts this work by: * Splits `TerminalControl` into separate lib and dll projects. We'll want control tests in the future, and for that, we'll need a lib. * Moves `ICoreSettings` back into the `Microsoft.Terminal.Core` namespace. We'll have other types in there soon too. * I could not tell you why this works suddenly. New VS versions? New cppwinrt version? Maybe we're just better at dealing with mdmerge bugs these days. * RENAMES `Microsoft.Terminal.TerminalControl` to `Microsoft.Terminal.Control`. This touches pretty much every file in the sln. Sorry about that (not sorry). An upcoming PR will move much of the logic in TermControl into a new `ControlCore` class that we'll add in `Microsoft.Terminal.Core`. `ControlCore` will then be unittest-able in the `UnitTests_TerminalCore`, which will help prevent regressions like #9455 ## Detailed Description of the Pull Request / Additional comments You're really gonna want to clean the sln first, then merge this into your branch, then rebuild. It's very likely that old winmds will get left behind. If you see something like ``` Error MDM2007 Cannot create type Microsoft.Terminal.TerminalControl.KeyModifiers in read-only metadata file Microsoft.Terminal.TerminalControl. ``` then that's what happened to you.
2021-03-17 15:47:24 -05:00
namespace winrt::Microsoft::Terminal::Control::implementation
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
TSFInputControl::TSFInputControl() :
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
_editContext{ nullptr },
Make Korean IME input more consistent (#4796) ## Summary of the Pull Request Korean IME was not working correctly due to way we were clearing the input buffer inside of `TSFInputControl`. We wanted to clear our input buffer and tell TSF to clear its input buffer as well when we receive a `CompositionCompleted` event. This works fine in some IME languages such as Chinese and Japanese. However, Korean IME composes characters differently in such a way where we can't tell TSF to clear their buffer during a `CompositionCompleted` event because it would clear the character that triggered the `CompositionCompleted` event in the first place. The solution in this PR is to keep our `_inputBuffer` intact until the user presses <kbd>Enter</kbd> or <kbd>Esc</kbd>, in which case we clear our buffer and the TSF buffer. I've chosen these two keys because it seems to make sense to clear the buffer after text is sent to the terminal with <kbd>Enter</kbd>, and <kbd>Esc</kbd> usually means to cancel a current composition anyway. This means we need to keep track of our last known "Composition Start Point", which is represented by `_activeTextStart`. Whenever we complete a composition, we'll send the portion of the input buffer between `_activeTextStart` and the end of the input buffer to the terminal. Then, we'll update `_activeTextStart` to be the end of the input buffer so that the next time we send text to the terminal, we'll only send the portion of our buffer that's "active". ## PR Checklist * [x] Closes #4226 * [x] CLA signed * [x] Tests added/passed ## Validation Steps Performed Manual testing with Chinese, Japanese, and Korean IME.
2020-03-04 20:01:01 +00:00
_inComposition{ false },
_activeTextStart{ 0 },
_focused{ false },
_currentTerminalCursorPos{ 0, 0 },
_currentCanvasWidth{ 0.0 },
_currentTextBlockHeight{ 0.0 },
_currentTextBounds{ 0, 0, 0, 0 },
Adjust TSFInputControl alignment (#5609) This PR fixes a couple of issues with TSFInputControl alignment: 1. The emoji picker IME in particular would show up overlapping the current buffer row because I stupidly didn't realize that `TextBlock.ActualHeight` is 0 right after initialization and before it has any text. So, the emoji picker will show up on the bottom of the 0 height TextBlock, which overlaps the current buffer row. This isn't a problem with CJK because inputting text _causes_ the IME to show up, so by the time the IME shows up, the TextBlock has text and accordingly has a height. 2. It turns out the emoji picker IME doesn't follow the `TextBlock` bottom, unlike Chinese and Japanese IME, so if a user were to compose near the edge of the screen and let the `TextBlock` start line wrapping, the emoji IME doesn't follow the bottom of the `TextBlock` as it grows. This means that the `TextBlock` position doesn't update in the middle of composition, and the `LayoutRequested` event that it fires at the beginning of composition is the only chance we get to tell the emoji IME where to place itself. It turns out when we reset `TextBlock.Text`, the ActualHeight doesn't get immediately reset back to the min size. So if a user were to bring up the emoji IME before `ActualHeight` is reset, the IME will show up way below the current buffer row. 3. We don't currently `TryRedrawCanvas` when the window position changes (resizing, dragging the window around), so sometimes dragging or resizing the Terminal doesn't update the position of the IME. Ideally it should be listening to some "window position changed" event, but alas we don't have that and it would be much harder than this incoming fix. We'll just track the window bounds as part of `TryRedrawCanvas` and redraw if it changes. For the most part, this will allow the IME to update to where the new window position is, but it'll only be called if we receive a `LayoutRequested` event. ## PR Checklist * [x] Closes #5470 * [x] CLA signed. * [x] Tests added/passed ## Validation Steps Performed I play with it for quite a bit.
2020-04-28 11:50:33 -07:00
_currentControlBounds{ 0, 0, 0, 0 },
_currentWindowBounds{ 0, 0, 0, 0 }
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
InitializeComponent();
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Create a CoreTextEditingContext for since we are acting like a custom edit control
auto manager = CoreTextServicesManager::GetForCurrentView();
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_editContext = manager.CreateEditContext();
// InputPane is manually shown inside of TermControl.
_editContext.InputPaneDisplayPolicy(CoreTextInputPaneDisplayPolicy::Manual);
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
2022-05-04 02:07:06 +08:00
// Set the input scope to AlphanumericHalfWidth in order to facilitate those CJK input methods to open in English mode by default.
// AlphanumericHalfWidth scope doesn't prevent input method from switching to composition mode, it accepts any character too.
// Besides, Text scope turns on typing intelligence, but that doesn't work in this project.
_editContext.InputScope(CoreTextInputScope::AlphanumericHalfWidth);
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_textRequestedRevoker = _editContext.TextRequested(winrt::auto_revoke, { this, &TSFInputControl::_textRequestedHandler });
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_selectionRequestedRevoker = _editContext.SelectionRequested(winrt::auto_revoke, { this, &TSFInputControl::_selectionRequestedHandler });
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_focusRemovedRevoker = _editContext.FocusRemoved(winrt::auto_revoke, { this, &TSFInputControl::_focusRemovedHandler });
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_textUpdatingRevoker = _editContext.TextUpdating(winrt::auto_revoke, { this, &TSFInputControl::_textUpdatingHandler });
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_selectionUpdatingRevoker = _editContext.SelectionUpdating(winrt::auto_revoke, { this, &TSFInputControl::_selectionUpdatingHandler });
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_formatUpdatingRevoker = _editContext.FormatUpdating(winrt::auto_revoke, { this, &TSFInputControl::_formatUpdatingHandler });
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_layoutRequestedRevoker = _editContext.LayoutRequested(winrt::auto_revoke, { this, &TSFInputControl::_layoutRequestedHandler });
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_compositionStartedRevoker = _editContext.CompositionStarted(winrt::auto_revoke, { this, &TSFInputControl::_compositionStartedHandler });
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_compositionCompletedRevoker = _editContext.CompositionCompleted(winrt::auto_revoke, { this, &TSFInputControl::_compositionCompletedHandler });
}
// Method Description:
// - Prepares this TSFInputControl to be removed from the UI hierarchy.
void TSFInputControl::Close()
{
// Explicitly disconnect the LayoutRequested handler -- it can cause problems during application teardown.
// See GH#4159 for more info.
// Also disconnect compositionCompleted and textUpdating explicitly. It seems to occasionally cause problems if
// a composition is active during application teardown.
_layoutRequestedRevoker.revoke();
_compositionCompletedRevoker.revoke();
_textUpdatingRevoker.revoke();
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
}
// Method Description:
// - NotifyFocusEnter handler for notifying CoreEditTextContext of focus enter
// when TerminalControl receives focus.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TSFInputControl::NotifyFocusEnter()
{
if (_editContext != nullptr)
{
_editContext.NotifyFocusEnter();
_focused = true;
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
}
}
// Method Description:
// - NotifyFocusEnter handler for notifying CoreEditTextContext of focus leaving.
// when TerminalControl no longer has focus.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TSFInputControl::NotifyFocusLeave()
{
if (_editContext != nullptr)
{
_editContext.NotifyFocusLeave();
_focused = false;
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
}
}
Make Korean IME input more consistent (#4796) ## Summary of the Pull Request Korean IME was not working correctly due to way we were clearing the input buffer inside of `TSFInputControl`. We wanted to clear our input buffer and tell TSF to clear its input buffer as well when we receive a `CompositionCompleted` event. This works fine in some IME languages such as Chinese and Japanese. However, Korean IME composes characters differently in such a way where we can't tell TSF to clear their buffer during a `CompositionCompleted` event because it would clear the character that triggered the `CompositionCompleted` event in the first place. The solution in this PR is to keep our `_inputBuffer` intact until the user presses <kbd>Enter</kbd> or <kbd>Esc</kbd>, in which case we clear our buffer and the TSF buffer. I've chosen these two keys because it seems to make sense to clear the buffer after text is sent to the terminal with <kbd>Enter</kbd>, and <kbd>Esc</kbd> usually means to cancel a current composition anyway. This means we need to keep track of our last known "Composition Start Point", which is represented by `_activeTextStart`. Whenever we complete a composition, we'll send the portion of the input buffer between `_activeTextStart` and the end of the input buffer to the terminal. Then, we'll update `_activeTextStart` to be the end of the input buffer so that the next time we send text to the terminal, we'll only send the portion of our buffer that's "active". ## PR Checklist * [x] Closes #4226 * [x] CLA signed * [x] Tests added/passed ## Validation Steps Performed Manual testing with Chinese, Japanese, and Korean IME.
2020-03-04 20:01:01 +00:00
// Method Description:
// - Clears the input buffer and tells the text server to clear their buffer as well.
// Also clears the TextBlock and sets the active text starting point to 0.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TSFInputControl::ClearBuffer()
{
if (!_inputBuffer.empty())
{
TextBlock().Text(L"");
const auto bufLen = ::base::ClampedNumeric<int32_t>(_inputBuffer.length());
_inputBuffer.clear();
_editContext.NotifyFocusLeave();
_editContext.NotifyTextChanged({ 0, bufLen }, 0, { 0, 0 });
_editContext.NotifyFocusEnter();
_activeTextStart = 0;
_inComposition = false;
}
}
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Method Description:
// - Redraw the canvas if certain dimensions have changed since the last
// redraw. This includes the Terminal cursor position, the Canvas width, and the TextBlock height.
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Arguments:
// - <none>
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Return Value:
// - <none>
void TSFInputControl::TryRedrawCanvas()
try
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
if (!_focused || !Canvas())
{
return;
}
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Get the cursor position in text buffer position
auto cursorArgs = winrt::make_self<CursorPositionEventArgs>();
_CurrentCursorPositionHandlers(*this, *cursorArgs);
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
const til::point cursorPos{ til::math::flooring, cursorArgs->CurrentPosition() };
const auto actualCanvasWidth{ Canvas().ActualWidth() };
const auto actualTextBlockHeight{ TextBlock().ActualHeight() };
Adjust TSFInputControl alignment (#5609) This PR fixes a couple of issues with TSFInputControl alignment: 1. The emoji picker IME in particular would show up overlapping the current buffer row because I stupidly didn't realize that `TextBlock.ActualHeight` is 0 right after initialization and before it has any text. So, the emoji picker will show up on the bottom of the 0 height TextBlock, which overlaps the current buffer row. This isn't a problem with CJK because inputting text _causes_ the IME to show up, so by the time the IME shows up, the TextBlock has text and accordingly has a height. 2. It turns out the emoji picker IME doesn't follow the `TextBlock` bottom, unlike Chinese and Japanese IME, so if a user were to compose near the edge of the screen and let the `TextBlock` start line wrapping, the emoji IME doesn't follow the bottom of the `TextBlock` as it grows. This means that the `TextBlock` position doesn't update in the middle of composition, and the `LayoutRequested` event that it fires at the beginning of composition is the only chance we get to tell the emoji IME where to place itself. It turns out when we reset `TextBlock.Text`, the ActualHeight doesn't get immediately reset back to the min size. So if a user were to bring up the emoji IME before `ActualHeight` is reset, the IME will show up way below the current buffer row. 3. We don't currently `TryRedrawCanvas` when the window position changes (resizing, dragging the window around), so sometimes dragging or resizing the Terminal doesn't update the position of the IME. Ideally it should be listening to some "window position changed" event, but alas we don't have that and it would be much harder than this incoming fix. We'll just track the window bounds as part of `TryRedrawCanvas` and redraw if it changes. For the most part, this will allow the IME to update to where the new window position is, but it'll only be called if we receive a `LayoutRequested` event. ## PR Checklist * [x] Closes #5470 * [x] CLA signed. * [x] Tests added/passed ## Validation Steps Performed I play with it for quite a bit.
2020-04-28 11:50:33 -07:00
const auto actualWindowBounds{ CoreWindow::GetForCurrentThread().Bounds() };
if (_currentTerminalCursorPos == cursorPos &&
_currentCanvasWidth == actualCanvasWidth &&
Adjust TSFInputControl alignment (#5609) This PR fixes a couple of issues with TSFInputControl alignment: 1. The emoji picker IME in particular would show up overlapping the current buffer row because I stupidly didn't realize that `TextBlock.ActualHeight` is 0 right after initialization and before it has any text. So, the emoji picker will show up on the bottom of the 0 height TextBlock, which overlaps the current buffer row. This isn't a problem with CJK because inputting text _causes_ the IME to show up, so by the time the IME shows up, the TextBlock has text and accordingly has a height. 2. It turns out the emoji picker IME doesn't follow the `TextBlock` bottom, unlike Chinese and Japanese IME, so if a user were to compose near the edge of the screen and let the `TextBlock` start line wrapping, the emoji IME doesn't follow the bottom of the `TextBlock` as it grows. This means that the `TextBlock` position doesn't update in the middle of composition, and the `LayoutRequested` event that it fires at the beginning of composition is the only chance we get to tell the emoji IME where to place itself. It turns out when we reset `TextBlock.Text`, the ActualHeight doesn't get immediately reset back to the min size. So if a user were to bring up the emoji IME before `ActualHeight` is reset, the IME will show up way below the current buffer row. 3. We don't currently `TryRedrawCanvas` when the window position changes (resizing, dragging the window around), so sometimes dragging or resizing the Terminal doesn't update the position of the IME. Ideally it should be listening to some "window position changed" event, but alas we don't have that and it would be much harder than this incoming fix. We'll just track the window bounds as part of `TryRedrawCanvas` and redraw if it changes. For the most part, this will allow the IME to update to where the new window position is, but it'll only be called if we receive a `LayoutRequested` event. ## PR Checklist * [x] Closes #5470 * [x] CLA signed. * [x] Tests added/passed ## Validation Steps Performed I play with it for quite a bit.
2020-04-28 11:50:33 -07:00
_currentTextBlockHeight == actualTextBlockHeight &&
_currentWindowBounds == actualWindowBounds)
{
return;
}
_currentTerminalCursorPos = cursorPos;
_currentCanvasWidth = actualCanvasWidth;
_currentTextBlockHeight = actualTextBlockHeight;
Adjust TSFInputControl alignment (#5609) This PR fixes a couple of issues with TSFInputControl alignment: 1. The emoji picker IME in particular would show up overlapping the current buffer row because I stupidly didn't realize that `TextBlock.ActualHeight` is 0 right after initialization and before it has any text. So, the emoji picker will show up on the bottom of the 0 height TextBlock, which overlaps the current buffer row. This isn't a problem with CJK because inputting text _causes_ the IME to show up, so by the time the IME shows up, the TextBlock has text and accordingly has a height. 2. It turns out the emoji picker IME doesn't follow the `TextBlock` bottom, unlike Chinese and Japanese IME, so if a user were to compose near the edge of the screen and let the `TextBlock` start line wrapping, the emoji IME doesn't follow the bottom of the `TextBlock` as it grows. This means that the `TextBlock` position doesn't update in the middle of composition, and the `LayoutRequested` event that it fires at the beginning of composition is the only chance we get to tell the emoji IME where to place itself. It turns out when we reset `TextBlock.Text`, the ActualHeight doesn't get immediately reset back to the min size. So if a user were to bring up the emoji IME before `ActualHeight` is reset, the IME will show up way below the current buffer row. 3. We don't currently `TryRedrawCanvas` when the window position changes (resizing, dragging the window around), so sometimes dragging or resizing the Terminal doesn't update the position of the IME. Ideally it should be listening to some "window position changed" event, but alas we don't have that and it would be much harder than this incoming fix. We'll just track the window bounds as part of `TryRedrawCanvas` and redraw if it changes. For the most part, this will allow the IME to update to where the new window position is, but it'll only be called if we receive a `LayoutRequested` event. ## PR Checklist * [x] Closes #5470 * [x] CLA signed. * [x] Tests added/passed ## Validation Steps Performed I play with it for quite a bit.
2020-04-28 11:50:33 -07:00
_currentWindowBounds = actualWindowBounds;
_RedrawCanvas();
}
CATCH_LOG()
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Method Description:
// - Redraw the Canvas and update the current Text Bounds and Control Bounds for
// the CoreTextEditContext.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TSFInputControl::_RedrawCanvas()
{
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Get Font Info as we use this is the pixel size for characters in the display
auto fontArgs = winrt::make_self<FontInfoEventArgs>();
_CurrentFontInfoHandlers(*this, *fontArgs);
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
const til::size fontSize{ til::math::flooring, fontArgs->FontSize() };
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// Convert text buffer cursor position to client coordinate position
// within the window. This point is in _pixels_
const auto clientCursorPos{ _currentTerminalCursorPos * fontSize };
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// Get scale factor for view
const auto scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
const til::point clientCursorInDips{ til::math::flooring, clientCursorPos.x / scaleFactor, clientCursorPos.y / scaleFactor };
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// Position our TextBlock at the cursor position
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
Canvas().SetLeft(TextBlock(), clientCursorInDips.x);
Canvas().SetTop(TextBlock(), clientCursorInDips.y);
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// calculate FontSize in pixels from Points
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
const double fontSizePx = (fontSize.height * 72) / USER_DEFAULT_SCREEN_DPI;
const auto unscaledFontSizePx = fontSizePx / scaleFactor;
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// Make sure to unscale the font size to correct for DPI! XAML needs
// things in DIPs, and the fontSize is in pixels.
Adjust TSFInputControl alignment (#5609) This PR fixes a couple of issues with TSFInputControl alignment: 1. The emoji picker IME in particular would show up overlapping the current buffer row because I stupidly didn't realize that `TextBlock.ActualHeight` is 0 right after initialization and before it has any text. So, the emoji picker will show up on the bottom of the 0 height TextBlock, which overlaps the current buffer row. This isn't a problem with CJK because inputting text _causes_ the IME to show up, so by the time the IME shows up, the TextBlock has text and accordingly has a height. 2. It turns out the emoji picker IME doesn't follow the `TextBlock` bottom, unlike Chinese and Japanese IME, so if a user were to compose near the edge of the screen and let the `TextBlock` start line wrapping, the emoji IME doesn't follow the bottom of the `TextBlock` as it grows. This means that the `TextBlock` position doesn't update in the middle of composition, and the `LayoutRequested` event that it fires at the beginning of composition is the only chance we get to tell the emoji IME where to place itself. It turns out when we reset `TextBlock.Text`, the ActualHeight doesn't get immediately reset back to the min size. So if a user were to bring up the emoji IME before `ActualHeight` is reset, the IME will show up way below the current buffer row. 3. We don't currently `TryRedrawCanvas` when the window position changes (resizing, dragging the window around), so sometimes dragging or resizing the Terminal doesn't update the position of the IME. Ideally it should be listening to some "window position changed" event, but alas we don't have that and it would be much harder than this incoming fix. We'll just track the window bounds as part of `TryRedrawCanvas` and redraw if it changes. For the most part, this will allow the IME to update to where the new window position is, but it'll only be called if we receive a `LayoutRequested` event. ## PR Checklist * [x] Closes #5470 * [x] CLA signed. * [x] Tests added/passed ## Validation Steps Performed I play with it for quite a bit.
2020-04-28 11:50:33 -07:00
TextBlock().FontSize(unscaledFontSizePx);
TextBlock().FontFamily(Media::FontFamily(fontArgs->FontFace()));
Add font weight options (#6048) ## Summary of the Pull Request Adds the ability to specify the font weight in the profiles, right next to the size and the font face. ## PR Checklist * [x] Closes #1751 * [x] I work here. * [x] Tested manually, see below. * [x] Added documentation to the schema * [x] Requires docs.microsoft.com update, filed as https://github.com/MicrosoftDocs/terminal/issues/26 * [x] I'm a core contributor. ## Detailed Description of the Pull Request / Additional comments - Weights can be specified according to the OpenType specification values. We accept either the friendly name or the numerical value that applies to each weight. - Weights are carried through per-profile and sent into the renderer. - Weights are carried through to the TSF/IME overlay. - The names are restricted to the set seen at https://docs.microsoft.com/en-us/uwp/api/windows.ui.text.fontweights. - There are alternate names at https://docs.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_font_weight for the same values (ultra-black is just an alias for extra-black at 950). ## Validation Steps Performed - Cascadia Code normal ![image](https://user-images.githubusercontent.com/18221333/82480181-46117380-9a88-11ea-9436-a5fe4ccd4350.png) - Cascadia Code bold ![image](https://user-images.githubusercontent.com/18221333/82480202-4f9adb80-9a88-11ea-9e27-a113b41387f5.png) - Segoe UI Semilight ![image](https://user-images.githubusercontent.com/18221333/82480306-73f6b800-9a88-11ea-93f7-d773ab7ccce8.png) - Segoe UI Black ![image](https://user-images.githubusercontent.com/18221333/82480401-9688d100-9a88-11ea-957c-0c8e03a8cc29.png) - Segoe UI 900 (value for Black) ![image](https://user-images.githubusercontent.com/18221333/82480774-26c71600-9a89-11ea-8cf6-aaeab1fd0747.png)
2020-05-20 13:17:17 -07:00
TextBlock().FontWeight(fontArgs->FontWeight());
Adjust TSFInputControl alignment (#5609) This PR fixes a couple of issues with TSFInputControl alignment: 1. The emoji picker IME in particular would show up overlapping the current buffer row because I stupidly didn't realize that `TextBlock.ActualHeight` is 0 right after initialization and before it has any text. So, the emoji picker will show up on the bottom of the 0 height TextBlock, which overlaps the current buffer row. This isn't a problem with CJK because inputting text _causes_ the IME to show up, so by the time the IME shows up, the TextBlock has text and accordingly has a height. 2. It turns out the emoji picker IME doesn't follow the `TextBlock` bottom, unlike Chinese and Japanese IME, so if a user were to compose near the edge of the screen and let the `TextBlock` start line wrapping, the emoji IME doesn't follow the bottom of the `TextBlock` as it grows. This means that the `TextBlock` position doesn't update in the middle of composition, and the `LayoutRequested` event that it fires at the beginning of composition is the only chance we get to tell the emoji IME where to place itself. It turns out when we reset `TextBlock.Text`, the ActualHeight doesn't get immediately reset back to the min size. So if a user were to bring up the emoji IME before `ActualHeight` is reset, the IME will show up way below the current buffer row. 3. We don't currently `TryRedrawCanvas` when the window position changes (resizing, dragging the window around), so sometimes dragging or resizing the Terminal doesn't update the position of the IME. Ideally it should be listening to some "window position changed" event, but alas we don't have that and it would be much harder than this incoming fix. We'll just track the window bounds as part of `TryRedrawCanvas` and redraw if it changes. For the most part, this will allow the IME to update to where the new window position is, but it'll only be called if we receive a `LayoutRequested` event. ## PR Checklist * [x] Closes #5470 * [x] CLA signed. * [x] Tests added/passed ## Validation Steps Performed I play with it for quite a bit.
2020-04-28 11:50:33 -07:00
// TextBlock's actual dimensions right after initialization is 0w x 0h. So,
// if an IME is displayed before TextBlock has text (like showing the emoji picker
// using Win+.), it'll be placed higher than intended.
TextBlock().MinWidth(unscaledFontSizePx);
TextBlock().MinHeight(unscaledFontSizePx);
_currentTextBlockHeight = std::max(unscaledFontSizePx, _currentTextBlockHeight);
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
const auto widthToTerminalEnd = _currentCanvasWidth - clientCursorInDips.x;
// Make sure that we're setting the MaxWidth to a positive number - a
// negative number here will crash us in mysterious ways with a useless
// stack trace
const auto newMaxWidth = std::max<double>(0.0, widthToTerminalEnd);
TextBlock().MaxWidth(newMaxWidth);
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// Get window in screen coordinates, this is the entire window including
// tabs. THIS IS IN DIPs
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
const til::point windowOrigin{ til::math::flooring, _currentWindowBounds.X, _currentWindowBounds.Y };
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// Get the offset (margin + tabs, etc..) of the control within the window
const til::point controlOrigin{ til::math::flooring,
this->TransformToVisual(nullptr).TransformPoint(Point(0, 0)) };
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// The controlAbsoluteOrigin is the origin of the control relative to
// the origin of the displays. THIS IS IN DIPs
const auto controlAbsoluteOrigin{ windowOrigin + controlOrigin };
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// Convert the control origin to pixels
const auto scaledFrameOrigin = til::point{ til::math::flooring, controlAbsoluteOrigin.x * scaleFactor, controlAbsoluteOrigin.y * scaleFactor };
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// Get the location of the cursor in the display, in pixels.
auto screenCursorPos{ scaledFrameOrigin + clientCursorPos };
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// GH #5007 - make sure to account for wrapping the IME composition at
// the right side of the viewport.
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
const auto textBlockHeight = ::base::ClampMul(_currentTextBlockHeight, scaleFactor);
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
// Get the bounds of the composition text, in pixels.
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
const til::rect textBounds{ til::point{ screenCursorPos.x, screenCursorPos.y },
til::size{ 0, textBlockHeight } };
Adjusts High DPI scaling to enable differential rendering (#5345) ## Summary of the Pull Request - Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI. ## References - #5185 ## PR Checklist * [x] Closes #5320, closes #3515, closes #1064 * [x] I work here. * [x] Manually tested. * [x] No doc. * [x] Am core contributor. Also discussed with some of them already via Teams. ## Detailed Description of the Pull Request / Additional comments **WAS:** - We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target. - When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is. - Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering. **NOW:** - When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels. - `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled. - `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI. - The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI. - A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that. ## Validation Steps Performed * [x] Check at 150% DPI. Print text, scroll text down and up, do selection. * [x] Check at 100% DPI. Print text, scroll text down and up, do selection. * [x] Span two different DPI monitors and drag between them. * [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648 Co-authored-by: Dustin Howett <duhowett@microsoft.com> Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 14:59:51 -07:00
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
_currentTextBounds = textBounds.to_winrt_rect();
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
Prepare til wrappers for migrating off of SMALL_RECT (#11902) This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
2022-01-13 22:09:29 +01:00
_currentControlBounds = Rect(static_cast<float>(screenCursorPos.x),
static_cast<float>(screenCursorPos.y),
0.0f,
static_cast<float>(fontSize.height));
}
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Method Description:
// - Handler for LayoutRequested event by CoreEditContext responsible
// for returning the current position the IME should be placed
// in screen coordinates on the screen. TSFInputControls internal
// XAML controls (TextBlock/Canvas) are also positioned and updated.
// NOTE: documentation says application should handle this event
// Arguments:
// - sender: CoreTextEditContext sending the request.
// - args: CoreTextLayoutRequestedEventArgs to be updated with position information.
// Return Value:
// - <none>
void TSFInputControl::_layoutRequestedHandler(CoreTextEditContext sender, const CoreTextLayoutRequestedEventArgs& args)
{
auto request = args.Request();
TryRedrawCanvas();
// Set the text block bounds
request.LayoutBounds().TextBounds(_currentTextBounds);
// Set the control bounds of the whole control
request.LayoutBounds().ControlBounds(_currentControlBounds);
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
}
// Method Description:
// - Handler for CompositionStarted event by CoreEditContext responsible
// for making internal TSFInputControl controls visible.
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Arguments:
// - sender: CoreTextEditContext sending the request. Not used in method.
// - args: CoreTextCompositionStartedEventArgs. Not used in method.
// Return Value:
// - <none>
void TSFInputControl::_compositionStartedHandler(CoreTextEditContext sender, const CoreTextCompositionStartedEventArgs& /*args*/)
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
_inComposition = true;
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
}
// Method Description:
// - Handler for CompositionCompleted event by CoreEditContext responsible
// for making internal TSFInputControl controls visible.
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Arguments:
// - sender: CoreTextEditContext sending the request. Not used in method.
// - args: CoreTextCompositionCompletedEventArgs. Not used in method.
// Return Value:
// - <none>
void TSFInputControl::_compositionCompletedHandler(CoreTextEditContext sender, const CoreTextCompositionCompletedEventArgs& /*args*/)
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
_inComposition = false;
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// only need to do work if the current buffer has text
if (!_inputBuffer.empty())
{
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
_SendAndClearText();
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
}
}
// Method Description:
// - Handler for FocusRemoved event by CoreEditContext responsible
// for removing focus for the TSFInputControl control accordingly
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
// when focus was forcibly removed from text input control.
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// NOTE: Documentation says application should handle this event
// Arguments:
// - sender: CoreTextEditContext sending the request. Not used in method.
// - object: CoreTextCompositionStartedEventArgs. Not used in method.
// Return Value:
// - <none>
void TSFInputControl::_focusRemovedHandler(CoreTextEditContext sender, const winrt::Windows::Foundation::IInspectable& /*object*/)
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
}
// Method Description:
// - Handler for TextRequested event by CoreEditContext responsible
// for returning the range of text requested.
// NOTE: Documentation says application should handle this event
// Arguments:
// - sender: CoreTextEditContext sending the request. Not used in method.
// - args: CoreTextTextRequestedEventArgs to be updated with requested range text.
// Return Value:
// - <none>
void TSFInputControl::_textRequestedHandler(CoreTextEditContext sender, const CoreTextTextRequestedEventArgs& args)
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
// the range the TSF wants to know about
const auto range = args.Request().Range();
try
{
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
const auto textEnd = ::base::ClampMin<size_t>(range.EndCaretPosition, _inputBuffer.length());
const auto length = ::base::ClampSub<size_t>(textEnd, range.StartCaretPosition);
const auto textRequested = _inputBuffer.substr(range.StartCaretPosition, length);
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
args.Request().Text(textRequested);
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
}
CATCH_LOG();
}
// Method Description:
// - Handler for SelectionRequested event by CoreEditContext responsible
// for returning the currently selected text.
// TSFInputControl currently doesn't allow selection, so nothing happens.
// NOTE: Documentation says application should handle this event
// Arguments:
// - sender: CoreTextEditContext sending the request. Not used in method.
// - args: CoreTextSelectionRequestedEventArgs for providing data for the SelectionRequested event. Not used in method.
// Return Value:
// - <none>
void TSFInputControl::_selectionRequestedHandler(CoreTextEditContext sender, const CoreTextSelectionRequestedEventArgs& /*args*/)
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
}
// Method Description:
// - Handler for SelectionUpdating event by CoreEditContext responsible
// for handling modifications to the range of text currently selected.
// TSFInputControl doesn't currently allow selection, so nothing happens.
// NOTE: Documentation says application should set its selection range accordingly
// Arguments:
// - sender: CoreTextEditContext sending the request. Not used in method.
// - args: CoreTextSelectionUpdatingEventArgs for providing data for the SelectionUpdating event. Not used in method.
// Return Value:
// - <none>
void TSFInputControl::_selectionUpdatingHandler(CoreTextEditContext sender, const CoreTextSelectionUpdatingEventArgs& /*args*/)
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
}
// Method Description:
// - Handler for TextUpdating event by CoreEditContext responsible
// for handling text updates.
// Arguments:
// - sender: CoreTextEditContext sending the request. Not used in method.
// - args: CoreTextTextUpdatingEventArgs contains new text to update buffer with.
// Return Value:
// - <none>
void TSFInputControl::_textUpdatingHandler(CoreTextEditContext sender, const CoreTextTextUpdatingEventArgs& args)
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
Make Korean IME input more consistent (#4796) ## Summary of the Pull Request Korean IME was not working correctly due to way we were clearing the input buffer inside of `TSFInputControl`. We wanted to clear our input buffer and tell TSF to clear its input buffer as well when we receive a `CompositionCompleted` event. This works fine in some IME languages such as Chinese and Japanese. However, Korean IME composes characters differently in such a way where we can't tell TSF to clear their buffer during a `CompositionCompleted` event because it would clear the character that triggered the `CompositionCompleted` event in the first place. The solution in this PR is to keep our `_inputBuffer` intact until the user presses <kbd>Enter</kbd> or <kbd>Esc</kbd>, in which case we clear our buffer and the TSF buffer. I've chosen these two keys because it seems to make sense to clear the buffer after text is sent to the terminal with <kbd>Enter</kbd>, and <kbd>Esc</kbd> usually means to cancel a current composition anyway. This means we need to keep track of our last known "Composition Start Point", which is represented by `_activeTextStart`. Whenever we complete a composition, we'll send the portion of the input buffer between `_activeTextStart` and the end of the input buffer to the terminal. Then, we'll update `_activeTextStart` to be the end of the input buffer so that the next time we send text to the terminal, we'll only send the portion of our buffer that's "active". ## PR Checklist * [x] Closes #4226 * [x] CLA signed * [x] Tests added/passed ## Validation Steps Performed Manual testing with Chinese, Japanese, and Korean IME.
2020-03-04 20:01:01 +00:00
const auto incomingText = args.Text();
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
const auto range = args.Range();
try
{
2020-03-24 17:00:18 -07:00
// When a user deletes the last character in their current composition, some machines
// will fire a CompositionCompleted before firing a TextUpdating event that deletes the last character.
// The TextUpdating will have a lower StartCaretPosition, so in this scenario, _activeTextStart
// needs to update to be the StartCaretPosition.
// A known issue related to this behavior is that the last character that's deleted from a composition
// will get sent to the terminal before we receive the TextUpdate to delete the character.
// See GH #5054.
_activeTextStart = ::base::ClampMin(_activeTextStart, ::base::ClampedNumeric<size_t>(range.StartCaretPosition));
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
_inputBuffer = _inputBuffer.replace(
range.StartCaretPosition,
Make Korean IME input more consistent (#4796) ## Summary of the Pull Request Korean IME was not working correctly due to way we were clearing the input buffer inside of `TSFInputControl`. We wanted to clear our input buffer and tell TSF to clear its input buffer as well when we receive a `CompositionCompleted` event. This works fine in some IME languages such as Chinese and Japanese. However, Korean IME composes characters differently in such a way where we can't tell TSF to clear their buffer during a `CompositionCompleted` event because it would clear the character that triggered the `CompositionCompleted` event in the first place. The solution in this PR is to keep our `_inputBuffer` intact until the user presses <kbd>Enter</kbd> or <kbd>Esc</kbd>, in which case we clear our buffer and the TSF buffer. I've chosen these two keys because it seems to make sense to clear the buffer after text is sent to the terminal with <kbd>Enter</kbd>, and <kbd>Esc</kbd> usually means to cancel a current composition anyway. This means we need to keep track of our last known "Composition Start Point", which is represented by `_activeTextStart`. Whenever we complete a composition, we'll send the portion of the input buffer between `_activeTextStart` and the end of the input buffer to the terminal. Then, we'll update `_activeTextStart` to be the end of the input buffer so that the next time we send text to the terminal, we'll only send the portion of our buffer that's "active". ## PR Checklist * [x] Closes #4226 * [x] CLA signed * [x] Tests added/passed ## Validation Steps Performed Manual testing with Chinese, Japanese, and Korean IME.
2020-03-04 20:01:01 +00:00
::base::ClampSub<size_t>(range.EndCaretPosition, range.StartCaretPosition),
incomingText);
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Emojis/Kaomojis/Symbols chosen through the IME without starting composition
// will be sent straight through to the terminal.
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
if (!_inComposition)
{
_SendAndClearText();
}
Make Korean IME input more consistent (#4796) ## Summary of the Pull Request Korean IME was not working correctly due to way we were clearing the input buffer inside of `TSFInputControl`. We wanted to clear our input buffer and tell TSF to clear its input buffer as well when we receive a `CompositionCompleted` event. This works fine in some IME languages such as Chinese and Japanese. However, Korean IME composes characters differently in such a way where we can't tell TSF to clear their buffer during a `CompositionCompleted` event because it would clear the character that triggered the `CompositionCompleted` event in the first place. The solution in this PR is to keep our `_inputBuffer` intact until the user presses <kbd>Enter</kbd> or <kbd>Esc</kbd>, in which case we clear our buffer and the TSF buffer. I've chosen these two keys because it seems to make sense to clear the buffer after text is sent to the terminal with <kbd>Enter</kbd>, and <kbd>Esc</kbd> usually means to cancel a current composition anyway. This means we need to keep track of our last known "Composition Start Point", which is represented by `_activeTextStart`. Whenever we complete a composition, we'll send the portion of the input buffer between `_activeTextStart` and the end of the input buffer to the terminal. Then, we'll update `_activeTextStart` to be the end of the input buffer so that the next time we send text to the terminal, we'll only send the portion of our buffer that's "active". ## PR Checklist * [x] Closes #4226 * [x] CLA signed * [x] Tests added/passed ## Validation Steps Performed Manual testing with Chinese, Japanese, and Korean IME.
2020-03-04 20:01:01 +00:00
else
{
Canvas().Visibility(Visibility::Visible);
const auto text = _inputBuffer.substr(_activeTextStart);
Make Korean IME input more consistent (#4796) ## Summary of the Pull Request Korean IME was not working correctly due to way we were clearing the input buffer inside of `TSFInputControl`. We wanted to clear our input buffer and tell TSF to clear its input buffer as well when we receive a `CompositionCompleted` event. This works fine in some IME languages such as Chinese and Japanese. However, Korean IME composes characters differently in such a way where we can't tell TSF to clear their buffer during a `CompositionCompleted` event because it would clear the character that triggered the `CompositionCompleted` event in the first place. The solution in this PR is to keep our `_inputBuffer` intact until the user presses <kbd>Enter</kbd> or <kbd>Esc</kbd>, in which case we clear our buffer and the TSF buffer. I've chosen these two keys because it seems to make sense to clear the buffer after text is sent to the terminal with <kbd>Enter</kbd>, and <kbd>Esc</kbd> usually means to cancel a current composition anyway. This means we need to keep track of our last known "Composition Start Point", which is represented by `_activeTextStart`. Whenever we complete a composition, we'll send the portion of the input buffer between `_activeTextStart` and the end of the input buffer to the terminal. Then, we'll update `_activeTextStart` to be the end of the input buffer so that the next time we send text to the terminal, we'll only send the portion of our buffer that's "active". ## PR Checklist * [x] Closes #4226 * [x] CLA signed * [x] Tests added/passed ## Validation Steps Performed Manual testing with Chinese, Japanese, and Korean IME.
2020-03-04 20:01:01 +00:00
TextBlock().Text(text);
}
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Notify the TSF that the update succeeded
args.Result(CoreTextTextUpdatingResult::Succeeded);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
// indicate updating failed.
args.Result(CoreTextTextUpdatingResult::Failed);
}
}
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
// Method Description:
Make Korean IME input more consistent (#4796) ## Summary of the Pull Request Korean IME was not working correctly due to way we were clearing the input buffer inside of `TSFInputControl`. We wanted to clear our input buffer and tell TSF to clear its input buffer as well when we receive a `CompositionCompleted` event. This works fine in some IME languages such as Chinese and Japanese. However, Korean IME composes characters differently in such a way where we can't tell TSF to clear their buffer during a `CompositionCompleted` event because it would clear the character that triggered the `CompositionCompleted` event in the first place. The solution in this PR is to keep our `_inputBuffer` intact until the user presses <kbd>Enter</kbd> or <kbd>Esc</kbd>, in which case we clear our buffer and the TSF buffer. I've chosen these two keys because it seems to make sense to clear the buffer after text is sent to the terminal with <kbd>Enter</kbd>, and <kbd>Esc</kbd> usually means to cancel a current composition anyway. This means we need to keep track of our last known "Composition Start Point", which is represented by `_activeTextStart`. Whenever we complete a composition, we'll send the portion of the input buffer between `_activeTextStart` and the end of the input buffer to the terminal. Then, we'll update `_activeTextStart` to be the end of the input buffer so that the next time we send text to the terminal, we'll only send the portion of our buffer that's "active". ## PR Checklist * [x] Closes #4226 * [x] CLA signed * [x] Tests added/passed ## Validation Steps Performed Manual testing with Chinese, Japanese, and Korean IME.
2020-03-04 20:01:01 +00:00
// - Send the portion of the textBuffer starting at _activeTextStart to the end of the buffer.
// Then clear the TextBlock and hide it until the next time text is received.
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
// Arguments:
// - <none>
// Return Value:
// - <none>
void TSFInputControl::_SendAndClearText()
{
const auto text = _inputBuffer.substr(_activeTextStart);
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
_CompositionCompletedHandlers(text);
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
Make Korean IME input more consistent (#4796) ## Summary of the Pull Request Korean IME was not working correctly due to way we were clearing the input buffer inside of `TSFInputControl`. We wanted to clear our input buffer and tell TSF to clear its input buffer as well when we receive a `CompositionCompleted` event. This works fine in some IME languages such as Chinese and Japanese. However, Korean IME composes characters differently in such a way where we can't tell TSF to clear their buffer during a `CompositionCompleted` event because it would clear the character that triggered the `CompositionCompleted` event in the first place. The solution in this PR is to keep our `_inputBuffer` intact until the user presses <kbd>Enter</kbd> or <kbd>Esc</kbd>, in which case we clear our buffer and the TSF buffer. I've chosen these two keys because it seems to make sense to clear the buffer after text is sent to the terminal with <kbd>Enter</kbd>, and <kbd>Esc</kbd> usually means to cancel a current composition anyway. This means we need to keep track of our last known "Composition Start Point", which is represented by `_activeTextStart`. Whenever we complete a composition, we'll send the portion of the input buffer between `_activeTextStart` and the end of the input buffer to the terminal. Then, we'll update `_activeTextStart` to be the end of the input buffer so that the next time we send text to the terminal, we'll only send the portion of our buffer that's "active". ## PR Checklist * [x] Closes #4226 * [x] CLA signed * [x] Tests added/passed ## Validation Steps Performed Manual testing with Chinese, Japanese, and Korean IME.
2020-03-04 20:01:01 +00:00
_activeTextStart = _inputBuffer.length();
TextBlock().Text(L"");
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
Adjust TSFInputControl alignment (#5609) This PR fixes a couple of issues with TSFInputControl alignment: 1. The emoji picker IME in particular would show up overlapping the current buffer row because I stupidly didn't realize that `TextBlock.ActualHeight` is 0 right after initialization and before it has any text. So, the emoji picker will show up on the bottom of the 0 height TextBlock, which overlaps the current buffer row. This isn't a problem with CJK because inputting text _causes_ the IME to show up, so by the time the IME shows up, the TextBlock has text and accordingly has a height. 2. It turns out the emoji picker IME doesn't follow the `TextBlock` bottom, unlike Chinese and Japanese IME, so if a user were to compose near the edge of the screen and let the `TextBlock` start line wrapping, the emoji IME doesn't follow the bottom of the `TextBlock` as it grows. This means that the `TextBlock` position doesn't update in the middle of composition, and the `LayoutRequested` event that it fires at the beginning of composition is the only chance we get to tell the emoji IME where to place itself. It turns out when we reset `TextBlock.Text`, the ActualHeight doesn't get immediately reset back to the min size. So if a user were to bring up the emoji IME before `ActualHeight` is reset, the IME will show up way below the current buffer row. 3. We don't currently `TryRedrawCanvas` when the window position changes (resizing, dragging the window around), so sometimes dragging or resizing the Terminal doesn't update the position of the IME. Ideally it should be listening to some "window position changed" event, but alas we don't have that and it would be much harder than this incoming fix. We'll just track the window bounds as part of `TryRedrawCanvas` and redraw if it changes. For the most part, this will allow the IME to update to where the new window position is, but it'll only be called if we receive a `LayoutRequested` event. ## PR Checklist * [x] Closes #5470 * [x] CLA signed. * [x] Tests added/passed ## Validation Steps Performed I play with it for quite a bit.
2020-04-28 11:50:33 -07:00
// After we reset the TextBlock to empty string, we want to make sure
// ActualHeight reflects the respective height. It seems that ActualHeight
// isn't updated until there's new text in the TextBlock, so the next time a user
// invokes "Win+." for the emoji picker IME, it would end up
// using the pre-reset TextBlock().ActualHeight().
TextBlock().UpdateLayout();
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
// hide the controls until text input starts again
Canvas().Visibility(Visibility::Collapsed);
Display Emojis, Kaomojis, and symbols while in IME mode (#4688) ## Summary of the Pull Request Currently, while in IME mode, selections with the Emoji/Kaomoji/Symbol Picker (which is brought up with <kbd>win+.</kbd>) are not displayed until the user starts a new composition. This is due to the fact that we hide the TextBlock when we receive a CompositionCompleted event, and we only show the TextBlock when we receive a CompositionStarted event. Input from the picker does not count as a composition, so we were never showing the text box, even if the symbols were thrown into the inputBuffer. In addition, we weren't receiving CompositionStarted events when we expected to. We should be showing the TextBlock when we receive _any_ text, so we should make the TextBlock visible inside of `TextUpdatingHandler`. Furthermore, some really helpful discussion in #3745 around wrapping the `NotifyTextChanged` call with a `NotifyFocusLeave` and a `NotifyFocusEnter` allowed the control to much more consistently determine when a CompositionStarted and a CompositionEnded. I've also went around and replaced casts with saturating casts, and have removed the line that sets the `textBlock.Width()` so that it would automatically set its width. This resolves the issue where while composing a sentence, the textBlock would be too small to contain all the text, so it would be cut off, but the composition is still valid and still able to continue. ## PR Checklist * [x] Closes #4148 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed ## Validation Steps Performed Tested picking emojis, kaomojis, and symbols with numerous different languages.
2020-02-26 10:36:02 -08:00
}
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
// Method Description:
// - Handler for FormatUpdating event by CoreEditContext responsible
// for handling different format updates for a particular range of text.
// TSFInputControl doesn't do anything with this event.
// Arguments:
// - sender: CoreTextEditContext sending the request. Not used in method.
// - args: CoreTextFormatUpdatingEventArgs Provides data for the FormatUpdating event. Not used in method.
// Return Value:
// - <none>
void TSFInputControl::_formatUpdatingHandler(CoreTextEditContext sender, const CoreTextFormatUpdatingEventArgs& /*args*/)
Add a Windows.UI.Text.Core IME overlay to TerminalControl (#1919) 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[1]. TSFInputControl is similar (overlay with IME text) to how old console (conimeinfo) handled IME. # Details TSFInputControl is a Windows.UI.Xaml.Controls.UserControl TSFInputControl contains a Canvas control for absolution positioning a TextBlock control within its 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[2]. ## 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. ### Calculating Screen Coordinates 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 lets 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 - 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 (#3640) - 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 (#3657) ## Future Considerations Ideally, we'd be able to interact with the console buffer directly and replace characters as the user types. ## Validation 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 [1]: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomEditControl [2]: https://docs.microsoft.com/en-us/windows/uwp/design/input/custom-text-input Closes #459 Closes #2213 Closes #3641
2019-11-21 16:25:50 -08:00
{
}
}