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

时间:2015-11-04 13:23:58

标签: c# globalization sendinput

背景

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

  1. 指定键盘扫描码
  2. 指定字符unicode
  3. 指定虚拟密钥代码
  4. 所有工作,但为了能够模拟CTRL + P等快捷方式我想使用虚拟键码。我目前手动将字符映射到虚拟键码,但这不是一个好方法,因为它对用户的OS键盘布局不敏感。例如,在英语(英国)键盘上的“。”字符可以映射到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);
    }
    

    使用英语(英国)的OS键盘布局,我看到以下结果:

    • 'e'=>虚拟密钥代码69
    • 'E'=>虚拟键码69 + shift
    • 'é'=>虚拟密钥代码69

    N.B。 69是HEX中的0x45,它对应于虚拟键码列表中的“E”键,例如此http://www.kbdedit.com/manual/low_level_vk_list.html

    'e'和'é'如何生成相同的虚拟密钥代码?通过按'e'+ ctrl + alt或'e'+ altgr输出英语(英国)键盘上的'é'。

    理论

    1. 我的代码错了,我没有正确提取ctrl和alt位。
    2. VkScanKey无法按预期工作,并且无法将“é”返回为“e”+ ctrl + alt(尽管MSDN文档表明它可以)。
    3. 别的。

1 个答案:

答案 0 :(得分:1)

看起来像理论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