Skip to content

Commit

Permalink
Allow IME input in WPF through a managed keyboard handler.
Browse files Browse the repository at this point in the history
  • Loading branch information
Antonyo committed Dec 7, 2018
1 parent 0df677a commit f39c4bd
Show file tree
Hide file tree
Showing 9 changed files with 718 additions and 11 deletions.
4 changes: 2 additions & 2 deletions CefSharp.Core/Internals/CefBrowserHostWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,15 +333,15 @@ void CefBrowserHostWrapper::ImeSetComposition(String^ text, cli::array<Compositi
}

//Replacement Range is Mac OSX only
_browserHost->ImeSetComposition(StringUtils::ToNative(text), underlinesVector, CefRange(), range);
_browserHost->ImeSetComposition(StringUtils::ToNative(text), underlinesVector, CefRange(UINT32_MAX, UINT32_MAX), range);

This comment has been minimized.

Copy link
@amaitland

amaitland Dec 7, 2018

@Antonyo The documentation says replacement range is only used on Mac, what difference does passing in max to a value that should be ignored make?

This comment has been minimized.

Copy link
@Antonyo

Antonyo Dec 9, 2018

Author Owner

To be honest I don't know what CEF is doing with the replacement range but if you pass CefRange() the composition always starts at the beggining of the textbox instead of the current cursor position. I copied the CefRange(UINT32_MAX, UINT32_MAX) value from cefsharp#2103

This comment has been minimized.

Copy link
@angshuman-agarwal

angshuman-agarwal Dec 27, 2018

@amaitland , @Antonyo is correct. I have created a sample project directly using his code here - https://github.com/angshuman-agarwal/CEFSHAPRP_WPF/tree/master without modifying anything in main CEFSHARP. If you try to run this directly, you will see cursor is in the beginning.

This comment has been minimized.

Copy link
@musli

musli Apr 12, 2021

Whether this submission supports versions below cefsharp63?
cefsharp63 is currently the highest version of the original windows 7 that does not require any environment to be installed (excluding vc 2013) and can run, so this is important

}

void CefBrowserHostWrapper::ImeCommitText(String^ text)
{
ThrowIfDisposed();

//Range and cursor position are Mac OSX only
_browserHost->ImeCommitText(StringUtils::ToNative(text), CefRange(), NULL);
_browserHost->ImeCommitText(StringUtils::ToNative(text), CefRange(UINT32_MAX, UINT32_MAX), NULL);
}

void CefBrowserHostWrapper::ImeFinishComposingText(bool keepSelection)
Expand Down
4 changes: 4 additions & 0 deletions CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,19 @@
<SubType>Designer</SubType>
</Page>
<Compile Include="Controls\CefSharpCommands.cs" />
<Compile Include="Controls\ChromiumWebBrowserIMESupport.cs" />
<Compile Include="Controls\ChromiumWebBrowserWithScreenshotSupport.cs" />
<Compile Include="Controls\NonReloadingTabControl.cs" />
<Compile Include="Handlers\AccessibilityHandler.cs" />
<Compile Include="Handlers\DisplayHandler.cs" />
<Compile Include="Handlers\DragHandler.cs" />
<Compile Include="Handlers\IMEWpfKeyboardHandler.cs" />
<Compile Include="Handlers\MenuHandler.cs" />
<Compile Include="Handlers\LifespanHandler.cs" />
<Compile Include="Handlers\RequestContextHandler.cs" />
<Compile Include="Handlers\WpfBrowserProcessHandler.cs" />
<Compile Include="IME\IMEHandler.cs" />
<Compile Include="IME\NativeIME.cs" />
<Compile Include="Program.cs" />
<Compile Include="SimpleMainWindow.xaml.cs">
<DependentUpon>SimpleMainWindow.xaml</DependentUpon>
Expand Down
83 changes: 83 additions & 0 deletions CefSharp.Wpf.Example/Controls/ChromiumWebBrowserIMESupport.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using CefSharp.Structs;
using CefSharp.Wpf.Example.Handlers;

namespace CefSharp.Wpf.Example.Controls
{
public class ChromiumWebBrowserIMESupport : ChromiumWebBrowser
{
public ChromiumWebBrowserIMESupport()
{
WpfKeyboardHandler = new IMEWpfKeyboardHandler(this);
}

static ChromiumWebBrowserIMESupport()
{
InputMethod.IsInputMethodEnabledProperty.OverrideMetadata(
typeof(ChromiumWebBrowserIMESupport),
new FrameworkPropertyMetadata(
true,
FrameworkPropertyMetadataOptions.Inherits,
(obj, e) =>
{
var browser = obj as ChromiumWebBrowserIMESupport;
if ((bool)e.NewValue && browser.GetBrowserHost() != null && Keyboard.FocusedElement == browser)
{
browser.GetBrowserHost().SendFocusEvent(true);
InputMethod.SetIsInputMethodSuspended(browser, true);
}
}));

InputMethod.IsInputMethodSuspendedProperty.OverrideMetadata(
typeof(ChromiumWebBrowserIMESupport),
new FrameworkPropertyMetadata(
true,
FrameworkPropertyMetadataOptions.Inherits));
}

protected override void OnImeCompositionRangeChanged(Range selectedRange, Structs.Rect[] characterBounds)
{
var imeKeyboardHandler = WpfKeyboardHandler as IMEWpfKeyboardHandler;
if (imeKeyboardHandler.IsActive)
{
var screenInfo = GetScreenInfo();
var scaleFactor = screenInfo.HasValue ? screenInfo.Value.DeviceScaleFactor : 1.0f;

UiThreadRunSync(() =>
{
var parentWindow = GetParentWindow();
if (parentWindow != null)
{
var point = TransformToAncestor(parentWindow).Transform(new System.Windows.Point(0, 0));
var rects = new List<Structs.Rect>();

foreach (var item in characterBounds)
rects.Add(new Structs.Rect(
(int)((point.X + item.X) * scaleFactor),
(int)((point.Y + item.Y) * scaleFactor),
(int)(item.Width * scaleFactor),
(int)(item.Height * scaleFactor)));

imeKeyboardHandler.ChangeCompositionRange(selectedRange, rects);
}
});
}

Visual GetParentWindow()
{
var current = VisualTreeHelper.GetParent(this);
while (current != null && !(current is Window))
current = VisualTreeHelper.GetParent(current);

return current as Window;
}
}
}
}
Loading

0 comments on commit f39c4bd

Please sign in to comment.