VkKeyScan返回相同的代码,不带重音和非重音字母的修饰符

本文关键字:返回 代码 VkKeyScan | 更新日期: 2023-09-27 18:20:34

背景:

我正在使用非托管函数SendInput模拟击键(https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx)。有3种方法可以调用此函数:

  1. 指定键盘扫描码
  2. 指定字符unicode
  3. 指定虚拟密钥代码

所有的工作,但为了能够模拟快捷键,如CTRL+p,我想使用虚拟键代码。我目前有一个从字符到虚拟键代码的手动映射,但这不是一个好方法,因为它对用户的操作系统键盘布局不敏感。例如,在英语(UK)键盘上,"."字符可以映射到VirtualKeyCode.OEM_PERIOD,但如果操作系统键盘布局为法语,则"."为VirtualKeyCode.OEM_PERIOD+SHIFT。

为了使我的代码更加健壮,我想调用方法VkKeyScan(https://msdn.microsoft.com/en-us/library/windows/desktop/ms646329(v=vs.85).aspx)传入一个字符以获得虚拟密钥代码(加上shift/ctrl/alt)。从理论上讲,这种方法可以解决所有问题。

问题:

声明:

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern short VkKeyScan(char ch);

用法:

var vkKeyScanResult = PInvoke.VkKeyScan(character);
var vk = vkKeyScanResult & 0xff;
var shift = (vkKeyScanResult >> 8 & 1) == 1;
var ctrl = (vkKeyScanResult >> 8 & 2) == 1;
var alt = (vkKeyScanResult >> 8 & 4) == 1;
if (vk != -1)
{
  Log.InfoFormat("'{0}' => virtual key code {1}{2}{3}{4}", 
      character, vk, shift ? "+shift" : null, ctrl ? "+ctrl" : null, alt ? "+alt" : null);
}

使用英语(英国)的操作系统键盘布局,我看到了以下结果:

  • 'e'=>虚拟密钥代码69
  • "E"=>虚拟钥匙代码69+移位
  • "é"=>虚拟密钥代码69

N.B.69在HEX中是0x45,它对应于虚拟密钥代码列表中的"E"密钥,例如http://www.kbdedit.com/manual/low_level_vk_list.html

"e"answers"é"怎么能生成相同的虚拟密钥代码?"英语(英国)键盘上的"é"是通过按"e"+ctrl+alt或"e"+altgr输出的。

理论:

  1. 我的代码是错误的,我没有正确提取ctrl和alt位
  2. VkScanKey不能像我预期的那样工作,也不能将"é"作为"e"+ctrl+alt返回(尽管MSDN文档表明它可以)
  3. 还有别的

VkKeyScan返回相同的代码,不带重音和非重音字母的修饰符

这看起来像理论1——我没有正确提取修饰符位。此代码有效:

var vkKeyScan = PInvoke.VkKeyScan(character);
var vkCode = vkKeyScan & 0xff;
var shift = (vkKeyScan & 0x100) > 0;
var ctrl = (vkKeyScan & 0x200) > 0;
var alt = (vkKeyScan & 0x400) > 0;

因此,问题要么与运算符排序有关(即&可能优先于>>(位移位)),尽管我不这么认为,因为我确实尝试在位移位周围使用括号,要么移位本身没有按预期工作。

如果您感兴趣,下面是使用工作代码的提交:https://github.com/JuliusSweetland/OptiKey/commit/0e61c52371638c61e0ef05834cd31a363181ea0d