-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathkeyboard_mouse.h
349 lines (309 loc) · 16.4 KB
/
keyboard_mouse.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/*
AutoHotkey
Copyright 2003-2008 Chris Mallett (support@autohotkey.com)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef keyboard_h
#define keyboard_h
#include "defines.h"
// The max number of keystrokes to Send prior to taking a break to pump messages:
#define MAX_LUMP_KEYS 50
// Logging keys to a file is disabled in the main version in an effort to prevent
// AutoHotkey from being branded as a key logger or trojan by various security firms and
// security software. Uncomment this line to re-enabled logging of keys to a file:
// #define ENABLE_KEY_HISTORY_FILE
// Maybe define more of these later, perhaps with ifndef (since they should be in the normal header, and probably
// will be eventually):
// ALREADY DEFINED: #define VK_HELP 0x2F
// In case a compiler with a non-updated header file is used:
#ifndef VK_BROWSER_BACK
#define VK_BROWSER_BACK 0xA6
#define VK_BROWSER_FORWARD 0xA7
#define VK_BROWSER_REFRESH 0xA8
#define VK_BROWSER_STOP 0xA9
#define VK_BROWSER_SEARCH 0xAA
#define VK_BROWSER_FAVORITES 0xAB
#define VK_BROWSER_HOME 0xAC
#define VK_VOLUME_MUTE 0xAD
#define VK_VOLUME_DOWN 0xAE
#define VK_VOLUME_UP 0xAF
#define VK_MEDIA_NEXT_TRACK 0xB0
#define VK_MEDIA_PREV_TRACK 0xB1
#define VK_MEDIA_STOP 0xB2
#define VK_MEDIA_PLAY_PAUSE 0xB3
#define VK_LAUNCH_MAIL 0xB4
#define VK_LAUNCH_MEDIA_SELECT 0xB5
#define VK_LAUNCH_APP1 0xB6
#define VK_LAUNCH_APP2 0xB7
#endif
// Create some "fake" virtual keys to simplify sections of the code.
// According to winuser.h, the following ranges (among others)
// are considered "unassigned" rather than "reserved", so should be
// fairly safe to use for the foreseeable future. 0xFF should probably
// be avoided since it's sometimes used as a failure indictor by API
// calls. And 0x00 should definitely be avoided because it is used
// to indicate failure by many functions that deal with virtual keys.
// 0x88 - 0x8F : unassigned
// 0x97 - 0x9F : unassigned (this range seems less likely to be used)
#define VK_NEW_MOUSE_FIRST 0x9C
#define VK_LBUTTON_LOGICAL 0x9C // v1.0.43: Added to support swapping of left/right mouse buttons in Control Panel.
#define VK_RBUTTON_LOGICAL 0x9D //
#define VK_WHEEL_DOWN 0x9E
#define VK_WHEEL_UP 0x9F
#define VK_NEW_MOUSE_LAST 0x9F
// These are the only keys for which another key with the same VK exists. Therefore, use scan code for these.
// If use VK for some of these (due to them being more likely to be used as hotkeys, thus minimizing the
// use of the keyboard hook), be sure to use SC for its counterpart.
// Always use the compressed version of scancode, i.e. 0x01 for the high-order byte rather than vs. 0xE0.
#define SC_NUMPADENTER 0x11C
#define SC_INSERT 0x152
#define SC_DELETE 0x153
#define SC_HOME 0x147
#define SC_END 0x14F
#define SC_UP 0x148
#define SC_DOWN 0x150
#define SC_LEFT 0x14B
#define SC_RIGHT 0x14D
#define SC_PGUP 0x149
#define SC_PGDN 0x151
// These are the same scan codes as their counterpart except the extended flag is 0 rather than
// 1 (0xE0 uncompressed):
#define SC_ENTER 0x1C
// In addition, the below dual-state numpad keys share the same scan code (but different vk's)
// regardless of the state of numlock:
#define SC_NUMPADDEL 0x53
#define SC_NUMPADINS 0x52
#define SC_NUMPADEND 0x4F
#define SC_NUMPADHOME 0x47
#define SC_NUMPADCLEAR 0x4C
#define SC_NUMPADUP 0x48
#define SC_NUMPADDOWN 0x50
#define SC_NUMPADLEFT 0x4B
#define SC_NUMPADRIGHT 0x4D
#define SC_NUMPADPGUP 0x49
#define SC_NUMPADPGDN 0x51
#define SC_NUMPADDOT SC_NUMPADDEL
#define SC_NUMPAD0 SC_NUMPADINS
#define SC_NUMPAD1 SC_NUMPADEND
#define SC_NUMPAD2 SC_NUMPADDOWN
#define SC_NUMPAD3 SC_NUMPADPGDN
#define SC_NUMPAD4 SC_NUMPADLEFT
#define SC_NUMPAD5 SC_NUMPADCLEAR
#define SC_NUMPAD6 SC_NUMPADRIGHT
#define SC_NUMPAD7 SC_NUMPADHOME
#define SC_NUMPAD8 SC_NUMPADUP
#define SC_NUMPAD9 SC_NUMPADPGUP
// These both have a unique vk and a unique sc (on most keyboards?), but they're listed here because
// MapVirtualKey doesn't support them under Win9x (except maybe NumLock itself):
#define SC_NUMLOCK 0x145
#define SC_NUMPADDIV 0x135
#define SC_NUMPADMULT 0x037
#define SC_NUMPADSUB 0x04A
#define SC_NUMPADADD 0x04E
// Note: A KeyboardProc() (hook) actually receives 0x36 for RSHIFT under both WinXP and Win98se, not 0x136.
// All the below have been verified to be accurate under Win98se and XP (except rctrl and ralt in XP).
#define SC_LCONTROL 0x01D
#define SC_RCONTROL 0x11D
#define SC_LSHIFT 0x02A
#define SC_RSHIFT 0x136 // Must be extended, at least on WinXP, or there will be problems, e.g. SetModifierLRState().
#define SC_LALT 0x038
#define SC_RALT 0x138
#define SC_LWIN 0x15B
#define SC_RWIN 0x15C
// UPDATE for v1.0.39: Changed sc_type to USHORT vs. UINT to save memory in structs such as sc_hotkey.
// This saves 60K of memory in one place, and possibly there are other large savings too.
// The following older comment dates back to 2003/inception and I don't remember its exact intent,
// but there is no current storage of mouse message constants in scan code variables:
// OLD: Although only need 9 bits for compressed and 16 for uncompressed scan code, use a full 32 bits
// so that mouse messages (WPARAM) can be stored as scan codes. Formerly USHORT (which is always 16-bit).
typedef USHORT sc_type; // Scan code.
typedef UCHAR vk_type; // Virtual key.
typedef UINT mod_type; // Standard Windows modifier type for storing MOD_CONTROL, MOD_WIN, MOD_ALT, MOD_SHIFT.
// The maximum number of virtual keys and scan codes that can ever exist.
// As of WinXP, these are absolute limits, except for scan codes for which there might conceivably
// be more if any non-standard keyboard or keyboard drivers generate scan codes that don't start
// with either 0x00 or 0xE0. UPDATE: Decided to allow all possible scancodes, rather than just 512,
// since a lookup array for the 16-bit scan code value will only consume 64K of RAM if the element
// size is one char. UPDATE: decided to go back to 512 scan codes, because WinAPI's KeyboardProc()
// itself can only handle that many (a 9-bit value). 254 is the largest valid vk, according to the
// WinAPI docs (I think 255 is value that is sometimes returned to indicate an invalid vk). But
// just in case something ever tries to access such arrays using the largest 8-bit value (255), add
// 1 to make it 0xFF, thus ensuring array indexes will always be in-bounds if they are 8-bit values.
#define VK_MAX 0xFF
#define SC_MAX 0x1FF
typedef UCHAR modLR_type; // Only the left-right win/alt/ctrl/shift rather than their generic counterparts.
#define MODLR_MAX 0xFF
#define MODLR_COUNT 8
#define MOD_LCONTROL 0x01
#define MOD_RCONTROL 0x02
#define MOD_LALT 0x04
#define MOD_RALT 0x08
#define MOD_LSHIFT 0x10
#define MOD_RSHIFT 0x20
#define MOD_LWIN 0x40
#define MOD_RWIN 0x80
struct CachedLayoutType
{
HKL hkl;
ResultType has_altgr;
};
struct key_to_vk_type // Map key names to virtual keys.
{
char *key_name;
vk_type vk;
};
struct key_to_sc_type // Map key names to scan codes.
{
char *key_name;
sc_type sc;
};
enum KeyStateTypes {KEYSTATE_LOGICAL, KEYSTATE_PHYSICAL, KEYSTATE_TOGGLE}; // For use with GetKeyJoyState(), etc.
enum KeyEventTypes {KEYDOWN, KEYUP, KEYDOWNANDUP};
/*
void SendKeys(char *aKeys, bool aSendRaw, SendModes aSendModeOrig, HWND aTargetWindow = NULL);
void SendKey(vk_type aVK, sc_type aSC, modLR_type aModifiersLR, modLR_type aModifiersLRPersistent
, int aRepeatCount, KeyEventTypes aEventType, modLR_type aKeyAsModifiersLR, HWND aTargetWindow
, int aX = COORD_UNSPECIFIED, int aY = COORD_UNSPECIFIED, bool aMoveOffset = false);
*/
// N11 sendahk to inject hotkeys into ahk from itself.
void SendKeys(char *aKeys, bool aSendRaw, SendModes aSendModeOrig, HWND aTargetWindow = NULL, unsigned int sendahk = 0);
void SendKey(vk_type aVK, sc_type aSC, modLR_type aModifiersLR, modLR_type aModifiersLRPersistent
, int aRepeatCount, KeyEventTypes aEventType, modLR_type aKeyAsModifiersLR, HWND aTargetWindow
, int aX = COORD_UNSPECIFIED, int aY = COORD_UNSPECIFIED, bool aMoveOffset = false, unsigned int sendahk = 0);
// N11
void SendKeySpecial(char aChar, int aRepeatCount);
void SendASC(char *aAscii);
struct PlaybackEvent
{
UINT message;
union
{
struct
{
sc_type sc; // Placed above vk for possibly better member stacking/alignment.
vk_type vk;
};
struct
{
// Screen coordinates, which can be negative. SHORT vs. INT is used because the likelihood
// have having a virtual display surface wider or taller than 32,767 seems too remote to
// justify increasing the struct size, which would impact the stack space and dynamic memory
// used by every script every time it uses the playback method to send keystrokes or clicks.
// Note: WM_LBUTTONDOWN uses WORDs vs. SHORTs, but they're not really comparable because
// journal playback/record both use screen coordinates but WM_LBUTTONDOWN et. al. use client
// coordinates.
SHORT x;
SHORT y;
};
DWORD time_to_wait; // This member is present only when message==0; otherwise, a struct is present.
};
};
LRESULT CALLBACK PlaybackProc(int aCode, WPARAM wParam, LPARAM lParam);
//#define JOURNAL_RECORD_MODE // Uncomment this line to debug/analyze via a crude journal record feature in place of SendPlay.
#ifdef JOURNAL_RECORD_MODE
LRESULT CALLBACK RecordProc(int aCode, WPARAM wParam, LPARAM lParam);
#endif
// Below uses a pseudo-random value. It's best that this be constant so that if multiple instances
// of the app are running, they will all ignore each other's keyboard & mouse events. Also, a value
// close to UINT_MAX might be a little better since it's might be less likely to be used as a pointer
// value by any apps that send keybd events whose ExtraInfo is really a pointer value:
#define KEY_IGNORE 0xFFC3D44F
#define KEY_PHYS_IGNORE (KEY_IGNORE - 1) // Same as above but marked as physical for other instances of the hook.
#define KEY_IGNORE_ALL_EXCEPT_MODIFIER (KEY_IGNORE - 2) // Non-physical and ignored only if it's not a modifier.
#define KEY_NOIGNORE (KEY_IGNORE - 3) // Non-physical and ignored only if it's not a modifier. // N11
// The default in the below is KEY_IGNORE_ALL_EXCEPT_MODIFIER, which causes standard calls to
// KeyEvent() to update g_modifiersLR_logical_non_ignored the same way it updates g_modifiersLR_logical.
// This is done because only the Send command has a realistic chance of interfering with (or being
// interfered with by) hook hotkeys (namely the modifiers used to decide whether to trigger them).
// There are two types of problems:
// 1) Hotkeys not firing due to Send having temporarily released one of that hotkey's modifiers that
// the user is still holding down. This causes the hotkey's suffix to flow through to the system,
// which is usually undesirable. This happens when the user is holding down a hotkey to auto-repeat
// it, and perhaps other times.
// 2) The wrong hotkey firing because Send has temporarily put a modifier into effect and (once again)
// the user is holding down the hotkey to auto-repeat it. If the Send's temp-down modifier happens
// to make the hotkey suffix match a different set of modifiers, the wrong hotkey would fire.
void KeyEvent(KeyEventTypes aEventType, vk_type aVK, sc_type aSC = 0, HWND aTargetWindow = NULL
, bool aDoKeyDelay = false, DWORD aExtraInfo = KEY_IGNORE_ALL_EXCEPT_MODIFIER);
ResultType PerformClick(char *aOptions);
void ParseClickOptions(char *aOptions, int &aX, int &aY, vk_type &aVK, KeyEventTypes &aEventType
, int &aRepeatCount, bool &aMoveOffset);
ResultType PerformMouse(ActionTypeType aActionType, char *aButton, char *aX1, char *aY1, char *aX2, char *aY2
, char *aSpeed, char *aOffsetMode, char *aRepeatCount = "", char *aDownUp = "");
void PerformMouseCommon(ActionTypeType aActionType, vk_type aVK, int aX1, int aY1, int aX2, int aY2
, int aRepeatCount, KeyEventTypes aEventType, int aSpeed, bool aMoveOffset);
void MouseClickDrag(vk_type aVK // Which button.
, int aX1, int aY1, int aX2, int aY2, int aSpeed, bool aMoveOffset);
void MouseClick(vk_type aVK // Which button.
, int aX, int aY, int aRepeatCount, int aSpeed, KeyEventTypes aEventType, bool aMoveOffset = false);
void MouseMove(int &aX, int &aY, DWORD &aEventFlags, int aSpeed, bool aMoveOffset);
void MouseEvent(DWORD aEventFlags, DWORD aData, DWORD aX = COORD_UNSPECIFIED, DWORD aY = COORD_UNSPECIFIED);
#define MSG_OFFSET_MOUSE_MOVE 0x80000000 // Bitwise flag, should be near/at high-order bit to avoid overlap messages.
void PutKeybdEventIntoArray(modLR_type aKeyAsModifiersLR, vk_type aVK, sc_type aSC, DWORD aEventFlags, DWORD aExtraInfo);
void PutMouseEventIntoArray(DWORD aEventFlags, DWORD aData, DWORD aX, DWORD aY);
ResultType ExpandEventArray();
void InitEventArray(void *aMem, UINT aMaxEvents, modLR_type aModifiersLR);
void SendEventArray(int &aFinalKeyDelay, modLR_type aModsDuringSend);
void CleanupEventArray(int aFinalKeyDelay);
EXTERN_G; // For the DoKeyDelay() prototype below.
extern SendModes sSendMode;
void DoKeyDelay(int aDelay = (sSendMode == SM_PLAY) ? g.KeyDelayPlay : g.KeyDelay);
void DoMouseDelay();
void UpdateKeyEventHistory(bool aKeyUp, vk_type aVK, sc_type aSC);
#define KEYEVENT_PHYS(event_type, vk, sc) KeyEvent(event_type, vk, sc, NULL, false, KEY_PHYS_IGNORE)
ToggleValueType ToggleKeyState(vk_type aVK, ToggleValueType aToggleValue);
void ToggleNumlockWin9x();
//void CapslockOffWin9x();
#define STD_MODS_TO_DISGUISE (MOD_LALT|MOD_RALT|MOD_LWIN|MOD_RWIN)
void SetModifierLRState(modLR_type aModifiersLRnew, modLR_type aModifiersLRnow, HWND aTargetWindow
, bool aDisguiseDownWinAlt, bool aDisguiseUpWinAlt, DWORD aExtraInfo = KEY_IGNORE_ALL_EXCEPT_MODIFIER);
modLR_type GetModifierLRState(bool aExplicitlyGet = false);
// The IsKeyDown9xNT() method is needed because GetKeyState() does not return the proper
// state under Win9x, at least for the modifier keys under certain conditions. The
// AutoIt3 author indicates that GetAsyncKeyState() is also unreliable and he uses
// this same method, so it seems best for now. Specify GetAsyncKeyState() first due
// to performance of short-circuit boolean. v1.0.42.01: Fixed to use 0x8000 vs. 0x80000000
// with GetAsyncKeyState (though luckily, because of the way a negative short gets promoted
// to a negative int, the old way of using 0x80000000 worked too).
#define IsKeyDown9xNT(vk) ( (GetAsyncKeyState(vk) & 0x8000) || ((GetKeyState(vk) & 0x8000)) )
#define IsKeyDown2kXP(vk) (GetKeyState(vk) & 0x8000)
#define IsKeyDownAsync(vk) (GetAsyncKeyState(vk) & 0x8000)
#define IsKeyToggledOn(vk) (GetKeyState(vk) & 0x01)
void AdjustKeyState(BYTE aKeyState[], modLR_type aModifiersLR);
modLR_type KeyToModifiersLR(vk_type aVK, sc_type aSC = 0, bool *pIsNeutral = NULL);
modLR_type ConvertModifiers(mod_type aModifiers);
mod_type ConvertModifiersLR(modLR_type aModifiersLR);
char *ModifiersLRToText(modLR_type aModifiersLR, char *aBuf);
#define LAYOUT_UNDETERMINED FAIL
bool ActiveWindowLayoutHasAltGr();
ResultType LayoutHasAltGr(HKL aLayout, ResultType aHasAltGr = LAYOUT_UNDETERMINED);
//---------------------------------------------------------------------
extern HKL g_HKL; // ahkx
char *SCtoKeyName(sc_type aSC, char *aBuf, int aBufSize);
char *VKtoKeyName(vk_type aVK, sc_type aSC, char *aBuf, int aBufSize);
sc_type TextToSC(char *aText);
vk_type TextToVK(char *aText, modLR_type *pModifiersLR = NULL, bool aExcludeThoseHandledByScanCode = false
, bool aAllowExplicitVK = true, HKL aKeybdLayout = g_HKL);
vk_type CharToVKAndModifiers(char aChar, modLR_type *pModifiersLR, HKL aKeybdLayout);
vk_type TextToSpecial(char *aText, UINT aTextLength, KeyEventTypes &aEventTypem, modLR_type &aModifiersLR
, bool aUpdatePersistent);
#ifdef ENABLE_KEY_HISTORY_FILE
ResultType KeyHistoryToFile(char *aFilespec = NULL, char aType = '\0', bool aKeyUp = false
, vk_type aVK = 0, sc_type aSC = 0);
#endif
char *GetKeyName(vk_type aVK, sc_type aSC, char *aBuf, int aBufSize);
sc_type vk_to_sc(vk_type aVK, bool aReturnSecondary = false);
vk_type sc_to_vk(sc_type aSC);
inline bool IsMouseVK(vk_type aVK)
{
return aVK >= VK_LBUTTON && aVK <= VK_XBUTTON2 && aVK != VK_CANCEL
|| aVK >= VK_NEW_MOUSE_FIRST && aVK <= VK_NEW_MOUSE_LAST;
}
#endif