-
Notifications
You must be signed in to change notification settings - Fork 9
/
keyboard-locker.ahk
283 lines (233 loc) · 7.11 KB
/
keyboard-locker.ahk
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
#Persistent
#SingleInstance Ignore
#Include %A_ScriptDir%\Ini.ahk
#Include %A_ScriptDir%\Settings.ahk
FileInstall, unlocked.ico, %A_ScriptDir%\unlocked.ico, 0
FileInstall, locked.ico, %A_ScriptDir%\locked.ico, 0
settings := new Settings()
;(DO NOT CHANGE) tracks whether or not the keyboard is currently locked
locked := false
;create the tray icon and do initial setup
initialize()
;set up the keyboard shortcut to lock the keyboard
Hotkey, % settings.Shortcut(), ShortcutTriggered
;end execution here - the rest of the file is functions and callbacks
return
initialize()
{
;initialize the tray icon and menu
Menu, Tray, Icon, %A_ScriptDir%\unlocked.ico
Menu, Tray, NoStandard
Menu, Tray, Tip, % "Press " . settings.ShortcutHint() . " to lock your keyboard"
Menu, Tray, Add, Lock keyboard, ToggleKeyboard
Menu, Tray, Click, 1
Menu, Tray, Default, Lock keyboard
if (settings.HideTooltips()) {
Menu, Tray, add, Show tray notifications, ToggleTray
} else {
Menu, Tray, add, Hide tray notifications, ToggleTray
}
Menu, Tray, Add, Exit, Exit
if (settings.LockOnOpen()) {
LockKeyboard(true)
} else if (!settings.HideTooltips()) {
TrayTip,,% "Press " . settings.ShortcutHint() . " to lock your keyboard",10,1
}
}
;callback for when the keyboard shortcut is pressed
ShortcutTriggered:
;check if shortcut is disabled in settings
if (settings.DisableShortcut())
{
return
}
;if we're already locked, stop here
if (locked)
{
return
}
;wait for each shortcut key to be released, so they don't get "stuck"
for index, key in StrSplit(settings.ShortcutHint(), "+")
{
KeyWait, %key%
}
LockKeyboard(true)
return
;"Lock/Unlock keyboard" menu clicked
ToggleKeyboard()
{
global locked
if (locked) {
LockKeyboard(false)
} else {
LockKeyboard(true)
}
}
;"Hide/Show tray notifications" menu clicked
ToggleTray()
{
if (settings.HideTooltips()) {
settings.SetHideTooltips(false)
Menu, Tray, Rename, Show tray notifications, Hide tray notifications
} else {
settings.SetHideTooltips(true)
Menu, Tray, Rename, Hide tray notifications, Show tray notifications
}
}
;"Exit" menu clicked
Exit()
{
ExitApp
}
;Lock or unlock the keyboard
LockKeyboard(lock)
{
global locked
;handle pointing to the keyboard hook
static hHook = 0
;lock status already matches what we were asked to do, no action necessary
if ((hHook != 0) = lock) {
return
}
if (lock) {
;check that we didn't leave ourselves without a way to unlock again
if(settings.DisablePassword() && settings.LockMouse())
{
MsgBox, You have disabled password unlocking and enabled mouse locking, which will prevent you from unlocking your system. Please re-enable one or the other.
return
}
;change the tray icon to a lock
Menu, Tray, Icon, %A_ScriptDir%\locked.ico
;hint at the unlock password
Menu, Tray, Tip, % "Type """ . settings.Password() . """ to unlock your keyboard"
;update menu to unlock
Menu, Tray, Rename, Lock keyboard, Unlock keyboard
;lock the keyboard
hHook := DllCall("SetWindowsHookEx", "Ptr", WH_KEYBOARD_LL:=13, "Ptr", RegisterCallback("Hook_Keyboard","Fast"), "Uint", DllCall("GetModuleHandle", "Uint", 0, "Ptr"), "Uint", 0, "Ptr")
locked := true
;also lock the mouse, if configured to do so
if (settings.LockMouse()) {
Hotkey, LButton, doNothing
Hotkey, RButton, doNothing
Hotkey, MButton, doNothing
BlockInput, MouseMove
}
;remind user what the password is
if (!settings.HideTooltips()) {
TrayTip,,% "Your keyboard is now locked.`nType """ . settings.Password() . """ to unlock it.",10,1
}
} else {
;unlock the keyboard
DllCall("UnhookWindowsHookEx", "Ptr", hHook)
hHook := 0
locked := false
;also unlock the mouse, if configured to do so
if (settings.LockMouse()) {
Hotkey, LButton, Off
Hotkey, MButton, Off
Hotkey, RButton, Off
BlockInput, MouseMoveOff
}
;change tray icon back to unlocked
Menu, Tray, Icon, %A_ScriptDir%\unlocked.ico
;hint at the keyboard shortcut to lock again
Menu, Tray, Tip, % "Press " . settings.ShortcutHint() . " to lock your keyboard"
;update menu to lock
Menu, Tray, Rename, Unlock keyboard, Lock keyboard
;remind user what the keyboard shortcut to lock is
if (!settings.HideTooltips()) {
TrayTip,,% "Your keyboard is now unlocked.`nPress " . settings.ShortcutHint() . " to lock it again.",10,1
}
if(settings.CloseOnUnlock())
{
ExitApp
}
}
}
;Catch and discard keypresses when the keyboard is locked, and monitor for password inputs
Hook_Keyboard(nCode, wParam, lParam)
{
;track our position while correctly typing the password
static count = 0
;is this a keyUp event (or keyDown)
isKeyUp := NumGet(lParam+0, 8, "UInt") & 0x80
;get the scan code of the key pressed/released
gotScanCode := NumGet(lParam+0, 4, "UInt")
;track the left/right shift keys, to handle capitals and symbols in passwords, because getkeystate calls don't work with our method of locking the keyboard
;if you can figure out how to use a getkeystate call to check for shift, or you have a better way to handle upper case letters and symbols, let me know
static shifted = 0
if(gotScanCode = 0x2A || gotScanCode = 0x36) {
if(isKeyUp) {
shifted := 0
} else {
shifted := 1
}
return 1
}
;check password progress/completion
if (!settings.DisablePassword() && !isKeyUp) {
expectedCharacter := SubStr(settings.Password(), count+1, 1)
expectedScanCode := GetKeySC(expectedCharacter)
requiresShift := requiresShift(expectedCharacter)
;did they type the correct next password letter?
if(expectedScanCode == gotScanCode && requiresShift == shifted) {
count := count + 1
;password is complete!
if(count == StrLen(settings.Password())) {
count = 0
shifted = 0
LockKeyboard(false)
}
} else {
count = 0
}
}
return 1
}
;Determine if this character requires shift to be pressed (capital letter or symbol)
requiresShift(chr)
{
;upper case characters always require shift
if(isUpperCase(chr)) {
return true
}
;symbols that require shift
static symbols = ["~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "{", "}", "|", ":", """", "<", ">", "?"]
if(inArray(chr, symbols)) {
return true
}
;anything else is false
return false
}
;Is the string (or character) upper case
isUpperCase(str)
{
if str is upper
return true
else
return false
}
;Is the string (or character) lower case
isLowerCase(str)
{
if str is lower
return true
else
return false
}
;Check if the haystack array contains the needle
inArray(needle, haystack) {
;only accept objects and arrays
if(!IsObject(haystack) || haystack.Length() == 0) {
return false
}
for index, value in haystack {
if (value == needle) {
return index
}
}
return false
}
;this is used to block mouse input
doNothing:
return