Added support for 4th and 5th (non-mouse-wheel) buttons and

"Internet" keyboard keys.
This commit is contained in:
crs 2003-05-04 21:40:42 +00:00
parent b840c61f6c
commit 0e58bab76c
10 changed files with 401 additions and 132 deletions

View File

@ -57,6 +57,7 @@ AC_PATH_XTRA
save_CPPFLAGS="$CPPFLAGS" save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$X_CFLAGS $CPPFLAGS" CPPFLAGS="$X_CFLAGS $CPPFLAGS"
AC_CHECK_HEADERS([X11/extensions/XTest.h]) 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]) 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" CPPFLAGS="$save_CPPFLAGS"

View File

@ -21,16 +21,38 @@
#include "CArchMiscWindows.h" #include "CArchMiscWindows.h"
#include <cstring> #include <cstring>
// 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 // 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[] = { static const char* g_vkToName[] = {
"vk 0x00", "vk 0x00",
"VK_LBUTTON", "Left Button",
"VK_RBUTTON", "Right Button",
"VK_CANCEL", "VK_CANCEL",
"VK_MBUTTON", "Middle Button",
"vk 0x05", "vk 0x05",
"vk 0x06", "vk 0x06",
"vk 0x07", "vk 0x07",
@ -192,24 +214,24 @@ static const char* g_vkToName[] = {
"VK_RCONTROL", "VK_RCONTROL",
"VK_LMENU", "VK_LMENU",
"VK_RMENU", "VK_RMENU",
"vk 0xa6", "VK_BROWSER_BACK",
"vk 0xa7", "VK_BROWSER_FORWARD",
"vk 0xa8", "VK_BROWSER_REFRESH",
"vk 0xa9", "VK_BROWSER_STOP",
"vk 0xaa", "VK_BROWSER_SEARCH",
"vk 0xab", "VK_BROWSER_FAVORITES",
"vk 0xac", "VK_BROWSER_HOME",
"vk 0xad", "VK_VOLUME_MUTE",
"vk 0xae", "VK_VOLUME_DOWN",
"vk 0xaf", "VK_VOLUME_UP",
"vk 0xb0", "VK_MEDIA_NEXT_TRACK",
"vk 0xb1", "VK_MEDIA_PREV_TRACK",
"vk 0xb2", "VK_MEDIA_STOP",
"vk 0xb3", "VK_MEDIA_PLAY_PAUSE",
"vk 0xb4", "VK_LAUNCH_MAIL",
"vk 0xb5", "VK_LAUNCH_MEDIA_SELECT",
"vk 0xb6", "VK_LAUNCH_APP1",
"vk 0xb7", "VK_LAUNCH_APP2",
"vk 0xb8", "vk 0xb8",
"vk 0xb9", "vk 0xb9",
"vk 0xba", "vk 0xba",
@ -384,7 +406,7 @@ KeyModifierMask
CMSWindowsPrimaryScreen::getToggleMask() const CMSWindowsPrimaryScreen::getToggleMask() const
{ {
KeyModifierMask mask = 0; KeyModifierMask mask = 0;
if (!m_lowLevel) {
// get key state from our shadow state // get key state from our shadow state
if ((m_keys[VK_CAPITAL] & 0x01) != 0) if ((m_keys[VK_CAPITAL] & 0x01) != 0)
mask |= KeyModifierCapsLock; mask |= KeyModifierCapsLock;
@ -392,16 +414,6 @@ CMSWindowsPrimaryScreen::getToggleMask() const
mask |= KeyModifierNumLock; mask |= KeyModifierNumLock;
if ((m_keys[VK_SCROLL] & 0x01) != 0) if ((m_keys[VK_SCROLL] & 0x01) != 0)
mask |= KeyModifierScrollLock; 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;
}
return mask; return mask;
} }
@ -409,46 +421,19 @@ CMSWindowsPrimaryScreen::getToggleMask() const
bool bool
CMSWindowsPrimaryScreen::isLockedToScreen() const CMSWindowsPrimaryScreen::isLockedToScreen() const
{ {
// virtual key table. the table defines the virtual keys that are // use shadow keyboard state in m_keys and m_buttons
// mapped to something (including mouse buttons, OEM and kanji keys for (UInt32 i = 0; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) {
// but not unassigned or undefined keys). if ((m_buttons[i] & 0x80) != 0) {
static const UInt32 s_mappedKeys[] = { LOG((CLOG_DEBUG "locked by \"%s\"", g_buttonToName[i]));
0xfbff331e, return true;
0x03ffffff, }
0x3ffffffe, }
0xffffffff, for (UInt32 i = 0; i < sizeof(m_keys) / sizeof(m_keys[0]); ++i) {
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) { if ((m_keys[i] & 0x80) != 0) {
LOG((CLOG_DEBUG "locked by \"%s\"", g_vkToName[i])); LOG((CLOG_DEBUG "locked by \"%s\"", g_vkToName[i]));
return true; 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;
}
}
}
}
}
// not locked // not locked
return false; return false;
@ -583,16 +568,9 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
return true; return true;
case SYNERGY_MSG_MOUSE_BUTTON: { case SYNERGY_MSG_MOUSE_BUTTON: {
static const int s_vkButton[] = {
0, // kButtonNone
VK_LBUTTON, // kButtonLeft, etc.
VK_MBUTTON,
VK_RBUTTON
};
// get which button // get which button
bool pressed = false; 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 // ignore message if posted prior to last mark change
if (!ignore()) { if (!ignore()) {
@ -600,19 +578,22 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN: case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_XBUTTONDOWN:
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK: case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
case WM_XBUTTONDBLCLK:
case WM_NCLBUTTONDOWN: case WM_NCLBUTTONDOWN:
case WM_NCMBUTTONDOWN: case WM_NCMBUTTONDOWN:
case WM_NCRBUTTONDOWN: case WM_NCRBUTTONDOWN:
case WM_NCXBUTTONDOWN:
case WM_NCLBUTTONDBLCLK: case WM_NCLBUTTONDBLCLK:
case WM_NCMBUTTONDBLCLK: case WM_NCMBUTTONDBLCLK:
case WM_NCRBUTTONDBLCLK: case WM_NCRBUTTONDBLCLK:
case WM_NCXBUTTONDBLCLK:
LOG((CLOG_DEBUG1 "event: button press button=%d", button)); LOG((CLOG_DEBUG1 "event: button press button=%d", button));
if (button != kButtonNone) { if (button != kButtonNone) {
m_receiver->onMouseDown(button); m_receiver->onMouseDown(button);
m_keys[s_vkButton[button]] |= 0x80;
} }
pressed = true; pressed = true;
break; break;
@ -620,13 +601,14 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
case WM_LBUTTONUP: case WM_LBUTTONUP:
case WM_MBUTTONUP: case WM_MBUTTONUP:
case WM_RBUTTONUP: case WM_RBUTTONUP:
case WM_XBUTTONUP:
case WM_NCLBUTTONUP: case WM_NCLBUTTONUP:
case WM_NCMBUTTONUP: case WM_NCMBUTTONUP:
case WM_NCRBUTTONUP: case WM_NCRBUTTONUP:
case WM_NCXBUTTONUP:
LOG((CLOG_DEBUG1 "event: button release button=%d", button)); LOG((CLOG_DEBUG1 "event: button release button=%d", button));
if (button != kButtonNone) { if (button != kButtonNone) {
m_receiver->onMouseUp(button); m_receiver->onMouseUp(button);
m_keys[s_vkButton[button]] &= ~0x80;
} }
pressed = false; pressed = false;
break; break;
@ -634,8 +616,13 @@ CMSWindowsPrimaryScreen::onPreDispatch(const CEvent* event)
} }
// keep our shadow key state up to date // keep our shadow key state up to date
if (button != kButtonNone) { if (button >= kButtonLeft && button <= kButtonExtra0 + 1) {
updateKey(s_vkButton[button], pressed); if (pressed) {
m_buttons[button] |= 0x80;
}
else {
m_buttons[button] &= ~0x80;
}
} }
return true; return true;
@ -1139,24 +1126,24 @@ static const KeyID g_virtualKey[][2] =
/* 0xa3 */ kKeyControl_R, kKeyControl_R, // VK_RCONTROL /* 0xa3 */ kKeyControl_R, kKeyControl_R, // VK_RCONTROL
/* 0xa4 */ kKeyAlt_L, kKeyAlt_L, // VK_LMENU /* 0xa4 */ kKeyAlt_L, kKeyAlt_L, // VK_LMENU
/* 0xa5 */ kKeyAlt_R, kKeyAlt_R, // VK_RMENU /* 0xa5 */ kKeyAlt_R, kKeyAlt_R, // VK_RMENU
/* 0xa6 */ kKeyNone, kKeyNone, // unassigned /* 0xa6 */ kKeyNone, kKeyWWWBack, // VK_BROWSER_BACK
/* 0xa7 */ kKeyNone, kKeyNone, // unassigned /* 0xa7 */ kKeyNone, kKeyWWWForward, // VK_BROWSER_FORWARD
/* 0xa8 */ kKeyNone, kKeyNone, // unassigned /* 0xa8 */ kKeyNone, kKeyWWWRefresh, // VK_BROWSER_REFRESH
/* 0xa9 */ kKeyNone, kKeyNone, // unassigned /* 0xa9 */ kKeyNone, kKeyWWWStop, // VK_BROWSER_STOP
/* 0xaa */ kKeyNone, kKeyNone, // unassigned /* 0xaa */ kKeyNone, kKeyWWWSearch, // VK_BROWSER_SEARCH
/* 0xab */ kKeyNone, kKeyNone, // unassigned /* 0xab */ kKeyNone, kKeyWWWFavorites, // VK_BROWSER_FAVORITES
/* 0xac */ kKeyNone, kKeyNone, // unassigned /* 0xac */ kKeyNone, kKeyWWWHome, // VK_BROWSER_HOME
/* 0xad */ kKeyNone, kKeyNone, // unassigned /* 0xad */ kKeyNone, kKeyAudioMute, // VK_VOLUME_MUTE
/* 0xae */ kKeyNone, kKeyNone, // unassigned /* 0xae */ kKeyNone, kKeyAudioDown, // VK_VOLUME_DOWN
/* 0xaf */ kKeyNone, kKeyNone, // unassigned /* 0xaf */ kKeyNone, kKeyAudioUp, // VK_VOLUME_UP
/* 0xb0 */ kKeyNone, kKeyNone, // unassigned /* 0xb0 */ kKeyNone, kKeyAudioNext, // VK_MEDIA_NEXT_TRACK
/* 0xb1 */ kKeyNone, kKeyNone, // unassigned /* 0xb1 */ kKeyNone, kKeyAudioPrev, // VK_MEDIA_PREV_TRACK
/* 0xb2 */ kKeyNone, kKeyNone, // unassigned /* 0xb2 */ kKeyNone, kKeyAudioStop, // VK_MEDIA_STOP
/* 0xb3 */ kKeyNone, kKeyNone, // unassigned /* 0xb3 */ kKeyNone, kKeyAudioPlay, // VK_MEDIA_PLAY_PAUSE
/* 0xb4 */ kKeyNone, kKeyNone, // unassigned /* 0xb4 */ kKeyNone, kKeyAppMail, // VK_LAUNCH_MAIL
/* 0xb5 */ kKeyNone, kKeyNone, // unassigned /* 0xb5 */ kKeyNone, kKeyAppMedia, // VK_LAUNCH_MEDIA_SELECT
/* 0xb6 */ kKeyNone, kKeyNone, // unassigned /* 0xb6 */ kKeyNone, kKeyAppUser1, // VK_LAUNCH_APP1
/* 0xb7 */ kKeyNone, kKeyNone, // unassigned /* 0xb7 */ kKeyNone, kKeyAppUser2, // VK_LAUNCH_APP2
/* 0xb8 */ kKeyNone, kKeyNone, // unassigned /* 0xb8 */ kKeyNone, kKeyNone, // unassigned
/* 0xb9 */ kKeyNone, kKeyNone, // unassigned /* 0xb9 */ kKeyNone, kKeyNone, // unassigned
/* 0xba */ kKeyNone, kKeyNone, // OEM specific /* 0xba */ kKeyNone, kKeyNone, // OEM specific
@ -1407,9 +1394,9 @@ CMSWindowsPrimaryScreen::mapKey(
} }
ButtonID ButtonID
CMSWindowsPrimaryScreen::mapButton(WPARAM button) const CMSWindowsPrimaryScreen::mapButton(WPARAM msg, LPARAM button) const
{ {
switch (button) { switch (msg) {
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
case WM_LBUTTONUP: case WM_LBUTTONUP:
@ -1434,6 +1421,21 @@ CMSWindowsPrimaryScreen::mapButton(WPARAM button) const
case WM_NCRBUTTONUP: case WM_NCRBUTTONUP:
return kButtonRight; 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: default:
return kButtonNone; return kButtonNone;
} }
@ -1446,8 +1448,9 @@ CMSWindowsPrimaryScreen::updateKeys()
// up-to-date results. i don't know why that is or why GetKeyState() // up-to-date results. i don't know why that is or why GetKeyState()
// should give different results. // should give different results.
// clear key state // clear key and button state
memset(m_keys, 0, sizeof(m_keys)); 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 // we only care about the modifier key states. other keys and the
// mouse buttons should be up. // mouse buttons should be up.

View File

@ -87,7 +87,7 @@ private:
// key and button queries // key and button queries
KeyID mapKey(WPARAM keycode, LPARAM info, KeyID mapKey(WPARAM keycode, LPARAM info,
KeyModifierMask* maskOut); KeyModifierMask* maskOut);
ButtonID mapButton(WPARAM button) const; ButtonID mapButton(WPARAM msg, LPARAM button) const;
void updateKey(UINT vkCode, bool press); void updateKey(UINT vkCode, bool press);
bool isModifier(UINT vkCode) const; bool isModifier(UINT vkCode) const;
@ -108,6 +108,9 @@ private:
// map of key state // map of key state
BYTE m_keys[256]; BYTE m_keys[256];
// map of button state
BYTE m_buttons[1 + kButtonExtra0 + 1];
// last mouse position // last mouse position
SInt32 m_x, m_y; SInt32 m_x, m_y;

View File

@ -28,6 +28,42 @@
#define SPI_SETMOUSESPEED 113 #define SPI_SETMOUSESPEED 113
#endif #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 // CMSWindowsSecondaryScreen
// //
@ -258,11 +294,12 @@ CMSWindowsSecondaryScreen::mouseDown(ButtonID button)
m_screen->syncDesktop(); m_screen->syncDesktop();
// map button id to button flag // map button id to button flag
DWORD flags = mapButton(button, true); DWORD data;
DWORD flags = mapButton(button, true, &data);
// send event // send event
if (flags != 0) { 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(); m_screen->syncDesktop();
// map button id to button flag // map button id to button flag
DWORD flags = mapButton(button, false); DWORD data;
DWORD flags = mapButton(button, false, &data);
// send event // send event
if (flags != 0) { 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 // map special KeyID keys to virtual key codes. if the key is an
// extended key then the entry is the virtual key code | 0x100. // extended key then the entry is the virtual key code | 0x100.
// unmapped keys have a 0 entry. // 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[] = static const UINT g_mapEE00[] =
{ {
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
@ -685,8 +765,12 @@ static const UINT g_mapEF00[] =
}; };
DWORD 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 system will swap the meaning of left/right for us if
// the user has configured a left-handed mouse but we don't // the user has configured a left-handed mouse but we don't
// want it to swap since we want the handedness of the // 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) { switch (button) {
case kButtonLeft: case kButtonLeft:
return press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; return press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
@ -714,6 +799,14 @@ CMSWindowsSecondaryScreen::mapButton(ButtonID button, bool press) const
case kButtonRight: case kButtonRight:
return press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; 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: default:
return 0; return 0;
} }
@ -727,7 +820,10 @@ CMSWindowsSecondaryScreen::mapKey(Keystrokes& keys, UINT& virtualKey,
// check for special keys // check for special keys
if ((id & 0xfffff000) == 0xe000) { 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]; virtualKey = g_mapEE00[id & 0xff];
} }
else if ((id & 0xff00) == 0xef00) { else if ((id & 0xff00) == 0xef00) {

View File

@ -98,7 +98,8 @@ private:
bool isMultimon() const; bool isMultimon() const;
// key and button queries and operations // 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 mapKey(Keystrokes&, UINT& virtualKey, KeyID,
KeyModifierMask, EKeyAction) const; KeyModifierMask, EKeyAction) const;
void doKeystrokes(const Keystrokes&, SInt32 count); void doKeystrokes(const Keystrokes&, SInt32 count);

View File

@ -45,6 +45,20 @@ typedef struct tagMOUSEHOOKSTRUCTWin2000 {
#define SM_MOUSEWHEELPRESENT 75 #define SM_MOUSEWHEELPRESENT 75
#endif #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 // globals
@ -152,35 +166,41 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
static static
bool bool
mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 wheel) mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
{ {
switch (wParam) { switch (wParam) {
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN: case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_XBUTTONDOWN:
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK: case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
case WM_XBUTTONDBLCLK:
case WM_LBUTTONUP: case WM_LBUTTONUP:
case WM_MBUTTONUP: case WM_MBUTTONUP:
case WM_RBUTTONUP: case WM_RBUTTONUP:
case WM_XBUTTONUP:
case WM_NCLBUTTONDOWN: case WM_NCLBUTTONDOWN:
case WM_NCMBUTTONDOWN: case WM_NCMBUTTONDOWN:
case WM_NCRBUTTONDOWN: case WM_NCRBUTTONDOWN:
case WM_NCXBUTTONDOWN:
case WM_NCLBUTTONDBLCLK: case WM_NCLBUTTONDBLCLK:
case WM_NCMBUTTONDBLCLK: case WM_NCMBUTTONDBLCLK:
case WM_NCRBUTTONDBLCLK: case WM_NCRBUTTONDBLCLK:
case WM_NCXBUTTONDBLCLK:
case WM_NCLBUTTONUP: case WM_NCLBUTTONUP:
case WM_NCMBUTTONUP: case WM_NCMBUTTONUP:
case WM_NCRBUTTONUP: case WM_NCRBUTTONUP:
case WM_NCXBUTTONUP:
// always relay the event. eat it if relaying. // 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; return g_relay;
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
if (g_relay) { if (g_relay) {
// relay event // relay event
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, wheel, 0); PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0);
} }
return g_relay; 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)) { if (mouseHookHandler(wParam, x, y, w)) {
return 1; return 1;
} }

View File

@ -699,6 +699,44 @@ CXWindowsPrimaryScreen::mapModifier(unsigned int state) const
return mask; 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 KeyID
CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const
{ {
@ -727,6 +765,10 @@ CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const
// MISCELLANY // MISCELLANY
return static_cast<KeyID>(keysym - 0xff00 + 0xef00); return static_cast<KeyID>(keysym - 0xff00 + 0xef00);
case 0x1008ff00:
// "Internet" keys
return g_map1008FF[keysym & 0xff];
default: { default: {
// lookup character in table // lookup character in table
UInt32 key = CXWindowsUtil::mapKeySymToUCS4(keysym); UInt32 key = CXWindowsUtil::mapKeySymToUCS4(keysym);
@ -743,10 +785,18 @@ CXWindowsPrimaryScreen::mapKey(XKeyEvent* event) const
ButtonID ButtonID
CXWindowsPrimaryScreen::mapButton(unsigned int button) const 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) { if (button >= 1 && button <= 3) {
return static_cast<ButtonID>(button); return static_cast<ButtonID>(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<ButtonID>(button - 2);
}
// unknown button
else { else {
return kButtonNone; return kButtonNone;
} }

View File

@ -34,6 +34,9 @@
# else # else
# error The XTest extension is required to build synergy # error The XTest extension is required to build synergy
# endif # endif
# if defined(HAVE_X11_XF86KEYSYM_H)
# include <X11/XF86keysym.h>
# endif
#endif #endif
// //
@ -263,7 +266,8 @@ void
CXWindowsSecondaryScreen::mouseWheel(SInt32 delta) CXWindowsSecondaryScreen::mouseWheel(SInt32 delta)
{ {
// choose button depending on rotation direction // choose button depending on rotation direction
const unsigned int xButton = mapButton((delta >= 0) ? 4 : 5); const unsigned int xButton = mapButton(static_cast<ButtonID>(
(delta >= 0) ? -1 : -2));
if (xButton == 0) { if (xButton == 0) {
return; return;
} }
@ -573,17 +577,30 @@ CXWindowsSecondaryScreen::getToggleState() const
unsigned int unsigned int
CXWindowsSecondaryScreen::mapButton(ButtonID id) const CXWindowsSecondaryScreen::mapButton(ButtonID id) const
{ {
// map button -1 to button 4 (+wheel)
if (id == static_cast<ButtonID>(-1)) {
id = 4;
}
// map button -2 to button 5 (-wheel)
else if (id == static_cast<ButtonID>(-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()) { if (id < 1 || id > m_buttons.size()) {
// out of range // out of range
return 0; return 0;
} }
else if (m_buttons[id - 1] == 0) {
// button not mapped // map button
return 0;
}
else {
return static_cast<unsigned int>(m_buttons[id - 1]); return static_cast<unsigned int>(m_buttons[id - 1]);
}
} }
KeyModifierMask 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::KeyCodeIndex
CXWindowsSecondaryScreen::findKey(KeyID id, KeyModifierMask& mask) const CXWindowsSecondaryScreen::findKey(KeyID id, KeyModifierMask& mask) const
{ {
@ -1388,6 +1452,12 @@ CXWindowsSecondaryScreen::findKey(KeyID id, KeyModifierMask& mask) const
if ((id & 0xfffff000) == 0xe000) { if ((id & 0xfffff000) == 0xe000) {
// special character // special character
switch (id & 0x0000ff00) { switch (id & 0x0000ff00) {
#if defined(HAVE_X11_XF86KEYSYM_H)
case 0xe000:
keysym = g_mapE000[id & 0xff];
break;
#endif
case 0xee00: case 0xee00:
// ISO 9995 Function and Modifier Keys // ISO 9995 Function and Modifier Keys
if (id == kKeyLeftTab) { if (id == kKeyLeftTab) {

View File

@ -70,8 +70,8 @@ static const KeyModifierID kKeyModifierIDLast = 6;
//! @name Key identifiers //! @name Key identifiers
//@{ //@{
// all identifiers except kKeyNone are equal to the corresponding // all identifiers except kKeyNone and those in 0xE000 to 0xE0FF
// X11 keysym - 0x1000. // inclusive are equal to the corresponding X11 keysym - 0x1000.
// no key // no key
static const KeyID kKeyNone = 0x0000; static const KeyID kKeyNone = 0x0000;
@ -211,6 +211,27 @@ static const KeyID kKeyHyper_R = 0xEFEE; /* Right hyper */
// more function and modifier keys // more function and modifier keys
static const KeyID kKeyLeftTab = 0xEE20; 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 #endif

View File

@ -29,6 +29,7 @@ static const ButtonID kButtonNone = 0;
static const ButtonID kButtonLeft = 1; static const ButtonID kButtonLeft = 1;
static const ButtonID kButtonMiddle = 2; static const ButtonID kButtonMiddle = 2;
static const ButtonID kButtonRight = 3; static const ButtonID kButtonRight = 3;
static const ButtonID kButtonExtra0 = 4;
//@} //@}
#endif #endif