C#写的winform程序窗口失去焦点时用mouse_event模拟鼠标单击失效

foolishfox492716591 2019-06-24 10:31:58
公司给客户开发的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();
}
}


}

下面是程序运行截图
...全文
1274 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
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(); } } }
  • 打赏
  • 举报
回复
上面是主程序代码
  • 打赏
  • 举报
回复
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];

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧