How to send key events to any control in a process (Views: 29)
Problem/Question/Abstract: I want to create a software keyboard in one form. When I press a key on the sofware keyboard, I would like to send the key's char to any form in my application. Answer: The following method will send key events to any control in your own process. It will not work reliably for windows in other processes. { Procedure PostKeyEx Parameters: hWindow: Target window to be send the keystroke key: Virtual keycode of the key to send. For printable keys this is simply the ANSI code (Ord(character)). shift: State of the modifier keys. This is a set, so you can set several of these keys (shift, control, alt, mouse buttons) in tandem. The TShiftState type is declared in the Classes Unit. specialkey: Normally this should be False. Set it to True to specify a key on the numeric keypad, for example. If this parameter is true, bit 24 of the lparam for the posted WM_KEY* messages will be set. Description: This procedure sets up Windows key state array to correctly reflect the requested pattern of modifier keys and then posts a WM_KEYDOWN/WM_KEYUP message pair to the target window. Then Application.ProcessMessages is called to process the messages before the keyboard state is restored. Error Conditions: May fail due to lack of memory for the two key state buffers. Will raise an exception in this case. Note: Setting the keyboard state will not work across applications running in different memory spaces on Win32 unless AttachThreadInput is used to connect to the target thread first. Created: 02/21/96 16:39:00 by Peter Below } procedure PostKeyEx(hWindow: HWnd; key: Word; const shift: TShiftState; specialkey: Boolean); type TBuffers = array[0..1] of TKeyboardState; var pKeyBuffers: ^TBuffers; lparam: LongInt; begin {check if the target window exists} if IsWindow(hWindow) then begin {set local variables to default values} pKeyBuffers := nil; lparam := MakeLong(0, MapVirtualKey(key, 0)); {modify lparam if special key requested} if specialkey then lparam := lparam or $1000000; {allocate space for the key state buffers} New(pKeyBuffers); try {Fill buffer 1 with current state so we can later restore it. Null out buffer 0 to get a "no key pressed" state.} GetKeyboardState(pKeyBuffers^[1]); FillChar(pKeyBuffers^[0], Sizeof(TKeyboardState), 0); {set the requested modifier keys to "down" state in the buffer} if ssShift in Shift then pKeyBuffers^[0][VK_SHIFT] := $80; if ssAlt in Shift then begin {Alt needs special treatment since a bit in lparam needs also be set} pKeyBuffers^[0][VK_MENU] := $80; lparam := lparam or $20000000; end; if ssCtrl in Shift then pKeyBuffers^[0][VK_CONTROL] := $80; if ssLeft in Shift then pKeyBuffers^[0][VK_LBUTTON] := $80; if ssRight in Shift then pKeyBuffers^[0][VK_RBUTTON] := $80; if ssMiddle in Shift then pKeyBuffers^[0][VK_MBUTTON] := $80; {make out new key state array the active key state map} SetKeyboardState(pKeyBuffers^[0]); {post the key messages} if ssAlt in Shift then begin PostMessage(hWindow, WM_SYSKEYDOWN, key, lparam); PostMessage(hWindow, WM_SYSKEYUP, key, lparam or $C0000000); end else begin PostMessage(hWindow, WM_KEYDOWN, key, lparam); PostMessage(hWindow, WM_KEYUP, key, lparam or $C0000000); end; {process the messages} Application.ProcessMessages; {restore the old key state map} SetKeyboardState(pKeyBuffers^[1]); finally {free the memory for the key state buffers} if pKeyBuffers < > nil then Dispose(pKeyBuffers); end; end; end; procedure TForm1.SpeedButton2Click(Sender: TObject); var W: HWnd; begin W := Memo1.Handle; PostKeyEx(W, VK_END, [ssCtrl, ssShift], False); {select all} PostKeyEx(W, Ord('C'), [ssCtrl], False); {copy to clipboard} PostKeyEx(W, Ord('C'), [ssShift], False); {replace with C} PostKeyEx(W, VK_RETURN, [], False); {new line} PostKeyEx(W, VK_END, [], False); {go to end} PostKeyEx(W, Ord('V'), [ssCtrl], False); {paste from keyboard} end; |