如何向一个应用程序发送按键消息,谢谢(50分)

  • 主题发起人 主题发起人 findya
  • 开始时间 开始时间
F

findya

Unregistered / Unconfirmed
GUEST, unregistred user!
请给出例子,谢谢
 
可以模拟键盘按键按下,程序如下:
unit SendKey;

interface

uses
SysUtils, Windows, Messages, Classes, KeyDefs;

type
{ Error codes }
TSendKeyError = (sk_None, sk_FailSetHook, sk_InvalidToken,
sk_UnknownError, sk_AlreadyPlaying);
{ first vk code to last vk code }
TvkKeySet = set of vk_LButton..vk_Scroll;

{ exceptions }
ESendKeyError = class(Exception);
ESKSetHookError = class(ESendKeyError);
ESKInvalidToken = class(ESendKeyError);
ESKAlreadyPlaying = class(ESendKeyError);

function SendKeys(S: String): TSendKeyError;
procedure WaitForHook;
procedure StopPlayback;

var
Playing: Boolean;

implementation

uses Forms;

type
{ a TList descendant that know how to dispose of its contents }
TMessageList = class(TList)
public
destructor Destroy; override;
end;

const
{ valid "sys" keys }
vkKeySet: TvkKeySet = [Ord('A')..Ord('Z'), vk_Menu, vk_F1..vk_F12];


destructor TMessageList.Destroy;
var
i: longint;
begin
{ deallocate all the message records before discarding the list }
for i := 0 to Count - 1 do
Dispose(PEventMsg(Items));
inherited Destroy;
end;

var
{ variables global to the DLL }
MsgCount: word = 0;
MessageBuffer: TEventMsg;
HookHandle: hHook = 0;
MessageList: TMessageList = Nil;
AltPressed, ControlPressed, ShiftPressed: Boolean;

procedure StopPlayback;
{ Unhook the hook, and clean up }
begin
{ if Hook is currently active, then unplug it }
if Playing then
UnhookWindowsHookEx(HookHandle);
MessageList.Free;
Playing := False;
end;

function Play(Code: integer; wParam, lParam: Longint): Longint; stdcal
l;
{ This is the JournalPlayback callback function. It is called by }
{ Windows when Windows polls for hardware events. The code parameter
}
{ indicates what to do. }
begin
case Code of
HC_SKIP:
{ HC_SKIP means to pull the next message out of our list. If we
}
{ are at the end of the list, it's okay to unhook the }
{ JournalPlayback hook from here. }
begin
{ increment message counter }
inc(MsgCount);
{ check to see if all messages have been played }
if MsgCount >= MessageList.Count then StopPlayback
{ otherwise copy next message from list into buffer }
else MessageBuffer := TEventMsg(MessageList.Items[MsgCount]^);

Result := 0;
end;
HC_GETNEXT:
{ HC_GETNEXT means to fill the wParam and lParam with the proper
}
{ values so that the message can be played back. DO NOT unhook
}
{ hook from within here. Return value indicates how much time }

{ until Windows should playback message. We'll return 0 so that
}
{ it is processed right away. }
begin
{ move message in buffer to message queue }
PEventMsg(lParam)^ := MessageBuffer;
Result := 0 { process immediately }
end
else
{ if Code isn't HC_SKIP or HC_GETNEXT, call next hook in chain }

Result := CallNextHookEx(HookHandle, Code, wParam, lParam);
end;
end;

procedure StartPlayback;
{ Initializes globals and sets the hook }
begin
{ grab first message from list and place in buffer in case we }
{ get a hc_GetNext before and hc_Skip }
MessageBuffer := TEventMsg(MessageList.Items[0]^);
{ initialize message count and play indicator }
MsgCount := 0;
{ initialize Alt, Control, and Shift key flags }
AltPressed := False;
ControlPressed := False;
ShiftPressed := False;
{ set the hook! }
HookHandle := SetWindowsHookEx(wh_JournalPlayback, Play, hInstance,
0);
if HookHandle = 0 then
raise ESKSetHookError.Create('Failed to set hook');
Playing := True;
end;

procedure MakeMessage(vKey: byte; M: Cardinal);
{ procedure builds a TEventMsg record that emulates a keystroke and }

{ adds it to message list }
var
E: PEventMsg;
begin
New(E); // allocate a message record

with E^ do
begin
message := M; // set message field
paramL := vKey; // vk code in ParamL
paramH := MapVirtualKey(vKey, 0); // scan code in ParamH
time := GetTickCount; // set time
hwnd := 0; // ignored
end;
MessageList.Add(E);
end;

procedure KeyDown(vKey: byte);
{ Generates KeyDownMessage }
begin
{ don't generate a "sys" key if the control key is pressed }
{ (This is a Windows quirk) }
if AltPressed and (not ControlPressed) and (vKey in vkKeySet) then

MakeMessage(vKey, wm_SysKeyDown)
else
MakeMessage(vKey, wm_KeyDown);
end;

procedure KeyUp(vKey: byte);
{ Generates KeyUp message }
begin
{ don't generate a "sys" key if the control key is pressed }
{ (This is a Windows quirk) }
if AltPressed and (not ControlPressed) and (vKey in vkKeySet) then
MakeMessage(vKey, wm_SysKeyUp)
else
MakeMessage(vKey, wm_KeyUp);
end;

procedure SimKeyPresses(VKeyCode: Word);
{ This function simulates keypresses for the given key, taking into }

{ account the current state of Alt, Control, and Shift keys }
begin
{ press Alt key if flag has been set }
if AltPressed then
KeyDown(vk_Menu);
{ press Control key if flag has been set }
if ControlPressed then
KeyDown(vk_Control);
{ if shift is pressed, or shifted key and control is not pressed...
}
if (((Hi(VKeyCode) and 1) <> 0) and (not ControlPressed)) or
ShiftPressed then
KeyDown(vk_Shift); { ...press shift }
KeyDown(Lo(VKeyCode)); { press key down }
KeyUp(Lo(VKeyCode)); { release key }
{ if shift is pressed, or shifted key and control is not pressed...
}
if (((Hi(VKeyCode) and 1) <> 0) and (not ControlPressed)) or
ShiftPressed then
KeyUp(vk_Shift); { ...release shift }
{ if shift flag is set, reset flag }
if ShiftPressed then begin
ShiftPressed := False;
end;
{ Release Control key if flag has been set, reset flag }
if ControlPressed then begin
KeyUp(vk_Control);
ControlPressed := False;
end;
{ Release Alt key if flag has been set, reset flag }
if AltPressed then begin
KeyUp(vk_Menu);
AltPressed := False;
end;
end;

procedure ProcessKey(S: String);
{ This function parses each character in the string to create the }
{ message list }
var
KeyCode: word;
Key: byte;
index: integer;
Token: TKeyString;
begin
index := 1;
repeat
case S[index] of
KeyGroupOpen:
{ It's the beginning of a special token! }
begin
Token := '';
inc(index);
while S[index] <> KeyGroupClose do begin
{ add to Token until the end token symbol is encountered }

Token := Token + S[index];
inc(index);
{ check to make sure the token's not too long }
if (Length(Token) = 7) and (S[index] <> KeyGroupClose) the
n
raise ESKInvalidToken.Create('No closing brace');
end;
{ look for token in array, Key parameter will }
{ contain vk code if successful }
if not FindKeyInArray(Token, Key) then
raise ESKInvalidToken.Create('Invalid token');
{ simulate keypress sequence }
SimKeyPresses(MakeWord(Key, 0));
end;
AltKey: AltPressed := True; // set Alt flag
ControlKey: ControlPressed := True; // set Control flag
ShiftKey: ShiftPressed := True; // set Shift flag
else begin
{ A normal character was pressed }
{ convert character into a word where the high byte contains }

{ the shift state and the low byte contains the vk code }
KeyCode := vkKeyScan(S[index]);
{ simulate keypress sequence }
SimKeyPresses(KeyCode);
end;
end;
Inc(index);
until index > Length(S);
end;

procedure WaitForHook;
begin
repeat Application.ProcessMessages until not Playing;
end;

function SendKeys(S: String): TSendKeyError;
{ This is the one entry point. Based on the string passed in the S }

{ parameter, this function creates a list of keyup/keydown messages, }

{ sets a JournalPlayback hook, and replays the keystroke messages. }

begin
Result := sk_None; // assume success
try
if Playing then raise ESKAlreadyPlaying.Create('');
MessageList := TMessageList.Create; // create list of messages
ProcessKey(S); // create messages from strin
g
StartPlayback; // set hook and play back messa
ges
except
{ if an exception occurs, return an error code, and clean up }
on E:ESendKeyError do
begin
MessageList.Free;
if E is ESKSetHookError then
Result := sk_FailSetHook
else if E is ESKInvalidToken then
Result := sk_InvalidToken
else if E is ESKAlreadyPlaying then
Result := sk_AlreadyPlaying;
end
else
Result := sk_UnknownError; // Catch-all exception handler
end;
end;

end.
 
这个程序的功能可能不错,但没有必要的注释,这样很难共享。希望能见到大家共享的程序
 
用到了hook?能说明一下吗,谢谢
 
这样说好了,比如我的程序myprog.exe要向Temp.exe发出<Ctrl + p>, 在myprog的代码中要如何实现,谢谢
 
没有人回文吗,帮帮忙啊
 
网上好多这样的代码!
 
Feizi,给一些例子吧谢谢,我找不到啊
 
看看下面这个例子.
---- 在windows Api中有一个函数RegisterHotKey用于设置敏感键,它的调用方式如下:

BOOL RegisterHotKey(
HWND hWnd, //响应该敏感键的窗口句柄
Int id, //该敏感键的唯一标示符
UINT fsModifiers, //该敏感键的辅助按键
UINT vk //该敏感键的键值
);
 

---- 其中敏感键的唯一标示符在Window中规定应用程序的取值范围为0x0000到0xBFFF之间,动态链接库的取值范围为0xC000到0xFFFF之间。为了保证其唯一性建议使用GlobalAddAtom函数来设置敏感键的唯一标示符。需要注意的是GlobalAddAtom还回的值是在0xC000到0xFFFF范围之间,为满足RegisterHotKey的调用要求,如果是在应用程序中设置敏感键可以利用GlobalAddAtom还回值减去0xC000。

---- 敏感键的辅助按键包括Mod_Ctrl 、Mod_Alt、Mod_Shift,对于Windows兼容键盘还支持Windows键,即其键面上有Windows标志的那个键,其值为Mod_win。

---- 在Delphi中建立一个“New Application”,在Tform1中的Private段中加入如下代码

private
{ Private declarations }
hotkeyid :integer;
procedure WMhotkeyhandle(var msg:Tmessage);
message wm_hotkey; //响应敏感键按键消息
在FormCreate事件中加入如下代码

hotkeyid:=GlobalAddAtom(pchar
(“UserDefineHotKey”))-$C000;
//减去$C000是为了保证取值范围的限制
registerhotkey(handle,hotkeyid,
MOD_CONTROL or mod_Altt,$41);
//敏感键为ctrl+Alt+A

 

二、敏感键的响应

---- 一旦敏感键设置成功,在程序应用过程中如果有相应敏感键被按下,Windows系统都会给你的应用程序发送一个消息WM_HOTKEY,不管你的应用程序是否为当前活动的。其中WM_HOTKEY消息的格式为:

idHotKey = (int) wParam;
// 该参数在设置系统级的敏感键有用,一般不予使用
fuModifiers = (UINT) LOWORD(lParam);
//敏感键的辅助按键
uVirtKey = (UINT) HIWORD(lParam);
//敏感键的键值
 

---- 因为Windows系统只是把一个WM_HotKey的消息发送给应用程序,要完成具体的事情需要一个消息处理程序,也就是上面Private段里的procedure WMhotkeyhandle(var msg:Tmessage); message wm_hotkey; 过程, 它的代码如下(这里只是简单地把窗口最前面显示)

procedure TForm1.Wmhotkeyhandle
(var msg:Tmessage);
begin
if (msg.LParamHi=$41) and
(msg.lparamLo=MOD_CONTROL or mod_Alt) then
begin
msg.Result:=1; //该消息已经处理
application.BringToFront;
//把窗口最前面显示
end;
end;
 

三、敏感键的释放

---- 在应用程序退出来之前应当把你所设置的敏感键释放掉,以释放其所占有的系统资源,这里需要调用两个Windows API函数UNREGISTERHOTKEY,它的调用格式如下:

BOOL UNREGISTERHOTKEY(
HWND HWND, //与敏感键关联的窗口句柄
INT ID //敏感键的标示符
);
也就是说只要在FormClose事件中加入如下代码

unregisterhotkey(handle,hotkeyid);
DeleteAtom(HotKeyID);

 

---- 到这里为止,你应当对敏感键技术有了全面的了解, 以上的例子相当简单同时也没有提供必要的调用成功检测,可以根据具体情况加以完善,希望对你的开发过程会有所帮助.
 
后退
顶部