-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathKeyState.bas
More file actions
287 lines (229 loc) · 8.53 KB
/
KeyState.bas
File metadata and controls
287 lines (229 loc) · 8.53 KB
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
Attribute VB_Name = "modKeyStates"
'Author: David Zimmer <dzzie@yahoo.com>
'AI: Claude.ai
'Site: http://sandsprite.com
'License: MIT
'---------------------------------------------------
'=========================================================================
' Keyboard and Win32 Helper Functions - Refactored
' Professional naming and cleaner implementation
'=========================================================================
Option Explicit
' Win32 API
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
' Win32 API for UTF-8 conversion
Declare Function MultiByteToWideChar Lib "kernel32" ( _
ByVal codePage As Long, _
ByVal dwFlags As Long, _
ByVal lpMultiByteStr As Long, _
ByVal cchMultiByte As Long, _
ByVal lpWideCharStr As Long, _
ByVal cchWideChar As Long) As Long
Declare Function WideCharToMultiByte Lib "kernel32" ( _
ByVal codePage As Long, _
ByVal dwFlags As Long, _
ByVal lpWideCharStr As Long, _
ByVal cchWideChar As Long, _
ByVal lpMultiByteStr As Long, _
ByVal cchMultiByte As Long, _
ByVal lpDefaultChar As Long, _
ByVal lpUsedDefaultChar As Long) As Long
Global Const CP_UTF8 As Long = 65001
' Virtual key codes
Private Const VK_SHIFT = &H10
Private Const VK_CONTROL = &H11
Private Const VK_MENU = &H12 ' ALT key
' Modifier key flags (matches Windows convention)
Public Enum ModifierKeys
MOD_NONE = 0
MOD_SHIFT = 1
MOD_ALT = 2
MOD_CONTROL = 4
MOD_SHIFT_CTRL = 5 ' Shift + Ctrl
MOD_SHIFT_ALT = 3 ' Shift + Alt
MOD_CTRL_ALT = 6 ' Ctrl + Alt
MOD_ALL = 7 ' Shift + Ctrl + Alt
End Enum
'=========================================================================
' UTF-8 Conversion Helpers
'=========================================================================
' Convert UTF-8 byte array to VB6 Unicode string
Function UTF8BytesToString(ByRef bytes() As Byte, ByVal byteCount As Long) As String
Dim wideChars As Long
Dim result As String
If byteCount = 0 Then
UTF8BytesToString = ""
Exit Function
End If
' Get required buffer size for wide chars
wideChars = MultiByteToWideChar(CP_UTF8, 0, VarPtr(bytes(0)), byteCount, 0, 0)
If wideChars = 0 Then
' Conversion failed - return empty string
UTF8BytesToString = ""
Exit Function
End If
' Allocate string buffer
result = String$(wideChars, 0)
' Convert UTF-8 to Unicode
wideChars = MultiByteToWideChar(CP_UTF8, 0, VarPtr(bytes(0)), byteCount, StrPtr(result), wideChars)
UTF8BytesToString = result
End Function
' Convert VB6 Unicode string to UTF-8 byte array
Function StringToUTF8Bytes(ByVal str As String) As Byte()
Dim utf8Len As Long
Dim result() As Byte
If Len(str) = 0 Then
ReDim result(0 To 0)
result(0) = 0 ' Null terminator
StringToUTF8Bytes = result
Exit Function
End If
' Get required buffer size for UTF-8
utf8Len = WideCharToMultiByte(CP_UTF8, 0, StrPtr(str), Len(str), 0, 0, 0, 0)
If utf8Len = 0 Then
ReDim result(0 To 0)
result(0) = 0
StringToUTF8Bytes = result
Exit Function
End If
' Allocate byte buffer (with null terminator)
ReDim result(0 To utf8Len) As Byte
' Convert to UTF-8
utf8Len = WideCharToMultiByte(CP_UTF8, 0, StrPtr(str), Len(str), VarPtr(result(0)), utf8Len, 0, 0)
result(utf8Len) = 0 ' Add null terminator
StringToUTF8Bytes = result
End Function
'=========================================================================
' Keyboard State Functions
'=========================================================================
' Get current modifier key state as a bitmask
' Returns: Combination of MOD_SHIFT (1), MOD_ALT (2), MOD_CONTROL (4)
Public Function GetModifierState() As Long
Dim modifiers As Long
modifiers = 0
If IsKeyPressed(VK_SHIFT) Then
modifiers = modifiers Or MOD_SHIFT
End If
If IsKeyPressed(VK_MENU) Then ' ALT key
modifiers = modifiers Or MOD_ALT
End If
If IsKeyPressed(VK_CONTROL) Then
modifiers = modifiers Or MOD_CONTROL
End If
GetModifierState = modifiers
End Function
' Check if a specific key is currently pressed
' Uses GetAsyncKeyState to check real-time key state
Public Function IsKeyPressed(ByVal virtualKeyCode As Long) As Boolean
Dim keyState As Integer
keyState = GetAsyncKeyState(virtualKeyCode)
' High-order bit set means key is currently pressed
IsKeyPressed = (keyState And &H8000&) <> 0
End Function
' Check if ONLY a specific modifier is pressed (no others)
Public Function IsModifierOnly(ByVal modifier As ModifierKeys) As Boolean
IsModifierOnly = (GetModifierState() = modifier)
End Function
' Check if a specific modifier is pressed (possibly with others)
Public Function IsModifierPressed(ByVal modifier As ModifierKeys) As Boolean
IsModifierPressed = (GetModifierState() And modifier) <> 0
End Function
'=========================================================================
' Convenience Functions for Common Key Combinations
'=========================================================================
Public Function IsCtrlPressed() As Boolean
IsCtrlPressed = IsKeyPressed(VK_CONTROL)
End Function
Public Function IsShiftPressed() As Boolean
IsShiftPressed = IsKeyPressed(VK_SHIFT)
End Function
Public Function IsAltPressed() As Boolean
IsAltPressed = IsKeyPressed(VK_MENU)
End Function
' Check for specific combinations
Public Function IsCtrlShiftPressed() As Boolean
IsCtrlShiftPressed = IsModifierOnly(MOD_SHIFT_CTRL)
End Function
Public Function IsCtrlOnly() As Boolean
IsCtrlOnly = IsModifierOnly(MOD_CONTROL)
End Function
Public Function IsShiftOnly() As Boolean
IsShiftOnly = IsModifierOnly(MOD_SHIFT)
End Function
'=========================================================================
' Win32 LPARAM/WPARAM Helper Functions
'=========================================================================
' Extract high and low words from a Long value
' Used for parsing Win32 message parameters
Public Sub SplitLong(ByVal value As Long, ByRef hiWord As Long, ByRef loWord As Long)
' Extract high word (upper 16 bits)
hiWord = (value And &HFFFF0000) \ &H10000
' Extract low word (lower 16 bits)
loWord = value And &HFFFF&
' Handle sign extension for negative low word
If loWord And &H8000& Then
loWord = loWord Or &HFFFF0000
End If
End Sub
' Alternative: Return as separate values
Public Function GetHiWord(ByVal value As Long) As Long
GetHiWord = (value And &HFFFF0000) \ &H10000
End Function
Public Function GetLoWord(ByVal value As Long) As Long
GetLoWord = value And &HFFFF&
If GetLoWord And &H8000& Then
GetLoWord = GetLoWord Or &HFFFF0000
End If
End Function
' Create a Long from two Words (useful for constructing lParam/wParam)
Public Function MakeLong(ByVal loWord As Integer, ByVal hiWord As Integer) As Long
MakeLong = (CLng(hiWord) * &H10000) Or (loWord And &HFFFF&)
End Function
'=========================================================================
' Usage Examples
'=========================================================================
' Example 1: Check for Ctrl+Space in WM_CHAR handler
' Old way:
' If wParam = 32 And piGetShiftState = 4 Then
'
' New way:
' If wParam = 32 And IsCtrlOnly() Then
' Example 2: Check for Ctrl+Shift+S
' Old way:
' If piGetShiftState = 5 Then ' 1 (shift) + 4 (ctrl)
'
' New way:
' If IsModifierOnly(MOD_SHIFT_CTRL) Then
' Or: If IsCtrlShiftPressed() Then
' Example 3: Check if Ctrl is pressed (regardless of other modifiers)
' Old way:
' If (piGetShiftState And 4) Then
'
' New way:
' If IsCtrlPressed() Then
' Or: If IsModifierPressed(MOD_CONTROL) Then
' Example 4: Parse mouse coordinates from lParam
' Old way:
' pGetHiWordLoWord lParam, y, x
'
' New way:
' SplitLong lParam, y, x
' Or: x = GetLoWord(lParam): y = GetHiWord(lParam)
' Example 5: In your Scintilla subclass handler
' Case WM_CHAR
' If wParam = 32 And IsCtrlOnly() Then
' ' Ctrl+Space pressed
' bHandled = True
' lReturn = 0
' RaiseEvent AutoCompleteEvent(Helper.WordAtCaret())
' End If
'
' Case WM_KEYDOWN
' Select Case wParam
' Case vbKeyS
' If IsCtrlOnly() Then
' ' Ctrl+S - Save
' ElseIf IsCtrlShiftPressed() Then
' ' Ctrl+Shift+S - Save As
' End If
' End Select