Author: Jonas Bilinkevicius
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.
1 {
2 Procedure PostKeyEx
3
4 Parameters:
5
6 hWindow:
7 Target window to be send the keystroke
8 key:
9 Virtual keycode of the key to send. For printable keys this is simply the ANSI code
10 (Ord(character)).
11 shift:
12 State of the modifier keys. This is a set, so you can set several of these keys
13 (shift, control, alt, mouse buttons) in tandem. The TShiftState type is declared in
14 the Classes Unit.
15 specialkey:
16 Normally this should be False. Set it to True to specify a key on the numeric
17 keypad, for example.
18 If this parameter is true, bit 24 of the lparam for the posted WM_KEY* messages
19 will be set.
20
21 Description:
22
23 This procedure sets up Windows key state array to correctly reflect the requested
24 pattern of modifier keys and then posts a WM_KEYDOWN/WM_KEYUP message pair to the
25 target window. Then Application.ProcessMessages is called to process the messages
26 before the keyboard state is restored.
27
28 Error Conditions:
29
30 May fail due to lack of memory for the two key state buffers. Will raise an
31 exception in this case.
32
33 Note:
34
35 Setting the keyboard state will not work across applications running in different
36 memory spaces on Win32 unless AttachThreadInput is used to connect to the target
37 thread first.
38
39 Created:
40
41 02/21/96 16:39:00 by Peter Below
42 }
43
44 procedure PostKeyEx(hWindow: HWnd; key: Word; const shift: TShiftState; specialkey:
45 Boolean);
46 type
47 TBuffers = array[0..1] of TKeyboardState;
48 var
49 pKeyBuffers: ^TBuffers;
50 lparam: LongInt;
51 begin
52 {check if the target window exists}
53 if IsWindow(hWindow) then
54 begin
55 {set local variables to default values}
56 pKeyBuffers := nil;
57 lparam := MakeLong(0, MapVirtualKey(key, 0));
58 {modify lparam if special key requested}
59 if specialkey then
60 lparam := lparam or $1000000;
61 {allocate space for the key state buffers}
62 New(pKeyBuffers);
63 try
64 {Fill buffer 1 with current state so we can later restore it.
65 Null out buffer 0 to get a "no key pressed" state.}
66 GetKeyboardState(pKeyBuffers^[1]);
67 FillChar(pKeyBuffers^[0], Sizeof(TKeyboardState), 0);
68 {set the requested modifier keys to "down" state in the buffer}
69 if ssShift in Shift then
70 pKeyBuffers^[0][VK_SHIFT] := $80;
71 if ssAlt in Shift then
72 begin
73 {Alt needs special treatment since a bit in lparam needs also be set}
74 pKeyBuffers^[0][VK_MENU] := $80;
75 lparam := lparam or $20000000;
76 end;
77 if ssCtrl in Shift then
78 pKeyBuffers^[0][VK_CONTROL] := $80;
79 if ssLeft in Shift then
80 pKeyBuffers^[0][VK_LBUTTON] := $80;
81 if ssRight in Shift then
82 pKeyBuffers^[0][VK_RBUTTON] := $80;
83 if ssMiddle in Shift then
84 pKeyBuffers^[0][VK_MBUTTON] := $80;
85 {make out new key state array the active key state map}
86 SetKeyboardState(pKeyBuffers^[0]);
87 {post the key messages}
88 if ssAlt in Shift then
89 begin
90 PostMessage(hWindow, WM_SYSKEYDOWN, key, lparam);
91 PostMessage(hWindow, WM_SYSKEYUP, key, lparam or $C0000000);
92 end
93 else
94 begin
95 PostMessage(hWindow, WM_KEYDOWN, key, lparam);
96 PostMessage(hWindow, WM_KEYUP, key, lparam or $C0000000);
97 end;
98 {process the messages}
99 Application.ProcessMessages;
100 {restore the old key state map}
101 SetKeyboardState(pKeyBuffers^[1]);
102 finally
103 {free the memory for the key state buffers}
104 if pKeyBuffers < > nil then
105 Dispose(pKeyBuffers);
106 end;
107 end;
108 end;
109
110 procedure TForm1.SpeedButton2Click(Sender: TObject);
111 var
112 W: HWnd;
113 begin
114 W := Memo1.Handle;
115 PostKeyEx(W, VK_END, [ssCtrl, ssShift], False); {select all}
116 PostKeyEx(W, Ord('C'), [ssCtrl], False); {copy to clipboard}
117 PostKeyEx(W, Ord('C'), [ssShift], False); {replace with C}
118 PostKeyEx(W, VK_RETURN, [], False); {new line}
119 PostKeyEx(W, VK_END, [], False); {go to end}
120 PostKeyEx(W, Ord('V'), [ssCtrl], False); {paste from keyboard}
121 end;
|