要了解您问题的答案,我们需要首先了解键盘输入的工作原理。
微软有一个完整的章节来讨论这个问题:
- https://learn.microsoft.com/en-gb/windows/win32/inputdev/about-keyboard-input https://learn.microsoft.com/en-gb/windows/win32/inputdev/about-keyboard-input
当按下某个键时keyboard https://en.wikipedia.org/wiki/Computer_keyboard#Control_processor, a 扫码 https://en.wikipedia.org/wiki/Scancode被生成。扫描码取决于设备。
Next:
键盘设备驱动程序接收来自键盘的扫描码
并将它们变成虚拟按键:
由系统定义的与设备无关的值,用于标识密钥的用途。
虚拟键代表键盘上的按键,而不是它们可以代表什么字符。所以,例如3
是一个虚拟键,但它的值被移动了(£
就我而言),不是,并且取决于所使用的键盘。
它们存储在设备相关的 KeyboardLayout 中。基本的函数调用如MapVirualKey
使用默认键盘布局(即您现在使用的键盘布局)。如果您想使用不同的布局,可以通过调用以下方式获取列表:
GetKeyboardLayoutList https://learn.microsoft.com/en-gb/windows/win32/api/winuser/nf-winuser-getkeyboardlayoutlist
因此,虚拟键和任何修饰符都会发送到键盘布局,并返回适当的字符,然后将其渲染到屏幕上,等等......
所以你的问题变成了,“我们如何找到 myKey + shift 的 Unicode/ASCII 值?”。没有任何特别简单的答案,例如在我的计算机上“shift 3 (£)”的 ASCII 值为 163,但“shift 4 ($)”的 ASCII 值为 36!
这些示例使用 Excel,而不是 Powerpoint。
让我们看看映射虚拟密钥` https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeya第一的。我没有使用过通用的键盘布局。
在模块中,添加以下声明:
' https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeya
Public Declare PtrSafe Function MapVirtualKeyA Lib "user32" ( _
ByVal uCode As Long, _
ByVal uMapType As Long) As Integer
并将以下子例程添加到 Button1:
Sub Button1_Click()
Cells.Clear
' MapVirtualKeyA
Cells(1, 1) = "MapVirtualKeyA"
Cells(1, 1).Font.Bold = 1
char = "3"
Cells(2, 1) = "char: " & char
Cells(2, 2) = MapVirtualKeyA(Asc(char), 2)
Cells(2, 3) = Chr(MapVirtualKeyA(Asc(char), 2))
char = "£"
Cells(3, 1) = "char: " & char
Cells(3, 2) = MapVirtualKeyA(Asc(char), 2)
Cells(3, 3) = Chr(MapVirtualKeyA(Asc(char), 2)) ' doesn't exist
第一次通话正常,第二次无法识别£
作为虚拟键(它不是),所以返回0
.
因此,这对于确定“shift 3”应该返回什么没有多大用处。
我们可以从中检索“shift”状态£
,通过使用VkKeyScan
API函数。
在模块中声明该函数:
' https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-vkkeyscana
Public Declare Function VkKeyScan Lib "user32" Alias "VkKeyScanA" ( _
ByVal cChar As Byte) As Integer
并将此代码添加到按钮:
'VkKeyScan
Cells(5, 1) = "VkKeyScan"
Cells(5, 1).Font.Bold = 1
char = "3"
keyScan = VkKeyScan(Asc(char))
shift = keyScan And &H100
ctrl = keyScan And &H200
vkKey = keyScan And &HFF
Cells(6, 1) = "char: " & char
Cells(6, 2) = "shift: " & shift
Cells(6, 3) = "ctrl: " & ctrl
Cells(6, 4) = keyScan
Cells(6, 5) = ChrW(keyScan)
Cells(6, 6) = vkKey
Cells(6, 7) = Chr(vkKey)
char = "£"
keyScan = VkKeyScan(Asc(char))
shift = keyScan And &H100
ctrl = keyScan And &H200
vkKey = keyScan And &HFF
Cells(7, 1) = "char: " & char
Cells(7, 2) = "shift: " & shift
Cells(7, 3) = "ctrl: " & ctrl
Cells(7, 4) = keyScan
Cells(7, 5) = ChrW(keyScan) ' wrong character
Cells(7, 6) = vkKey
Cells(7, 7) = Chr(vkKey)
这提供了更多信息,但仍然没有给我们答案。
这里有两种解决方案,两者几乎相同:
- 发送输入 https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput
- SendKeys https://learn.microsoft.com/en-us/office/vba/Language/Reference/user-interface-help/sendkeys-statement
SendInput
是官方的 Win32API 处理方式,但涉及相当长的代码,并且由 VBA 整齐地包装起来SendKeys
功能。
SendKeys
将文本输出发送到当前活动的光标。
Cells(10, 1).Select
SendKeys ("3+3~")
While Cells(10, 1) = ""
DoEvents
Wend
Cells(10, 2) = Asc(Mid(Cells(10, 1), 1, 1))
Cells(10, 3) = Asc(Mid(Cells(10, 1), 2, 1))
End Sub
Cells(10, 1).Select
将光标放在我们想要的位置。
+
用于模拟“移位”,并且~
模拟“输入”。
等待处理器赶上......,我们就得到了“£”的 ASCII 值!