如何使 WPF 输入控件在触摸屏上获得焦点时显示虚拟键盘

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19085931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:57:46  来源:igfitidea点击:

How to make WPF input control show virtual Keyboard when it got focus in touch screen

wpfwpf-controlstouch

提问by

For our WPF application, when it runs on touch screen(Surface Pro .etc), the TextBox/PasswordBoxcontrol cannot show virtual keyboardwhen they get focused.

对于我们的 WPF 应用程序,当它在触摸屏(Surface Pro .etc)运行时,TextBox/PasswordBox控件在获得焦点时无法显示虚拟键盘

Any good way to implement this feature in WPF?

在 WPF 中实现此功能的任何好方法?



Updated:

更新:

what we want to achieve finally is something like that:

我们最终想要实现的是这样的:

If user run app on PC, we don't care about this feature, which means whether user has physical keyboard, we do nothing just like normal WPF application running on PC.

如果用户在 PC 上运行应用程序,我们不关心此功能,即用户是否有物理键盘,我们什么都不做,就像在 PC 上运行的普通 WPF 应用程序一样。

If user run on Surface Pro, when he clicks the TextBox, the built-in virtual keyboard can show up, and which should be user-friendly, such as the keyboard would never cover up the input element.

如果用户在 Surface Pro 上运行,当他点击 时TextBox,内置的虚拟键盘会出现,并且应该是用户友好的,例如键盘永远不会覆盖输入元素。



Updated 2:

更新 2:

So, WPF cannot easily set some property to implement this feature? In my opinion, this feature should be built-in WPF, I don't understand why I cannot find an easy way to achieve.

那么,WPF 不能轻易设置一些属性来实现这个功能吗?在我看来,这个功能应该是WPF内置的,我不明白为什么找不到简单的方法来实现。

采纳答案by Savaratkar

Try this,

尝试这个,

First check for a physical keyboard presence:

首先检查物理键盘是否存在:

KeyboardCapabilities keyboardCapabilities = new Windows.Devices.Input.KeyboardCapabilities();
return  keyboardCapabilities.KeyboardPresent != 0 ? true : false;

If you do not find a physical keyboard, use the in-built virtual keyboard of windows:

如果找不到物理键盘,请使用 Windows 内置的虚拟键盘:

Process.Start(Environment.GetFolderPath(Environment.SpecialFolder.System) + Path.DirectorySeparatorChar + "osk.exe");

Got help from here: link 1link 2

从这里得到帮助: 链接 1链接 2

回答by Dmitry Lyalin

I've published a sample on how to trigger the touch keyboard in WPF applications when a user clicks into a Textbox, its here:

我已经发布了一个关于如何在用户单击文本框时触发 WPF 应用程序中的触摸键盘的示例,它在这里:

http://code.msdn.microsoft.com/Enabling-Windows-8-Touch-7fb4e6de

http://code.msdn.microsoft.com/Enabling-Windows-8-Touch-7fb4e6de

It has been something I've been working on for many months, i'm glad to finally contribute this example to our community. Please let me know if there are any questions, suggestions, problems, etc in the sample Q&A pane

这是我几个月以来一直在努力的事情,我很高兴最终将这个例子贡献给我们的社区。如果示例问答窗格中有任何问题、建议、问题等,请告诉我

回答by gakera

This solution is very simple: http://code.msdn.microsoft.com/windowsapps/Enabling-Windows-8-Touch-7fb4e6de

这个解决方案很简单:http: //code.msdn.microsoft.com/windowsapps/Enabling-Windows-8-Touch-7fb4e6de

The steps are detailed in the link above, here is the short version:

步骤在上面的链接中有详细说明,这里是简短版本:

  • Add a UIAutomationClient reference
  • Use IFrameworkInputPane from managed code (DLL at link or convert inputpanelconfiguration.idl to DLL, see steps below)
  • Create new class InkInputHelper to disable inking support (code below)
  • Call InkInputHelper.DisableWPFTabletSupport();from MainWindowconstructor or similar
  • Add using System.Windows.Interop;
  • Add to MainWindow_Loaded or similar:

        System.Windows.Automation.AutomationElement asForm =
        System.Windows.Automation.AutomationElement.FromHandle(new WindowInteropHelper(this).Handle);
        InputPanelConfigurationLib.InputPanelConfiguration inputPanelConfig = new InputPanelConfigurationLib.InputPanelConfiguration();
        inputPanelConfig.EnableFocusTracking();
    
  • 添加 UIAutomationClient 引用
  • 使用托管代码中的 IFrameworkInputPane(链接中的 DLL 或将 inputpanelconfiguration.idl 转换为 DLL,请参阅以下步骤)
  • 创建新类 InkInputHelper 以禁用墨迹支持(下面的代码)
  • InkInputHelper.DisableWPFTabletSupport();MainWindow构造函数或类似调用
  • 添加 using System.Windows.Interop;
  • 添加到 MainWindow_Loaded 或类似:

        System.Windows.Automation.AutomationElement asForm =
        System.Windows.Automation.AutomationElement.FromHandle(new WindowInteropHelper(this).Handle);
        InputPanelConfigurationLib.InputPanelConfiguration inputPanelConfig = new InputPanelConfigurationLib.InputPanelConfiguration();
        inputPanelConfig.EnableFocusTracking();
    


To convert inputpanelconfiguration.idl to DLL

将 inputpanelconfiguration.idl 转换为 DLL

On Windows 8.1: c:\Program Files (x86)\Windows Kits\8.1\Include\um\inputpanelconfiguration.idl

在 Windows 8.1 上:c:\Program Files (x86)\Windows Kits\8.1\Include\um\inputpanelconfiguration.idl

To build a DLL from the IDL use the following steps:

要从 IDL 构建 DLL,请使用以下步骤:

  • Start a command prompt
  • Use the MIDL compiler tool to build a Type Library TLB file
    • Example: midl /tbld {filename}
  • Use the TLBIMP tool to convert the above generated Type Library (TLB file) into a DLL that .NET can use by running the following command
    • Example: TLBIMP.exe InputpanelConfiguration.tlb /publickey:{pathToKey} /delaysign
  • 启动命令提示符
  • 使用 MIDL 编译器工具构建类型库 TLB 文件
    • 例子: midl /tbld {filename}
  • 使用TLBIMP工具将上面生成的Type Library(TLB文件)转换成.NET可以使用的DLL,运行以下命令
    • 例子: TLBIMP.exe InputpanelConfiguration.tlb /publickey:{pathToKey} /delaysign


InkInputHelper class:

InkInputHelper 类:

using System;
using System.Reflection;
using System.Windows.Input;

namespace ModernWPF.Win8TouchKeyboard.Desktop
{
public static class InkInputHelper
{
    public static void DisableWPFTabletSupport()
    {
        // Get a collection of the tablet devices for this window.  
        TabletDeviceCollection devices = System.Windows.Input.Tablet.TabletDevices;

        if (devices.Count > 0)
        {
            // Get the Type of InputManager.
            Type inputManagerType = typeof(System.Windows.Input.InputManager);

            // Call the StylusLogic method on the InputManager.Current instance.
            object stylusLogic = inputManagerType.InvokeMember("StylusLogic",
                        BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                        null, InputManager.Current, null);

            if (stylusLogic != null)
            {
                //  Get the type of the stylusLogic returned from the call to StylusLogic.
                Type stylusLogicType = stylusLogic.GetType();

                // Loop until there are no more devices to remove.
                while (devices.Count > 0)
                {
                    // Remove the first tablet device in the devices collection.
                    stylusLogicType.InvokeMember("OnTabletRemoved",
                            BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
                            null, stylusLogic, new object[] { (uint)0 });
                }
            }
        }
    }
}
}

This should work. Again, much better info and a downloadable sample in the link. I only copy pasted the basics for archiving purposes.

这应该有效。同样,链接中有更好的信息和可下载的示例。我只复制粘贴了基本的存档目的。

回答by Макс Федотов

I created a library to automate everything concerning TabTip integration in WPF app.

我创建了一个库来自动化 WPF 应用程序中有关 TabTip 集成的所有内容。

You can get it on nuget, and after that all you need is a simple config in your apps startup logic:

您可以在nuget上获取它,之后您只需要在应用程序启动逻辑中进行一个简单的配置:

TabTipAutomation.BindTo<TextBox>();

You can bind TabTip automation logic to any UIElement. Virtual Keyboard will open when any element of specified type will get focus, and it will close when element will lose focus. Not only that, but TabTipAutomation will move UIElement (or Window) into view, so that TabTip will not block focused element.

您可以将 TabTip 自动化逻辑绑定到任何 UIElement。当指定类型的任何元素获得焦点时,虚拟键盘将打开,当元素失去焦点时将关闭。不仅如此,TabTipAutomation 还会将 UIElement(或 Window)移动到视图中,以便 TabTip 不会阻塞焦点元素。

For more info refer to the project site.

有关更多信息,请参阅项目站点

回答by itsho

回答by user895440

I saw this done in a TechEd session, you need to first disable Inking support (DisableWPFTabletSupport) then you can create an InputPanelConfiguration (AutomationElement.FromHandle(new WindowsInteropHelper(this).Handle) and call EnableFocusTracking.

我在 TechEd 会话中看到了这一点,您需要首先禁用墨迹支持 (DisableWPFTabletSupport),然后您可以创建 InputPanelConfiguration (AutomationElement.FromHandle(new WindowsInteropHelper(this).Handle) 并调用 EnableFocusTracking。

DisableWPFTabletSupport: http://msdn.microsoft.com/en-us/library/ee230087.aspx

禁用 WPFTabletSupport:http: //msdn.microsoft.com/en-us/library/ee230087.aspx

EnableFocusTracking: http://msdn.microsoft.com/en-us/library/windows/desktop/jj126268(v=vs.85).aspx

EnableFocusTracking:http: //msdn.microsoft.com/en-us/library/windows/desktop/jj126268(v=vs.85) .aspx

回答by ThrowingDwarf

 public static class InkInputHelper
    {
        public static void DisableWPFTabletSupport()
        {
            // Get a collection of the tablet devices for this window.  
            TabletDeviceCollection devices = System.Windows.Input.Tablet.TabletDevices;

            if (devices.Count > 0)
            {
                // Get the Type of InputManager.
                Type inputManagerType = typeof(System.Windows.Input.InputManager);

                // Call the StylusLogic method on the InputManager.Current instance.
                object stylusLogic = inputManagerType.InvokeMember("StylusLogic",
                            BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                            null, InputManager.Current, null);

                if (stylusLogic != null)
                {
                    //  Get the type of the stylusLogic returned from the call to StylusLogic.
                    Type stylusLogicType = stylusLogic.GetType();

                    // Loop until there are no more devices to remove.
                    while (devices.Count > 0)
                    {
                        // Remove the first tablet device in the devices collection.
                        stylusLogicType.InvokeMember("OnTabletRemoved",
                                BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
                                null, stylusLogic, new object[] { (uint)0 });
                    }
                }
            }
        }
    }

use that class to determine if there is a physical keyboard, or a similar way that might better suit your needs.

使用该类来确定是否有物理键盘,或可能更适合您需求的类似方式。

i used this class to open and close the keyboard wherever i wanted.

我使用这个类在任何我想要的地方打开和关闭键盘。

 class KeyboardManager
    {

        public static void LaunchOnScreenKeyboard()
        {
            var processes = Process.GetProcessesByName("osk").ToArray();
            if (processes.Any())
                return;
            string keyboardManagerPath = "KeyboardExecuter.exe";
           Process.Start(keyboardManagerPath);
        }

        public static void KillOnScreenKeyboard()
        {
            var processes = Process.GetProcessesByName("osk").ToArray();
            foreach (var proc in processes)
            {
                proc.Kill();
            }
        }
        public static void killTabTip()
        {
            var processes = Process.GetProcessesByName("TabTip").ToArray();
            foreach (var proc in processes)
            {
                proc.Kill();
            }
        }

        public static void LaunchTabTip()
        {
            Process.Start("TabTip.exe");
        }
    }

keep in mind the following: i added a copy of both osk.exe AND tabtip.exe. adding this in my program solved an issue where either tabtip or osk wouldnt work on 32/64 bits.

请记住以下几点:我添加了 osk.exe 和 tabtip.exe 的副本。在我的程序中添加它解决了 tabtip 或 osk 无法在 32/64 位上工作的问题。

osk is the keyboard, tabtip is the docked version of it. keyboardexecuter is a program i made which is used as a fallback method.

osk 是键盘,tabtip 是它的停靠版本。键盘执行器是我制作的一个程序,用作后备方法。

note* i can currently not test this on a touch screen device. you have to try that on your own.

注意* 我目前无法在触摸屏设备上进行测试。你必须自己尝试。

for this to all work correctly i used this code in my mainwindow:

为此,我在主窗口中使用了此代码:

public int selectedTableNum;
        public MainWindow()
        {
            InitializeComponent();

            Loaded += MainWindow_Loaded;

            // Disables inking in the WPF application and enables us to track touch events to properly trigger the touch keyboard
            InkInputHelper.DisableWPFTabletSupport();
            //remove navigationbar
            Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
            {
                var navWindow = Window.GetWindow(this) as NavigationWindow;
                if (navWindow != null) navWindow.ShowsNavigationUI = false;
            }));


            KeyboardManager.LaunchTabTip();

        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            //Windows 8 API to enable touch keyboard to monitor for focus tracking in this WPF application
            InputPanelConfiguration cp = new InputPanelConfiguration();
            IInputPanelConfiguration icp = cp as IInputPanelConfiguration;
            if (icp != null)
                icp.EnableFocusTracking();
            mainFrame.Content = new LoginPage();
        }
        //public bool HasTouchInput()
        //{
        //    foreach (TabletDevice tabletDevice in Tablet.TabletDevices)
        //    {
        //        //Only detect if it is a touch Screen not how many touches (i.e. Single touch or Multi-touch)
        //        if (tabletDevice.Type == TabletDeviceType.Touch)
        //            return true;
        //    }

        //    return false;
        //}

i included the comments because it might be usefull to someone if there is an error.

我包含了评论,因为如果有错误,它可能对某人有用。

the inputpanel configuration:

输入面板配置:

[Guid("41C81592-514C-48BD-A22E-E6AF638521A6")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInputPanelConfiguration
{
    /// <summary>
    /// Enables a client process to opt-in to the focus tracking mechanism for Windows Store apps that controls the invoking and dismissing semantics of the touch keyboard.
    /// </summary>
    /// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
    int EnableFocusTracking();
}

[ComImport, Guid("2853ADD3-F096-4C63-A78F-7FA3EA837FB7")]
class InputPanelConfiguration
{
}

i hope this might help future visitors of this question.

我希望这可以帮助这个问题的未来访问者。

回答by Jiri Kral

The easiest option when not requiring SecureString output is to use TextBox and use something like Wingdings as font.

不需要 SecureString 输出时最简单的选择是使用 TextBox 并使用 Wingdings 之类的字体作为字体。