C#基于winform创建触摸屏可用的模拟键盘

        创作背景:因项目需求,需要创建一个可以运行在触摸屏上的模拟键盘,开机自启动,启动后显示的是圆形悬浮框,当有输入需求时(改为鼠标左键长按300ms以上),显示键盘,或者双击圆形悬浮框显示键盘。我们知道想要完成此功能,大致需要如下知识储备:1、使用SendKeys类来模拟键盘输入。;2、使用全局钩子来监控某些触发事件(例如何时需要显示键盘等)。在开放过程中,也有一些小tips,在后文涉及到的地方会有详尽描述,文章末尾也有相关源码链接。

        相关功能:1、首先要在窗体代码前添加相关设置,使操作键盘时,窗体不获取焦点(一旦获取焦点,需要输入的进程就无法获取输入光标了)。以下代码放置在窗体的类中即可。

  /// <summary>
  /// 此段代码不可删除
  /// </summary>
  protected override CreateParams CreateParams
  {
      get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= (int)0x08000000L;
                return cp;
            }
   }

        2、利用SendKeys类来模拟键盘输入。示例代码如下:

/// <summary>
        /// 普通按键
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_SendText_Click(object sender, EventArgs e)
        {
            Button button = (Button)sender;
            string strBtnTxt = button.Text;

            strBtnTxt = StringConvert.GetFinalStr(strBtnTxt);

            if (strBtnTxt.Length == 1)
            {
                if (char.IsLetter(strBtnTxt[0]))
                {
                    SendKeys.Send(strBtnTxt.ToLower());
                }
                else
                {
                    SendKeys.Send(strBtnTxt);
                }
            }
            else if (strBtnTxt.Length > 1)
            {
                SendKeys.Send("{" + strBtnTxt + "}");
            }
        }

        3、使用全局钩子监控鼠标状态。本意是想监控所有进程,看是否存在需要输入的编辑框获取到焦点,但是经过多次尝试之后并没有成功,这里也希望各位大佬指正并给出建议。那我退而求其次,利用鼠标左键长按300毫秒以上的状态来判断是否唤醒键盘。钩子的部分代码如下:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WFTouch
{
    public class MouseHook
    {
        private const int WM_MOUSEMOVE = 0x200;
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_RBUTTONDOWN = 0x204;
        private const int WM_MBUTTONDOWN = 0x207;
        private const int WM_LBUTTONUP = 0x202;
        private const int WM_RBUTTONUP = 0x205;
        private const int WM_MBUTTONUP = 0x208;
        private const int WM_LBUTTONDBLCLK = 0x203;
        private const int WM_RBUTTONDBLCLK = 0x206;
        private const int WM_MBUTTONDBLCLK = 0x209;


        static int hMouseHook = 0;

        public const int WH_MOUSE_LL = 14;//low level mouse event
        public const int WH_MOUSE = 7;//normal level mouse event

        static HookProc MouseHookProcedure;
        [StructLayout(LayoutKind.Sequential)]
        public class POINT
        {
            public int x;
            public int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        public class MouseHookStruct
        {
            public POINT pt;
            public int hWnd;
            public int wHitTestCode;
            public int dwExtraInfo;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetLastError();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("kernel32.dll")]
        private static extern int GetCurrentThreadId();//获取在系统中的线程ID

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

        public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

        public MouseHook()
        {
        }

        ~MouseHook()
        {
            Stop();
        }

        public static void Start()
        {
            if (hMouseHook == 0)
            {
                MouseHookProcedure = new HookProc(MouseHookProc);

                hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, GetModuleHandle("user32"), 0);//第一个参数是WH_MOUSE_LL,表示捕获所有线程的鼠标消息,同时最后一个参数必须是0
                if (hMouseHook == 0)
                {
                    int errorCode = GetLastError();
                }
            }
        }

        public static void Stop()
        {
            bool retMouse = true;
            if (hMouseHook != 0)
            {
                retMouse = UnhookWindowsHookEx(hMouseHook);
                hMouseHook = 0;
            }
        }

        private static int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            StaticClass.strMDC = wParam.ToString();
            //只处理鼠标左键按下的情况
            if (wParam == WM_LBUTTONDOWN && nCode >= 0)
            {
                MouseButtons button = MouseButtons.None;
                int clickCount = 0;

                switch (wParam)
                {
                    case WM_LBUTTONDOWN:
                        button = MouseButtons.Left;
                        clickCount = 1;
                        break;
                    case WM_LBUTTONUP:
                        button = MouseButtons.Left;
                        clickCount = 1;
                        break;
                    case WM_LBUTTONDBLCLK:
                        button = MouseButtons.Left;
                        clickCount = 2;
                        break;
                    case WM_RBUTTONDOWN:
                        button = MouseButtons.Right;
                        clickCount = 1;
                        break;
                    case WM_RBUTTONUP:
                        button = MouseButtons.Right;
                        clickCount = 1;
                        break;
                    case WM_RBUTTONDBLCLK:
                        button = MouseButtons.Right;
                        clickCount = 2;
                        break;
                }
                StaticClass.strMDC = clickCount.ToString();
                MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
                MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0);
            }
            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
        }
    }
}

        4、钩子的调用。在主窗口类中进行调用,这里我是使用的Timer控件,可根据需要使用线程也可以。在timer的执行方法中,调用ttttt()方法即可,方法名称是测试的时候随意定义的,确实有点随意,大家担待😀。其中还有其他功能的部分操作,涉及到窗口显示的大小等。

    Stopwatch stopwatchSign = new Stopwatch();
        public void ttttt()
        {
            if (stopwatchSign != null && stopwatchSign.ElapsedMilliseconds >= 300)
            {
                this.WindowState = FormWindowState.Normal;
                this.Width = StaticClass.width;
                this.Height = StaticClass.height;
                stopwatchSign.Reset();
            }
            if (StaticClass.strMDC.Equals("1") && !stopwatchSign.IsRunning && !this.Visible)
            {
                stopwatchSign.Restart();
            }
            if (!StaticClass.strMDC.Equals("1"))
            {
                stopwatchSign.Stop();
            }
        }

        5、圆形悬浮框。话不多说,关键代码如下:

    private void TopForm_Load1(object sender, EventArgs e)
        {
            string strPath = System.AppDomain.CurrentDomain.BaseDirectory + "keyboard.png";
            backgroundImage = new Bitmap(strPath);

            // 设置窗口区域为圆角矩形
            Region = new Region(new Rectangle(0, 0, Width, Height));
            GraphicsPath path = new GraphicsPath();
            path.AddEllipse(0, 0, Width, Height);
            Region = new Region(path);
        }

        protected override void OnResize(EventArgs e)
        {
            //base.OnResize(e);
            base.OnResize(e);
            // 调整背景图片以填满窗口
            this.Invalidate(); // 触发重绘
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            // 不执行任何操作,避免默认的矩形绘制
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            // 在窗口上绘制背景图片
            e.Graphics.DrawImage(backgroundImage, 0, 0, Width, Height);
        }

        以上是此项目的一些重要功能点,其余的均是相互调用和细节处理,相对简单。完整的代码在我的主页中可以找到,如果大家么有积分下载,又特别想要源码,可以在文章末尾留言。源码没有进行优化处理,一些测试代码尚有残留,仅供参考。

        代码链接:点击跳转至源码地址

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "c"这个字母是拉丁字母表中的第三个字母,也是英语字母表中的一个字母。它的发音是/k/,在一些单词中,它也可以表示/s/的发音,比如city(城市)。在国际音标中,它的音标为/siː/。 此外,在计算机编程方面,"c"也是一种编程语言,被广泛用于系统软件开发、嵌入式系统和其他高性能应用程序。C语言于1972年由贝尔实验室的Dennis Ritchie在贝尔实验室开发出来,是一种通用的、面向过程的、静态类型的编程语言。它为开发者提供了底层控制的能力,同时也相对易学易用,因此在计算机科学、计算机工程和软件工程等领域广泛应用。 此外,在音乐方面,"C"也代表降C调,是西方音乐中的一个调式,以C音为音高基准。在乐谱上,"C"也被用作音符的标记,表示C音。 综上所述,"c"是一个普遍存在于我们日常生活中的字母,无论是语言、编程和音乐等方面都扮演着重要的角色。 ### 回答2: C是计算机科学中的一种编程语言。它由美国贝尔实验室的丹尼斯·里奇在20世纪70年代早期开发。C语言是一种通用的编程语言,它具有高效性和灵活性,因此被广泛用于软件开发领域。 C语言具有简洁的语法和功能强大的库,可以支持底层的硬件操作,是编写操作系统、驱动程序和嵌入式系统的首选语言。此外,C语言还支持指针操作,使得程序可以直接访问和修改内存中的数据,提高了程序的执行效率。 相对于其他编程语言而言,C语言的学习曲线较为陡峭,需要对计算机的底层原理有一定的了解。但是一旦掌握了C语言的基本概念和语法,掌握其他编程语言也会变得更容易。 C语言具有良好的可移植性,相同的源代码可以在不同的计算机系统上编译和运行,这极大地方便了软件开发和维护。而且,C语言可以与其他语言进行混合编程,使得不同语言的优势可以互相结合,提高了开发效率。 总之,C语言是一种非常重要的编程语言,它在计算机科学和软件开发领域扮演着重要的角色。掌握C语言可以使程序员具备更深入的编程理解和能力,为未来的职业发展打下坚实基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值