公司给客户开发的web程序A,有个表单里面是项目信息,客户有另一个web程序B(另一个公司开发的),也有一个表单里面是项目信息,现在客户要求,填写A时要把比较长的内容(比如项目名称)自动填写到B的表单上,由于浏览器的同源策略以及对剪切板访问的限制,顾通过js操作剪切板这个思路基本走不通。
后来上网查阅相关内容改用如下思路:
1.程序A中通过JS操作剪切板将项目信息存放到剪切板
2.C#开发一个winform程序,该程序加了一个定时器,每秒取一次剪切板,将项目信息读取存放到一个数组中,在该程序中通过键盘钩子监听ALT+P按键,先点击程序B的表单使获得焦点,按下ALT+P按键时,将数组内容通过剪切板和模拟键盘ctrl+v和tab操作,依次复制到目标表单中。
目前遇到的问题是当按下ALT+P时,程序B的表单立刻失去焦点(我把表单换成一个空的文本文件用记事本打开测试,记事本也失去焦点),由于失去焦点,模拟按键ctrl+v和tab操作也无法完成后续动作,我在响应函数加了System.Windows.Forms.MessageBox.Show弹窗,当点击弹窗确认按钮时却运行正常,请问大神这是什么原因因为字数限制只能截取部分代码了,后面会贴出来的,谢谢大家//3.判断输入键值(实现KeyDown事件) 
        private void hook_KeyDown(object sender, KeyEventArgs e)
        {
            //判断按下的键(Alt + P) 
            if (e.KeyValue == (int)Keys.P && (int)Control.ModifierKeys == (int)Keys.Alt)
            {
                //System.Windows.Forms.MessageBox.Show("按下了指定快捷键组合");
                strArr[0] = this.textBox1.Text;
                strArr[1] = this.textBox2.Text;
                strArr[2] = this.textBox3.Text;
                strArr[3] = this.textBox4.Text;
                //radioButton1对应公开招标单选按钮
                if (this.radioButton1.Checked)
                {
                    publicBid();
                }
                ////radioButton2对应竞价采购单选按钮
                if (this.radioButton2.Checked) {
                    priceBid();
                }
            }
        }[System.Runtime.InteropServices.DllImport("user32")]
        private static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
        //移动鼠标 
        const int MOUSEEVENTF_MOVE = 0x0001;
        //模拟鼠标左键按下 
        const int MOUSEEVENTF_LEFTDOWN = 0x0002;
        //模拟鼠标左键抬起 
        const int MOUSEEVENTF_LEFTUP = 0x0004;
        //模拟鼠标右键按下 
        const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
        //模拟鼠标右键抬起 
        const int MOUSEEVENTF_RIGHTUP = 0x0010;
        //模拟鼠标中键按下 
        const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        //模拟鼠标中键抬起 
        const int MOUSEEVENTF_MIDDLEUP = 0x0040;
        //标示是否采用绝对坐标 
        const int MOUSEEVENTF_ABSOLUTE = 0x8000; private void publicBid()
        {             //mouse_event模拟鼠标单击是为了强制让表单B获取焦点,实际上加了也没用
            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
            foreach (string v in strArr)
            {
                //System.Windows.Forms.MessageBox.Show(v);
                Clipboard.SetText(v);
                ctrlVClick();
                tabClick();
            }
        }        private void priceBid()
        {
            //mouse_event模拟鼠标单击是为了强制让表单B获取焦点,实际上加了也没用
            mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
            for (int i = 0; i < hitNumbers; i++)
            {
                //System.Windows.Forms.MessageBox.Show(strArr[i]);
                Clipboard.SetText(strArr[i]);
                ctrlVClick();
                tabClick();
                if (i == 2)
                {
                    tabClick();
                }
            }
        }下面是程序运行截图

解决方案 »

  1.   

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Text.RegularExpressions;
    using System.Runtime.InteropServices;
    using Microsoft.Win32;
    namespace Macros
    {
        public partial class Main : Form
        {
            public Main()
            {
                InitializeComponent();
                var k_hook = new KeyboardHook();
                k_hook.KeyDownEvent += new KeyEventHandler(hook_KeyDown);
                k_hook.Start();//安装键盘钩子
            }        //3.判断输入键值(实现KeyDown事件) 
            private void hook_KeyDown(object sender, KeyEventArgs e)
            {
                //判断按下的键(Alt + P) 
                if (e.KeyValue == (int)Keys.P && (int)Control.ModifierKeys == (int)Keys.Alt)
                {
                    //System.Windows.Forms.MessageBox.Show("按下了指定快捷键组合");
                    strArr[0] = this.textBox1.Text;
                    strArr[1] = this.textBox2.Text;
                    strArr[2] = this.textBox3.Text;
                    strArr[3] = this.textBox4.Text;
                    if (this.radioButton1.Checked)
                    {
                        publicBid();
                    }
                    if (this.radioButton2.Checked) {
                        priceBid();
                    }
                }
            }
            public String[] strArr=new String[4];
            public const int hitNumbers=4;
            #region bVk参数 常量定义        public const byte vbKeyLButton = 0x1;    // 鼠标左键
            public const byte vbKeyRButton = 0x2;    // 鼠标右键
            public const byte vbKeyCancel = 0x3;     // CANCEL 键
            public const byte vbKeyMButton = 0x4;    // 鼠标中键
            public const byte vbKeyBack = 0x8;       // BACKSPACE 键
            public const byte vbKeyTab = 0x9;        // TAB 键
            public const byte vbKeyClear = 0xC;      // CLEAR 键
            public const byte vbKeyReturn = 0xD;     // ENTER 键
            public const byte vbKeyShift = 0x10;     // SHIFT 键
            public const byte vbKeyControl = 0x11;   // CTRL 键
            public const byte vbKeyAlt = 18;         // Alt 键  (键码18)
            public const byte vbKeyMenu = 0x12;      // MENU 键
            public const byte vbKeyPause = 0x13;     // PAUSE 键
            public const byte vbKeyCapital = 0x14;   // CAPS LOCK 键
            public const byte vbKeyEscape = 0x1B;    // ESC 键
            public const byte vbKeySpace = 0x20;     // SPACEBAR 键
            public const byte vbKeyPageUp = 0x21;    // PAGE UP 键
            public const byte vbKeyEnd = 0x23;       // End 键
            public const byte vbKeyHome = 0x24;      // HOME 键
            public const byte vbKeyLeft = 0x25;      // LEFT ARROW 键
            public const byte vbKeyUp = 0x26;        // UP ARROW 键
            public const byte vbKeyRight = 0x27;     // RIGHT ARROW 键
            public const byte vbKeyDown = 0x28;      // DOWN ARROW 键
            public const byte vbKeySelect = 0x29;    // Select 键
            public const byte vbKeyPrint = 0x2A;     // PRINT SCREEN 键
            public const byte vbKeyExecute = 0x2B;   // EXECUTE 键
            public const byte vbKeySnapshot = 0x2C;  // SNAPSHOT 键
            public const byte vbKeyDelete = 0x2E;    // Delete 键
            public const byte vbKeyHelp = 0x2F;      // HELP 键
            public const byte vbKeyNumlock = 0x90;   // NUM LOCK 键        //常用键 字母键A到Z
            public const byte vbKeyA = 65;
            public const byte vbKeyB = 66;
            public const byte vbKeyC = 67;
            public const byte vbKeyD = 68;
            public const byte vbKeyE = 69;
            public const byte vbKeyF = 70;
            public const byte vbKeyG = 71;
            public const byte vbKeyH = 72;
            public const byte vbKeyI = 73;
            public const byte vbKeyJ = 74;
            public const byte vbKeyK = 75;
            public const byte vbKeyL = 76;
            public const byte vbKeyM = 77;
            public const byte vbKeyN = 78;
            public const byte vbKeyO = 79;
            public const byte vbKeyP = 80;
            public const byte vbKeyQ = 81;
            public const byte vbKeyR = 82;
            public const byte vbKeyS = 83;
            public const byte vbKeyT = 84;
            public const byte vbKeyU = 85;
            public const byte vbKeyV = 86;
            public const byte vbKeyW = 87;
            public const byte vbKeyX = 88;
            public const byte vbKeyY = 89;
            public const byte vbKeyZ = 90;        //数字键盘0到9
            public const byte vbKey0 = 48;    // 0 键
            public const byte vbKey1 = 49;    // 1 键
            public const byte vbKey2 = 50;    // 2 键
            public const byte vbKey3 = 51;    // 3 键
            public const byte vbKey4 = 52;    // 4 键
            public const byte vbKey5 = 53;    // 5 键
            public const byte vbKey6 = 54;    // 6 键
            public const byte vbKey7 = 55;    // 7 键
            public const byte vbKey8 = 56;    // 8 键
            public const byte vbKey9 = 57;    // 9 键
            public const byte vbKeyNumpad0 = 0x60;    //0 键
            public const byte vbKeyNumpad1 = 0x61;    //1 键
            public const byte vbKeyNumpad2 = 0x62;    //2 键
            public const byte vbKeyNumpad3 = 0x63;    //3 键
            public const byte vbKeyNumpad4 = 0x64;    //4 键
            public const byte vbKeyNumpad5 = 0x65;    //5 键
            public const byte vbKeyNumpad6 = 0x66;    //6 键
            public const byte vbKeyNumpad7 = 0x67;    //7 键
            public const byte vbKeyNumpad8 = 0x68;    //8 键
            public const byte vbKeyNumpad9 = 0x69;    //9 键
            public const byte vbKeyMultiply = 0x6A;   // MULTIPLICATIONSIGN(*)键
            public const byte vbKeyAdd = 0x6B;        // PLUS SIGN(+) 键
            public const byte vbKeySeparator = 0x6C;  // ENTER 键
            public const byte vbKeySubtract = 0x6D;   // MINUS SIGN(-) 键
            public const byte vbKeyDecimal = 0x6E;    // DECIMAL POINT(.) 键
            public const byte vbKeyDivide = 0x6F;     // DIVISION SIGN(/) 键
            //F1到F12按键
            public const byte vbKeyF1 = 0x70;   //F1 键
            public const byte vbKeyF2 = 0x71;   //F2 键
            public const byte vbKeyF3 = 0x72;   //F3 键
            public const byte vbKeyF4 = 0x73;   //F4 键
            public const byte vbKeyF5 = 0x74;   //F5 键
            public const byte vbKeyF6 = 0x75;   //F6 键
            public const byte vbKeyF7 = 0x76;   //F7 键
            public const byte vbKeyF8 = 0x77;   //F8 键
            public const byte vbKeyF9 = 0x78;   //F9 键
            public const byte vbKeyF10 = 0x79;  //F10 键
            public const byte vbKeyF11 = 0x7A;  //F11 键
            public const byte vbKeyF12 = 0x7B;  //F12 键        #endregion        #region
            [System.Runtime.InteropServices.DllImport("user32")]
            private static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
            //移动鼠标 
            const int MOUSEEVENTF_MOVE = 0x0001;
            //模拟鼠标左键按下 
            const int MOUSEEVENTF_LEFTDOWN = 0x0002;
            //模拟鼠标左键抬起 
            const int MOUSEEVENTF_LEFTUP = 0x0004;
            //模拟鼠标右键按下 
            const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
            //模拟鼠标右键抬起 
            const int MOUSEEVENTF_RIGHTUP = 0x0010;
            //模拟鼠标中键按下 
            const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
            //模拟鼠标中键抬起 
            const int MOUSEEVENTF_MIDDLEUP = 0x0040;
            //标示是否采用绝对坐标 
            const int MOUSEEVENTF_ABSOLUTE = 0x8000; 
            #endregion        #region 引用win32api方法        /// <summary>
            /// 导入模拟键盘的方法
            /// </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);
            #endregion        private void tabClick()
            {
                keybd_event(vbKeyTab, 0, 0, 0);
                keybd_event(vbKeyTab, 0, 2, 0);
            }        private void ctrlVClick()
            {
                keybd_event(vbKeyControl, 0, 0, 0);
                keybd_event(vbKeyV, 0, 0, 0);
                keybd_event(vbKeyControl, 0, 2, 0);
                keybd_event(vbKeyV, 0, 2, 0);
            }        private void publicBid()
            {
                mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                foreach (string v in strArr)
                {
                    //System.Windows.Forms.MessageBox.Show(v);
                    Clipboard.SetText(v);
                    ctrlVClick();
                    tabClick();
                }
            }        private void priceBid()
            {
                mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
                for (int i = 0; i < hitNumbers; i++)
                {
                    //System.Windows.Forms.MessageBox.Show(strArr[i]);
                    Clipboard.SetText(strArr[i]);
                    ctrlVClick();
                    tabClick();
                    if (i == 2)
                    {
                        tabClick();
                    }
                }
            }        private void timer1_Tick(object sender, EventArgs e)
            {
                // GetDataObject检索当前剪贴板上的数据
                IDataObject iData = Clipboard.GetDataObject();
                //将数据与指定的格式进行匹配,返回bool
                if (iData.GetDataPresent(DataFormats.Text))
                {
                    // GetData检索数据并指定一个格式
                    //this.textBox1.Text = (string)iData.GetData(DataFormats.Text);
                    String myStr = (string)iData.GetData(DataFormats.Text);
                    if (!string.IsNullOrEmpty(myStr))
                    {
                        if(myStr.Contains("|")){
                            strArr = myStr.Split(new Char[] { '|' });
                            if (strArr.Length == 4)
                            {
                                this.textBox1.Text = strArr[0] == "NULL" ? "" : strArr[0];
                                this.textBox2.Text = strArr[1] == "NULL" ? "" : strArr[1];
                                this.textBox3.Text = strArr[2] == "NULL" ? "" : strArr[2];
                                this.textBox4.Text = strArr[3] == "NULL" ? "" : strArr[3];
                     
      

  2.   

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using System.Reflection;namespace Macros
    {
        class KeyboardHook
        {
            public event KeyEventHandler KeyDownEvent;
            public event KeyPressEventHandler KeyPressEvent;
            public event KeyEventHandler KeyUpEvent;
            public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
            static int hKeyboardHook = 0; //声明键盘钩子处理的初始值
            //值在Microsoft SDK的Winuser.h里查询
            //转载自http://www.bianceng.cn/Programming/csharp/201410/45484.htm
            public const int WH_KEYBOARD_LL = 13;   //线程键盘钩子监听鼠标消息设为2,全局键盘监听鼠标消息设为13
            HookProc KeyboardHookProcedure; //声明KeyboardHookProcedure作为HookProc类型
            //键盘结构
            [StructLayout(LayoutKind.Sequential)]
            public class KeyboardHookStruct
            {
                public int vkCode;  //定一个虚拟键码。该代码必须有一个价值的范围1至254
                public int scanCode; // 指定的硬件扫描码的关键
                public int flags;  // 键标志
                public int time; // 指定的时间戳记的这个讯息
                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("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);
            // 取得当前线程编号(线程钩子需要用到)
            [DllImport("kernel32.dll")]
            static extern int GetCurrentThreadId();
            //使用WINDOWS API函数代替获取当前实例的函数,防止钩子失效
            [DllImport("kernel32.dll")]
            public static extern IntPtr GetModuleHandle(string name);
            public void Start()
            {
                // 安装键盘钩子
                if (hKeyboardHook == 0)
                {
                    KeyboardHookProcedure = new HookProc(KeyboardHookProc);
                    hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 0);
                    //hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
                    //************************************
                    //键盘线程钩子
                    //SetWindowsHookEx( 2,KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());//指定要监听的线程idGetCurrentThreadId(),
                    //键盘全局钩子,需要引用空间(using System.Reflection;)
                    //SetWindowsHookEx( 13,MouseHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);
                    //
                    //关于SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函数将钩子加入到钩子链表中,说明一下四个参数:
                    //idHook 钩子类型,即确定钩子监听何种消息,上面的代码中设为2,即监听键盘消息并且是线程钩子,如果是全局钩子监听键盘消息应设为13,
                    //线程钩子监听鼠标消息设为7,全局钩子监听鼠标消息设为14。lpfn 钩子子程的地址指针。如果dwThreadId参数为0 或是一个由别的进程创建的
                    //线程的标识,lpfn必须指向DLL中的钩子子程。 除此以外,lpfn可以指向当前进程的一段钩子子程代码。钩子函数的入口地址,当钩子钩到任何
                    //消息后便调用这个函数。hInstance应用程序实例的句柄。标识包含lpfn所指的子程的DLL。如果threadId 标识当前进程创建的一个线程,而且子
                    //程代码位于当前进程,hInstance必须为NULL。可以很简单的设定其为本应用程序的实例句柄。threaded 与安装的钩子子程相关联的线程的标识符
                    //如果为0,钩子子程与所有的线程关联,即为全局钩子
                    //************************************
                    //如果SetWindowsHookEx失败
                    if (hKeyboardHook == 0)
                    {
                        Stop();
                        throw new Exception("安装键盘钩子失败");
                    }
                }
            }
            public void Stop()
            {
                bool retKeyboard = true;
                if (hKeyboardHook != 0)
                {
                    retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
                    hKeyboardHook = 0;
                }
                if (!(retKeyboard)) throw new Exception("卸载钩子失败!");
            }
            //ToAscii职能的转换指定的虚拟键码和键盘状态的相应字符或字符
            [DllImport("user32")]
            public static extern int ToAscii(int uVirtKey, //[in] 指定虚拟关键代码进行翻译。
                                             int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。高阶位的这个值设定的关键,如果是(不压)
                                             byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。如果高阶位的字节是一套,关键是下跌(按下)。在低比特,如果设置表明,关键是对切换。在此功能,只有肘位的CAPS LOCK键是相关的。在切换状态的NUM个锁和滚动锁定键被忽略。
                                             byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。
                                             int fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.
            //获取按键的状态
            [DllImport("user32")]
            public static extern int GetKeyboardState(byte[] pbKeyState);
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
            private static extern short GetKeyState(int vKey);
            private const int WM_KEYDOWN = 0x100;//KEYDOWN
            private const int WM_KEYUP = 0x101;//KEYUP
            private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN
            private const int WM_SYSKEYUP = 0x105;//SYSKEYUP
            private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
            {
                // 侦听键盘事件
                if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))
                {
                    KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                    // raise KeyDown
                    if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
                    {
                        Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
                        KeyEventArgs e = new KeyEventArgs(keyData);
                        KeyDownEvent(this, e);
                    }
                    //键盘按下
                    if (KeyPressEvent != null && wParam == WM_KEYDOWN)
                    {
                        byte[] keyState = new byte[256];
                        GetKeyboardState(keyState);
                        byte[] inBuffer = new byte[2];
                        if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1)
                        {
                            KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);
                            KeyPressEvent(this, e);
                        }
                    }
                    // 键盘抬起
                    if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
                    {
                        Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
                        KeyEventArgs e = new KeyEventArgs(keyData);
                        KeyUpEvent(this, e);
                    }
                }
                //如果返回1,则结束消息,这个消息到此为止,不再传递。
                //如果返回0或调用CallNextHookEx函数则消息出了这个钩子继续往下传递,也就是传给消息真正的接受者
                return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
            }
            ~KeyboardHook()
            {
                Stop();
            }
        }
    }