您可以使用相同的IInputPane2 界面来触发触摸键盘。 CefSharp.Wpf.HwndHost 需要使用 IRenderProcessMessageHandler 来接收焦点更改,因为 VirtualKeyboardRequested 事件特定于 CefSharp.Wpf。
由于IRenderProcessMessageHandler.OnFocusedNodeChanged 事件以相当高的频率触发,并且在不需要 OSK 的情况下,需要对事件进行过滤和去抖动。使用 Rx.Net 做到这一点很简单。 A full example can be found on Github.
Project:
- 将 TFM 设置为
net6.0-windows10.0.19041
- 添加
<PackageReference Include="CefSharp.Wpf.HwndHost" Version="98.1.210" />
- 添加
<PackageReference Include="System.Reactive" Version="5.0.0" />
Program.cs:
Cef.EnableHighDPISupport();
var settings = new CefSettings();
CefSharpSettings.FocusedNodeChangedEnabled = true;
settings.CefCommandLineArgs.Add("disable-usb-keyboard-detect", "1");
Cef.Initialize(settings);
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
private Lazy<(IInputPaneInterop ipi, IInputPane2 ip)> sip;
public MainWindow()
{
InitializeComponent();
sip = new Lazy<(IInputPaneInterop ipi, IInputPane2 ip)>(() =>
{
var hwnd = new WindowInteropHelper(this).Handle;
var ipi = InputPane.As<IInputPaneInterop>();
var ip = ipi.GetForWindow(hwnd, typeof(IInputPane2).GUID);
return (ipi, ip);
});
var oskSubject = new Subject<bool>();
cwb.RenderProcessMessageHandler = new OskRenderProcessMessageHandler(oskSubject.OnNext);
oskSubject
.Throttle(TimeSpan.FromMilliseconds(200))
.ObserveOn(SynchronizationContext.Current ?? throw new InvalidOperationException("No syncctx"))
.Subscribe(PopOsk);
}
protected override void OnClosed(EventArgs e)
{
if (sip.IsValueCreated)
{
var (ipi, ip) = sip.Value;
Marshal.FinalReleaseComObject(ip);
Marshal.FinalReleaseComObject(ipi);
}
base.OnClosed(e);
}
private void PopOsk(bool shouldShow)
{
var (_, ip) = sip.Value;
if (shouldShow)
{
Debug.WriteLine($"Showing SIP");
ip.TryShow();
}
else
{
Debug.WriteLine($"Hiding SIP");
ip.TryHide();
}
}
}
internal class OskRenderProcessMessageHandler : IRenderProcessMessageHandler
{
private readonly Action<bool> SetOsk;
public OskRenderProcessMessageHandler(Action<bool> popOsk)
{
this.SetOsk = popOsk;
}
public void OnContextCreated(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame)
{
// nop
}
public void OnContextReleased(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame)
{
// nop
}
public void OnFocusedNodeChanged(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IDomNode? node)
{
SetOsk(node != null && "input".Equals(node.TagName, StringComparison.InvariantCultureIgnoreCase));
}
public void OnUncaughtException(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, JavascriptException exception)
{
// nop
}
}
[ComImport, Guid("75CF2C57-9195-4931-8332-F0B409E916AF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IInputPaneInterop
{
void _VtblGap1_3();
IInputPane2 GetForWindow([In] IntPtr appWindow, [In] ref Guid riid);
}
[ComImport, Guid("8A6B3F26-7090-4793-944C-C3F2CDE26276"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IInputPane2
{
void _VtblGap1_3();
bool TryShow();
bool TryHide();
}
为了说明的目的省略了错误检查。
一般注意事项:
- 仅在 Windows 10 Enterprise 20H2 (10.0.19042) 及更高版本中进行了测试。未在 W11 上测试
- 不应存在硬件键盘(或 GPIO 应指示键盘已禁用 - 例如:Lenovo Yoga 处于平板电脑模式)
- 系统必须配置为在桌面模式下使用触摸键盘(要求不明确)
- 应用启动时的行为因触摸输入设备和系统状态而异
- 行为因
BorderStyle 而异
- 触发手势必须源自触摸 - 不能使用鼠标进行测试