Reputation: 3405
I am playing around with translating user's keystrokes between the different installed languages on their Windows machine. I found this article about virtual-key codes, and how they map to characters, and also this function to perform the mapping. But it doesn't seem to work like I expected it to.
This is my attempt at sending the virtual-key code of "A" (which is 0x41), and translating it to the character "ש" in the Hebrew keyboard (which is what pressing that key outputs to the screen, while the user is on the Hebrew keyboard layout). It still prints only "A", regardless of my current active layout.
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <tchar.h>
int main()
{
HKL lpList[2];
GetKeyboardLayoutList(2, lpList); // returns {0x04090409 , 0xf03d040d} on my machine, which is {en-US, he-IL}
HKL hkl = lpList[1]; // sets to he-IL
char ch = MapVirtualKeyEx(0x41, MAPVK_VK_TO_CHAR, hkl); //0x41 is the Virtual Key of the keyboard button 'A'
std::cout << "ch: " << ch << std::endl; //prints "ch: A", I want it to print "ch: ש"
}
What am I missing? Is there some other way to achieve what I am trying to do?
I just tried
UINT VKCode = LOBYTE(VkKeyScan('ש')); // returns 0xbf
UINT ScanCode = MapVirtualKeyEx(VKCode, MAPVK_VK_TO_VSC, hkl); // returns 0x35
UINT VKCode2 = MapVirtualKeyEx(ScanCode, MAPVK_VSC_TO_VK, hkl); // once again 0xbf - unsurprisingly
TCHAR ch = MapVirtualKeyEx(VKCode2, MAPVK_VK_TO_CHAR, hkl); // now it returns '.'
So I convert char -> vk -> sc -> vk -> char, and end up with a different character than the one I started with. Maybe there is a different way to convert a `virtual-key code* to char?
Upvotes: 0
Views: 3272
Reputation: 3890
You can use ToUnicodeEx
API.
And if you want to output characters correctly, you can refer to: How to print Latin characters to the C++ console properly on Windows?
I created a sample and used the following code:
int main()
{
SetConsoleOutputCP(1256);
_setmode(_fileno(stdout), _O_U16TEXT);
HKL lpList[2];
GetKeyboardLayoutList(2, lpList);
HKL hkl = lpList[1]; // sets to he-IL
UINT VKCode = (VkKeyScanExW(L'ש',hkl));
UINT ScanCode = MapVirtualKeyExW(VKCode, MAPVK_VK_TO_VSC, hkl);
UINT VKCode2 = MapVirtualKeyExW(ScanCode, MAPVK_VSC_TO_VK, hkl);
TCHAR ch1 = MapVirtualKeyExW(VKCode2, MAPVK_VK_TO_CHAR, hkl);
BYTE uKeyboardState[256];
WCHAR oBuffer[5] = {};
//Initialization of KeyBoardState
for (int i = 0; i < 256; ++i)
{
uKeyboardState[i] = 0;
}
TCHAR buffer[1024];
ToUnicodeEx(VKCode, ScanCode, uKeyboardState, buffer, 1024, 0, hkl);
wcout << buffer;
return 0;
}
And it works for me:
Upvotes: 1
Reputation: 1
According to the documentation pages (MapVirtualKeyExA function and MapVirtualKeyExW function) the function returns an UINT
and not a char
:
UINT MapVirtualKeyW( UINT uCode, UINT uMapType );
Depending on your projact settings you'll need to inerpret this result either as char
or as wchar_t
, that's the reason.
You can overcome this, if you use TCHAR ch = ...
, and let the project settings expand the TCHAR
macro to the correct type properly.
The harder part is to decide if you need to use std::cout
or std::wcout
(std::cout, std::wcout). You could use some type check (e.g. if(std::is_same(ch,wchar_t)) { ... } else { ... }
) to do this properly.
Upvotes: 0