/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ // -=- SInput.cxx // // A number of routines that accept VNC input event data and perform // the appropriate actions under Win32 #define XK_MISCELLANY #define XK_LATIN1 #define XK_CURRENCY #include #include #include #include #include #include #include #include #include #include #if(defined(INPUT_MOUSE) && defined(RFB_HAVE_MONITORINFO) && defined(MOUSEEVENTF_VIRTUALDESK)) #define RFB_HAVE_SENDINPUT #else #pragma message(" NOTE: Not building SendInput support.") #endif using namespace rfb; static LogWriter vlog("SInput"); #ifdef RFB_HAVE_SENDINPUT typedef UINT (WINAPI *_SendInput_proto)(UINT, LPINPUT, int); static win32::DynamicFn<_SendInput_proto> _SendInput(_T("user32.dll"), "SendInput"); #endif // // -=- Pointer implementation for Win32 // static DWORD buttonDownMapping[8] = { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL, 0, 0, 0 }; static DWORD buttonUpMapping[8] = { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL, 0, 0, 0 }; static DWORD buttonDataMapping[8] = { 0, 0, 0, 120, -120, 0, 0, 0 }; win32::SPointer::SPointer() : last_buttonmask(0) { } void win32::SPointer::pointerEvent(const Point& pos, int buttonmask) { // - We are specifying absolute coordinates DWORD flags = MOUSEEVENTF_ABSOLUTE; // - Has the pointer moved since the last event? if (!last_position.equals(pos)) flags |= MOUSEEVENTF_MOVE; // - If the system swaps left and right mouse buttons then we must // swap them here to negate the effect, so that we do the actual // action we mean to do if (::GetSystemMetrics(SM_SWAPBUTTON)) { bool leftDown = buttonmask & 1; bool rightDown = buttonmask & 4; buttonmask = (buttonmask & ~(1 | 4)); if (leftDown) buttonmask |= 4; if (rightDown) buttonmask |= 1; } DWORD data = 0; for (int i = 0; i < 8; i++) { if ((buttonmask & (1<= 32 && keysym <= 126) || (keysym >= 160 && keysym <= 255)) { // ordinary Latin-1 character if (deadKeyAware) { // Detect dead chars and generate the dead char followed by space so // that we'll end up with the original char. for (unsigned int i = 0; i < deadChars.size(); i++) { if (keysym == deadChars[i]) { SHORT dc = VkKeyScan(keysym); if (dc != -1) { if (down) { vlog.info("latin-1 dead key: 0x%x vkCode 0x%x mod 0x%x " "followed by space", keysym, LOBYTE(dc), HIBYTE(dc)); doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), true); doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), false); doKeyEventWithModifiers(VK_SPACE, 0, true); doKeyEventWithModifiers(VK_SPACE, 0, false); } return; } } } } SHORT s = VkKeyScan(keysym); if (s == -1) { if (down) { // not a single keypress - try synthesizing dead chars. for (unsigned int j = 0; j < sizeof(latin1ToDeadChars) / sizeof(latin1ToDeadChars_t); j++) { if (keysym == latin1ToDeadChars[j].latin1Char) { for (unsigned int i = 0; i < deadChars.size(); i++) { if (deadChars[i] == latin1ToDeadChars[j].deadChar) { SHORT dc = VkKeyScan(latin1ToDeadChars[j].deadChar); SHORT bc = VkKeyScan(latin1ToDeadChars[j].baseChar); if (dc != -1 && bc != -1) { vlog.info("latin-1 key: 0x%x dead key vkCode 0x%x mod 0x%x " "followed by vkCode 0x%x mod 0x%x", keysym, LOBYTE(dc), HIBYTE(dc), LOBYTE(bc), HIBYTE(bc)); doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), true); doKeyEventWithModifiers(LOBYTE(dc), HIBYTE(dc), false); doKeyEventWithModifiers(LOBYTE(bc), HIBYTE(bc), true); doKeyEventWithModifiers(LOBYTE(bc), HIBYTE(bc), false); return; } break; } } break; } } vlog.info("ignoring unrecognised Latin-1 keysym 0x%x",keysym); } return; } BYTE vkCode = LOBYTE(s); BYTE modifierState = HIBYTE(s); vlog.debug("latin-1 key: 0x%x vkCode 0x%x mod 0x%x down %d", keysym, vkCode, modifierState, down); doKeyEventWithModifiers(vkCode, modifierState, down); } else { // see if it's a recognised keyboard key, otherwise ignore it if (vkMap.find(keysym) == vkMap.end()) { vlog.info("ignoring unknown keysym 0x%x",keysym); return; } BYTE vkCode = vkMap[keysym]; DWORD flags = 0; if (extendedMap[keysym]) flags |= KEYEVENTF_EXTENDEDKEY; if (!down) flags |= KEYEVENTF_KEYUP; vlog.debug("keyboard key: keysym 0x%x vkCode 0x%x ext %d down %d", keysym, vkCode, extendedMap[keysym], down); if (down && (vkCode == VK_DELETE) && ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) && ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0)) { rfb::win32::emulateCtrlAltDel(); return; } doKeyboardEvent(vkCode, flags); } }