WPF开发经验-实现Win10虚拟触摸键盘
阅读原文时间:2023年07月08日阅读:3

项目有个需求,需要实现纯触控操作进行键盘输入。项目部署在Win10系统上,考虑有两种方案来实现。

  1. 通过调用Win10自带的触摸键盘来实现;
  2. 通过WPF实现一个触摸键盘来实现;

简单附上一个调用Win10系统的TabTip.exe的操作类。

public class TabTipHelper
{
private const int WM_SYSCOMMAND = 274;
private const uint SC_CLOSE = 61536;
private const uint SC_RESTORE = 0xF120;
private const uint SC_MAXIMIZE = 0xF030;
private const uint SC_MINIMIZE = 0xF020;

\[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)\]  
private static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

\[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)\]  
private static extern bool PostMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);

\[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)\]  
private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

\[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)\]  
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

\[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)\]  
private static extern int RegisterWindowMessage(string lpString);

public static int ShowTaptip()  
{  
    try  
    {  
        dynamic file = "C:\\\\Program Files\\\\Common Files\\\\microsoft shared\\\\ink\\\\TabTip.exe";  
        if (!System.IO.File.Exists(file))  
            return -1;  
        Process.Start(file);  
        return 1;  
    }  
    catch (Exception)  
    {  
        return 255;  
    }  
}

public static async Task ShowTaptipAsync()  
{  
    await Task.Run(() => ShowTaptip());  
}

public static void CloseTaptip()  
{  
    var touchhWnd = new IntPtr(0);  
    touchhWnd = FindWindow("IPTip\_Main\_Window", null);  
    if (touchhWnd == IntPtr.Zero)  
        return;  
    PostMessage(touchhWnd, WM\_SYSCOMMAND, SC\_CLOSE, 0);  
}  

}


下图为demo效果:

当TextBox获取焦点时,弹出键盘。当TextBox失去焦点时,隐藏键盘。

点击键盘的右上角的关闭键或Esc键隐藏键盘。

因项目不需要全键位,所有针对性地对键位进行了删减和排列。



3.1 SoftKeyboardControl控件

使用WPF的UserControl实现虚拟键盘,下附SoftKeyboardControl的后台代码。

/// <summary>  
/// SoftKeyboardControl.xaml 的交互逻辑  
/// </summary>  
public partial class SoftKeyboardControl : UserControl  
{  
    /// <summary>  
    /// Windows提供的一个模拟键盘API。  
    /// Keybd\_event()函数能触发一个按键事件,生成一个 WM\_KEYDOWN 或 WM\_KEYUP 消息。  
    /// </summary>  
    /// <param name="bVk" >按键的虚拟键值</param>  
    /// <param name= "bScan" >扫描码,一般不用设置,用0代替就行</param>  
    /// <param name= "dwFlags" >选项标志:0:表示按下,2:表示松开</param>  
    /// <param name= "dwExtraInfo">一般设置为0</param>  
    \[DllImport("User32.dll")\]  
    public static extern void keybd\_event(byte bVK, byte bScan, int dwFlags, int dwExtraInfo);

    public SoftKeyboardControl()  
    {  
        InitializeComponent();  
        CreateKeys();  
        KeyCommand = new RoutedCommand();  
        CommandBinding cmdBinding = new CommandBinding(KeyCommand, KeyCommand\_Excuted, KeyCommand\_CanExcute);  
        CommandBindings.Add(cmdBinding);  
    }

    #region 虚拟键值

    /// <summary>  
    /// 键和虚拟键值的字典  
    /// </summary>  
    private Dictionary<string, byte> keys;

    /// <summary>  
    /// 初始化虚拟键值的字典  
    /// </summary>  
    private void CreateKeys()  
    {  
        keys = new Dictionary<string, byte>()  
        {  
            #region 数字键盘

            { "0",0x60},  
            { "1",0x61},  
            { "2",0x62},  
            { "3",0x63},  
            { "4",0x64},  
            { "5",0x65},  
            { "6",0x66},  
            { "7",0x67},  
            { "8",0x68},  
            { "9",0x69},

            { "-",0x6d},  
            { ".",0x6E},

            #endregion

            #region Q字母行

            { "q", 0x51},  
            { "w", 0x57},  
            { "e", 0x45},  
            { "r", 0x52},  
            { "t", 0x54},  
            { "y", 0x59},  
            { "u", 0x55},  
            { "i", 0x49},  
            { "o", 0x4f},  
            { "p", 0x50},

            { "Q", 0x51},  
            { "W", 0x57},  
            { "E", 0x45},  
            { "R", 0x52},  
            { "T", 0x54},  
            { "Y", 0x59},  
            { "U", 0x55},  
            { "I", 0x49},  
            { "O", 0x4f},  
            { "P", 0x50},

            #endregion

            #region A字母行

            { "a", 0x41},  
            { "s", 0x53},  
            { "d", 0x44},  
            { "f", 0x46},  
            { "g", 0x47},  
            { "h", 0x48},  
            { "j", 0x4A},  
            { "k", 0x4B},  
            { "l", 0x4C},

            { "A", 0x41},  
            { "S", 0x53},  
            { "D", 0x44},  
            { "F", 0x46},  
            { "G", 0x47},  
            { "H", 0x48},  
            { "J", 0x4A},  
            { "K", 0x4B},  
            { "L", 0x4C},

            #endregion

            #region Z字母行

            { "z", 0x5A},  
            { "x", 0x58},  
            { "c", 0x43},  
            { "v", 0x56},  
            { "b", 0x42},  
            { "n", 0x4E},  
            { "m", 0x4D},

            { "Z", 0x5A},  
            { "X", 0x58},  
            { "C", 0x43},  
            { "V", 0x56},  
            { "B", 0x42},  
            { "N", 0x4E},  
            { "M", 0x4D},

            #endregion

            #region other

            {"BackSpace",0x08 },  
            {"Tab",0x09 },  
            {"Enter",0x0d },  
            {"Shift",0x10 },  
            {"Ctrl",0x11 },  
            {"CapsLock",0x14 },  
            {"Space",0x20 },

            #endregion  
        };  
    }

    #endregion

    #region DependencyProperty

    public static readonly DependencyProperty CapsProperty = DependencyProperty.Register(  
        "Caps", typeof(bool), typeof(SoftKeyboardControl), new PropertyMetadata(default(bool)));  
    public bool Caps  
    {  
        get { return (bool)GetValue(CapsProperty); }  
        set { SetValue(CapsProperty, value); }  
    }

    public static readonly DependencyProperty CtrlProperty = DependencyProperty.Register(  
        "Ctrl", typeof(bool), typeof(SoftKeyboardControl), new PropertyMetadata(default(bool)));

    public bool Ctrl  
    {  
        get { return (bool)GetValue(CtrlProperty); }  
        set { SetValue(CtrlProperty, value); }  
    }

    public static readonly DependencyProperty ShiftProperty = DependencyProperty.Register(  
        "Shift", typeof(bool), typeof(SoftKeyboardControl), new PropertyMetadata(default(bool)));

    public bool Shift  
    {  
        get { return (bool)GetValue(ShiftProperty); }  
        set { SetValue(ShiftProperty, value); }  
    }

    #endregion

    #region Command

    public ICommand KeyCommand { get; set; }  
    private void KeyCommand\_CanExcute(object sender, CanExecuteRoutedEventArgs e)  
    {  
        e.CanExecute = true;  
    }  
    private void KeyCommand\_Excuted(object sender, ExecutedRoutedEventArgs e)  
    {  
        if (e.Parameter != null)  
        {  
            var code = e.Parameter.ToString();  
            if (keys.ContainsKey(code))  
            {  
                byte b = keys\[code\];  
                try  
                {  
                    keybd\_event(b, 0, 0, 0);  
                }  
                catch (Exception ex)  
                {  
                    Console.WriteLine(ex.Message);  
                }  
            }  
        }  
    }

    public ICommand CloseCommand { get; set; }

    #endregion

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)  
    {  
        base.OnPropertyChanged(e);  
        if (e.Property == CapsProperty)  
        {  
            keybd\_event(0x14, 0, 0, 0);//按下  
            keybd\_event(0x14, 0, 2, 0); //抬起  
        }  
        else if (e.Property == ShiftProperty)  
        {  
            keybd\_event(0x10, 0, 0, 0);  
            keybd\_event(0x10, 0, 2, 0);  
        }  
        else if (e.Property == CtrlProperty)  
        {  
            keybd\_event(0x11, 0, 0, 0);  
            keybd\_event(0x11, 0, 2, 0);  
        }  
    }  
}

/// <summary>  
/// 大小写转换  
/// </summary>  
public class UpperConverter : IValueConverter  
{  
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)  
    {  
        if (parameter == null)  
        {  
            return "";  
        }

        if (value == null)  
        {  
            return parameter.ToString();  
        }

        if ((bool)value)  
        {  
            return parameter.ToString().ToUpper();  
        }  
        else  
        {  
            return parameter.ToString().ToLower();  
        }  
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)  
    {  
        throw new NotImplementedException();  
    }  
}

下附SoftKeyboardControl的前台代码。

注:其中按钮的样式是自己的控件库中实现的,未贴出。