/********************************************************************** * VkKeyScanA (USER32.@) * * VkKeyScan translates an ANSI character to a virtual-key and shift code * for the current keyboard. * high-order byte yields : * 0 Unshifted * 1 Shift * 2 Ctrl * 3-5 Shift-key combinations that are not used for characters * 6 Ctrl-Alt * 7 Ctrl-Alt-Shift * I.e. : Shift = 1, Ctrl = 2, Alt = 4. * FIXME : works ok except for dead chars : * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00 * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00 */ SHORT WINAPI VkKeyScanA(CHAR cChar) { WCHAR wChar; if (IsDBCSLeadByte(cChar)) return -1; MultiByteToWideChar(CP_ACP, 0, &cChar, 1, &wChar, 1); return VkKeyScanW(wChar); }
/* * @implemented */ DWORD WINAPI OemKeyScan(WORD wOemChar) { WCHAR p; SHORT Vk; UINT Scan; MultiByteToWideChar(CP_OEMCP, 0, (PCSTR)&wOemChar, 1, &p, 1); Vk = VkKeyScanW(p); Scan = MapVirtualKeyW((Vk & 0x00ff), 0); if (!Scan) return -1; /* Page 450-1, MS W2k SuperBible by SAMS. Return, low word has the scan code and high word has the shift state. */ return ((Vk & 0xff00) << 8) | Scan; }
VOID GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer, PGUI_CONSOLE_DATA GuiData) { /* * This function supposes that the system clipboard was opened. */ PCONSRV_CONSOLE Console = Buffer->Header.Console; HANDLE hData; LPWSTR str; WCHAR CurChar = 0; USHORT VkKey; // MAKEWORD(low = vkey_code, high = shift_state); INPUT_RECORD er; hData = GetClipboardData(CF_UNICODETEXT); if (hData == NULL) return; str = GlobalLock(hData); if (str == NULL) return; DPRINT("Got data <%S> from clipboard\n", str); er.EventType = KEY_EVENT; er.Event.KeyEvent.wRepeatCount = 1; while (*str) { /* \r or \n characters. Go to the line only if we get "\r\n" sequence. */ if (CurChar == L'\r' && *str == L'\n') { str++; continue; } CurChar = *str++; /* Get the key code (+ shift state) corresponding to the character */ VkKey = VkKeyScanW(CurChar); if (VkKey == 0xFFFF) { DPRINT1("FIXME: TODO: VkKeyScanW failed - Should simulate the key!\n"); /* * We don't really need the scan/key code because we actually only * use the UnicodeChar for output purposes. It may pose few problems * later on but it's not of big importance. One trick would be to * convert the character to OEM / multibyte and use MapVirtualKey * on each byte (simulating an Alt-0xxx OEM keyboard press). */ } /* Pressing some control keys */ /* Pressing the character key, with the control keys maintained pressed */ er.Event.KeyEvent.bKeyDown = TRUE; er.Event.KeyEvent.wVirtualKeyCode = LOBYTE(VkKey); er.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(LOBYTE(VkKey), MAPVK_VK_TO_VSC); er.Event.KeyEvent.uChar.UnicodeChar = CurChar; er.Event.KeyEvent.dwControlKeyState = 0; if (HIBYTE(VkKey) & 1) er.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; if (HIBYTE(VkKey) & 2) er.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; // RIGHT_CTRL_PRESSED; if (HIBYTE(VkKey) & 4) er.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; // RIGHT_ALT_PRESSED; ConioProcessInputEvent(Console, &er); /* Up all the character and control keys */ er.Event.KeyEvent.bKeyDown = FALSE; ConioProcessInputEvent(Console, &er); } GlobalUnlock(hData); }
VOID GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer, PGUI_CONSOLE_DATA GuiData) { /* * This function supposes that the system clipboard was opened. */ PCONSRV_CONSOLE Console = Buffer->Header.Console; HANDLE hData; LPWSTR str; WCHAR CurChar = 0; USHORT VkKey; // MAKEWORD(low = vkey_code, high = shift_state); INPUT_RECORD er; hData = GetClipboardData(CF_UNICODETEXT); if (hData == NULL) return; str = GlobalLock(hData); if (str == NULL) return; DPRINT("Got data <%S> from clipboard\n", str); er.EventType = KEY_EVENT; er.Event.KeyEvent.wRepeatCount = 1; while (*str) { /* \r or \n characters. Go to the line only if we get "\r\n" sequence. */ if (CurChar == L'\r' && *str == L'\n') { str++; continue; } CurChar = *str++; /* Get the key code (+ shift state) corresponding to the character */ VkKey = VkKeyScanW(CurChar); if (VkKey == 0xFFFF) { DPRINT1("VkKeyScanW failed - Should simulate the key...\n"); continue; } /* Pressing some control keys */ /* Pressing the character key, with the control keys maintained pressed */ er.Event.KeyEvent.bKeyDown = TRUE; er.Event.KeyEvent.wVirtualKeyCode = LOBYTE(VkKey); er.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(LOBYTE(VkKey), MAPVK_VK_TO_CHAR); er.Event.KeyEvent.uChar.UnicodeChar = CurChar; er.Event.KeyEvent.dwControlKeyState = 0; if (HIBYTE(VkKey) & 1) er.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; if (HIBYTE(VkKey) & 2) er.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; // RIGHT_CTRL_PRESSED; if (HIBYTE(VkKey) & 4) er.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; // RIGHT_ALT_PRESSED; ConioProcessInputEvent(Console, &er); /* Up all the character and control keys */ er.Event.KeyEvent.bKeyDown = FALSE; ConioProcessInputEvent(Console, &er); } GlobalUnlock(hData); }
//------------------------------------------------- void PushBuffer(HWND wndFocused) { SHORT scanCode; WPARAM lParam; PostMessage(wndFocused,WM_KEYUP,VK_PAUSE, (LPARAM(VK_PAUSE_SCAN)<<16)+LPARAM(IsReleased)+1); if (pShMem->keyMode == UNICODE_CHARSET && pShMem->codeTable.encoding == UNICODE_UCS2) { if (!pShMem->options.useUnicodeClipboard && pShMem->unicodePlatform && IsWindowUnicode(wndFocused)) { for (int i=0; i<VnKbd.keysPushed; i++) { scanCode = VkKeyScanW(VnKbd.uniPush[i]); lParam = (scanCode << 16) + 1; PostMessageW(wndFocused, (pShMem->options.useIME)? WM_IME_CHAR : WM_CHAR, VnKbd.uniPush[i], lParam); } } else { OpenClipboard(pShMem->hMainDlg); EmptyClipboard(); VnKbd.uniPush[VnKbd.keysPushed] = 0; // null-terminated VnKbd.ansiPush[VnKbd.keysPushed] = 0; VnKbd.keysPushed++; HGLOBAL hBuf = GlobalAlloc(GMEM_MOVEABLE, sizeof(WORD) * VnKbd.keysPushed); HGLOBAL hBufAnsi = GlobalAlloc(GMEM_MOVEABLE, VnKbd.keysPushed); LPVOID pBuf = GlobalLock(hBuf); LPVOID pBufAnsi = GlobalLock(hBufAnsi); memcpy(pBuf, VnKbd.uniPush, sizeof(WORD) * VnKbd.keysPushed); memcpy(pBufAnsi, VnKbd.ansiPush, VnKbd.keysPushed); GlobalUnlock(hBuf); GlobalUnlock(hBufAnsi); SetClipboardData(CF_UNICODETEXT, hBuf); SetClipboardData(CF_TEXT, hBufAnsi); CloseClipboard(); sendPasteCmd(); ClipboardIsEmpty = 0; } } else if (pShMem->keyMode == DECOMPOSED_UNICODE_CHARSET) { if (pShMem->unicodePlatform && IsWindowUnicode(wndFocused)) { for (int i=0; i<VnKbd.keysPushed; i++) { scanCode = VkKeyScanW(VnKbd.uniPush[i]); lParam = (scanCode << 16) + 1; PostMessageW(wndFocused, (pShMem->options.useIME)? WM_IME_CHAR : WM_CHAR, VnKbd.uniPush[i],lParam); } } else { if (ViKeyboardLayout != NULL) { ActivateKeyboardLayout(ViKeyboardLayout, 0); LayoutChangeForced = 1; } int count = WideCharToMultiByte(1258, 0, VnKbd.uniPush, VnKbd.keysPushed, (char *)VnKbd.ansiPush, VnKbd.keysPushed, 0, 0); for (int i=0; i<count; i++) { scanCode = VkKeyScan(VnKbd.ansiPush[i]); lParam = (scanCode << 16) + 1; PostMessage(wndFocused, (pShMem->options.useIME)? WM_IME_CHAR : WM_CHAR, VnKbd.ansiPush[i], lParam); } } } else { if (pShMem->keyMode == WINCP1258_CHARSET && ViKeyboardLayout!=NULL) { ActivateKeyboardLayout(ViKeyboardLayout, 0); LayoutChangeForced = 1; } for (int i=0; i<VnKbd.keysPushed; i++) { scanCode = VkKeyScan(VnKbd.ansiPush[i]); lParam = (scanCode << 16) + 1; // PostMessage(wndFocused, WM_IME_CHAR, VnKbd.ansiPush[i], lParam); PostMessage(wndFocused, (pShMem->options.useIME)? WM_IME_CHAR : WM_CHAR, VnKbd.ansiPush[i], lParam); } } return; }
void KeyMap::PCtoX(BYTE virtKey, DWORD keyData, ClientConnection* clientCon) { bool down = ((keyData & 0x80000000) == 0); bool extended = ((keyData & 0x1000000) != 0); bool repeated = ((keyData & 0xc0000000) == 0x40000000); UINT extVkey = virtKey + (extended ? 256 : 0); // exclude winkey when not scroll-lock if (virtKey==91 || virtKey==92) return; vnclog.Print(8, _T("\nPCtoX: %svirtKey 0x%02x%s%s, keyData 0x%08x\n"), (extended ? _T("extended ") : _T("")), virtKey, (repeated ? _T(" repeated") : _T("")), (down ? _T(" down") : _T(" up")), keyData); // If this is a key release then just send the associated sent KeySym when // this key was pressed if (!down) { vnclog.Print(8, _T("Release the associated KeySym when this VirtKey was pressed\n")); if (downUnicode[extVkey]) { vnclog.Print(8, _T(" 0x%04x (%c): "), downUnicode[extVkey], downUnicode[extVkey]); downUnicode[extVkey] = NULL; } else { vnclog.Print(8, _T(" Control character: ")); } releaseKey(clientCon, extVkey); vnclog.Print(8, _T("\n")); GetKeyboardState(KBKeysState); if (!((KBKeysState[VK_MENU] & 0x80) && (KBKeysState[VK_CONTROL] & 0x80))) { if (storedDeadChar && reset) { reset=false; keybd_event(VK_SPACE, 0, 0, 0); keybd_event(VK_SPACE, 0, KEYEVENTF_KEYUP, 0); } } return; } // We try to look it up in our key table // Look up the desired code in the keyMap table try to find the exact match according to // the extended flag, then try the opposite of the extended flag CARD32 foundXCode = XK_VoidSymbol; bool exactMatched = false; vnclog.Print(8, _T("Looking in key table ")); for (UINT i = 0; i < (sizeof(keyMap) / sizeof(vncKeyMapping_t)); i++) { if (keyMap[i].WinCode == virtKey) { foundXCode = keyMap[i].XCode; if (extended == keyMap[i].extVK) { exactMatched = true; break; } } } if (foundXCode != XK_VoidSymbol) { vnclog.Print(8, _T("-> keyMap gives (from %s extended flag) KeySym %u (0x%08x)\n"), (exactMatched ? _T("matched") : _T("opposite")), foundXCode, foundXCode); pressKey(clientCon, extVkey, foundXCode); vnclog.Print(8, _T("\n")); return; } else { vnclog.Print(8, _T("-> not in special keyMap\n")); } // Under CE, we're not so concerned about this bit because we handle a WM_CHAR message later #ifndef UNDER_CE GetKeyboardState(KBKeysState); ModifierKeyReleaser lctrl(clientCon, VK_CONTROL, 0); ModifierKeyReleaser lalt(clientCon, VK_MENU, 0); ModifierKeyReleaser ralt(clientCon, VK_MENU, 1); if ((KBKeysState[VK_MENU] & 0x80) && (KBKeysState[VK_CONTROL] & 0x80)) { // This is a Ctrl-Alt (AltGr) key on international keyboards (= LCtrl-RAlt) // Ex. Ctrl-Alt-Q gives '@' on German keyboards vnclog.Print(8, _T("Ctrl-Alt pressed:\n")); // We must release Control and Alt (AltGr) if they were both pressed, so the character // is seen without them by the VNC server // We don't release the Right Control; this allows German users // to use it for doing Ctrl-AltGr-x, e.g. Ctl-@, etc lctrl.release(downKeysym); lalt.release(downKeysym); ralt.release(downKeysym); } else { // This is not a Ctrl-Alt (AltGr) key vnclog.Print(8, _T("Ctrl-Alt not pressed, fake release any Ctrl key\n")); // There are no KeySym corresponding to control characters, e.g. Ctrl-F // The server has already known whether the Ctrl key is pressed from the previouse key event // So we are interested in the key that would be there if the Ctrl key were not pressed KBKeysState[VK_CONTROL] = KBKeysState[VK_LCONTROL] = KBKeysState[VK_RCONTROL] = 0; } int ret; if (storedDeadChar) { SHORT virtDeadKey; BYTE prevModifierState = 0; vnclog.Print(8, _T("[Storing base character modifier(s)]\n")); StoreModifier(&prevModifierState, KBKeysState); virtDeadKey = VkKeyScanW(storedDeadChar); vnclog.Print(8, _T("[A dead key was stored, restoring the dead key state:") _T(" 0x%02x (%c) using virtDeadKey 0x%02x] "), storedDeadChar, storedDeadChar, virtDeadKey); SetModifier(HIBYTE(virtDeadKey), KBKeysState); vnclog.Print(8, _T("\n")); ToUnicode((virtDeadKey & 0xff), 0, KBKeysState, ucsChar, (sizeof(ucsChar) / sizeof(WCHAR)), 0); vnclog.Print(8, _T("[Restoring base character modifier(s)] ")); SetModifier(prevModifierState, KBKeysState); vnclog.Print(8, _T("\n")); storedDeadChar = 0; ret = ToUnicode(virtKey, 0, KBKeysState, ucsChar, (sizeof(ucsChar) / sizeof(WCHAR)), 0); } else ret = ToUnicode(virtKey, 0, KBKeysState, ucsChar, (sizeof(ucsChar) / sizeof(WCHAR)), 0); if (ucsChar[0]==8364) { //euro // return; } if (ret < 0 || ret==2) { // It is a dead key vnclog.Print(8, _T("ToUnicode returns dead key: 0x%02x (%c) "), *ucsChar, *ucsChar); if (sendDeadKey) { // We try to look it up in our dead key table // Look up the desired code in the deadKeyMap table foundXCode = XK_VoidSymbol; for (UINT i = 0; i < (sizeof(deadKeyMap) / sizeof(vncDeadKeyMapping_t)); i++) { if (deadKeyMap[i].deadKeyChar == *ucsChar) { foundXCode = deadKeyMap[i].XCode; break; } } if (foundXCode != XK_VoidSymbol) { vnclog.Print(8, _T("-> deadKeyMap gives KeySym %u (0x%08x)\n"), foundXCode, foundXCode); pressKey(clientCon, extVkey, foundXCode); } else { vnclog.Print(8, _T("-> not in deadKeyMap\n")); } } else { storedDeadChar = *ucsChar; reset=true; vnclog.Print(8, _T("-> Store the dead key state, wait for next key-stroke\n")); } FlushDeadKey(KBKeysState); } else if (ret > 0) { vnclog.Print(8, _T("ToUnicode returns %d character(s):\n"), ret); for (int i = 0; i < ret; i++) { CARD32 xChar = UCS2X(*(ucsChar+i)); if (xChar != XK_VoidSymbol) { downUnicode[extVkey] = *(ucsChar+i); pressKey(clientCon, extVkey, xChar); } } } else { vnclog.Print(8, _T("No character is generated by this key event\n")); } #endif vnclog.Print(8, _T("\n")); };