代码之家  ›  专栏  ›  技术社区  ›  user8128167

如何才能让windows 10平板电脑中的“触摸屏键盘”停止在wpf应用程序中打开两次?

  •  0
  • user8128167  · 技术社区  · 8 年前

    请注意,我花了很多时间在网上搜索帖子,包括so,但迄今为止都没有成功。

    问题在于,由于Windows 10而自动打开的触摸屏键盘 Touch Keyboard and Handwriting Panel Service 每当有人点击一个文本框,而在windows 8.1之前,键盘被打开只是因为c api调用从我们的结构资产管理(sam)应用程序。因此,在windows 10中,每当有人点击一次文本框时,虚拟键盘就会被打开两次,一次是由于sam c api调用,另一次是由于 触摸键盘和手写板服务 是的。

    请注意,我们已尝试禁用 触摸键盘和手写板服务 但这会导致触摸屏键盘根本不出现。

    通常,让操作系统使用 触摸键盘和手写面板服务 但问题是,我们有时需要显示触摸屏键盘,而其他时间只显示数字键盘,所以仅仅依靠windows服务是不可取的。

    以下是在Windows 8.1中成功控制键盘的类:

    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Threading;
    using System.Windows.Input;
    
    namespace Cpr.Apps.Sam.Controls
    {
        /// <summary>
        /// Shows or hides the touch keyboard on tablets.
        /// </summary>
        public class TouchKeyboard
        {
            /// <summary>
            /// The touch keyboard app's file path.
            /// </summary>
            private static string _touchKeyboardAppFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles), @"Microsoft Shared\ink\TabTip.exe");
    
            /// <summary>
            /// Set to true if the app is currently running on a touch device and false otherwise.
            /// </summary>
            private static bool _isTouchScreen = Tablet.TabletDevices.Cast<TabletDevice>().Any(tabletDevice => tabletDevice.Type == TabletDeviceType.Touch);
    
            /// <summary>
            /// The keyboard visible flag.
            /// </summary>
            /// <remarks>
            /// This flag only keeps track of the keyboard's visibility if it was set using this class.
            /// </remarks>
            private static bool _isKeyboardVisible;
    
            /// <summary>
            /// The delay after which the keyboard will be hidden, in seconds.
            /// </summary>
            /// <remarks>
            /// The keyboard is not hidden immediately when the associated input field loses the keyboard focus, so that it will
            /// not flicker if another input field with this behavior obtains the keyboard focus immediately afterwards.
            /// </remarks>
            private const double KEYBOARD_HIDE_DELAY = 0.25;
    
            /// <summary>
            /// The number of milliseconds per second. Used for time conversions.
            /// </summary>
            private const long MILLISECONDS_PER_SECOND = 1000;
    
            /// <summary>
            /// True if the current device has a touch screen and false otherwise.
            /// </summary>
            public static bool IsTouchScreen
            {
                get { return _isTouchScreen; }
            }
    
            /// <summary>
            /// Shows the touch keyboard if the app is running on a touch device.
            /// </summary>
            /// <remarks>
            /// This method does nothing if the app is not currently running on a touch device.
            /// </remarks>
            public static void Show()
            {
                // check if the app is running on a touch device
                if (_isTouchScreen && _touchKeyboardAppFilePath != null)
                {
                    try
                    {
                        // launch the touch keyboard app
                        Process.Start(_touchKeyboardAppFilePath);
    
                        // set the keyboard visible flag
                        _isKeyboardVisible = true;
                    }
                    catch (Exception)
                    {
                        // do nothing
                    }
                }
            }
    
            /// <summary>
            /// Hides the touch keyboard if the app is running on a touch device.
            /// </summary>
            /// <remarks>
            /// This method does nothing if the app is not currently running on a touch device.
            /// </remarks>
            public static void Hide()
            {
                // check if the app is running on a touch device
                if (_isTouchScreen)
                {
                    // reset the keyboard visible flag
                    _isKeyboardVisible = false;
    
                    // hide the keyboard after a delay so that if another input field with this behavior obtains the focus immediately,
                    // the keyboard will not flicker
                    Timer timer = null;
                    timer = new Timer((obj) =>
                    {
                        // check if the keyboard should still be hidden
                        if (!_isKeyboardVisible)
                        {
                            // check if the keyboard is visible
                            var touchKeyboardWindowHandle = FindWindow("IPTip_Main_Window", null);
                            if (touchKeyboardWindowHandle != _nullPointer)
                            {
                                // hide the keyboard
                                SendMessage(touchKeyboardWindowHandle, WM_SYSCOMMAND, SC_CLOSE, _nullPointer);
                            }
                        }
    
                        // release the timer
                        timer.Dispose();
                    }, null, (long)(KEYBOARD_HIDE_DELAY * MILLISECONDS_PER_SECOND), Timeout.Infinite);
                }
            }
    
            // Win32 null pointer parameter
            private static IntPtr _nullPointer = new IntPtr(0);
    
            // Win32 command from the Window menu
            private const uint WM_SYSCOMMAND = 0x0112;
    
            // Win32 command to close a window
            private static IntPtr SC_CLOSE = new IntPtr(0xF060);
    
            // Win32 API to get a window reference
            [DllImport("user32.dll", CharSet = CharSet.Unicode)]
            private static extern IntPtr FindWindow(string sClassName, string sAppName);
    
            // Win32 API to send a message to a window
            [DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
            private static extern IntPtr SendMessage(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
        }
    }
    

    以及:

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Interactivity;
    using Cpr.Apps.Sam.Controls;
    
    namespace Cpr.Apps.Sam.Styles.Behaviors
    {
        /// <summary>
        /// Behavior that shows the touch keyboard (on tablets only) when the associated control gets the keyboard focus.
        /// </summary>
        public class ControlShowTouchKeyboardOnFocusBehavior : Behavior<Control>
        {
            protected override void OnAttached()
            {
                base.OnAttached();
    
                // add the event handlers
                WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "GotKeyboardFocus", OnGotKeyboardFocus);
                WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "LostKeyboardFocus", OnLostKeyboardFocus);
            }
    
            /// <summary>
            /// Called when the associated control receives the keyboard focus.
            /// </summary>
            /// <param name="sender">The object triggering this event.</param>
            /// <param name="e">The event parameters.</param>
            private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
            {
                // show the touch keyboard
                TouchKeyboard.Show();
                var textBox = sender as TextBox;
                if (textBox != null)
                    textBox.SelectionStart = Math.Max(0, textBox.Text.Length);  //Move the caret to the end of the text in the text box.
            }
    
            /// <summary>
            /// Called when the associated control loses the keyboard focus.
            /// </summary>
            /// <param name="sender">The object triggering this event.</param>
            /// <param name="e">The event parameters.</param>
            private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
            {
                // hide the touch keyboard
                TouchKeyboard.Hide();
            }
        }
    }
    

    基本上,我的问题是,我如何才能使windows 10中的触摸屏键盘的行为与windows 8.1中的相同?是否有一些配置值可以在操作系统设置上更改,或者我需要更改注册表中的某些内容?它们之间的区别是什么 Touch Panel and Handwriting Service 在Windows 8.1和Windows 10中?短暂性脑缺血发作

    更新:

    请注意,我已经探索过使用“屏幕键盘”,我相信它是基于COM的,而不是较新的“触摸屏键盘”,但这没有帮助,因为最终是因为这个COM键盘需要管理员权限来关闭或最小化它。这就是我用“屏幕键盘”所做的尝试:

    using System;
    using System.Diagnostics;
    using System.Linq;
    using System.Management;
    using System.Runtime.InteropServices;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Interactivity;
    using Cpr.Apps.Sam.Controls;
    
    namespace Cpr.Apps.Sam.Styles.Behaviors
    {
        /// <summary>
        /// Behavior that shows the touch keyboard (on tablets only) when the associated control gets the keyboard focus.
        /// </summary>
        public class ControlShowTouchKeyboardOnFocusBehavior : Behavior<Control>
        {
            [DllImport("User32")]
            private static extern int ShowWindow(int hwnd, int nCmdShow);
    
            private const int SW_HIDE = 0;
            private const int SW_RESTORE = 9;
            private int hWnd;
            private readonly string _USB = "USB";
            private readonly string _keyboard = @"osk.exe";
            private Process _keyboardProcess = null;
            private ProcessStartInfo _startInfo = null;
    
            protected override void OnAttached()
            {
                base.OnAttached();
    
                // add the event handlers
                WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "GotKeyboardFocus", OnGotKeyboardFocus);
                WeakEventManager<Control, KeyboardFocusChangedEventArgs>.AddHandler(AssociatedObject, "LostKeyboardFocus", OnLostKeyboardFocus);
            }
    
            private bool GetKeyboardPresent()
            {
                bool flag = false;
                foreach (ManagementBaseObject managementBaseObject in new ManagementObjectSearcher("Select * from Win32_Keyboard").Get())
                {
                    foreach (PropertyData property in managementBaseObject.Properties)
                    {
                        if (Convert.ToString(property.Value).Contains(this._USB))
                        {
                            flag = true;
                            break;
                        }
                    }
                }
    
                return flag;
            }
    
            /// <summary>
            /// Called when the associated control receives the keyboard focus.
            /// </summary>
            /// <param name="sender">The object triggering this event.</param>
            /// <param name="e">The event parameters.</param>
            private void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
            {
                // show the touch keyboard
                // TouchKeyboard call here not needed in Windows 10 because of “Touch Keyboard and Handwriting Panel Service” causes virtual keyboard to show up twice.  Use on screen keyboard instead. 
                //TouchKeyboard.Show();
                if (!this.GetKeyboardPresent())
                {
                    //_keyboardProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
                    Process[] pocesses = Process.GetProcessesByName(_keyboard);
    
                    if (pocesses.Any())
                    {
                        foreach (var proc in pocesses)
                        {
                            hWnd = (int) proc.MainWindowHandle;
                            ShowWindow(hWnd, SW_RESTORE);
                        }
                    }
                    else
                    {
                        _startInfo = new ProcessStartInfo(_keyboard);
                        _keyboardProcess = new Process
                        {
                            EnableRaisingEvents = true,
                            StartInfo = _startInfo
                        };
                        _keyboardProcess.Exited += new EventHandler(ProcessExited);
                        //Don't need this because it is for parent process: AppDomain.CurrentDomain.ProcessExit += (a, b) => _keyboardProcess.Kill();
                        _keyboardProcess.Start();
                    }
    
                }
    
                var textBox = sender as TextBox;
                if (textBox != null)
                    textBox.SelectionStart = Math.Max(0, textBox.Text.Length);  //Move the caret to the end of the text in the text box.
            }
    
            /// <summary>
            /// Called when the associated control loses the keyboard focus.
            /// </summary>
            /// <param name="sender">The object triggering this event.</param>
            /// <param name="e">The event parameters.</param>
            private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
            {
                // hide the touch keyboard
                // TouchKeyboard call here not needed in Windows 10 because of “Touch Keyboard and Handwriting Panel Service” causes virtual keyboard to show up twice.  Use on screen keyboard instead. 
                //TouchKeyboard.Hide();
                if (!GetKeyboardPresent() && _keyboardProcess != null)
                {
                    //Keyboard doesn't minimize if I call Kill() or SW_HIDE, and instead this simply causes the textbox to lose focus so commented out this code
                    //Process[] pocesses = Process.GetProcessesByName("osk");
    
                    //for (int i = 0; i < pocesses.Count(); i++)
                    //{
                    //    var proc = pocesses[i];
                    //    proc.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
                        //hWnd = (int)proc.MainWindowHandle;
                        //ShowWindow(hWnd, SW_HIDE);
                    //}
    
                    //Task.Delay(500);
                }
            }
    
            private void ProcessExited(object sender, System.EventArgs e)
            {
                Debug.WriteLine("Exited _keyboardProcess");
                _keyboardProcess = null;
            }
        }
    }
    

    更新2:

    看起来我可能需要将我的应用从wpf移植到winrt才能在windows 10上运行:请参见 https://docs.microsoft.com/en-us/windows/uwp/porting/ 上面写着

    从wpf和silverlight移动到winrt

    在里面

    相关主题

    1 回复  |  直到 8 年前
        1
  •  0
  •   user8128167    8 年前

    最终使用了一个定制的wpf软件键盘,它内置在c中,而不是windows的触摸键盘和手写面板服务触摸屏键盘和屏幕键盘。