diff --git a/configure.in b/configure.in index 92deeadb..a5453acf 100644 --- a/configure.in +++ b/configure.in @@ -57,6 +57,7 @@ AC_PATH_XTRA save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$X_CFLAGS $CPPFLAGS" AC_CHECK_HEADERS([X11/extensions/XTest.h]) +AC_CHECK_HEADERS([X11/XF86keysym.h]) AC_CHECK_LIB(Xinerama, XineramaQueryExtension, AC_CHECK_HEADERS([X11/extensions/Xinerama.h]) [X_LIBS="$X_LIBS -lXinerama"], , [$X_LIBS -lXext -lX11 $X_EXTRA_LIBS]) CPPFLAGS="$save_CPPFLAGS" diff --git a/lib/platform/CMSWindowsPrimaryScreen.cpp b/lib/platform/CMSWindowsPrimaryScreen.cpp index bc5257ff..92d3e832 100644 --- a/lib/platform/CMSWindowsPrimaryScreen.cpp +++ b/lib/platform/CMSWindowsPrimaryScreen.cpp @@ -21,16 +21,38 @@ #include "CArchMiscWindows.h" #include +// X button stuff +#if !defined(WM_XBUTTONDOWN) +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_NCXBUTTONDOWN 0x00AB +#define WM_NCXBUTTONUP 0x00AC +#define WM_NCXBUTTONDBLCLK 0x00AD +#define MOUSEEVENTF_XDOWN 0x0100 +#define MOUSEEVENTF_XUP 0x0200 +#define XBUTTON1 0x0001 +#define XBUTTON2 0x0002 +#endif + // // map virtual key id to a name // +static const char* g_buttonToName[] = { + "button 0", + "Left Button", + "Middle Button", + "Right Button", + "X Button 1", + "X Button 2" +}; static const char* g_vkToName[] = { "vk 0x00", - "VK_LBUTTON", - "VK_RBUTTON", + "Left Button", + "Right Button", "VK_CANCEL", - "VK_MBUTTON", + "Middle Button", "vk 0x05", "vk 0x06", "vk 0x07", @@ -192,24 +214,24 @@ static const char* g_vkToName[] = { "VK_RCONTROL", "VK_LMENU", "VK_RMENU", - "vk 0xa6", - "vk 0xa7", - "vk 0xa8", - "vk 0xa9", - "vk 0xaa", - "vk 0xab", - "vk 0xac", - "vk 0xad", - "vk 0xae", - "vk 0xaf", - "vk 0xb0", - "vk 0xb1", - "vk 0xb2", - "vk 0xb3", - "vk 0xb4", - "vk 0xb5", - "vk 0xb6", - "vk 0xb7", + "VK_BROWSER_BACK", + "VK_BROWSER_FORWARD", + "VK_BROWSER_REFRESH", + "VK_BROWSER_STOP", + "VK_BROWSER_SEARCH", + "VK_BROWSER_FAVORITES", + "VK_BROWSER_HOME", + "VK_VOLUME_MUTE", + "VK_VOLUME_DOWN", + "VK_VOLUME_UP", + "VK_MEDIA_NEXT_TRACK", + "VK_MEDIA_PREV_TRACK", + "VK_MEDIA_STOP", + "VK_MEDIA_PLAY_PAUSE", + "VK_LAUNCH_MAIL", + "VK_LAUNCH_MEDIA_SELECT", + "VK_LAUNCH_APP1", + "VK_LAUNCH_APP2", "vk 0xb8", "vk 0xb9", "vk 0xba", @@ -384,24 +406,14 @@ KeyModifierMask CMSWindowsPrimaryScreen::getToggleMask() const { KeyModifierMask mask = 0; - if (!m_lowLevel) { - // get key state from our shadow state - 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; - } - else { - // get key state from the system when using low level hooks - if ((GetKeyState(VK_CAPITAL) & 0x01) != 0) - mask |= KeyModifierCapsLock; - if ((GetKeyState(VK_NUMLOCK) & 0x01) != 0) - mask |= KeyModifierNumLock; - if ((GetKeyState(VK_SCROLL) & 0x01) != 0) - mask |= KeyModifierScrollLock; - } + + // get key state from our shadow state + 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; return mask; } @@ -409,44 +421,17 @@ CMSWindowsPrimaryScreen::getToggleMask() const bool CMSWindowsPrimaryScreen::isLockedToScreen() const { - // virtual key table. the table defines the virtual keys that are - // mapped to something (including mouse buttons, OEM and kanji keys - // but not unassigned or undefined keys). - static const UInt32 s_mappedKeys[] = { - 0xfbff331e, - 0x03ffffff, - 0x3ffffffe, - 0xffffffff, - 0x000300ff, - 0xfc000000, - 0xf8000001, - 0x7ffffe5f - }; - - // check each key. if we're capturing events at a low level we - // can query the keyboard state using GetKeyState(). if not we - // resort to using our shadow keyboard state since the system's - // shadow state won't be in sync (because our window is not - // getting keyboard events). - if (!m_lowLevel) { - // use shadow keyboard state in m_keys - for (UInt32 i = 0; i < 256; ++i) { - if ((m_keys[i] & 0x80) != 0) { - LOG((CLOG_DEBUG "locked by \"%s\"", g_vkToName[i])); - return true; - } + // use shadow keyboard state in m_keys and m_buttons + for (UInt32 i = 0; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) { + if ((m_buttons[i] & 0x80) != 0) { + LOG((CLOG_DEBUG "locked by \"%s\"", g_buttonToName[i])); + return true; } } - else { - for (UInt32 i = 0; i < 256 / 32; ++i) { - for (UInt32 b = 1, j = 0; j < 32; b <<= 1, ++j) { - if ((s_mappedKeys[i] & b) != 0) { - if (GetKeyState(i * 32 + j) < 0) { - LOG((CLOG_DEBUG "locked by \"%s\"", g_vkToName[i * 32 + j])); - return true; - } - } - } + for (UInt32 i = 0; i < sizeof(m_keys) / sizeof(m_keys[0]); ++i) { + if ((m_keys[i] & 0x80) != 0) { + LOG((CLOG_DEBUG "locked by \"%s\"", g_vkToName[i])); + return true; } } @@ -583,16 +568,9 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event) return true; case SYNERGY_MSG_MOUSE_BUTTON: { - static const int s_vkButton[] = { - 0, // kButtonNone - VK_LBUTTON, // kButtonLeft, etc. - VK_MBUTTON, - VK_RBUTTON - }; - // get which button bool pressed = false; - const ButtonID button = mapButton(msg->wParam); + const ButtonID button = mapButton(msg->wParam, msg->lParam); // ignore message if posted prior to last mark change if (!ignore()) { @@ -600,19 +578,22 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event) case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: + case WM_XBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: + case WM_XBUTTONDBLCLK: case WM_NCLBUTTONDOWN: case WM_NCMBUTTONDOWN: case WM_NCRBUTTONDOWN: + case WM_NCXBUTTONDOWN: case WM_NCLBUTTONDBLCLK: case WM_NCMBUTTONDBLCLK: case WM_NCRBUTTONDBLCLK: + case WM_NCXBUTTONDBLCLK: LOG((CLOG_DEBUG1 "event: button press button=%d", button)); if (button != kButtonNone) { m_receiver->onMouseDown(button); - m_keys[s_vkButton[button]] |= 0x80; } pressed = true; break; @@ -620,13 +601,14 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event) case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: + case WM_XBUTTONUP: case WM_NCLBUTTONUP: case WM_NCMBUTTONUP: case WM_NCRBUTTONUP: + case WM_NCXBUTTONUP: LOG((CLOG_DEBUG1 "event: button release button=%d", button)); if (button != kButtonNone) { m_receiver->onMouseUp(button); - m_keys[s_vkButton[button]] &= ~0x80; } pressed = false; break; @@ -634,8 +616,13 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event) } // keep our shadow key state up to date - if (button != kButtonNone) { - updateKey(s_vkButton[button], pressed); + if (button >= kButtonLeft && button <= kButtonExtra0 + 1) { + if (pressed) { + m_buttons[button] |= 0x80; + } + else { + m_buttons[button] &= ~0x80; + } } return true; @@ -1139,24 +1126,24 @@ static const KeyID g_virtualKey[][2] = /* 0xa3 */ kKeyControl_R, kKeyControl_R, // VK_RCONTROL /* 0xa4 */ kKeyAlt_L, kKeyAlt_L, // VK_LMENU /* 0xa5 */ kKeyAlt_R, kKeyAlt_R, // VK_RMENU - /* 0xa6 */ kKeyNone, kKeyNone, // unassigned - /* 0xa7 */ kKeyNone, kKeyNone, // unassigned - /* 0xa8 */ kKeyNone, kKeyNone, // unassigned - /* 0xa9 */ kKeyNone, kKeyNone, // unassigned - /* 0xaa */ kKeyNone, kKeyNone, // unassigned - /* 0xab */ kKeyNone, kKeyNone, // unassigned - /* 0xac */ kKeyNone, kKeyNone, // unassigned - /* 0xad */ kKeyNone, kKeyNone, // unassigned - /* 0xae */ kKeyNone, kKeyNone, // unassigned - /* 0xaf */ kKeyNone, kKeyNone, // unassigned - /* 0xb0 */ kKeyNone, kKeyNone, // unassigned - /* 0xb1 */ kKeyNone, kKeyNone, // unassigned - /* 0xb2 */ kKeyNone, kKeyNone, // unassigned - /* 0xb3 */ kKeyNone, kKeyNone, // unassigned - /* 0xb4 */ kKeyNone, kKeyNone, // unassigned - /* 0xb5 */ kKeyNone, kKeyNone, // unassigned - /* 0xb6 */ kKeyNone, kKeyNone, // unassigned - /* 0xb7 */ kKeyNone, kKeyNone, // unassigned + /* 0xa6 */ kKeyNone, kKeyWWWBack, // VK_BROWSER_BACK + /* 0xa7 */ kKeyNone, kKeyWWWForward, // VK_BROWSER_FORWARD + /* 0xa8 */ kKeyNone, kKeyWWWRefresh, // VK_BROWSER_REFRESH + /* 0xa9 */ kKeyNone, kKeyWWWStop, // VK_BROWSER_STOP + /* 0xaa */ kKeyNone, kKeyWWWSearch, // VK_BROWSER_SEARCH + /* 0xab */ kKeyNone, kKeyWWWFavorites, // VK_BROWSER_FAVORITES + /* 0xac */ kKeyNone, kKeyWWWHome, // VK_BROWSER_HOME + /* 0xad */ kKeyNone, kKeyAudioMute, // VK_VOLUME_MUTE + /* 0xae */ kKeyNone, kKeyAudioDown, // VK_VOLUME_DOWN + /* 0xaf */ kKeyNone, kKeyAudioUp, // VK_VOLUME_UP + /* 0xb0 */ kKeyNone, kKeyAudioNext, // VK_MEDIA_NEXT_TRACK + /* 0xb1 */ kKeyNone, kKeyAudioPrev, // VK_MEDIA_PREV_TRACK + /* 0xb2 */ kKeyNone, kKeyAudioStop, // VK_MEDIA_STOP + /* 0xb3 */ kKeyNone, kKeyAudioPlay, // VK_MEDIA_PLAY_PAUSE + /* 0xb4 */ kKeyNone, kKeyAppMail, // VK_LAUNCH_MAIL + /* 0xb5 */ kKeyNone, kKeyAppMedia, // VK_LAUNCH_MEDIA_SELECT + /* 0xb6 */ kKeyNone, kKeyAppUser1, // VK_LAUNCH_APP1 + /* 0xb7 */ kKeyNone, kKeyAppUser2, // VK_LAUNCH_APP2 /* 0xb8 */ kKeyNone, kKeyNone, // unassigned /* 0xb9 */ kKeyNone, kKeyNone, // unassigned /* 0xba */ kKeyNone, kKeyNone, // OEM specific @@ -1407,9 +1394,9 @@ CMSWindowsPrimaryScreen::mapKey( } ButtonID -CMSWindowsPrimaryScreen::mapButton(WPARAM button) const +CMSWindowsPrimaryScreen::mapButton(WPARAM msg, LPARAM button) const { - switch (button) { + switch (msg) { case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP: @@ -1434,6 +1421,21 @@ CMSWindowsPrimaryScreen::mapButton(WPARAM button) const case WM_NCRBUTTONUP: return kButtonRight; + case WM_XBUTTONDOWN: + case WM_XBUTTONDBLCLK: + case WM_XBUTTONUP: + case WM_NCXBUTTONDOWN: + case WM_NCXBUTTONDBLCLK: + case WM_NCXBUTTONUP: + switch (button) { + case XBUTTON1: + return kButtonExtra0 + 0; + + case XBUTTON2: + return kButtonExtra0 + 1; + } + return kButtonNone; + default: return kButtonNone; } @@ -1446,8 +1448,9 @@ CMSWindowsPrimaryScreen::updateKeys() // up-to-date results. i don't know why that is or why GetKeyState() // should give different results. - // clear key state + // clear key and button state memset(m_keys, 0, sizeof(m_keys)); + memset(m_buttons, 0, sizeof(m_buttons)); // we only care about the modifier key states. other keys and the // mouse buttons should be up. diff --git a/lib/platform/CMSWindowsPrimaryScreen.h b/lib/platform/CMSWindowsPrimaryScreen.h index bb5c0eb0..dfe40adf 100644 --- a/lib/platform/CMSWindowsPrimaryScreen.h +++ b/lib/platform/CMSWindowsPrimaryScreen.h @@ -87,7 +87,7 @@ private: // key and button queries KeyID mapKey(WPARAM keycode, LPARAM info, KeyModifierMask* maskOut); - ButtonID mapButton(WPARAM button) const; + ButtonID mapButton(WPARAM msg, LPARAM button) const; void updateKey(UINT vkCode, bool press); bool isModifier(UINT vkCode) const; @@ -108,6 +108,9 @@ private: // map of key state BYTE m_keys[256]; + // map of button state + BYTE m_buttons[1 + kButtonExtra0 + 1]; + // last mouse position SInt32 m_x, m_y; diff --git a/lib/platform/CMSWindowsSecondaryScreen.cpp b/lib/platform/CMSWindowsSecondaryScreen.cpp index 35fd8c74..d6ad9c47 100644 --- a/lib/platform/CMSWindowsSecondaryScreen.cpp +++ b/lib/platform/CMSWindowsSecondaryScreen.cpp @@ -28,6 +28,42 @@ #define SPI_SETMOUSESPEED 113 #endif +// X button stuff +#if !defined(WM_XBUTTONDOWN) +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_NCXBUTTONDOWN 0x00AB +#define WM_NCXBUTTONUP 0x00AC +#define WM_NCXBUTTONDBLCLK 0x00AD +#define MOUSEEVENTF_XDOWN 0x0100 +#define MOUSEEVENTF_XUP 0x0200 +#define XBUTTON1 0x0001 +#define XBUTTON2 0x0002 +#endif + +// multimedia keys +#if !defined(VK_BROWSER_BACK) +#define VK_BROWSER_BACK 0xA6 +#define VK_BROWSER_FORWARD 0xA7 +#define VK_BROWSER_REFRESH 0xA8 +#define VK_BROWSER_STOP 0xA9 +#define VK_BROWSER_SEARCH 0xAA +#define VK_BROWSER_FAVORITES 0xAB +#define VK_BROWSER_HOME 0xAC +#define VK_VOLUME_MUTE 0xAD +#define VK_VOLUME_DOWN 0xAE +#define VK_VOLUME_UP 0xAF +#define VK_MEDIA_NEXT_TRACK 0xB0 +#define VK_MEDIA_PREV_TRACK 0xB1 +#define VK_MEDIA_STOP 0xB2 +#define VK_MEDIA_PLAY_PAUSE 0xB3 +#define VK_LAUNCH_MAIL 0xB4 +#define VK_LAUNCH_MEDIA_SELECT 0xB5 +#define VK_LAUNCH_APP1 0xB6 +#define VK_LAUNCH_APP2 0xB7 +#endif + // // CMSWindowsSecondaryScreen // @@ -258,11 +294,12 @@ CMSWindowsSecondaryScreen::mouseDown(ButtonID button) m_screen->syncDesktop(); // map button id to button flag - DWORD flags = mapButton(button, true); + DWORD data; + DWORD flags = mapButton(button, true, &data); // send event if (flags != 0) { - mouse_event(flags, 0, 0, 0, 0); + mouse_event(flags, 0, 0, data, 0); } } @@ -273,11 +310,12 @@ CMSWindowsSecondaryScreen::mouseUp(ButtonID button) m_screen->syncDesktop(); // map button id to button flag - DWORD flags = mapButton(button, false); + DWORD data; + DWORD flags = mapButton(button, false, &data); // send event if (flags != 0) { - mouse_event(flags, 0, 0, 0, 0); + mouse_event(flags, 0, 0, data, 0); } } @@ -606,6 +644,48 @@ CMSWindowsSecondaryScreen::getToggleState() const // map special KeyID keys to virtual key codes. if the key is an // extended key then the entry is the virtual key code | 0x100. // unmapped keys have a 0 entry. +static const UINT g_mapE000[] = +{ + /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x18 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x28 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x48 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x68 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x88 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x98 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xa0 */ 0, 0, 0, 0, + /* 0xa4 */ 0, 0, VK_BROWSER_BACK|0x100, VK_BROWSER_FORWARD|0x100, + /* 0xa8 */ VK_BROWSER_REFRESH|0x100, VK_BROWSER_STOP|0x100, + /* 0xaa */ VK_BROWSER_SEARCH|0x100, VK_BROWSER_FAVORITES|0x100, + /* 0xac */ VK_BROWSER_HOME|0x100, VK_VOLUME_MUTE|0x100, + /* 0xae */ VK_VOLUME_DOWN|0x100, VK_VOLUME_UP|0x100, + /* 0xb0 */ VK_MEDIA_NEXT_TRACK|0x100, VK_MEDIA_PREV_TRACK|0x100, + /* 0xb2 */ VK_MEDIA_STOP|0x100, VK_MEDIA_PLAY_PAUSE|0x100, + /* 0xb4 */ VK_LAUNCH_MAIL|0x100, VK_LAUNCH_MEDIA_SELECT|0x100, + /* 0xb6 */ VK_LAUNCH_APP1|0x100, VK_LAUNCH_APP2|0x100, + /* 0xb8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xe8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0 +}; static const UINT g_mapEE00[] = { /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, @@ -685,8 +765,12 @@ static const UINT g_mapEF00[] = }; DWORD -CMSWindowsSecondaryScreen::mapButton(ButtonID button, bool press) const +CMSWindowsSecondaryScreen::mapButton(ButtonID button, + bool press, DWORD* inData) const { + DWORD dummy; + DWORD* data = (inData != NULL) ? inData : &dummy; + // the system will swap the meaning of left/right for us if // the user has configured a left-handed mouse but we don't // want it to swap since we want the handedness of the @@ -703,7 +787,8 @@ CMSWindowsSecondaryScreen::mapButton(ButtonID button, bool press) const } } - // map button id to button flag + // map button id to button flag and button data + *data = 0; switch (button) { case kButtonLeft: return press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; @@ -714,6 +799,14 @@ CMSWindowsSecondaryScreen::mapButton(ButtonID button, bool press) const case kButtonRight: return press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; + case kButtonExtra0 + 0: + *data = XBUTTON1; + return press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; + + case kButtonExtra0 + 1: + *data = XBUTTON2; + return press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; + default: return 0; } @@ -727,7 +820,10 @@ CMSWindowsSecondaryScreen::mapKey(Keystrokes& keys, UINT& virtualKey, // check for special keys if ((id & 0xfffff000) == 0xe000) { - if ((id & 0xff00) == 0xee00) { + if ((id & 0xff00) == 0xe000) { + virtualKey = g_mapE000[id & 0xff]; + } + else if ((id & 0xff00) == 0xee00) { virtualKey = g_mapEE00[id & 0xff]; } else if ((id & 0xff00) == 0xef00) { diff --git a/lib/platform/CMSWindowsSecondaryScreen.h b/lib/platform/CMSWindowsSecondaryScreen.h index 3acff252..b975b46c 100644 --- a/lib/platform/CMSWindowsSecondaryScreen.h +++ b/lib/platform/CMSWindowsSecondaryScreen.h @@ -98,7 +98,8 @@ private: bool isMultimon() const; // key and button queries and operations - DWORD mapButton(ButtonID button, bool press) const; + DWORD mapButton(ButtonID button, + bool press, DWORD* data) const; KeyModifierMask mapKey(Keystrokes&, UINT& virtualKey, KeyID, KeyModifierMask, EKeyAction) const; void doKeystrokes(const Keystrokes&, SInt32 count); diff --git a/lib/platform/CSynergyHook.cpp b/lib/platform/CSynergyHook.cpp index 1742f91c..d5dcc1e5 100644 --- a/lib/platform/CSynergyHook.cpp +++ b/lib/platform/CSynergyHook.cpp @@ -45,6 +45,20 @@ typedef struct tagMOUSEHOOKSTRUCTWin2000 { #define SM_MOUSEWHEELPRESENT 75 #endif +// X button stuff +#if !defined(WM_XBUTTONDOWN) +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_NCXBUTTONDOWN 0x00AB +#define WM_NCXBUTTONUP 0x00AC +#define WM_NCXBUTTONDBLCLK 0x00AD +#define MOUSEEVENTF_XDOWN 0x0100 +#define MOUSEEVENTF_XUP 0x0200 +#define XBUTTON1 0x0001 +#define XBUTTON2 0x0002 +#endif + // // globals @@ -152,35 +166,41 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam) static bool -mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 wheel) +mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) { switch (wParam) { case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: + case WM_XBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: + case WM_XBUTTONDBLCLK: case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: + case WM_XBUTTONUP: case WM_NCLBUTTONDOWN: case WM_NCMBUTTONDOWN: case WM_NCRBUTTONDOWN: + case WM_NCXBUTTONDOWN: case WM_NCLBUTTONDBLCLK: case WM_NCMBUTTONDBLCLK: case WM_NCRBUTTONDBLCLK: + case WM_NCXBUTTONDBLCLK: case WM_NCLBUTTONUP: case WM_NCMBUTTONUP: case WM_NCRBUTTONUP: + case WM_NCXBUTTONUP: // always relay the event. eat it if relaying. - PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_BUTTON, wParam, 0); + PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_BUTTON, wParam, data); return g_relay; case WM_MOUSEWHEEL: if (g_relay) { // relay event - PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, wheel, 0); + PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0); } return g_relay; @@ -276,7 +296,10 @@ mouseHook(int code, WPARAM wParam, LPARAM lParam) } } - // handle the message + // handle the message. note that we don't handle X buttons + // here. that's okay because they're only supported on + // win2k and winxp and up and on those platforms we'll get + // get the mouse events through the low level hook. if (mouseHookHandler(wParam, x, y, w)) { return 1; } diff --git a/lib/platform/CXWindowsPrimaryScreen.cpp b/lib/platform/CXWindowsPrimaryScreen.cpp index b4469cb1..857ad119 100644 --- a/lib/platform/CXWindowsPrimaryScreen.cpp +++ b/lib/platform/CXWindowsPrimaryScreen.cpp @@ -699,6 +699,44 @@ CXWindowsPrimaryScreen::mapModifier(unsigned int state) const return mask; } +// map "Internet" keys to KeyIDs +static const KeySym g_map1008FF[] = +{ + /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ 0, kKeyAudioDown, kKeyAudioMute, kKeyAudioUp, + /* 0x14 */ kKeyAudioPlay, kKeyAudioStop, kKeyAudioPrev, kKeyAudioNext, + /* 0x18 */ kKeyWWWHome, kKeyAppMail, 0, kKeyWWWSearch, 0, 0, 0, 0, + /* 0x20 */ 0, 0, 0, 0, 0, 0, kKeyWWWBack, kKeyWWWForward, + /* 0x28 */ kKeyWWWStop, kKeyWWWRefresh, 0, 0, 0, 0, 0, 0, + /* 0x30 */ kKeyWWWFavorites, 0, kKeyAppMedia, 0, 0, 0, 0, 0, + /* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 */ kKeyAppUser1, kKeyAppUser2, 0, 0, 0, 0, 0, 0, + /* 0x48 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x68 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x88 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x98 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xb8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xe8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0 +}; + KeyID CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const { @@ -727,6 +765,10 @@ CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const // MISCELLANY return static_cast(keysym - 0xff00 + 0xef00); + case 0x1008ff00: + // "Internet" keys + return g_map1008FF[keysym & 0xff]; + default: { // lookup character in table UInt32 key = CXWindowsUtil::mapKeySymToUCS4(keysym); @@ -743,10 +785,18 @@ CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const ButtonID CXWindowsPrimaryScreen::mapButton(unsigned int button) const { - // FIXME -- should use button mapping? + // first three buttons map to 1, 2, 3 (kButtonLeft, Middle, Right) if (button >= 1 && button <= 3) { return static_cast(button); } + + // buttons 4 and 5 are ignored here. they're used for the wheel. + // buttons 6, 7, etc and up map to 4, 5, etc. + else if (button >= 6) { + return static_cast(button - 2); + } + + // unknown button else { return kButtonNone; } diff --git a/lib/platform/CXWindowsSecondaryScreen.cpp b/lib/platform/CXWindowsSecondaryScreen.cpp index 5f9c89ca..78ccc57a 100644 --- a/lib/platform/CXWindowsSecondaryScreen.cpp +++ b/lib/platform/CXWindowsSecondaryScreen.cpp @@ -34,6 +34,9 @@ # else # error The XTest extension is required to build synergy # endif +# if defined(HAVE_X11_XF86KEYSYM_H) +# include +# endif #endif // @@ -263,7 +266,8 @@ void CXWindowsSecondaryScreen::mouseWheel(SInt32 delta) { // choose button depending on rotation direction - const unsigned int xButton = mapButton((delta >= 0) ? 4 : 5); + const unsigned int xButton = mapButton(static_cast( + (delta >= 0) ? -1 : -2)); if (xButton == 0) { return; } @@ -573,17 +577,30 @@ CXWindowsSecondaryScreen::getToggleState() const unsigned int CXWindowsSecondaryScreen::mapButton(ButtonID id) const { + // map button -1 to button 4 (+wheel) + if (id == static_cast(-1)) { + id = 4; + } + + // map button -2 to button 5 (-wheel) + else if (id == static_cast(-2)) { + id = 5; + } + + // map buttons 4, 5, etc. to 6, 7, etc. to make room for buttons + // 4 and 5 used to simulate the mouse wheel. + else if (id >= 4) { + id += 2; + } + + // check button is in legal range if (id < 1 || id > m_buttons.size()) { // out of range return 0; } - else if (m_buttons[id - 1] == 0) { - // button not mapped - return 0; - } - else { - return static_cast(m_buttons[id - 1]); - } + + // map button + return static_cast(m_buttons[id - 1]); } KeyModifierMask @@ -1380,6 +1397,53 @@ CXWindowsSecondaryScreen::isToggleKeysym(KeySym key) } } +// map special KeyID keys to KeySyms +#if defined(HAVE_X11_XF86KEYSYM_H) +static const KeySym g_mapE000[] = +{ + /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x18 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x28 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x40 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x48 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x68 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x88 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x98 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xa0 */ 0, 0, 0, 0, + /* 0xa4 */ 0, 0, + /* 0xa6 */ XF86XK_Back, XF86XK_Forward, + /* 0xa8 */ XF86XK_Refresh, XF86XK_Stop, + /* 0xaa */ XF86XK_Search, XF86XK_Favorites, + /* 0xac */ XF86XK_HomePage, XF86XK_AudioMute, + /* 0xae */ XF86XK_AudioLowerVolume, XF86XK_AudioRaiseVolume, + /* 0xb0 */ XF86XK_AudioNext, XF86XK_AudioPrev, + /* 0xb2 */ XF86XK_AudioStop, XF86XK_AudioPlay, + /* 0xb4 */ XF86XK_Mail, XF86XK_AudioMedia, + /* 0xb6 */ XF86XK_Launch0, XF86XK_Launch1, + /* 0xb8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xe8 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0 +}; +#endif + CXWindowsSecondaryScreen::KeyCodeIndex CXWindowsSecondaryScreen::findKey(KeyID id, KeyModifierMask& mask) const { @@ -1388,6 +1452,12 @@ CXWindowsSecondaryScreen::findKey(KeyID id, KeyModifierMask& mask) const if ((id & 0xfffff000) == 0xe000) { // special character switch (id & 0x0000ff00) { +#if defined(HAVE_X11_XF86KEYSYM_H) + case 0xe000: + keysym = g_mapE000[id & 0xff]; + break; +#endif + case 0xee00: // ISO 9995 Function and Modifier Keys if (id == kKeyLeftTab) { diff --git a/lib/synergy/KeyTypes.h b/lib/synergy/KeyTypes.h index 9cef9c71..9af4dd0b 100644 --- a/lib/synergy/KeyTypes.h +++ b/lib/synergy/KeyTypes.h @@ -70,8 +70,8 @@ static const KeyModifierID kKeyModifierIDLast = 6; //! @name Key identifiers //@{ -// all identifiers except kKeyNone are equal to the corresponding -// X11 keysym - 0x1000. +// all identifiers except kKeyNone and those in 0xE000 to 0xE0FF +// inclusive are equal to the corresponding X11 keysym - 0x1000. // no key static const KeyID kKeyNone = 0x0000; @@ -211,6 +211,27 @@ static const KeyID kKeyHyper_R = 0xEFEE; /* Right hyper */ // more function and modifier keys static const KeyID kKeyLeftTab = 0xEE20; + +// extended keys +static const KeyID kKeyWWWBack = 0xE0A6; +static const KeyID kKeyWWWForward = 0xE0A7; +static const KeyID kKeyWWWRefresh = 0xE0A8; +static const KeyID kKeyWWWStop = 0xE0A9; +static const KeyID kKeyWWWSearch = 0xE0AA; +static const KeyID kKeyWWWFavorites = 0xE0AB; +static const KeyID kKeyWWWHome = 0xE0AC; +static const KeyID kKeyAudioMute = 0xE0AD; +static const KeyID kKeyAudioDown = 0xE0AE; +static const KeyID kKeyAudioUp = 0xE0AF; +static const KeyID kKeyAudioNext = 0xE0B0; +static const KeyID kKeyAudioPrev = 0xE0B1; +static const KeyID kKeyAudioStop = 0xE0B2; +static const KeyID kKeyAudioPlay = 0xE0B3; +static const KeyID kKeyAppMail = 0xE0B4; +static const KeyID kKeyAppMedia = 0xE0B5; +static const KeyID kKeyAppUser1 = 0xE0B6; +static const KeyID kKeyAppUser2 = 0xE0B7; + //@} #endif diff --git a/lib/synergy/MouseTypes.h b/lib/synergy/MouseTypes.h index 6d68ee52..e4988553 100644 --- a/lib/synergy/MouseTypes.h +++ b/lib/synergy/MouseTypes.h @@ -29,6 +29,7 @@ static const ButtonID kButtonNone = 0; static const ButtonID kButtonLeft = 1; static const ButtonID kButtonMiddle = 2; static const ButtonID kButtonRight = 3; +static const ButtonID kButtonExtra0 = 4; //@} #endif