Mar 7, 2009

用程序模拟键盘按键

小众软件的文章“Win7 Appinn Desktop - 模拟 Windows 7 的盲按显示桌面效果”介绍了一个把鼠标移到屏幕左上角或者右下角点一下就可以做到“Win+D”效果的小程序。

这是个挺不错的应用,但是尽管原程序只有几百KB,运行以后它要用到5-6MB。我觉得程序中或许有冗余的东西,不过原程序是用AutoHotkey写的,我对AHK不是很熟悉——确切的说,我也不是很喜欢AHK这类语言。or程序?所以我想要自己写个类似的东西。不过,说实话我的能力实在不是很强。幸好还有Google大婶在。

首先我要做的是实现——用程序模拟键盘按键。

先看一下下面的乱七八糟的C++ code。

// CPP_SimulateWinD.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>

/***********
int _tmain(int argc, _TCHAR* argv[])
{
printf("Program Started...\n\n");
LASTINPUTINFO myInfo;
myInfo.cbSize = sizeof(myInfo);
BOOL myResult = GetLastInputInfo(&myInfo);
if(myResult) printf("Get info successfully...");
printf("...Program Completed\n\n");

system("PAUSE");
return 0;
}
*******************/

INPUT *key;
INPUT *key2;
INPUT Inputs[2];

void _SendInput(char ch);
void _SendInput();
void _SendInputV2();

void main(){

char end;
HWND windowHandle = FindWindow(0, "*new 1 - Notepad++");
//INPUT *key;
if(windowHandle == NULL)
printf("Notepad++ window not found.");
SetForegroundWindow(windowHandle);
Sleep(1000);

key = new INPUT;
key2 = new INPUT;
//for(int i='A'; i<'Z'; i++){
// _SendInput(i);
//}
//_SendInput();
_SendInputV2();
printf("Key inputted.");

system("PAUSE");
}

void _SendInput(char ch){
key->type = INPUT_KEYBOARD;
key->ki.wVk = ch;
//key->ki.wVk = VK_LWIN;
key->ki.dwFlags = 0;
key->ki.time = 0;
key->ki.wScan = 0;
key->ki.dwExtraInfo = KEYEVENTF_KEYUP;
SendInput(1, key, sizeof(INPUT));
//key->ki.dwExtraInfo = KEYEVENTF_KEYUP;
//SendInput(1, key, sizeof(INPUT));
Sleep(500);
}

void _SendInput(){
key->type = INPUT_KEYBOARD;
//key->ki.wVk = 'D';
key->ki.wVk = VK_LWIN;
key->ki.dwFlags = 0;
key->ki.time = 0;
key->ki.wScan = 0;
//key->ki.dwExtraInfo = KEYEVENTF_KEYUP;
key->ki.dwExtraInfo = 0;
SendInput(1, key, sizeof(INPUT));

key2->type = INPUT_KEYBOARD;
key2->ki.wVk = 'D';
//key2->ki.wVk = VK_LWIN;
key2->ki.dwFlags = 0;
key2->ki.time = 0;
key2->ki.wScan = 0;
//key2->ki.dwExtraInfo = KEYEVENTF_KEYUP;
key2->ki.dwExtraInfo = 0;
SendInput(1, key2, sizeof(INPUT));
key->ki.dwExtraInfo = KEYEVENTF_KEYUP;
SendInput(1, key, sizeof(INPUT));
key2->ki.dwExtraInfo = KEYEVENTF_KEYUP;
SendInput(1, key2, sizeof(INPUT));
//key->ki.dwExtraInfo = KEYEVENTF_KEYUP;
//SendInput(1, key, sizeof(INPUT));
Sleep(500);
}

void _SendInputV2(){
memset(Inputs, 0, sizeof(INPUT));
Inputs[0].type = INPUT_KEYBOARD;
//Inputs[0].ki.wVk = VK_LWIN;
Inputs[0].ki.wVk = 'F';
Inputs[1] = Inputs[0];
Inputs[1].ki.wVk = 'D';
SendInput(2, Inputs, sizeof(INPUT));
//Release WinKey + D
Inputs[0].ki.dwFlags = KEYEVENTF_KEYUP;
Inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(2, Inputs, sizeof(INPUT));
}

如上面code中所示,三个methods分别用来做:

void _SendInput(char ch):接受一个character,并把它发送给当前in focus的窗口,相当于按了一下相对应的键。
void _SendInput():我是想要做出Win+D的show desktop的效果的,这个method和下一个都是这个目的。不过,这个里面,WInKey和D是分别定义的,当然在SendInput() method也是被call了两次。结果是这样子不行,所以有了下面的Version。
void _SendInputV2():这个里面WinKey和D定义在一个INPUT array里面,而SendInput()同样只调用了一次,pass给它的是那个array。这个成功了。

有一点需要注意的是,在SendInput()模拟过Win+D之后要set两个INPUT structure的ki.dwFlags成KEYEVENTF_KEYUP再调用一下这个SendInput(),这样子就release了WinKey+D键了——因为第一次SendInput()时,两个按键是被按着(press)并没有放开(release)的,而改过上面所说的flag后,再一次SendInput()就相当于松开了两个按键。

另外,code中用到的几个function,在MSDN中都有相应的条目。

SendInput Function
FindWindow Function
INPUT Structure
KEYBDINPUT Structure

另外一篇中文的文章“用应用程序模拟键盘和鼠标按键”提到了用Keybd_eventmouse_event这两个function来做同样的事情。这两个function连同上面我用到的几个都是MSDN Library中的,等有时间了我再研究一下它们的异同吧。

No comments:

Post a Comment