mirror of
https://github.com/debauchee/barrier.git
synced 2024-12-24 03:23:15 +03:00
d2135af0d9
CServer to the primary screen when the configuration changes so it can make necessary adjustments (the win32 primary screen must tell the hook dll about the new jump zones). changed includes of some std c++ library files to go through our own include files. these wrap the include with stuff to keep vc++ quiet when compiling at warning level 4, which is what it does now. it also works around missing <istream> and <ostream> on g++2.96. added missing std:: where necessary. g++ doesn't really support namespaces so it lets references without the namespace slip through. added workaround or fix. not sure if istringstream::str(string) should reset eofbit. it does on g++ but does not on vc++. added clear() after str() so it works either way. added low-level keyboard hook to win32. if available (it's only available on NT SP3 and up) it allows us to catch and handle alt+tab, alt+esc, ctrl+esc, and windows key hot keys. i think that leaves only ctrl+alt+del and accessibility functions uncaught on those systems.
1158 lines
32 KiB
C++
1158 lines
32 KiB
C++
#include "CMSWindowsPrimaryScreen.h"
|
|
#include "CMSWindowsClipboard.h"
|
|
#include "CServer.h"
|
|
#include "CSynergyHook.h"
|
|
#include "XSynergy.h"
|
|
#include "CThread.h"
|
|
#include "CLog.h"
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
//
|
|
// CMSWindowsPrimaryScreen
|
|
//
|
|
|
|
CMSWindowsPrimaryScreen::CMSWindowsPrimaryScreen() :
|
|
m_server(NULL),
|
|
m_active(false),
|
|
m_window(NULL),
|
|
m_nextClipboardWindow(NULL),
|
|
m_clipboardOwner(NULL),
|
|
m_hookLibrary(NULL),
|
|
m_mark(0),
|
|
m_markReceived(0)
|
|
{
|
|
// detect operating system
|
|
OSVERSIONINFO version;
|
|
version.dwOSVersionInfoSize = sizeof(version);
|
|
if (GetVersionEx(&version) == 0) {
|
|
log((CLOG_WARN "cannot determine OS: %d", GetLastError()));
|
|
}
|
|
m_is95Family = (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
|
}
|
|
|
|
CMSWindowsPrimaryScreen::~CMSWindowsPrimaryScreen()
|
|
{
|
|
assert(m_window == NULL);
|
|
assert(m_hookLibrary == NULL);
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::run()
|
|
{
|
|
// change our priority
|
|
CThread::getCurrentThread().setPriority(-3);
|
|
|
|
// run event loop
|
|
log((CLOG_INFO "entering event loop"));
|
|
doRun();
|
|
log((CLOG_INFO "exiting event loop"));
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::stop()
|
|
{
|
|
doStop();
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::open(CServer* server)
|
|
{
|
|
assert(m_server == NULL);
|
|
assert(server != NULL);
|
|
|
|
// set the server
|
|
m_server = server;
|
|
|
|
// open the display
|
|
openDisplay();
|
|
|
|
// get keyboard state
|
|
updateKeys();
|
|
|
|
// send screen info
|
|
SInt32 w, h;
|
|
getScreenSize(&w, &h);
|
|
m_server->setInfo(w, h, getJumpZoneSize(), 0, 0);
|
|
|
|
// enter the screen
|
|
doEnter();
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::close()
|
|
{
|
|
assert(m_server != NULL);
|
|
|
|
// close the display
|
|
closeDisplay();
|
|
|
|
// done with server
|
|
m_server = NULL;
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::enter(SInt32 x, SInt32 y)
|
|
{
|
|
log((CLOG_INFO "entering primary at %d,%d", x, y));
|
|
assert(m_active == true);
|
|
|
|
doEnter();
|
|
|
|
// warp to requested location
|
|
warpCursor(x, y);
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::doEnter()
|
|
{
|
|
// not active anymore
|
|
m_active = false;
|
|
|
|
// release keyboard/mouse and set the zones that should cause a jump
|
|
/* FIXME
|
|
if (UnregisterHotKey(m_window, 0x0001) != 0) {
|
|
log((CLOG_INFO "released hot key"));
|
|
}
|
|
else {
|
|
log((CLOG_INFO "failed to release hot key: %d", GetLastError()));
|
|
}
|
|
*/
|
|
if (m_is95Family) {
|
|
DWORD dummy = 0;
|
|
SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, FALSE, &dummy, 0);
|
|
}
|
|
SInt32 w, h;
|
|
getScreenSize(&w, &h);
|
|
SetZoneFunc setZone = (SetZoneFunc)GetProcAddress(
|
|
m_hookLibrary, "setZone");
|
|
setZone(m_server->getActivePrimarySides(), w, h, getJumpZoneSize());
|
|
|
|
// restore the active window and hide our window. we can only set
|
|
// the active window for another thread if we first attach our input
|
|
// to that thread.
|
|
ReleaseCapture();
|
|
if (m_lastActiveWindow != NULL) {
|
|
DWORD myThread = GetCurrentThreadId();
|
|
if (AttachThreadInput(myThread, m_lastActiveThread, TRUE)) {
|
|
// FIXME -- shouldn't raise window if X-Mouse is enabled
|
|
// but i have no idea how to do that or check if enabled.
|
|
SetActiveWindow(m_lastActiveWindow);
|
|
AttachThreadInput(myThread, m_lastActiveThread, FALSE);
|
|
}
|
|
}
|
|
ShowWindow(m_window, SW_HIDE);
|
|
|
|
// all messages prior to now are invalid
|
|
nextMark();
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::leave()
|
|
{
|
|
log((CLOG_INFO "leaving primary"));
|
|
assert(m_active == false);
|
|
|
|
// do non-warp enter stuff
|
|
// get state of keys as we leave
|
|
updateKeys();
|
|
|
|
// all messages prior to now are invalid
|
|
nextMark();
|
|
|
|
// remember the active window before we leave. GetActiveWindow()
|
|
// will only return the active window for the thread's queue (i.e.
|
|
// our app) but we need the globally active window. get that by
|
|
// attaching input to the foreground window's thread then calling
|
|
// GetActiveWindow() and then detaching our input.
|
|
m_lastActiveWindow = NULL;
|
|
m_lastForegroundWindow = GetForegroundWindow();
|
|
m_lastActiveThread = GetWindowThreadProcessId(
|
|
m_lastForegroundWindow, NULL);
|
|
if (m_lastActiveThread != 0) {
|
|
DWORD myThread = GetCurrentThreadId();
|
|
if (AttachThreadInput(myThread, m_lastActiveThread, TRUE)) {
|
|
m_lastActiveWindow = GetActiveWindow();
|
|
AttachThreadInput(myThread, m_lastActiveThread, FALSE);
|
|
}
|
|
}
|
|
|
|
// show our window
|
|
ShowWindow(m_window, SW_SHOW);
|
|
|
|
// relay all mouse and keyboard events
|
|
SetRelayFunc setRelay = (SetRelayFunc)GetProcAddress(
|
|
m_hookLibrary, "setRelay");
|
|
setRelay();
|
|
if (m_is95Family) {
|
|
// disable ctrl+alt+del, alt+tab, ctrl+esc
|
|
DWORD dummy = 0;
|
|
SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &dummy, 0);
|
|
}
|
|
/* FIXME
|
|
if (RegisterHotKey(m_window, 0x0001, MOD_ALT, VK_TAB) != 0) {
|
|
log((CLOG_INFO "got hot key"));
|
|
}
|
|
else {
|
|
log((CLOG_INFO "failed to get hot key: %d", GetLastError()));
|
|
}
|
|
*/
|
|
|
|
// get keyboard input and capture mouse
|
|
SetActiveWindow(m_window);
|
|
SetFocus(m_window);
|
|
SetCapture(m_window);
|
|
|
|
// warp the mouse to the center of the screen
|
|
getScreenSize(&m_xCenter, &m_yCenter);
|
|
m_xCenter >>= 1;
|
|
m_yCenter >>= 1;
|
|
warpCursor(m_xCenter, m_yCenter);
|
|
|
|
// discard messages until after the warp
|
|
nextMark();
|
|
|
|
// local client now active
|
|
m_active = true;
|
|
|
|
// if we think we own the clipboard but we don't then somebody
|
|
// grabbed the clipboard on this screen without us knowing.
|
|
// tell the server that this screen grabbed the clipboard.
|
|
//
|
|
// this works around bugs in the clipboard viewer chain.
|
|
// sometimes NT will simply never send WM_DRAWCLIPBOARD
|
|
// messages for no apparent reason and rebooting fixes the
|
|
// problem. since we don't want a broken clipboard until the
|
|
// next reboot we do this double check. clipboard ownership
|
|
// won't be reflected on other screens until we leave but at
|
|
// least the clipboard itself will work.
|
|
HWND clipboardOwner = GetClipboardOwner();
|
|
if (m_clipboardOwner != clipboardOwner) {
|
|
try {
|
|
m_clipboardOwner = clipboardOwner;
|
|
if (m_clipboardOwner != m_window) {
|
|
m_server->grabClipboard(kClipboardClipboard);
|
|
m_server->grabClipboard(kClipboardSelection);
|
|
}
|
|
}
|
|
catch (XBadClient&) {
|
|
// ignore
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::onConfigure()
|
|
{
|
|
if (!m_active) {
|
|
SInt32 w, h;
|
|
getScreenSize(&w, &h);
|
|
SetZoneFunc setZone = (SetZoneFunc)GetProcAddress(
|
|
m_hookLibrary, "setZone");
|
|
setZone(m_server->getActivePrimarySides(), w, h, getJumpZoneSize());
|
|
}
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
|
|
{
|
|
// set the cursor position without generating an event
|
|
SetCursorPos(x, y);
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::setClipboard(
|
|
ClipboardID id, const IClipboard* src)
|
|
{
|
|
assert(m_window != NULL);
|
|
|
|
CMSWindowsClipboard dst(m_window);
|
|
CClipboard::copy(&dst, src);
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::grabClipboard(ClipboardID id)
|
|
{
|
|
assert(m_window != NULL);
|
|
|
|
CMSWindowsClipboard clipboard(m_window);
|
|
if (clipboard.open(0)) {
|
|
clipboard.close();
|
|
}
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::getSize(
|
|
SInt32* width, SInt32* height) const
|
|
{
|
|
getScreenSize(width, height);
|
|
}
|
|
|
|
SInt32 CMSWindowsPrimaryScreen::getJumpZoneSize() const
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::getClipboard(
|
|
ClipboardID id, IClipboard* dst) const
|
|
{
|
|
assert(m_window != NULL);
|
|
|
|
CMSWindowsClipboard src(m_window);
|
|
CClipboard::copy(dst, &src);
|
|
}
|
|
|
|
KeyModifierMask CMSWindowsPrimaryScreen::getToggleMask() const
|
|
{
|
|
KeyModifierMask mask = 0;
|
|
if ((GetKeyState(VK_CAPITAL) & 0x01) != 0)
|
|
mask |= KeyModifierCapsLock;
|
|
if ((GetKeyState(VK_NUMLOCK) & 0x01) != 0)
|
|
mask |= KeyModifierNumLock;
|
|
if ((GetKeyState(VK_SCROLL) & 0x01) != 0)
|
|
mask |= KeyModifierScrollLock;
|
|
return mask;
|
|
}
|
|
|
|
bool CMSWindowsPrimaryScreen::isLockedToScreen() const
|
|
{
|
|
// check buttons
|
|
if (GetAsyncKeyState(VK_LBUTTON) < 0 ||
|
|
GetAsyncKeyState(VK_MBUTTON) < 0 ||
|
|
GetAsyncKeyState(VK_RBUTTON) < 0) {
|
|
return true;
|
|
}
|
|
|
|
// check keys
|
|
BYTE keys[256];
|
|
if (GetKeyboardState(keys)) {
|
|
for (unsigned int i = 0; i < sizeof(keys); ++i) {
|
|
if ((keys[i] & 0x80) != 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// not locked
|
|
return false;
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::onOpenDisplay()
|
|
{
|
|
assert(m_window == NULL);
|
|
assert(m_server != NULL);
|
|
|
|
// initialize clipboard owner to current owner. we don't want
|
|
// to take ownership of the clipboard just by starting up.
|
|
m_clipboardOwner = GetClipboardOwner();
|
|
|
|
// get screen size
|
|
// note -- we use a fullscreen window to grab input. it should
|
|
// be possible to use a 1x1 window but i've run into problems
|
|
// with losing keyboard input (focus?) in that case.
|
|
// unfortunately, hiding the full screen window causes all other
|
|
// windows to redraw.
|
|
SInt32 w, h;
|
|
getScreenSize(&w, &h);
|
|
|
|
// create the window
|
|
m_window = CreateWindowEx(WS_EX_TOPMOST |
|
|
WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW,
|
|
(LPCTSTR)getClass(), "Synergy",
|
|
WS_POPUP,
|
|
0, 0, w, h, NULL, NULL,
|
|
getInstance(),
|
|
NULL);
|
|
assert(m_window != NULL);
|
|
|
|
// install our clipboard snooper
|
|
m_nextClipboardWindow = SetClipboardViewer(m_window);
|
|
|
|
// load the hook library
|
|
bool hooked = false;
|
|
m_hookLibrary = LoadLibrary("synrgyhk");
|
|
if (m_hookLibrary != NULL) {
|
|
// install input hooks
|
|
InstallFunc install = (InstallFunc)GetProcAddress(
|
|
m_hookLibrary, "install");
|
|
if (install != NULL) {
|
|
hooked = (install(m_window) != 0);
|
|
}
|
|
}
|
|
if (!hooked) {
|
|
log((CLOG_ERR "failed to install hooks"));
|
|
ChangeClipboardChain(m_window, m_nextClipboardWindow);
|
|
m_nextClipboardWindow = NULL;
|
|
DestroyWindow(m_window);
|
|
m_window = NULL;
|
|
// FIXME -- throw
|
|
}
|
|
|
|
// initialize marks
|
|
m_mark = 0;
|
|
m_markReceived = 0;
|
|
nextMark();
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::onCloseDisplay()
|
|
{
|
|
assert(m_window != NULL);
|
|
|
|
// uninstall input hooks
|
|
UninstallFunc uninstall = (UninstallFunc)GetProcAddress(
|
|
m_hookLibrary, "uninstall");
|
|
if (uninstall != NULL) {
|
|
uninstall();
|
|
}
|
|
|
|
// done with hook library
|
|
FreeLibrary(m_hookLibrary);
|
|
m_hookLibrary = NULL;
|
|
|
|
// remove clipboard snooper
|
|
ChangeClipboardChain(m_window, m_nextClipboardWindow);
|
|
m_nextClipboardWindow = NULL;
|
|
|
|
// destroy window
|
|
DestroyWindow(m_window);
|
|
m_window = NULL;
|
|
}
|
|
|
|
bool CMSWindowsPrimaryScreen::onPreTranslate(MSG* msg)
|
|
{
|
|
// handle event
|
|
switch (msg->message) {
|
|
case SYNERGY_MSG_MARK:
|
|
m_markReceived = msg->wParam;
|
|
return true;
|
|
|
|
case SYNERGY_MSG_KEY:
|
|
// ignore if not at current mark
|
|
if (m_mark == m_markReceived) {
|
|
KeyModifierMask mask;
|
|
const KeyID key = mapKey(msg->wParam, msg->lParam, &mask);
|
|
if (key != kKeyNone) {
|
|
if ((msg->lParam & 0x80000000) == 0) {
|
|
// key press
|
|
const SInt32 repeat = (SInt32)(msg->lParam & 0xffff);
|
|
if (repeat >= 2) {
|
|
log((CLOG_DEBUG1 "event: key repeat key=%d mask=0x%04x count=%d", key, mask, repeat));
|
|
m_server->onKeyRepeat(key, mask, repeat);
|
|
}
|
|
else {
|
|
log((CLOG_DEBUG1 "event: key press key=%d mask=0x%04x", key, mask));
|
|
m_server->onKeyDown(key, mask);
|
|
}
|
|
|
|
// update key state
|
|
updateKey(msg->wParam, true);
|
|
}
|
|
else {
|
|
// key release
|
|
log((CLOG_DEBUG1 "event: key release key=%d mask=0x%04x", key, mask));
|
|
m_server->onKeyUp(key, mask);
|
|
|
|
// update key state
|
|
updateKey(msg->wParam, false);
|
|
}
|
|
}
|
|
else {
|
|
log((CLOG_DEBUG2 "event: cannot map key wParam=%d lParam=0x%08x", msg->wParam, msg->lParam));
|
|
}
|
|
}
|
|
return true;
|
|
|
|
case SYNERGY_MSG_MOUSE_BUTTON:
|
|
// ignore if not at current mark
|
|
if (m_mark == m_markReceived) {
|
|
const ButtonID button = mapButton(msg->wParam);
|
|
switch (msg->wParam) {
|
|
case WM_LBUTTONDOWN:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
log((CLOG_DEBUG1 "event: button press button=%d", button));
|
|
if (button != kButtonNone) {
|
|
m_server->onMouseDown(button);
|
|
}
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
case WM_MBUTTONUP:
|
|
case WM_RBUTTONUP:
|
|
log((CLOG_DEBUG1 "event: button release button=%d", button));
|
|
if (button != kButtonNone) {
|
|
m_server->onMouseUp(button);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
|
|
case SYNERGY_MSG_MOUSE_WHEEL:
|
|
// ignore if not at current mark
|
|
if (m_mark == m_markReceived) {
|
|
log((CLOG_ERR "event: button wheel delta=%d %d", msg->wParam, msg->lParam));
|
|
m_server->onMouseWheel(msg->wParam);
|
|
}
|
|
return true;
|
|
|
|
case SYNERGY_MSG_MOUSE_MOVE:
|
|
// ignore if not at current mark
|
|
if (m_mark == m_markReceived) {
|
|
SInt32 x = (SInt32)msg->wParam;
|
|
SInt32 y = (SInt32)msg->lParam;
|
|
if (!m_active) {
|
|
log((CLOG_DEBUG2 "event: inactive move %d,%d", x, y));
|
|
m_server->onMouseMovePrimary(x, y);
|
|
}
|
|
else {
|
|
// get mouse deltas
|
|
x -= m_xCenter;
|
|
y -= m_yCenter;
|
|
|
|
// ignore if the mouse didn't move
|
|
if (x != 0 && y != 0) {
|
|
log((CLOG_DEBUG2 "event: active move %d,%d", x, y));
|
|
|
|
// warp mouse back to center
|
|
warpCursor(m_xCenter, m_yCenter);
|
|
|
|
// send motion
|
|
m_server->onMouseMoveSecondary(x, y);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
LRESULT CMSWindowsPrimaryScreen::onEvent(
|
|
HWND hwnd, UINT msg,
|
|
WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg) {
|
|
/*
|
|
case WM_HOTKEY:
|
|
log((CLOG_INFO "hot key: %d, %d, %s %s %s", wParam, HIWORD(lParam), (LOWORD(lParam) & MOD_ALT) ? "ALT" : "", (LOWORD(lParam) & MOD_CONTROL) ? "CTRL" : "", (LOWORD(lParam) & MOD_SHIFT) ? "SHIFT" : "", (LOWORD(lParam) & MOD_WIN) ? "WIN" : ""));
|
|
return 0;
|
|
*/
|
|
|
|
case WM_PAINT:
|
|
ValidateRect(hwnd, NULL);
|
|
return 0;
|
|
|
|
case WM_DRAWCLIPBOARD:
|
|
log((CLOG_DEBUG "clipboard was taken"));
|
|
|
|
// first pass it on
|
|
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
|
|
|
|
// now notify server that somebody changed the clipboard.
|
|
// skip that if we're the new owner.
|
|
try {
|
|
m_clipboardOwner = GetClipboardOwner();
|
|
if (m_clipboardOwner != m_window) {
|
|
m_server->grabClipboard(kClipboardClipboard);
|
|
m_server->grabClipboard(kClipboardSelection);
|
|
}
|
|
}
|
|
catch (XBadClient&) {
|
|
// ignore. this can happen if we receive this event
|
|
// before we've fully started up.
|
|
}
|
|
return 0;
|
|
|
|
case WM_CHANGECBCHAIN:
|
|
if (m_nextClipboardWindow == (HWND)wParam)
|
|
m_nextClipboardWindow = (HWND)lParam;
|
|
else
|
|
SendMessage(m_nextClipboardWindow, msg, wParam, lParam);
|
|
return 0;
|
|
|
|
case WM_DISPLAYCHANGE: {
|
|
// screen resolution has changed
|
|
SInt32 w, h;
|
|
updateScreenSize();
|
|
getScreenSize(&w, &h);
|
|
|
|
// recompute center pixel of screen
|
|
m_xCenter = w >> 1;
|
|
m_yCenter = h >> 1;
|
|
|
|
// warp mouse to center if active
|
|
if (m_active) {
|
|
warpCursor(m_xCenter, m_yCenter);
|
|
}
|
|
|
|
// tell hook about resize if not active
|
|
else {
|
|
SetZoneFunc setZone = (SetZoneFunc)GetProcAddress(
|
|
m_hookLibrary, "setZone");
|
|
setZone(m_server->getActivePrimarySides(), w, h, getJumpZoneSize());
|
|
}
|
|
|
|
// send new screen info
|
|
POINT pos;
|
|
GetCursorPos(&pos);
|
|
m_server->setInfo(w, h, getJumpZoneSize(), pos.x, pos.y);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::nextMark()
|
|
{
|
|
assert(m_window != NULL);
|
|
|
|
PostMessage(m_window, SYNERGY_MSG_MARK, ++m_mark, 0);
|
|
}
|
|
|
|
static const KeyID g_virtualKey[] =
|
|
{
|
|
/* 0x00 */ kKeyNone, // reserved
|
|
/* 0x01 */ kKeyNone, // VK_LBUTTON
|
|
/* 0x02 */ kKeyNone, // VK_RBUTTON
|
|
/* 0x03 */ 0xff6b, // VK_CANCEL XK_Break
|
|
/* 0x04 */ kKeyNone, // VK_MBUTTON
|
|
/* 0x05 */ kKeyNone, // undefined
|
|
/* 0x06 */ kKeyNone, // undefined
|
|
/* 0x07 */ kKeyNone, // undefined
|
|
/* 0x08 */ 0xff08, // VK_BACK XK_Backspace
|
|
/* 0x09 */ 0xff09, // VK_TAB VK_Tab
|
|
/* 0x0a */ kKeyNone, // undefined
|
|
/* 0x0b */ kKeyNone, // undefined
|
|
/* 0x0c */ 0xff0b, // VK_CLEAR XK_Clear
|
|
/* 0x0d */ 0xff0d, // VK_RETURN XK_Return
|
|
/* 0x0e */ kKeyNone, // undefined
|
|
/* 0x0f */ kKeyNone, // undefined
|
|
/* 0x10 */ 0xffe1, // VK_SHIFT XK_Shift_L
|
|
/* 0x11 */ 0xffe3, // VK_CONTROL XK_Control_L
|
|
/* 0x12 */ 0xffe9, // VK_MENU XK_Alt_L
|
|
/* 0x13 */ 0xff13, // VK_PAUSE XK_Pause
|
|
/* 0x14 */ 0xffe5, // VK_CAPITAL XK_Caps_Lock
|
|
/* 0x15 */ kKeyNone, // VK_KANA
|
|
/* 0x16 */ kKeyNone, // VK_HANGUL
|
|
/* 0x17 */ kKeyNone, // VK_JUNJA
|
|
/* 0x18 */ kKeyNone, // VK_FINAL
|
|
/* 0x19 */ kKeyNone, // VK_KANJI
|
|
/* 0x1a */ kKeyNone, // undefined
|
|
/* 0x1b */ 0xff1b, // VK_ESCAPE XK_Escape
|
|
/* 0x1c */ kKeyNone, // VK_CONVERT
|
|
/* 0x1d */ kKeyNone, // VK_NONCONVERT
|
|
/* 0x1e */ kKeyNone, // VK_ACCEPT
|
|
/* 0x1f */ kKeyNone, // VK_MODECHANGE
|
|
/* 0x20 */ 0x0020, // VK_SPACE XK_space
|
|
/* 0x21 */ 0xff55, // VK_PRIOR XK_Prior
|
|
/* 0x22 */ 0xff56, // VK_NEXT XK_Next
|
|
/* 0x23 */ 0xff57, // VK_END XK_End
|
|
/* 0x24 */ 0xff50, // VK_HOME XK_Home
|
|
/* 0x25 */ 0xff51, // VK_LEFT XK_Left
|
|
/* 0x26 */ 0xff52, // VK_UP XK_Up
|
|
/* 0x27 */ 0xff53, // VK_RIGHT XK_Right
|
|
/* 0x28 */ 0xff54, // VK_DOWN XK_Down
|
|
/* 0x29 */ 0xff60, // VK_SELECT XK_Select
|
|
/* 0x2a */ kKeyNone, // VK_PRINT
|
|
/* 0x2b */ 0xff62, // VK_EXECUTE XK_Execute
|
|
/* 0x2c */ 0xff61, // VK_SNAPSHOT XK_Print
|
|
/* 0x2d */ 0xff63, // VK_INSERT XK_Insert
|
|
/* 0x2e */ 0xffff, // VK_DELETE XK_Delete
|
|
/* 0x2f */ 0xff6a, // VK_HELP XK_Help
|
|
/* 0x30 */ kKeyNone, // VK_0 XK_0
|
|
/* 0x31 */ kKeyNone, // VK_1 XK_1
|
|
/* 0x32 */ kKeyNone, // VK_2 XK_2
|
|
/* 0x33 */ kKeyNone, // VK_3 XK_3
|
|
/* 0x34 */ kKeyNone, // VK_4 XK_4
|
|
/* 0x35 */ kKeyNone, // VK_5 XK_5
|
|
/* 0x36 */ kKeyNone, // VK_6 XK_6
|
|
/* 0x37 */ kKeyNone, // VK_7 XK_7
|
|
/* 0x38 */ kKeyNone, // VK_8 XK_8
|
|
/* 0x39 */ kKeyNone, // VK_9 XK_9
|
|
/* 0x3a */ kKeyNone, // undefined
|
|
/* 0x3b */ kKeyNone, // undefined
|
|
/* 0x3c */ kKeyNone, // undefined
|
|
/* 0x3d */ kKeyNone, // undefined
|
|
/* 0x3e */ kKeyNone, // undefined
|
|
/* 0x3f */ kKeyNone, // undefined
|
|
/* 0x40 */ kKeyNone, // undefined
|
|
/* 0x41 */ kKeyNone, // VK_A XK_A
|
|
/* 0x42 */ kKeyNone, // VK_B XK_B
|
|
/* 0x43 */ kKeyNone, // VK_C XK_C
|
|
/* 0x44 */ kKeyNone, // VK_D XK_D
|
|
/* 0x45 */ kKeyNone, // VK_E XK_E
|
|
/* 0x46 */ kKeyNone, // VK_F XK_F
|
|
/* 0x47 */ kKeyNone, // VK_G XK_G
|
|
/* 0x48 */ kKeyNone, // VK_H XK_H
|
|
/* 0x49 */ kKeyNone, // VK_I XK_I
|
|
/* 0x4a */ kKeyNone, // VK_J XK_J
|
|
/* 0x4b */ kKeyNone, // VK_K XK_K
|
|
/* 0x4c */ kKeyNone, // VK_L XK_L
|
|
/* 0x4d */ kKeyNone, // VK_M XK_M
|
|
/* 0x4e */ kKeyNone, // VK_N XK_N
|
|
/* 0x4f */ kKeyNone, // VK_O XK_O
|
|
/* 0x50 */ kKeyNone, // VK_P XK_P
|
|
/* 0x51 */ kKeyNone, // VK_Q XK_Q
|
|
/* 0x52 */ kKeyNone, // VK_R XK_R
|
|
/* 0x53 */ kKeyNone, // VK_S XK_S
|
|
/* 0x54 */ kKeyNone, // VK_T XK_T
|
|
/* 0x55 */ kKeyNone, // VK_U XK_U
|
|
/* 0x56 */ kKeyNone, // VK_V XK_V
|
|
/* 0x57 */ kKeyNone, // VK_W XK_W
|
|
/* 0x58 */ kKeyNone, // VK_X XK_X
|
|
/* 0x59 */ kKeyNone, // VK_Y XK_Y
|
|
/* 0x5a */ kKeyNone, // VK_Z XK_Z
|
|
/* 0x5b */ 0xffe7, // VK_LWIN XK_Meta_L
|
|
/* 0x5c */ 0xffe8, // VK_RWIN XK_Meta_R
|
|
/* 0x5d */ 0xff67, // VK_APPS XK_Menu
|
|
/* 0x5e */ kKeyNone, // undefined
|
|
/* 0x5f */ kKeyNone, // undefined
|
|
/* 0x60 */ 0xffb0, // VK_NUMPAD0 XK_KP_0
|
|
/* 0x61 */ 0xffb1, // VK_NUMPAD1 XK_KP_1
|
|
/* 0x62 */ 0xffb2, // VK_NUMPAD2 XK_KP_2
|
|
/* 0x63 */ 0xffb3, // VK_NUMPAD3 XK_KP_3
|
|
/* 0x64 */ 0xffb4, // VK_NUMPAD4 XK_KP_4
|
|
/* 0x65 */ 0xffb5, // VK_NUMPAD5 XK_KP_5
|
|
/* 0x66 */ 0xffb6, // VK_NUMPAD6 XK_KP_6
|
|
/* 0x67 */ 0xffb7, // VK_NUMPAD7 XK_KP_7
|
|
/* 0x68 */ 0xffb8, // VK_NUMPAD8 XK_KP_8
|
|
/* 0x69 */ 0xffb9, // VK_NUMPAD9 XK_KP_9
|
|
/* 0x6a */ 0xffaa, // VK_MULTIPLY XK_KP_Multiply
|
|
/* 0x6b */ 0xffab, // VK_ADD XK_KP_Add
|
|
/* 0x6c */ 0xffac, // VK_SEPARATOR XK_KP_Separator
|
|
/* 0x6d */ 0xffad, // VK_SUBTRACT XK_KP_Subtract
|
|
/* 0x6e */ 0xffae, // VK_DECIMAL XK_KP_Decimal
|
|
/* 0x6f */ 0xffaf, // VK_DIVIDE XK_KP_Divide
|
|
/* 0x70 */ 0xffbe, // VK_F1 XK_F1
|
|
/* 0x71 */ 0xffbf, // VK_F2 XK_F2
|
|
/* 0x72 */ 0xffc0, // VK_F3 XK_F3
|
|
/* 0x73 */ 0xffc1, // VK_F4 XK_F4
|
|
/* 0x74 */ 0xffc2, // VK_F5 XK_F5
|
|
/* 0x75 */ 0xffc3, // VK_F6 XK_F6
|
|
/* 0x76 */ 0xffc4, // VK_F7 XK_F7
|
|
/* 0x77 */ 0xffc5, // VK_F8 XK_F8
|
|
/* 0x78 */ 0xffc6, // VK_F9 XK_F9
|
|
/* 0x79 */ 0xffc7, // VK_F10 XK_F10
|
|
/* 0x7a */ 0xffc8, // VK_F11 XK_F11
|
|
/* 0x7b */ 0xffc9, // VK_F12 XK_F12
|
|
/* 0x7c */ 0xffca, // VK_F13 XK_F13
|
|
/* 0x7d */ 0xffcb, // VK_F14 XK_F14
|
|
/* 0x7e */ 0xffcc, // VK_F15 XK_F15
|
|
/* 0x7f */ 0xffcd, // VK_F16 XK_F16
|
|
/* 0x80 */ 0xffce, // VK_F17 XK_F17
|
|
/* 0x81 */ 0xffcf, // VK_F18 XK_F18
|
|
/* 0x82 */ 0xffd0, // VK_F19 XK_F19
|
|
/* 0x83 */ 0xffd1, // VK_F20 XK_F20
|
|
/* 0x84 */ 0xffd2, // VK_F21 XK_F21
|
|
/* 0x85 */ 0xffd3, // VK_F22 XK_F22
|
|
/* 0x86 */ 0xffd4, // VK_F23 XK_F23
|
|
/* 0x87 */ 0xffd5, // VK_F24 XK_F24
|
|
/* 0x88 */ kKeyNone, // unassigned
|
|
/* 0x89 */ kKeyNone, // unassigned
|
|
/* 0x8a */ kKeyNone, // unassigned
|
|
/* 0x8b */ kKeyNone, // unassigned
|
|
/* 0x8c */ kKeyNone, // unassigned
|
|
/* 0x8d */ kKeyNone, // unassigned
|
|
/* 0x8e */ kKeyNone, // unassigned
|
|
/* 0x8f */ kKeyNone, // unassigned
|
|
/* 0x90 */ 0xff7f, // VK_NUMLOCK XK_Num_Lock
|
|
/* 0x91 */ 0xff14, // VK_SCROLL XK_Scroll_Lock
|
|
/* 0x92 */ kKeyNone, // unassigned
|
|
/* 0x93 */ kKeyNone, // unassigned
|
|
/* 0x94 */ kKeyNone, // unassigned
|
|
/* 0x95 */ kKeyNone, // unassigned
|
|
/* 0x96 */ kKeyNone, // unassigned
|
|
/* 0x97 */ kKeyNone, // unassigned
|
|
/* 0x98 */ kKeyNone, // unassigned
|
|
/* 0x99 */ kKeyNone, // unassigned
|
|
/* 0x9a */ kKeyNone, // unassigned
|
|
/* 0x9b */ kKeyNone, // unassigned
|
|
/* 0x9c */ kKeyNone, // unassigned
|
|
/* 0x9d */ kKeyNone, // unassigned
|
|
/* 0x9e */ kKeyNone, // unassigned
|
|
/* 0x9f */ kKeyNone, // unassigned
|
|
/* 0xa0 */ 0xffe1, // VK_LSHIFT XK_Shift_L
|
|
/* 0xa1 */ 0xffe2, // VK_RSHIFT XK_Shift_R
|
|
/* 0xa2 */ 0xffe3, // VK_LCONTROL XK_Control_L
|
|
/* 0xa3 */ 0xffe4, // VK_RCONTROL XK_Control_R
|
|
/* 0xa4 */ 0xffe9, // VK_LMENU XK_Alt_L
|
|
/* 0xa5 */ 0xffea, // VK_RMENU XK_Alt_R
|
|
/* 0xa6 */ kKeyNone, // unassigned
|
|
/* 0xa7 */ kKeyNone, // unassigned
|
|
/* 0xa8 */ kKeyNone, // unassigned
|
|
/* 0xa9 */ kKeyNone, // unassigned
|
|
/* 0xaa */ kKeyNone, // unassigned
|
|
/* 0xab */ kKeyNone, // unassigned
|
|
/* 0xac */ kKeyNone, // unassigned
|
|
/* 0xad */ kKeyNone, // unassigned
|
|
/* 0xae */ kKeyNone, // unassigned
|
|
/* 0xaf */ kKeyNone, // unassigned
|
|
/* 0xb0 */ kKeyNone, // unassigned
|
|
/* 0xb1 */ kKeyNone, // unassigned
|
|
/* 0xb2 */ kKeyNone, // unassigned
|
|
/* 0xb3 */ kKeyNone, // unassigned
|
|
/* 0xb4 */ kKeyNone, // unassigned
|
|
/* 0xb5 */ kKeyNone, // unassigned
|
|
/* 0xb6 */ kKeyNone, // unassigned
|
|
/* 0xb7 */ kKeyNone, // unassigned
|
|
/* 0xb8 */ kKeyNone, // unassigned
|
|
/* 0xb9 */ kKeyNone, // unassigned
|
|
/* 0xba */ kKeyNone, // OEM specific
|
|
/* 0xbb */ kKeyNone, // OEM specific
|
|
/* 0xbc */ kKeyNone, // OEM specific
|
|
/* 0xbd */ kKeyNone, // OEM specific
|
|
/* 0xbe */ kKeyNone, // OEM specific
|
|
/* 0xbf */ kKeyNone, // OEM specific
|
|
/* 0xc0 */ kKeyNone, // OEM specific
|
|
/* 0xc1 */ kKeyNone, // unassigned
|
|
/* 0xc2 */ kKeyNone, // unassigned
|
|
/* 0xc3 */ kKeyNone, // unassigned
|
|
/* 0xc4 */ kKeyNone, // unassigned
|
|
/* 0xc5 */ kKeyNone, // unassigned
|
|
/* 0xc6 */ kKeyNone, // unassigned
|
|
/* 0xc7 */ kKeyNone, // unassigned
|
|
/* 0xc8 */ kKeyNone, // unassigned
|
|
/* 0xc9 */ kKeyNone, // unassigned
|
|
/* 0xca */ kKeyNone, // unassigned
|
|
/* 0xcb */ kKeyNone, // unassigned
|
|
/* 0xcc */ kKeyNone, // unassigned
|
|
/* 0xcd */ kKeyNone, // unassigned
|
|
/* 0xce */ kKeyNone, // unassigned
|
|
/* 0xcf */ kKeyNone, // unassigned
|
|
/* 0xd0 */ kKeyNone, // unassigned
|
|
/* 0xd1 */ kKeyNone, // unassigned
|
|
/* 0xd2 */ kKeyNone, // unassigned
|
|
/* 0xd3 */ kKeyNone, // unassigned
|
|
/* 0xd4 */ kKeyNone, // unassigned
|
|
/* 0xd5 */ kKeyNone, // unassigned
|
|
/* 0xd6 */ kKeyNone, // unassigned
|
|
/* 0xd7 */ kKeyNone, // unassigned
|
|
/* 0xd8 */ kKeyNone, // unassigned
|
|
/* 0xd9 */ kKeyNone, // unassigned
|
|
/* 0xda */ kKeyNone, // unassigned
|
|
/* 0xdb */ kKeyNone, // OEM specific
|
|
/* 0xdc */ kKeyNone, // OEM specific
|
|
/* 0xdd */ kKeyNone, // OEM specific
|
|
/* 0xde */ kKeyNone, // OEM specific
|
|
/* 0xdf */ kKeyNone, // OEM specific
|
|
/* 0xe0 */ kKeyNone, // OEM specific
|
|
/* 0xe1 */ kKeyNone, // OEM specific
|
|
/* 0xe2 */ kKeyNone, // OEM specific
|
|
/* 0xe3 */ kKeyNone, // OEM specific
|
|
/* 0xe4 */ kKeyNone, // OEM specific
|
|
/* 0xe5 */ kKeyNone, // unassigned
|
|
/* 0xe6 */ kKeyNone, // OEM specific
|
|
/* 0xe7 */ kKeyNone, // unassigned
|
|
/* 0xe8 */ kKeyNone, // unassigned
|
|
/* 0xe9 */ kKeyNone, // OEM specific
|
|
/* 0xea */ kKeyNone, // OEM specific
|
|
/* 0xeb */ kKeyNone, // OEM specific
|
|
/* 0xec */ kKeyNone, // OEM specific
|
|
/* 0xed */ kKeyNone, // OEM specific
|
|
/* 0xee */ kKeyNone, // OEM specific
|
|
/* 0xef */ kKeyNone, // OEM specific
|
|
/* 0xf0 */ kKeyNone, // OEM specific
|
|
/* 0xf1 */ kKeyNone, // OEM specific
|
|
/* 0xf2 */ kKeyNone, // OEM specific
|
|
/* 0xf3 */ kKeyNone, // OEM specific
|
|
/* 0xf4 */ kKeyNone, // OEM specific
|
|
/* 0xf5 */ kKeyNone, // OEM specific
|
|
/* 0xf6 */ kKeyNone, // VK_ATTN
|
|
/* 0xf7 */ kKeyNone, // VK_CRSEL
|
|
/* 0xf8 */ kKeyNone, // VK_EXSEL
|
|
/* 0xf9 */ kKeyNone, // VK_EREOF
|
|
/* 0xfa */ kKeyNone, // VK_PLAY
|
|
/* 0xfb */ kKeyNone, // VK_ZOOM
|
|
/* 0xfc */ kKeyNone, // reserved
|
|
/* 0xfd */ kKeyNone, // VK_PA1
|
|
/* 0xfe */ kKeyNone, // VK_OEM_CLEAR
|
|
/* 0xff */ kKeyNone // reserved
|
|
};
|
|
|
|
KeyID CMSWindowsPrimaryScreen::mapKey(
|
|
WPARAM vkCode, LPARAM info,
|
|
KeyModifierMask* maskOut)
|
|
{
|
|
// note: known microsoft bugs
|
|
// Q72583 -- MapVirtualKey() maps keypad keys incorrectly
|
|
// 95,98: num pad vk code -> invalid scan code
|
|
// 95,98,NT4: num pad scan code -> bad vk code except
|
|
// SEPARATOR, MULTIPLY, SUBTRACT, ADD
|
|
|
|
static const KeyID XK_Multi_key = 0xff20;
|
|
|
|
assert(maskOut != NULL);
|
|
|
|
// map modifier key
|
|
KeyModifierMask mask = 0;
|
|
if (((m_keys[VK_LSHIFT] |
|
|
m_keys[VK_RSHIFT] |
|
|
m_keys[VK_SHIFT]) & 0x80) != 0)
|
|
mask |= KeyModifierShift;
|
|
if (((m_keys[VK_LCONTROL] |
|
|
m_keys[VK_RCONTROL] |
|
|
m_keys[VK_CONTROL]) & 0x80) != 0)
|
|
mask |= KeyModifierControl;
|
|
if (((m_keys[VK_LMENU] |
|
|
m_keys[VK_RMENU] |
|
|
m_keys[VK_MENU]) & 0x80) != 0)
|
|
mask |= KeyModifierAlt;
|
|
if (((m_keys[VK_LWIN] |
|
|
m_keys[VK_RWIN]) & 0x80) != 0)
|
|
mask |= KeyModifierMeta;
|
|
if ((m_keys[VK_CAPITAL] & 0x01) != 0)
|
|
mask |= KeyModifierCapsLock;
|
|
if ((m_keys[VK_NUMLOCK] & 0x01) != 0)
|
|
mask |= KeyModifierNumLock;
|
|
if ((m_keys[VK_SCROLL] & 0x01) != 0)
|
|
mask |= KeyModifierScrollLock;
|
|
*maskOut = mask;
|
|
log((CLOG_DEBUG2 "key in vk=%d info=0x%08x mask=0x%04x", vkCode, info, mask));
|
|
|
|
// get the scan code
|
|
UINT scanCode = static_cast<UINT>((info & 0xff0000) >> 16);
|
|
|
|
// convert virtual key to one that distinguishes between left and
|
|
// right for keys that have left/right versions. known scan codes
|
|
// that don't have left/right versions are passed through unchanged.
|
|
// unknown scan codes return 0.
|
|
UINT vkCode2 = MapVirtualKey(scanCode, 3);
|
|
|
|
// work around bug Q72583 (bad num pad conversion in MapVirtualKey())
|
|
if (vkCode >= VK_NUMPAD0 && vkCode <= VK_DIVIDE)
|
|
vkCode2 = vkCode;
|
|
|
|
// MapVirtualKey() appears to map VK_LWIN, VK_RWIN, VK_APPS to
|
|
// some other meaningless virtual key. work around that bug.
|
|
else if (vkCode >= VK_LWIN && vkCode <= VK_APPS)
|
|
vkCode2 = vkCode;
|
|
|
|
// if MapVirtualKey failed then use original virtual key
|
|
else if (vkCode2 == 0)
|
|
vkCode2 = vkCode;
|
|
|
|
// sadly, win32 will not distinguish between the left and right
|
|
// control and alt keys using the above function. however, we
|
|
// can check for those: if bit 24 of info is set then the key
|
|
// is a "extended" key, such as the right control and right alt
|
|
// keys.
|
|
if ((info & 0x1000000) != 0) {
|
|
switch (vkCode2) {
|
|
case VK_CONTROL:
|
|
case VK_LCONTROL:
|
|
vkCode2 = VK_RCONTROL;
|
|
break;
|
|
|
|
case VK_MENU:
|
|
case VK_LMENU:
|
|
vkCode2 = VK_RMENU;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// use left/right distinguishing virtual key
|
|
vkCode = vkCode2;
|
|
log((CLOG_DEBUG1 "key vk=%d scan=%d", vkCode, scanCode));
|
|
|
|
// handle some keys via table lookup
|
|
KeyID id = g_virtualKey[vkCode];
|
|
if (id != kKeyNone) {
|
|
return id;
|
|
}
|
|
|
|
// check for dead keys
|
|
if (MapVirtualKey(vkCode, 2) >= 0x8000) {
|
|
return XK_Multi_key;
|
|
}
|
|
|
|
// ToAscii() maps ctrl+letter to the corresponding control code
|
|
// and ctrl+backspace to delete. if we've got a control code or
|
|
// delete then do ToAscii() again but without the control state.
|
|
// ToAscii() interprets the control modifier state which we don't
|
|
// want. so save the control state then clear it.
|
|
BYTE lControl = m_keys[VK_LCONTROL];
|
|
BYTE rControl = m_keys[VK_RCONTROL];
|
|
BYTE control = m_keys[VK_CONTROL];
|
|
m_keys[VK_LCONTROL] = 0;
|
|
m_keys[VK_RCONTROL] = 0;
|
|
m_keys[VK_CONTROL] = 0;
|
|
|
|
// convert to ascii
|
|
WORD ascii;
|
|
int result = ToAscii(vkCode, scanCode, m_keys, &ascii, 0);
|
|
|
|
// restore control state
|
|
m_keys[VK_LCONTROL] = lControl;
|
|
m_keys[VK_RCONTROL] = rControl;
|
|
m_keys[VK_CONTROL] = control;
|
|
|
|
// if result is less than zero then it was a dead key. that key
|
|
// is remembered by the keyboard which we don't want. remove it
|
|
// by calling ToAscii() again with arbitrary arguments.
|
|
if (result < 0) {
|
|
ToAscii(vkCode, scanCode, m_keys, &ascii, 0);
|
|
return XK_Multi_key;
|
|
}
|
|
|
|
// if result is 1 then the key was succesfully converted
|
|
else if (result == 1) {
|
|
return static_cast<KeyID>(ascii & 0x00ff);
|
|
}
|
|
|
|
// if result is 2 then a previous dead key could not be composed.
|
|
// put the old dead key back.
|
|
else if (result == 2) {
|
|
// get the scan code of the dead key and the shift state
|
|
// required to generate it.
|
|
vkCode = VkKeyScan(static_cast<TCHAR>(ascii & 0x00ff));
|
|
|
|
// set shift state required to generate key
|
|
BYTE keys[256];
|
|
memset(keys, 0, sizeof(keys));
|
|
if (vkCode & 0x0100)
|
|
keys[VK_SHIFT] = 0x80;
|
|
if (vkCode & 0x0100)
|
|
keys[VK_CONTROL] = 0x80;
|
|
if (vkCode & 0x0100)
|
|
keys[VK_MENU] = 0x80;
|
|
|
|
// strip shift state off of virtual key code
|
|
vkCode &= 0x00ff;
|
|
|
|
// get the scan code for the key
|
|
scanCode = MapVirtualKey(vkCode, 0);
|
|
|
|
// put it back
|
|
ToAscii(vkCode, scanCode, keys, &ascii, 0);
|
|
return XK_Multi_key;
|
|
}
|
|
|
|
// cannot convert key
|
|
return kKeyNone;
|
|
}
|
|
|
|
ButtonID CMSWindowsPrimaryScreen::mapButton(
|
|
WPARAM button) const
|
|
{
|
|
switch (button) {
|
|
case WM_LBUTTONDOWN:
|
|
case WM_LBUTTONUP:
|
|
return kButtonLeft;
|
|
|
|
case WM_MBUTTONDOWN:
|
|
case WM_MBUTTONUP:
|
|
return kButtonMiddle;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
case WM_RBUTTONUP:
|
|
return kButtonRight;
|
|
|
|
default:
|
|
return kButtonNone;
|
|
}
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::updateKeys()
|
|
{
|
|
// not using GetKeyboardState() because that doesn't seem to give
|
|
// up-to-date results. i don't know why that is or why GetKeyState()
|
|
// should give different results.
|
|
|
|
// clear key state
|
|
memset(m_keys, 0, sizeof(m_keys));
|
|
|
|
// we only care about the modifier key states
|
|
m_keys[VK_LSHIFT] = static_cast<BYTE>(GetKeyState(VK_LSHIFT));
|
|
m_keys[VK_RSHIFT] = static_cast<BYTE>(GetKeyState(VK_RSHIFT));
|
|
m_keys[VK_SHIFT] = static_cast<BYTE>(GetKeyState(VK_SHIFT));
|
|
m_keys[VK_LCONTROL] = static_cast<BYTE>(GetKeyState(VK_LCONTROL));
|
|
m_keys[VK_RCONTROL] = static_cast<BYTE>(GetKeyState(VK_RCONTROL));
|
|
m_keys[VK_CONTROL] = static_cast<BYTE>(GetKeyState(VK_CONTROL));
|
|
m_keys[VK_LMENU] = static_cast<BYTE>(GetKeyState(VK_LMENU));
|
|
m_keys[VK_RMENU] = static_cast<BYTE>(GetKeyState(VK_RMENU));
|
|
m_keys[VK_MENU] = static_cast<BYTE>(GetKeyState(VK_MENU));
|
|
m_keys[VK_LWIN] = static_cast<BYTE>(GetKeyState(VK_LWIN));
|
|
m_keys[VK_RWIN] = static_cast<BYTE>(GetKeyState(VK_RWIN));
|
|
m_keys[VK_APPS] = static_cast<BYTE>(GetKeyState(VK_APPS));
|
|
m_keys[VK_CAPITAL] = static_cast<BYTE>(GetKeyState(VK_CAPITAL));
|
|
m_keys[VK_NUMLOCK] = static_cast<BYTE>(GetKeyState(VK_NUMLOCK));
|
|
m_keys[VK_SCROLL] = static_cast<BYTE>(GetKeyState(VK_SCROLL));
|
|
}
|
|
|
|
void CMSWindowsPrimaryScreen::updateKey(
|
|
UINT vkCode, bool press)
|
|
{
|
|
if (press) {
|
|
switch (vkCode) {
|
|
case VK_LSHIFT:
|
|
case VK_RSHIFT:
|
|
case VK_SHIFT:
|
|
m_keys[vkCode] |= 0x80;
|
|
m_keys[VK_SHIFT] |= 0x80;
|
|
break;
|
|
|
|
case VK_LCONTROL:
|
|
case VK_RCONTROL:
|
|
case VK_CONTROL:
|
|
m_keys[vkCode] |= 0x80;
|
|
m_keys[VK_CONTROL] |= 0x80;
|
|
break;
|
|
|
|
case VK_LMENU:
|
|
case VK_RMENU:
|
|
case VK_MENU:
|
|
m_keys[vkCode] |= 0x80;
|
|
m_keys[VK_MENU] |= 0x80;
|
|
break;
|
|
|
|
case VK_LWIN:
|
|
case VK_RWIN:
|
|
case VK_APPS:
|
|
m_keys[vkCode] |= 0x80;
|
|
break;
|
|
|
|
case VK_CAPITAL:
|
|
case VK_NUMLOCK:
|
|
case VK_SCROLL:
|
|
// toggle keys
|
|
m_keys[vkCode] |= 0x80;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
switch (vkCode) {
|
|
case VK_LSHIFT:
|
|
case VK_RSHIFT:
|
|
case VK_SHIFT:
|
|
m_keys[vkCode] &= ~0x80;
|
|
if (((m_keys[VK_LSHIFT] | m_keys[VK_RSHIFT]) & 0x80) == 0) {
|
|
m_keys[VK_SHIFT] &= ~0x80;
|
|
}
|
|
break;
|
|
|
|
case VK_LCONTROL:
|
|
case VK_RCONTROL:
|
|
case VK_CONTROL:
|
|
m_keys[vkCode] &= ~0x80;
|
|
if (((m_keys[VK_LCONTROL] | m_keys[VK_RCONTROL]) & 0x80) == 0) {
|
|
m_keys[VK_CONTROL] &= ~0x80;
|
|
}
|
|
break;
|
|
|
|
case VK_LMENU:
|
|
case VK_RMENU:
|
|
case VK_MENU:
|
|
m_keys[vkCode] &= ~0x80;
|
|
if (((m_keys[VK_LMENU] | m_keys[VK_RMENU]) & 0x80) == 0) {
|
|
m_keys[VK_MENU] &= ~0x80;
|
|
}
|
|
break;
|
|
|
|
case VK_LWIN:
|
|
case VK_RWIN:
|
|
case VK_APPS:
|
|
m_keys[vkCode] &= ~0x80;
|
|
break;
|
|
|
|
case VK_CAPITAL:
|
|
case VK_NUMLOCK:
|
|
case VK_SCROLL:
|
|
// toggle keys
|
|
m_keys[vkCode] &= ~0x80;
|
|
m_keys[vkCode] ^= 0x01;
|
|
break;
|
|
}
|
|
}
|
|
}
|