#c #windows #input
#c #Windows #ввод
Вопрос:
Я пытаюсь реализовать ввод с клавиатуры на C, и я не понимаю, как захватить измененные коды клавиш и получить из него символ. Конечно, я могу создать огромный оператор switch, подобный этому:
// if (shift is pressed) {
switch (vkCode)
{
case 0x30:
log(")");
break;
case 0x31:
log("!");
break;
case 0x32:
//...
Это было бы нормально для одного языка, но реализация этого для разных раскладок клавиатуры была бы кошмаром.
Я нашел простой способ преобразовать виртуальную клавишу в символ, соответствующий активной раскладке клавиатуры:
HKL lang = GetLang();
UINT ck = MapVirtualKeyEx(vKey, MAPVK_VK_TO_CHAR, lang);
printf("%c", ck);
Есть ли способ получить измененный символ аналогичным образом?
Или как бы это сделать?
Комментарии:
1. Что именно вы подразумеваете под
"modified keycode"
and"modified char"
? Вы хотите сопоставить определенные виртуальные ключевые коды с определенными символами? Что не так с вашим решением использованияMapVirtualKeyEx
? Разве это не делает именно то, что вы хотите?2. @AndreasWenzel В основном MapVirtualKeyEx принимает виртуальный ключ и возвращает символ в зависимости от того, какая у вас раскладка клавиатуры. Но это может не учитываться, если вы удерживаете клавишу-модификатор нажатой, например, клавишу alt, для получения, скажем, «* «.
3. Вы говорите, что вам нужно нажать
"alt key"
, чтобы произвести*
? Вы имеете в видуSHIFT
ключ?4. @AndreasWenzel Да, извините 🙂
Ответ №1:
Если вы вызываете TranslateMessage
цикл сообщений, эта функция приведет к созданию дополнительного WM_CHAR
сообщения при получении WM_KEYDOWN
сообщения. Это WM_CHAR
сообщение будет содержать введенный символ с учетом того, нажата ли SHIFTклавиша. Например, если пользователь вводит a b
, удерживая SHIFTклавишу, то WM_CHAR
сообщение будет содержать код символа для a B
.
Как указано выше, TranslateMessage
сделает всю работу за вас. Если по какой-либо причине вы не хотите использовать эту функцию, вы можете попробовать использовать функции ToAscii
или ToUnicode
вместо этого. Но, как указано в документации, у этих функций есть недостаток, заключающийся в том, что они не могут правильно обрабатывать мертвые клавиши. Поэтому я рекомендую использовать TranslateMessage
.
Комментарии:
1. Хорошо, прямо сейчас я использую WndProc и WM_INPUT для получения необработанного ввода с клавиатуры, потому что я использую ввод клавиш и для простой игры. Есть ли способ вместо прослушивания WM_CHAR напрямую запрашивать WM_CHAR, когда я получаю сообщение WM_INPUT?
2. Я думаю, вы указали мне правильное направление. Я изучу функцию «ToUnicode».
3. @objectnabb: Я считаю, что для простой игры нет необходимости использовать необработанный ввод с клавиатуры. Должно быть проще использовать
WM_KEYDOWN
иWM_KEYUP
, хотя вам также может потребоваться обработатьWM_SYSKEYDOWN
иWM_SYSKEYUP
. ФункцияTranslateMessage
создаст дополнительноеWM_CHAR
сообщение. Если вам действительно нужен необработанный ввод с клавиатуры, я считаю, что его можно обрабатыватьWM_INPUT
в дополнение ко всем другим упомянутым сообщениям, но это может привести к беспорядку, и я сомневаюсь, что это будет лучшим решением.
Ответ №2:
Благодаря некоторым указателям Андреаса Венцеля в комментариях я понял, как добиться того, чего я хотел. В принципе, мы хотим использовать ToUnicodeEx
. В нем есть некоторые оговорки, и я бы рекомендовал ознакомиться с документацией.
Для идентификации языка ToUnicodeEx
требуется входной идентификатор локали (HKL), который можно получить с помощью функции GetKeyboardLayout .
На случай, если кто-то захочет сделать что-то подобное, я оставлю пример.
if(GetRawInputData((HRAWINPUT)lParam, RID_INPUT, buffer, amp;dwSize, sizeof(RAWINPUTHEADER)) == dwSize)
{
RAWINPUT* raw = (RAWINPUT*)buffer;
if (raw->header.dwType == RIM_TYPEKEYBOARD)
{
const RAWKEYBOARD rk = raw->data.keyboard;
USHORT MakeCode = rk.Message; // scanCode
USHORT Flags = rk.Flags;
USHORT VKey = rk.VKey; // virtual Key
UINT Message = rk.Message;
ULONG ExtraInf = rk.ExtraInformation;
if ((Flags amp; RI_KEY_BREAK) != 0)
break;
HKL lang = GetLang();
CHAR c[H_KEY_SIZE];
ZeroMemory(c, H_KEY_SIZE);
BYTE lpKeyState[256];
GetKeyboardState(lpKeyState);
WCHAR pwszBuff[12];
int res = ToUnicodeEx(VKey, MakeCode, lpKeyState, pwszBuff, 12, 0, lang);
if (res == 0)
{
// The specified virtual key has no translation for the current state of the keyboard.
// Nothing was written to the buffer specified by pwszBuff.
// Handle this if you want
}
strcat_s(c, H_KEY_SIZE, (CONST PCHAR)pwszBuff);
printf("output: %s ", c);
}
}