Background:
I am simulating keystrokes using the unmanaged function SendInput (https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx). There are 3 ways to call this function:
- Specify a keyboard scancode
- Specify a character unicode
- Specify a virtual key code
All work, but to be able to simulate shortcuts such as CTRL+P I want to use the virtual key code. I currently have a manual mapping of character to virtual key code, but this is not a good approach as it is not sensitive to the user's OS keyboard layout. For example on an English (UK) keyboard the "." character can be mapped to VirtualKeyCode.OEM_PERIOD, but if the OS keyboard layout is French then "." is VirtualKeyCode.OEM_PERIOD + SHIFT.
To make my code more robust I want to call the method VkKeyScan (https://msdn.microsoft.com/en-us/library/windows/desktop/ms646329(v=vs.85).aspx) passing in a character to get the virtual key code (plus shift/ctrl/alt). This approach, in theory, takes care of everything.
The problem:
Declaration:
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern short VkKeyScan(char ch);
Usage:
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);
}
With an OS keyboard layout of English (UK) I am seeing the following results:
- 'e' => virtual key code 69
- 'E' => virtual key code 69+shift
- 'é' => virtual key code 69
N.B. 69 is 0x45 in HEX, which corresponds to the 'E' key in virtual key code lists such as this http://www.kbdedit.com/manual/low_level_vk_list.html
How can 'e' and 'é' both produce the same virtual key code? 'é' on an English (UK) keyboard is output by pressing 'e'+ctrl+alt or 'e'+altgr.
Theories:
- My code is wrong and I am not extracting the ctrl and alt bits correctly.
- VkScanKey doesn't work as I expect it to and is not capable of returning things like 'é' as 'e'+ctrl+alt (although the MSDN documentation suggests that it can).
- Something else.
It looks like theory 1 - that I wasn't extracting the modifier bits correctly. This code works:
var vkKeyScan = PInvoke.VkKeyScan(character);
var vkCode = vkKeyScan & 0xff;
var shift = (vkKeyScan & 0x100) > 0;
var ctrl = (vkKeyScan & 0x200) > 0;
var alt = (vkKeyScan & 0x400) > 0;
So the problem was either something to do with the operator ordering (i.e. the & may have been taking priority over the >> (bit shift)), although I don't think so as I did try with brackets around the bit shift, OR the shift itself wasn't working as expected.
Here is the commit with working code if you're interested: https://github.com/JuliusSweetland/OptiKey/commit/0e61c52371638c61e0ef05834cd31a363181ea0d
来源:https://stackoverflow.com/questions/33523071/vkkeyscan-returning-same-code-without-modifiers-for-accented-and-unaccented-lett