C# WinForm 下的虚拟键盘

Posted on 2014-11-13 22:56  kunsen  阅读(1777)  评论(0编辑  收藏  举报
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;
 
namespace VirtualKeyboard
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new vkForm());
        }
    }
 
    public class vkButton : Label
    {
 
        public vkButton(string text)
        {
            New(text, new Size(30, 30), new Font("tahoma", 12, FontStyle.Bold));
        }
 
        public vkButton(string text, Size size, Font font)
        {
            New(text, size, font);
        }
 
        public void New(string text, Size size, Font font)
        {
            this.Text = text;   //设置控件的 Text 属性
            this.Font = font;  //控件所使用的字体
            this.Size = size;  //控件呈现的大小尺寸
            //定义控件为自绘模式并使用双缓存
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint
                            | ControlStyles.OptimizedDoubleBuffer, true);
            //添加鼠标事件响应事件
            this.MouseUp += new MouseEventHandler(btnNormal);
            this.MouseDown += new MouseEventHandler(btnPressed);
            this.MouseLeave += new EventHandler(btnNormal);
            this.MouseHover += new EventHandler(btnHover);
            //实例化后默认常规状态的颜色
            this.NormalColor = Color.LightSteelBlue;
            this.HoverColor = Color.Orange;
            this.PressedColor = Color.Red;
        }
 
        public Color HoverColor { setget; }    //鼠标激活时的颜色的属性
        public Color NormalColor { setget; } //正常状态的颜色的属性
        public Color PressedColor { set; get; } //鼠标按下时的颜色的属性
 
        private void btnNormal(object o, EventArgs e)
        {
            //这里绘画常规状态的控件界面
            Graphics graphic = this.CreateGraphics(); //创建绘图对象
            btnPaint(graphic, this.ForeColor, NormalColor); //绘画界面
            graphic.Dispose(); //及时释放对象资源
        }
 
        private void btnHover(object o, EventArgs e)
        {
            //这里绘画鼠标激活时的控件界面
            Graphics graphic = this.CreateGraphics();
            btnPaint(graphic, this.ForeColor, HoverColor);
            graphic.Dispose();
        }
 
        private void btnPressed(object o, EventArgs e)
        {
            //这里绘画鼠标按下后的控件界面
            Graphics graphic = this.CreateGraphics();
            btnPaint(graphic, this.ForeColor, PressedColor);
            graphic.Dispose();
        }
 
        protected override void OnPaint(PaintEventArgs e)
        {
            btnPaint(e.Graphics, this.ForeColor, this.NormalColor);
        }
 
        /* 此方法用于根据传入的参数绘制控件界面*/
        private void btnPaint(Graphics graphic, Color foreColor, Color backgroundColor)
        {
            graphic.Clear(this.BackColor);  //以背景色清除图象
            Color lightColor, darkColor;    //定义高亮和暗部分的颜色
            StringFormat textFormat = new StringFormat(); //用于设置文字格式
            LinearGradientBrush brush; //定义渐变笔刷
            Rectangle rect = new Rectangle(0, 0, this.Width - 1, this.Height - 1); //获取矩型区域
            lightColor = Color.FromArgb(0, backgroundColor);  //获取高亮颜色
            darkColor = Color.FromArgb(255, backgroundColor); //获取暗颜色
            //生成渐变笔刷实例
            brush = new LinearGradientBrush(rect, lightColor, darkColor,
                                                            LinearGradientMode.BackwardDiagonal);
 
            graphic.FillRectangle(brush, rect); //使用渐变画笔刷填充 
            graphic.DrawRectangle(new Pen(foreColor), rect); //使用前景色画边框
            textFormat.Alignment = StringAlignment.Center; //设置文字垂直对齐方式          
            textFormat.LineAlignment = StringAlignment.Center; //设置文字水平对齐方式
            //绘画控件显示的正文
            graphic.DrawString(this.Text, this.Font, new SolidBrush(foreColor), rect, textFormat);
        }
    }
 
    public static class Win32API
    {
        [DllImport("user32.dll", EntryPoint = "SendMessageW")]
        public static extern int SendMessage(
             int hwnd,
             int wMsg,
             int wParam,
             int lParam);
 
        [DllImport("user32.dll", EntryPoint = "PostMessageW")]
        public static extern int PostMessage(
             int hwnd,
             int wMsg,
             int wParam,
             int lParam);
 
        [DllImport("user32.dll")]
        public static extern int GetForegroundWindow();
 
        [DllImport("user32.dll")]
        public static extern int GetFocus();
 
        [DllImport("user32.dll")]
        public static extern int AttachThreadInput(
             int idAttach,
             int idAttachTo,
             int fAttach);
 
        [DllImport("user32.dll")]
        public static extern int GetWindowThreadProcessId(
             int hwnd,
             int lpdwProcessId);
 
        [DllImport("kernel32.dll")]
        public static extern int GetCurrentThreadId();
 
        public const int WM_MOUSEACTIVATE = 0x21;
        public const int WM_KEYDOWN = 0x100;
        public const int MA_NOACTIVATE = 3;
        public const int WS_EX_NOACTIVATE = 0x8000000;
    }
 
    public class vkForm : Form
    {
        private vkButton[] vk = new vkButton[36];
        private vkButton btnExit;
        private Point offset;
 
        protected override void OnLoad(EventArgs e)
        {
            btnExit = new vkButton("Exit Sample");
            btnExit.Dock = DockStyle.Bottom;
            btnExit.Size = new Size(130, 30);
            //先添加26个字母的虚拟按键
            for (int i = 0; i < 26; i++)
            {
                //使用刚才建立的按钮类实例化每个虚拟按钮
                //字母A对应ASCII代码为 65,即B为 66,如此类推
                vk[i] = new vkButton(((char)(i + 65)).ToString());
            }
            //继续添加0-9的数字键
            for (int i = 0; i < 10; i++)
            {
                //实例化各个数字的虚拟按钮,0 对应ASCII代码为 48
                vk[26 + i] = new vkButton(((char)(i + 48)).ToString());
            }
            this.TopMost = true;
            this.ControlBox = false;
            this.Size = new Size(330, 180);
            this.Controls.AddRange(vk);    //加入所有的虚拟按键
            this.Controls.Add(btnExit);  //加入一个退出程序的按钮
            int x = 10;
            int y = 10;
            for (int i = 0; i < vk.Length; i++)
            {
                vk[i].Click += btnCommon_Click;  //为按钮添加事件响应
                vk[i].Location = new Point(x, y);
                x += 32 + 2;
                if (x + 32 >= this.Width)
                {
                    y += 32;
                    x = 10;
                }
            }
            btnExit.Click += btnExit_Click; //为退出按钮添加事件响应
        }
 
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Point offset = e.Location;
                offset = this.PointToScreen(e.Location);
                this.Left = offset.X - this.offset.X;
                this.Top = offset.Y - this.offset.Y;
            }
        }
 
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                offset = e.Location;
            }
        }
 
        private void AttachThreadInput(bool b)
        {
            //设置线程亲和,附到前台窗口所在线程,只有在线程内才可以获取线程内控件的焦点
            //线程亲和: AttachThreadInput(目标线程标识, 当前线程标识, 非零值关联) 零表示取消
            //窗口所在的线程的标识: GetWindowThreadProcessId(窗体句柄, 这里返回进程标识)
            //当前的前台窗口的句柄: GetForegroundWindow()
            //当前程序所在的线程标识: GetCurrentThreadId()
            Win32API.AttachThreadInput(
                   Win32API.GetWindowThreadProcessId(
                            Win32API.GetForegroundWindow(), 0),
                   Win32API.GetCurrentThreadId(), Convert.ToInt32(b));
        }
 
        private void btnCommon_Click(object o, EventArgs e)
        {
            AttachThreadInput(true); //设置线程亲和的关联
            int getFocus = Win32API.GetFocus();
            //o为object类型,使用强制转换成vkButton
            char keyvalue = ((vkButton)o).Text.ToCharArray()[0];
            //向前台窗口发送按键消息
            Win32API.PostMessage(getFocus, Win32API.WM_KEYDOWN, (byte)keyvalue, 0);
            AttachThreadInput(false); //取消线程亲和的关联
        }
 
        private void btnExit_Click(object o, EventArgs e)
        {
            Application.Exit();
        }
 
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            //若在窗体上产生鼠标点击事件的消息则使消息返回值标记为不激活
            //程序内部的窗口切换仅需返回 MA_NOACTIVATE 即可,若相对其它
            //的程序窗口切换时 还需要设置 WS_EX_NOACTIVATE 样式
            if (m.Msg == Win32API.WM_MOUSEACTIVATE)
                m.Result = (IntPtr)Win32API.MA_NOACTIVATE;
                //MA_ACTIVATE 激活窗体,但不删除鼠标消息。
                //MA_NOACTIVATE 不激活窗体,也不删除鼠标消息。
                //MA_ACTIVATEANDEAT 激活窗体,删除鼠标消息。
                //MA_NOACTIVATEANDEAT 不激活窗体,但删除鼠标消息。
        }
 
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                //为窗体样式添加不激活标识
                cp.ExStyle = Win32API.WS_EX_NOACTIVATE;
                return cp;
            }
        }
    }
}