Fixed keyboard handling on windows 95 family.
This commit is contained in:
parent
e50146119f
commit
97046541b9
|
@ -13,7 +13,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CMSWindowsDesks.h"
|
#include "CMSWindowsDesks.h"
|
||||||
#include "CMSWindowsDesktop.h"
|
|
||||||
#include "CMSWindowsScreen.h"
|
#include "CMSWindowsScreen.h"
|
||||||
#include "IScreenSaver.h"
|
#include "IScreenSaver.h"
|
||||||
#include "XScreen.h"
|
#include "XScreen.h"
|
||||||
|
@ -200,6 +199,27 @@ CMSWindowsDesks::fakeKeyEvent(
|
||||||
KeyButton button, UINT virtualKey,
|
KeyButton button, UINT virtualKey,
|
||||||
bool press, bool /*isAutoRepeat*/) const
|
bool press, bool /*isAutoRepeat*/) const
|
||||||
{
|
{
|
||||||
|
// win 95 family doesn't understand handed modifier virtual keys
|
||||||
|
if (m_is95Family) {
|
||||||
|
switch (virtualKey) {
|
||||||
|
case VK_LSHIFT:
|
||||||
|
case VK_RSHIFT:
|
||||||
|
virtualKey = VK_SHIFT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_LCONTROL:
|
||||||
|
case VK_RCONTROL:
|
||||||
|
virtualKey = VK_CONTROL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_LMENU:
|
||||||
|
case VK_RMENU:
|
||||||
|
virtualKey = VK_MENU;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// synthesize event
|
||||||
DWORD flags = 0;
|
DWORD flags = 0;
|
||||||
if (((button & 0x100u) != 0)) {
|
if (((button & 0x100u) != 0)) {
|
||||||
flags |= KEYEVENTF_EXTENDEDKEY;
|
flags |= KEYEVENTF_EXTENDEDKEY;
|
||||||
|
@ -552,6 +572,14 @@ CMSWindowsDesks::deskLeave(CDesk* desk, HKL keyLayout)
|
||||||
SetWindowPos(desk->m_window, HWND_TOPMOST, x, y, w, h,
|
SetWindowPos(desk->m_window, HWND_TOPMOST, x, y, w, h,
|
||||||
SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
||||||
|
|
||||||
|
// if not using low-level hooks we have to also activate the
|
||||||
|
// window to ensure we don't lose keyboard focus.
|
||||||
|
// FIXME -- see if this can be avoided. if so then always
|
||||||
|
// disable the window (see handling of SYNERGY_MSG_SWITCH).
|
||||||
|
if (!desk->m_lowLevel) {
|
||||||
|
SetActiveWindow(desk->m_window);
|
||||||
|
}
|
||||||
|
|
||||||
// switch to requested keyboard layout
|
// switch to requested keyboard layout
|
||||||
ActivateKeyboardLayout(keyLayout, 0);
|
ActivateKeyboardLayout(keyLayout, 0);
|
||||||
}
|
}
|
||||||
|
@ -594,11 +622,6 @@ CMSWindowsDesks::deskThread(void* vdesk)
|
||||||
// ignore
|
// ignore
|
||||||
LOG((CLOG_DEBUG "can't create desk window for %s", desk->m_name.c_str()));
|
LOG((CLOG_DEBUG "can't create desk window for %s", desk->m_name.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// a window on the primary screen should never activate
|
|
||||||
if (m_isPrimary && desk->m_window != NULL) {
|
|
||||||
EnableWindow(desk->m_window, FALSE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell main thread that we're ready
|
// tell main thread that we're ready
|
||||||
|
@ -636,6 +659,10 @@ CMSWindowsDesks::deskThread(void* vdesk)
|
||||||
desk->m_lowLevel = true;
|
desk->m_lowLevel = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a window on the primary screen with low-level hooks
|
||||||
|
// should never activate.
|
||||||
|
EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -573,7 +573,8 @@ const KeyID CMSWindowsKeyState::s_virtualKey[][2] =
|
||||||
/* 0xff */ kKeyNone, kKeyNone // reserved
|
/* 0xff */ kKeyNone, kKeyNone // reserved
|
||||||
};
|
};
|
||||||
|
|
||||||
// map special KeyID keys to virtual key codes
|
// map special KeyID keys to virtual key codes plus whether or not
|
||||||
|
// the key maps to an extended scan code
|
||||||
const UINT CMSWindowsKeyState::s_mapE000[] =
|
const UINT CMSWindowsKeyState::s_mapE000[] =
|
||||||
{
|
{
|
||||||
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
@ -597,15 +598,15 @@ const UINT CMSWindowsKeyState::s_mapE000[] =
|
||||||
/* 0x90 */ 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,
|
/* 0x98 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0xa0 */ 0, 0, 0, 0,
|
/* 0xa0 */ 0, 0, 0, 0,
|
||||||
/* 0xa4 */ 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD,
|
/* 0xa4 */ 0, 0, VK_BROWSER_BACK | 0x100u, VK_BROWSER_FORWARD | 0x100u,
|
||||||
/* 0xa8 */ VK_BROWSER_REFRESH, VK_BROWSER_STOP,
|
/* 0xa8 */ VK_BROWSER_REFRESH | 0x100u, VK_BROWSER_STOP | 0x100u,
|
||||||
/* 0xaa */ VK_BROWSER_SEARCH, VK_BROWSER_FAVORITES,
|
/* 0xaa */ VK_BROWSER_SEARCH | 0x100u, VK_BROWSER_FAVORITES | 0x100u,
|
||||||
/* 0xac */ VK_BROWSER_HOME, VK_VOLUME_MUTE,
|
/* 0xac */ VK_BROWSER_HOME | 0x100u, VK_VOLUME_MUTE | 0x100u,
|
||||||
/* 0xae */ VK_VOLUME_DOWN, VK_VOLUME_UP,
|
/* 0xae */ VK_VOLUME_DOWN | 0x100u, VK_VOLUME_UP | 0x100u,
|
||||||
/* 0xb0 */ VK_MEDIA_NEXT_TRACK, VK_MEDIA_PREV_TRACK,
|
/* 0xb0 */ VK_MEDIA_NEXT_TRACK | 0x100u, VK_MEDIA_PREV_TRACK | 0x100u,
|
||||||
/* 0xb2 */ VK_MEDIA_STOP, VK_MEDIA_PLAY_PAUSE,
|
/* 0xb2 */ VK_MEDIA_STOP | 0x100u, VK_MEDIA_PLAY_PAUSE | 0x100u,
|
||||||
/* 0xb4 */ VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT,
|
/* 0xb4 */ VK_LAUNCH_MAIL | 0x100u, VK_LAUNCH_MEDIA_SELECT | 0x100u,
|
||||||
/* 0xb6 */ VK_LAUNCH_APP1, VK_LAUNCH_APP2,
|
/* 0xb6 */ VK_LAUNCH_APP1 | 0x100u, VK_LAUNCH_APP2 | 0x100u,
|
||||||
/* 0xb8 */ 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,
|
/* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
@ -666,35 +667,41 @@ const UINT CMSWindowsKeyState::s_mapEF00[] =
|
||||||
/* 0x38 */ 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,
|
/* 0x40 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0x48 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x48 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0x50 */ VK_HOME, VK_LEFT, VK_UP, VK_RIGHT,
|
/* 0x50 */ VK_HOME | 0x100u, VK_LEFT | 0x100u,
|
||||||
/* 0x54 */ VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
|
/* 0x52 */ VK_UP | 0x100u, VK_RIGHT | 0x100u,
|
||||||
|
/* 0x54 */ VK_DOWN | 0x100u, VK_PRIOR | 0x100u,
|
||||||
|
/* 0x56 */ VK_NEXT | 0x100u, VK_END | 0x100u,
|
||||||
/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0x60 */ VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT,
|
/* 0x60 */ VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT | 0x100u,
|
||||||
/* 0x64 */ 0, 0, 0, VK_APPS,
|
/* 0x64 */ 0, 0, 0, VK_APPS | 0x100u,
|
||||||
/* 0x68 */ 0, 0, VK_HELP, VK_CANCEL, 0, 0, 0, 0,
|
/* 0x68 */ 0, 0, VK_HELP, VK_CANCEL | 0x100u, 0, 0, 0, 0,
|
||||||
/* 0x70 */ 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, VK_NUMLOCK,
|
/* 0x78 */ 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK | 0x100u,
|
||||||
/* 0x80 */ VK_SPACE, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x80 */ VK_SPACE, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0x88 */ 0, VK_TAB, 0, 0, 0, VK_RETURN, 0, 0,
|
/* 0x88 */ 0, VK_TAB, 0, 0, 0, VK_RETURN | 0x100u, 0, 0,
|
||||||
/* 0x90 */ 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP,
|
/* 0x90 */ 0, 0, 0, 0, 0, VK_HOME, VK_LEFT, VK_UP,
|
||||||
/* 0x98 */ VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT,
|
/* 0x98 */ VK_RIGHT, VK_DOWN, VK_PRIOR, VK_NEXT,
|
||||||
/* 0x9c */ VK_END, 0, VK_INSERT, VK_DELETE,
|
/* 0x9c */ VK_END, 0, VK_INSERT, VK_DELETE,
|
||||||
/* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0xa8 */ 0, 0, VK_MULTIPLY, VK_ADD,
|
/* 0xa8 */ 0, 0, VK_MULTIPLY, VK_ADD,
|
||||||
/* 0xac */ VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
|
/* 0xac */ VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE | 0x100u,
|
||||||
/* 0xb0 */ VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,
|
/* 0xb0 */ VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,
|
||||||
/* 0xb4 */ VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
|
/* 0xb4 */ VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
|
||||||
/* 0xb8 */ VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, VK_F1, VK_F2,
|
/* 0xb8 */ VK_NUMPAD8, VK_NUMPAD9, 0, 0, 0, 0, VK_F1, VK_F2,
|
||||||
/* 0xc0 */ VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,
|
/* 0xc0 */ VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,
|
||||||
/* 0xc8 */ VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18,
|
/* 0xc8 */ VK_F11, VK_F12, VK_F13 | 0x100u, VK_F14 | 0x100u,
|
||||||
/* 0xd0 */ VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0,
|
/* 0xcc */ VK_F15 | 0x100u, VK_F16 | 0x100u,
|
||||||
|
/* 0xce */ VK_F17 | 0x100u, VK_F18 | 0x100u,
|
||||||
|
/* 0xd0 */ VK_F19 | 0x100u, VK_F20 | 0x100u,
|
||||||
|
/* 0xd2 */ VK_F21 | 0x100u, VK_F22 | 0x100u,
|
||||||
|
/* 0xd4 */ VK_F23 | 0x100u, VK_F24 | 0x100u, 0, 0,
|
||||||
/* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0xe0 */ 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL,
|
/* 0xe0 */ 0, VK_LSHIFT, VK_RSHIFT | 0x100u, VK_LCONTROL,
|
||||||
/* 0xe4 */ VK_RCONTROL, VK_CAPITAL, 0, 0,
|
/* 0xe4 */ VK_RCONTROL | 0x100u, VK_CAPITAL, 0, 0,
|
||||||
/* 0xe8 */ 0, VK_LMENU, VK_RMENU, VK_LWIN,
|
/* 0xe8 */ 0, VK_LMENU, VK_RMENU | 0x100u, VK_LWIN | 0x100u,
|
||||||
/* 0xec */ VK_RWIN, 0, 0, 0,
|
/* 0xec */ VK_RWIN | 0x100u, 0, 0, 0,
|
||||||
/* 0xf0 */ 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, VK_DELETE
|
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, VK_DELETE | 0x100u
|
||||||
};
|
};
|
||||||
|
|
||||||
CMSWindowsKeyState::CMSWindowsKeyState(CMSWindowsDesks* desks) :
|
CMSWindowsKeyState::CMSWindowsKeyState(CMSWindowsDesks* desks) :
|
||||||
|
@ -733,7 +740,7 @@ CMSWindowsKeyState::fixKey(void* target, UINT virtualKey)
|
||||||
KeyID key = mapKeyFromEvent(virtualKey, lParam, &mask);
|
KeyID key = mapKeyFromEvent(virtualKey, lParam, &mask);
|
||||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
||||||
CKeyState::sendKeyEvent(target, false, false, key, mask, 1, button);
|
CKeyState::sendKeyEvent(target, false, false, key, mask, 1, button);
|
||||||
CKeyState::setKeyDown(button, false);
|
setKeyDown(button, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,6 +748,7 @@ KeyID
|
||||||
CMSWindowsKeyState::mapKeyFromEvent(WPARAM charAndVirtKey,
|
CMSWindowsKeyState::mapKeyFromEvent(WPARAM charAndVirtKey,
|
||||||
LPARAM info, KeyModifierMask* maskOut) const
|
LPARAM info, KeyModifierMask* maskOut) const
|
||||||
{
|
{
|
||||||
|
// FIXME -- look into this
|
||||||
// note: known microsoft bugs
|
// note: known microsoft bugs
|
||||||
// Q72583 -- MapVirtualKey() maps keypad keys incorrectly
|
// Q72583 -- MapVirtualKey() maps keypad keys incorrectly
|
||||||
// 95,98: num pad vk code -> invalid scan code
|
// 95,98: num pad vk code -> invalid scan code
|
||||||
|
@ -837,27 +845,6 @@ CMSWindowsKeyState::virtualKeyToButton(UINT virtualKey) const
|
||||||
return m_virtKeyToScanCode[virtualKey & 0xffu];
|
return m_virtKeyToScanCode[virtualKey & 0xffu];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CMSWindowsKeyState::setKeyDown(KeyButton button, bool down)
|
|
||||||
{
|
|
||||||
CKeyState::setKeyDown(button, down);
|
|
||||||
|
|
||||||
// special case: we detect ctrl+alt+del being pressed on some
|
|
||||||
// systems but we don't detect the release of those keys. so
|
|
||||||
// if ctrl, alt, and del are down then mark them up.
|
|
||||||
if (down && isKeyDown(m_virtKeyToScanCode[VK_DELETE])) {
|
|
||||||
KeyModifierMask mask = getActiveModifiers();
|
|
||||||
if ((mask & (KeyModifierControl | KeyModifierAlt)) ==
|
|
||||||
(KeyModifierControl | KeyModifierAlt)) {
|
|
||||||
CKeyState::setKeyDown(m_virtKeyToScanCode[VK_LCONTROL], false);
|
|
||||||
CKeyState::setKeyDown(m_virtKeyToScanCode[VK_RCONTROL], false);
|
|
||||||
CKeyState::setKeyDown(m_virtKeyToScanCode[VK_LMENU], false);
|
|
||||||
CKeyState::setKeyDown(m_virtKeyToScanCode[VK_RMENU], false);
|
|
||||||
CKeyState::setKeyDown(m_virtKeyToScanCode[VK_DELETE], false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CMSWindowsKeyState::sendKeyEvent(void* target,
|
CMSWindowsKeyState::sendKeyEvent(void* target,
|
||||||
bool press, bool isAutoRepeat,
|
bool press, bool isAutoRepeat,
|
||||||
|
@ -865,7 +852,7 @@ CMSWindowsKeyState::sendKeyEvent(void* target,
|
||||||
SInt32 count, KeyButton button)
|
SInt32 count, KeyButton button)
|
||||||
{
|
{
|
||||||
if (press || isAutoRepeat) {
|
if (press || isAutoRepeat) {
|
||||||
// if AltGr required for this key then make sure
|
// if AltGr is required for this key then make sure
|
||||||
// the ctrl and alt keys are *not* down on the
|
// the ctrl and alt keys are *not* down on the
|
||||||
// client. windows simulates AltGr with ctrl and
|
// client. windows simulates AltGr with ctrl and
|
||||||
// alt for some inexplicable reason and clients
|
// alt for some inexplicable reason and clients
|
||||||
|
@ -950,37 +937,6 @@ CMSWindowsKeyState::sendKeyEvent(void* target,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// key release. if the key isn't down according to
|
|
||||||
// our table then we never got the key press event
|
|
||||||
// for it. if it's not a modifier key then we'll
|
|
||||||
// synthesize the press first. only do this on
|
|
||||||
// the windows 95 family, which eats certain special
|
|
||||||
// keys like alt+tab, ctrl+esc, etc.
|
|
||||||
if (m_is95Family && isKeyDown(button)) {
|
|
||||||
switch (m_scanCodeToVirtKey[button]) {
|
|
||||||
case VK_LSHIFT:
|
|
||||||
case VK_RSHIFT:
|
|
||||||
case VK_SHIFT:
|
|
||||||
case VK_LCONTROL:
|
|
||||||
case VK_RCONTROL:
|
|
||||||
case VK_CONTROL:
|
|
||||||
case VK_LMENU:
|
|
||||||
case VK_RMENU:
|
|
||||||
case VK_MENU:
|
|
||||||
case VK_CAPITAL:
|
|
||||||
case VK_NUMLOCK:
|
|
||||||
case VK_SCROLL:
|
|
||||||
case VK_LWIN:
|
|
||||||
case VK_RWIN:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
CKeyState::sendKeyEvent(target,
|
|
||||||
true, false, key, mask, 1, button);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// do key up
|
// do key up
|
||||||
CKeyState::sendKeyEvent(target, false, false, key, mask, 1, button);
|
CKeyState::sendKeyEvent(target, false, false, key, mask, 1, button);
|
||||||
}
|
}
|
||||||
|
@ -1065,47 +1021,35 @@ CMSWindowsKeyState::doUpdateKeys()
|
||||||
// KeyModifierModeSwitch mask can be converted to keystrokes. it
|
// KeyModifierModeSwitch mask can be converted to keystrokes. it
|
||||||
// must be mapped before the Alt modifier so that the Alt modifier
|
// must be mapped before the Alt modifier so that the Alt modifier
|
||||||
// takes precedence when mapping keystrokes to modifier masks.
|
// takes precedence when mapping keystrokes to modifier masks.
|
||||||
//
|
|
||||||
// we have to explicitly set the extended key flag for some
|
|
||||||
// modifiers because the win32 API is inadequate.
|
|
||||||
KeyButtons keys;
|
KeyButtons keys;
|
||||||
keys.push_back((KeyButton)(MapVirtualKey(VK_RMENU, 0) | 0x100));
|
keys.push_back(mapVirtKeyToButton(VK_RMENU));
|
||||||
addModifier(KeyModifierModeSwitch, keys);
|
addModifier(KeyModifierModeSwitch, keys);
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back((KeyButton)MapVirtualKey(VK_LSHIFT, 0));
|
keys.push_back(mapVirtKeyToButton(VK_LSHIFT));
|
||||||
keys.push_back((KeyButton)(MapVirtualKey(VK_RSHIFT, 0) | 0x100));
|
keys.push_back(mapVirtKeyToButton(VK_RSHIFT));
|
||||||
addModifier(KeyModifierShift, keys);
|
addModifier(KeyModifierShift, keys);
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back((KeyButton)MapVirtualKey(VK_LCONTROL, 0));
|
keys.push_back(mapVirtKeyToButton(VK_LCONTROL));
|
||||||
keys.push_back((KeyButton)(MapVirtualKey(VK_RCONTROL, 0) | 0x100));
|
keys.push_back(mapVirtKeyToButton(VK_RCONTROL));
|
||||||
addModifier(KeyModifierControl, keys);
|
addModifier(KeyModifierControl, keys);
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back((KeyButton)MapVirtualKey(VK_LMENU, 0));
|
keys.push_back(mapVirtKeyToButton(VK_LMENU));
|
||||||
keys.push_back((KeyButton)(MapVirtualKey(VK_RMENU, 0) | 0x100));
|
keys.push_back(mapVirtKeyToButton(VK_RMENU));
|
||||||
addModifier(KeyModifierAlt, keys);
|
addModifier(KeyModifierAlt, keys);
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back((KeyButton)(MapVirtualKey(VK_LWIN, 0) | 0x100));
|
keys.push_back(mapVirtKeyToButton(VK_LWIN));
|
||||||
keys.push_back((KeyButton)(MapVirtualKey(VK_RWIN, 0) | 0x100));
|
keys.push_back(mapVirtKeyToButton(VK_RWIN));
|
||||||
addModifier(KeyModifierSuper, keys);
|
addModifier(KeyModifierSuper, keys);
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back((KeyButton)MapVirtualKey(VK_CAPITAL, 0));
|
keys.push_back(mapVirtKeyToButton(VK_CAPITAL));
|
||||||
addModifier(KeyModifierCapsLock, keys);
|
addModifier(KeyModifierCapsLock, keys);
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back((KeyButton)(MapVirtualKey(VK_NUMLOCK, 0) | 0x100));
|
keys.push_back(mapVirtKeyToButton(VK_NUMLOCK));
|
||||||
addModifier(KeyModifierNumLock, keys);
|
addModifier(KeyModifierNumLock, keys);
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back((KeyButton)MapVirtualKey(VK_SCROLL, 0));
|
keys.push_back(mapVirtKeyToButton(VK_SCROLL));
|
||||||
addModifier(KeyModifierScrollLock, keys);
|
addModifier(KeyModifierScrollLock, keys);
|
||||||
|
|
||||||
/* FIXME -- potential problem here on win me
|
|
||||||
// win me (sony vaio laptop):
|
|
||||||
// MapVirtualKey(vk, 0):
|
|
||||||
// VK_SHIFT mapped; VK_LSHIFT, VK_RSHIFT not mapped
|
|
||||||
// VK_CONTROL mapped; VK_LCONTROL, VK_RCONTROL not mapped
|
|
||||||
// VK_MENU mapped; VK_LMENU, VK_RMENU not mapped
|
|
||||||
// MapVirtualKey(sc, 3):
|
|
||||||
// all scan codes unmapped (function apparently unimplemented)
|
|
||||||
*/
|
|
||||||
BYTE keyState[256];
|
BYTE keyState[256];
|
||||||
GetKeyboardState(keyState);
|
GetKeyboardState(keyState);
|
||||||
for (UINT i = 1; i < 256; ++i) {
|
for (UINT i = 1; i < 256; ++i) {
|
||||||
|
@ -1123,63 +1067,20 @@ CMSWindowsKeyState::doUpdateKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
// map to a scancode and back to a virtual key
|
// map to a scancode and back to a virtual key
|
||||||
UINT scancode = MapVirtualKey(i, 0);
|
KeyButton button2;
|
||||||
UINT virtKey = MapVirtualKey(scancode, 3);
|
KeyButton button = mapVirtKeyToButton(i, button2);
|
||||||
if (virtKey == 0) {
|
if (button == 0) {
|
||||||
// assume MapVirtualKey(xxx, 3) is unimplemented
|
continue;
|
||||||
virtKey = i;
|
|
||||||
}
|
|
||||||
else if (scancode == 0) {
|
|
||||||
// the VK_PAUSE virtual key doesn't map properly
|
|
||||||
if (i == VK_PAUSE) {
|
|
||||||
// i hope this works on all keyboards
|
|
||||||
scancode = 0x45;
|
|
||||||
virtKey = i;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need some adjustments due to inadequacies in the API.
|
|
||||||
// the API provides no means to query the keyboard by scan
|
|
||||||
// code that i can see. so we're doing it by virtual key.
|
|
||||||
// but a single virtual key can map to multiple physical
|
|
||||||
// keys. for example, VK_HOME maps to NumPad 7 and to the
|
|
||||||
// (extended key) Home key. this means we can never tell
|
|
||||||
// which of the two keys is pressed.
|
|
||||||
//
|
|
||||||
// this is a problem if a key is down when this method is
|
|
||||||
// called. if the extended key is down we'll record the
|
|
||||||
// non-extended key as being down. when the extended key
|
|
||||||
// goes up, we'll record that correctly and leave the
|
|
||||||
// non-extended key as being down. to deal with that we
|
|
||||||
// always re-check the keyboard state if we think we're
|
|
||||||
// locked to a screen because a key is down. the re-check
|
|
||||||
// should clear it up.
|
|
||||||
//
|
|
||||||
// the win32 functions that take scan codes are:
|
|
||||||
|
|
||||||
//
|
|
||||||
// if the mapped virtual key doesn't match the starting
|
|
||||||
// point then there's a really good chance that that virtual
|
|
||||||
// key is mapped to an extended key. however, this is not
|
|
||||||
// the case for modifiers that don't distinguish between left
|
|
||||||
// and right. also VK_NUMLOCK gets mapped to a non-extended
|
|
||||||
// key but it should be.
|
|
||||||
if (virtKey != i || i == VK_NUMLOCK) {
|
|
||||||
if (i != VK_SHIFT && i != VK_CONTROL && i != VK_MENU) {
|
|
||||||
scancode |= 0x100;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// okay, now we have the scan code for the virtual key.
|
// okay, now we have the scan code for the virtual key.
|
||||||
m_scanCodeToVirtKey[scancode] = i;
|
m_scanCodeToVirtKey[button] = i;
|
||||||
m_virtKeyToScanCode[i] = (KeyButton)scancode;
|
m_scanCodeToVirtKey[button2] = i;
|
||||||
|
m_virtKeyToScanCode[i] = button;
|
||||||
|
|
||||||
// save the key state
|
// save the key state
|
||||||
if ((keyState[i] & 0x80) != 0) {
|
if ((keyState[i] & 0x80) != 0) {
|
||||||
setKeyDown((KeyButton)scancode, true);
|
setKeyDown(button, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggle state applies to all keys but we only want it for
|
// toggle state applies to all keys but we only want it for
|
||||||
|
@ -1214,27 +1115,27 @@ KeyButton
|
||||||
CMSWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
|
CMSWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
|
||||||
KeyModifierMask mask, bool isAutoRepeat) const
|
KeyModifierMask mask, bool isAutoRepeat) const
|
||||||
{
|
{
|
||||||
UINT virtualKey = 0;
|
UINT extVirtualKey = 0;
|
||||||
|
|
||||||
// check for special keys
|
// check for special keys
|
||||||
if ((id & 0xfffff000u) == 0xe000u) {
|
if ((id & 0xfffff000u) == 0xe000u) {
|
||||||
if ((id & 0xff00u) == 0xe000u) {
|
if ((id & 0xff00u) == 0xe000u) {
|
||||||
virtualKey = s_mapE000[id & 0xffu];
|
extVirtualKey = s_mapE000[id & 0xffu];
|
||||||
}
|
}
|
||||||
else if ((id & 0xff00) == 0xee00) {
|
else if ((id & 0xff00) == 0xee00) {
|
||||||
virtualKey = s_mapEE00[id & 0xffu];
|
extVirtualKey = s_mapEE00[id & 0xffu];
|
||||||
}
|
}
|
||||||
else if ((id & 0xff00) == 0xef00) {
|
else if ((id & 0xff00) == 0xef00) {
|
||||||
virtualKey = s_mapEF00[id & 0xffu];
|
extVirtualKey = s_mapEF00[id & 0xffu];
|
||||||
}
|
}
|
||||||
if (virtualKey == 0) {
|
if (extVirtualKey == 0) {
|
||||||
LOG((CLOG_DEBUG2 "unknown special key"));
|
LOG((CLOG_DEBUG2 "unknown special key"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// special handling of VK_SNAPSHOT
|
// special handling of VK_SNAPSHOT
|
||||||
if (virtualKey == VK_SNAPSHOT) {
|
if (extVirtualKey == VK_SNAPSHOT) {
|
||||||
// ignore key repeats on print screen
|
// ignore key repeats on print screen
|
||||||
if (!isAutoRepeat) {
|
if (!isAutoRepeat) {
|
||||||
// active window (with alt) or fullscreen (without alt)?
|
// active window (with alt) or fullscreen (without alt)?
|
||||||
|
@ -1251,7 +1152,7 @@ CMSWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle other special keys
|
// handle other special keys
|
||||||
if (virtualKey != 0) {
|
if (extVirtualKey != 0) {
|
||||||
// compute required modifiers
|
// compute required modifiers
|
||||||
KeyModifierMask requiredMask = 0;
|
KeyModifierMask requiredMask = 0;
|
||||||
KeyModifierMask outMask = 0;
|
KeyModifierMask outMask = 0;
|
||||||
|
@ -1262,6 +1163,7 @@ CMSWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
|
||||||
// (e.g. add, multiply) and their main keyboard counterparts.
|
// (e.g. add, multiply) and their main keyboard counterparts.
|
||||||
// therefore, we can ignore the num-lock state for movement virtual
|
// therefore, we can ignore the num-lock state for movement virtual
|
||||||
// keys but not for numeric keys.
|
// keys but not for numeric keys.
|
||||||
|
UINT virtualKey = (extVirtualKey & 0xffu);
|
||||||
if (virtualKey >= VK_NUMPAD0 && virtualKey <= VK_DIVIDE) {
|
if (virtualKey >= VK_NUMPAD0 && virtualKey <= VK_DIVIDE) {
|
||||||
requiredMask |= KeyModifierNumLock;
|
requiredMask |= KeyModifierNumLock;
|
||||||
if ((getActiveModifiers() & KeyModifierNumLock) != 0) {
|
if ((getActiveModifiers() & KeyModifierNumLock) != 0) {
|
||||||
|
@ -1277,9 +1179,12 @@ CMSWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
|
||||||
}
|
}
|
||||||
|
|
||||||
// now generate the keystrokes and return the resulting modifier mask
|
// now generate the keystrokes and return the resulting modifier mask
|
||||||
KeyButton scanCode = m_virtKeyToScanCode[virtualKey];
|
KeyButton button = m_virtKeyToScanCode[virtualKey];
|
||||||
LOG((CLOG_DEBUG2 "KeyID 0x%08x to virtual key %d scan code 0x%04x mask 0x%04x", id, virtualKey, scanCode, outMask));
|
if ((extVirtualKey & 0x100u) != 0) {
|
||||||
return mapToKeystrokes(keys, scanCode,
|
button |= 0x100u;
|
||||||
|
}
|
||||||
|
LOG((CLOG_DEBUG2 "KeyID 0x%08x to virtual key %d scan code 0x%03x mask 0x%04x", id, virtualKey, button, outMask));
|
||||||
|
return mapToKeystrokes(keys, button,
|
||||||
outMask, requiredMask, isAutoRepeat);
|
outMask, requiredMask, isAutoRepeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1407,6 +1312,196 @@ CMSWindowsKeyState::getCodePageFromLangID(LANGID langid) const
|
||||||
return codePage;
|
return codePage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyButton
|
||||||
|
CMSWindowsKeyState::mapVirtKeyToButton(UINT virtualKey,
|
||||||
|
KeyButton& extended) const
|
||||||
|
{
|
||||||
|
// this method does what MapVirtualKey(virtualKey, 0) should do.
|
||||||
|
// we have to explicitly set the extended key flag for some
|
||||||
|
// modifiers because the win32 API is inadequate. we also find
|
||||||
|
// the unextended and the extended scancodes for those virtual
|
||||||
|
// keys that have both except for VK_SHIFT, VK_CONTROL, and VK_MENU.
|
||||||
|
//
|
||||||
|
// the windows 95 family doesn't map the side distinguishing virtual
|
||||||
|
// keys. but we know that VK_CONTROL maps to VK_LCONTROL and
|
||||||
|
// that VK_RCONTROL is the same scan code | 0x100. similarly for
|
||||||
|
// VK_MENU. but VK_RSHIFT cannot be determined that way so we
|
||||||
|
// search for it.
|
||||||
|
extended = 0;
|
||||||
|
KeyButton button;
|
||||||
|
if (m_is95Family) {
|
||||||
|
UINT scancode;
|
||||||
|
switch (virtualKey) {
|
||||||
|
case VK_LSHIFT:
|
||||||
|
button = (KeyButton)MapVirtualKey(VK_SHIFT, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_RSHIFT:
|
||||||
|
// we have to search
|
||||||
|
scancode = MapVirtualKey(VK_SHIFT, 0);
|
||||||
|
for (UINT i = 1; i < 256; ++i) {
|
||||||
|
if (i != scancode && MapVirtualKey(i, 1) == VK_SHIFT) {
|
||||||
|
return (KeyButton)(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case VK_LCONTROL:
|
||||||
|
case VK_RCONTROL:
|
||||||
|
button = (KeyButton)MapVirtualKey(VK_CONTROL, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_LMENU:
|
||||||
|
case VK_RMENU:
|
||||||
|
button = (KeyButton)MapVirtualKey(VK_MENU, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_PAUSE:
|
||||||
|
// mapped to 0. i hope this works on all keyboards.
|
||||||
|
button = (KeyButton)0x45u;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_DIVIDE:
|
||||||
|
// mapped to 0. i hope this works on all keyboards.
|
||||||
|
button = (KeyButton)0x35u;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
button = (KeyButton)MapVirtualKey(virtualKey, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (virtualKey) {
|
||||||
|
case VK_PAUSE:
|
||||||
|
// mapped to 0. i hope this works on all keyboards.
|
||||||
|
button = (KeyButton)0x45u;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
button = (KeyButton)MapVirtualKey(virtualKey, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// map extended keys
|
||||||
|
switch (virtualKey) {
|
||||||
|
case VK_RETURN: // Return/numpad Enter
|
||||||
|
case VK_PRIOR: // numpad PageUp/PageUp
|
||||||
|
case VK_NEXT: // numpad PageDown/PageDown
|
||||||
|
case VK_END: // numpad End/End
|
||||||
|
case VK_HOME: // numpad Home/Home
|
||||||
|
case VK_LEFT: // numpad Left/Left
|
||||||
|
case VK_UP: // numpad Up/Up
|
||||||
|
case VK_RIGHT: // numpad Right/Right
|
||||||
|
case VK_DOWN: // numpad Down/Down
|
||||||
|
case VK_INSERT: // numpad Insert/Insert
|
||||||
|
case VK_DELETE: // numpad Delete/Delete
|
||||||
|
// case VK_SELECT:
|
||||||
|
// case VK_EXECUTE:
|
||||||
|
// case VK_HELP:
|
||||||
|
extended = (KeyButton)(button | 0x100u);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if the win32 API can help us determine an extended key.
|
||||||
|
// if the remapped virtual key doesn't match the starting
|
||||||
|
// point then there's a really good chance that that virtual
|
||||||
|
// key is mapped to an extended key. however, this is not
|
||||||
|
// the case for modifiers that don't distinguish between left
|
||||||
|
// and right.
|
||||||
|
UINT virtualKey2 = MapVirtualKey(button, 3);
|
||||||
|
if (virtualKey2 != 0 && virtualKey2 != virtualKey) {
|
||||||
|
switch (virtualKey) {
|
||||||
|
case VK_SHIFT:
|
||||||
|
case VK_CONTROL:
|
||||||
|
case VK_MENU:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_NUMPAD0:
|
||||||
|
case VK_NUMPAD1:
|
||||||
|
case VK_NUMPAD2:
|
||||||
|
case VK_NUMPAD3:
|
||||||
|
case VK_NUMPAD4:
|
||||||
|
case VK_NUMPAD5:
|
||||||
|
case VK_NUMPAD6:
|
||||||
|
case VK_NUMPAD7:
|
||||||
|
case VK_NUMPAD8:
|
||||||
|
case VK_NUMPAD9:
|
||||||
|
case VK_MULTIPLY:
|
||||||
|
case VK_ADD:
|
||||||
|
case VK_SEPARATOR:
|
||||||
|
case VK_SUBTRACT:
|
||||||
|
case VK_DECIMAL:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
button |= 0x100u;
|
||||||
|
extended = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note other extended keys that the win32 API won't help us with.
|
||||||
|
// on the windows 95 family this is the only way to find extended
|
||||||
|
// keys since MapVirtualKey(N, 3) is unimplemented.
|
||||||
|
switch (virtualKey) {
|
||||||
|
case VK_CANCEL:
|
||||||
|
case VK_LWIN:
|
||||||
|
case VK_RWIN:
|
||||||
|
case VK_APPS:
|
||||||
|
// case VK_SEPARATOR:
|
||||||
|
case VK_DIVIDE:
|
||||||
|
case VK_F13:
|
||||||
|
case VK_F14:
|
||||||
|
case VK_F15:
|
||||||
|
case VK_F16:
|
||||||
|
case VK_F17:
|
||||||
|
case VK_F18:
|
||||||
|
case VK_F19:
|
||||||
|
case VK_F20:
|
||||||
|
case VK_F21:
|
||||||
|
case VK_F22:
|
||||||
|
case VK_F23:
|
||||||
|
case VK_F24:
|
||||||
|
case VK_NUMLOCK:
|
||||||
|
case VK_RSHIFT:
|
||||||
|
case VK_RCONTROL:
|
||||||
|
case VK_RMENU:
|
||||||
|
case VK_BROWSER_BACK:
|
||||||
|
case VK_BROWSER_FORWARD:
|
||||||
|
case VK_BROWSER_REFRESH:
|
||||||
|
case VK_BROWSER_STOP:
|
||||||
|
case VK_BROWSER_SEARCH:
|
||||||
|
case VK_BROWSER_FAVORITES:
|
||||||
|
case VK_BROWSER_HOME:
|
||||||
|
case VK_VOLUME_MUTE:
|
||||||
|
case VK_VOLUME_DOWN:
|
||||||
|
case VK_VOLUME_UP:
|
||||||
|
case VK_MEDIA_NEXT_TRACK:
|
||||||
|
case VK_MEDIA_PREV_TRACK:
|
||||||
|
case VK_MEDIA_STOP:
|
||||||
|
case VK_MEDIA_PLAY_PAUSE:
|
||||||
|
case VK_LAUNCH_MAIL:
|
||||||
|
case VK_LAUNCH_MEDIA_SELECT:
|
||||||
|
case VK_LAUNCH_APP1:
|
||||||
|
case VK_LAUNCH_APP2:
|
||||||
|
button |= 0x100u;
|
||||||
|
extended = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyButton
|
||||||
|
CMSWindowsKeyState::mapVirtKeyToButton(UINT virtualKey) const
|
||||||
|
{
|
||||||
|
KeyButton dummy;
|
||||||
|
return mapVirtKeyToButton(virtualKey, dummy);
|
||||||
|
}
|
||||||
|
|
||||||
KeyButton
|
KeyButton
|
||||||
CMSWindowsKeyState::mapCharacter(Keystrokes& keys,
|
CMSWindowsKeyState::mapCharacter(Keystrokes& keys,
|
||||||
char c, HKL hkl, bool isAutoRepeat) const
|
char c, HKL hkl, bool isAutoRepeat) const
|
||||||
|
|
|
@ -64,7 +64,6 @@ public:
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IKeyState overrides
|
// IKeyState overrides
|
||||||
virtual void setKeyDown(KeyButton button, bool down);
|
|
||||||
virtual void sendKeyEvent(void* target,
|
virtual void sendKeyEvent(void* target,
|
||||||
bool press, bool isAutoRepeat,
|
bool press, bool isAutoRepeat,
|
||||||
KeyID key, KeyModifierMask mask,
|
KeyID key, KeyModifierMask mask,
|
||||||
|
@ -88,6 +87,14 @@ private:
|
||||||
// convert a language ID to a code page
|
// convert a language ID to a code page
|
||||||
UINT getCodePageFromLangID(LANGID langid) const;
|
UINT getCodePageFromLangID(LANGID langid) const;
|
||||||
|
|
||||||
|
// map a virtual key to a button. this tries to deal with the
|
||||||
|
// broken win32 API as best it can.
|
||||||
|
KeyButton mapVirtKeyToButton(UINT virtualKey,
|
||||||
|
KeyButton& extended) const;
|
||||||
|
|
||||||
|
// same as above and discard extended
|
||||||
|
KeyButton mapVirtKeyToButton(UINT virtualKey) const;
|
||||||
|
|
||||||
// map character \c c given keyboard layout \c hkl to the keystrokes
|
// map character \c c given keyboard layout \c hkl to the keystrokes
|
||||||
// to generate it.
|
// to generate it.
|
||||||
KeyButton mapCharacter(Keystrokes& keys,
|
KeyButton mapCharacter(Keystrokes& keys,
|
||||||
|
|
|
@ -83,6 +83,7 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary,
|
||||||
m_mark(0),
|
m_mark(0),
|
||||||
m_markReceived(0),
|
m_markReceived(0),
|
||||||
m_keyLayout(NULL),
|
m_keyLayout(NULL),
|
||||||
|
m_fixTimer(NULL),
|
||||||
m_screensaver(NULL),
|
m_screensaver(NULL),
|
||||||
m_screensaverNotify(false),
|
m_screensaverNotify(false),
|
||||||
m_nextClipboardWindow(NULL),
|
m_nextClipboardWindow(NULL),
|
||||||
|
@ -218,6 +219,13 @@ CMSWindowsScreen::disable()
|
||||||
CArchMiscWindows::kDISPLAY);
|
CArchMiscWindows::kDISPLAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// uninstall fix key timer
|
||||||
|
if (m_fixTimer != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer);
|
||||||
|
EVENTQUEUE->deleteTimer(m_fixTimer);
|
||||||
|
m_fixTimer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// stop snooping the clipboard
|
// stop snooping the clipboard
|
||||||
ChangeClipboardChain(m_window, m_nextClipboardWindow);
|
ChangeClipboardChain(m_window, m_nextClipboardWindow);
|
||||||
m_nextClipboardWindow = NULL;
|
m_nextClipboardWindow = NULL;
|
||||||
|
@ -680,6 +688,10 @@ CMSWindowsScreen::onPreDispatch(HWND hwnd,
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case SYNERGY_MSG_SCREEN_SAVER:
|
case SYNERGY_MSG_SCREEN_SAVER:
|
||||||
return onScreensaver(wParam != 0);
|
return onScreensaver(wParam != 0);
|
||||||
|
|
||||||
|
case SYNERGY_MSG_DEBUG:
|
||||||
|
LOG((CLOG_INFO "hook: 0x%08x 0x%08x", wParam, lParam));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_isPrimary) {
|
if (m_isPrimary) {
|
||||||
|
@ -693,27 +705,6 @@ bool
|
||||||
CMSWindowsScreen::onPreDispatchPrimary(HWND,
|
CMSWindowsScreen::onPreDispatchPrimary(HWND,
|
||||||
UINT message, WPARAM wParam, LPARAM lParam)
|
UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
// fake a key release for the windows keys if we think they're
|
|
||||||
// down but they're really up. we have to do this because if the
|
|
||||||
// user presses and releases a windows key without pressing any
|
|
||||||
// other key while it's down then the system will eat the key
|
|
||||||
// release. if we don't detect that and synthesize the release
|
|
||||||
// then the client won't take the usual windows key release action
|
|
||||||
// (which on windows is to show the start menu).
|
|
||||||
//
|
|
||||||
// since the key could go up at any time we'll check the state on
|
|
||||||
// every event. only check on the windows 95 family since the NT
|
|
||||||
// family reports the key release as usual. obviously we skip
|
|
||||||
// this if the event is for a windows key itself.
|
|
||||||
if (m_is95Family && message != SYNERGY_MSG_KEY) {
|
|
||||||
if (wParam != VK_LWIN) {
|
|
||||||
m_keyState->fixKey(getEventTarget(), VK_LWIN);
|
|
||||||
}
|
|
||||||
if (wParam != VK_RWIN) {
|
|
||||||
m_keyState->fixKey(getEventTarget(), VK_RWIN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle event
|
// handle event
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case SYNERGY_MSG_MARK:
|
case SYNERGY_MSG_MARK:
|
||||||
|
@ -840,22 +831,67 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, lParam=0x%08x", (wParam & 0xff00u) >> 8, wParam & 0xffu, lParam));
|
LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, lParam=0x%08x", (wParam & 0xff00u) >> 8, wParam & 0xffu, lParam));
|
||||||
|
|
||||||
// update key state. ignore key repeats.
|
// fix up key state
|
||||||
|
fixKeys();
|
||||||
|
|
||||||
|
// get key info
|
||||||
KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16);
|
KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16);
|
||||||
if ((lParam & 0xc0000000u) == 0x00000000) {
|
bool down = ((lParam & 0xc0000000u) == 0x00000000u);
|
||||||
|
bool up = ((lParam & 0x80000000u) == 0x80000000u);
|
||||||
|
bool wasDown = isKeyDown(button);
|
||||||
|
|
||||||
|
// the windows keys are a royal pain on the windows 95 family.
|
||||||
|
// the system eats the key up events if and only if the windows
|
||||||
|
// key wasn't combined with another key, i.e. it was tapped.
|
||||||
|
// fixKeys() and scheduleFixKeys() are all about synthesizing
|
||||||
|
// the missing key up. but even windows itself gets a little
|
||||||
|
// confused and sets bit 30 in lParam if you tap the windows
|
||||||
|
// key twice. that bit means the key was previously down and
|
||||||
|
// that makes some sense since the up event was missing.
|
||||||
|
// anyway, on the windows 95 family we forget about windows
|
||||||
|
// key repeats and treat anything that's not a key down as a
|
||||||
|
// key up.
|
||||||
|
if (m_is95Family &&
|
||||||
|
((wParam & 0xffu) == VK_LWIN || (wParam & 0xffu) == VK_RWIN)) {
|
||||||
|
down = !up;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update key state. ignore key repeats.
|
||||||
|
if (down) {
|
||||||
m_keyState->setKeyDown(button, true);
|
m_keyState->setKeyDown(button, true);
|
||||||
}
|
}
|
||||||
else if ((lParam & 0x80000000u) == 0x80000000) {
|
else if (up) {
|
||||||
m_keyState->setKeyDown(button, false);
|
m_keyState->setKeyDown(button, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// schedule a timer if we need to fix keys later
|
||||||
|
scheduleFixKeys();
|
||||||
|
|
||||||
|
// special case: we detect ctrl+alt+del being pressed on some
|
||||||
|
// systems but we don't detect the release of those keys. so
|
||||||
|
// if ctrl, alt, and del are down then mark them up.
|
||||||
|
KeyModifierMask mask = getActiveModifiers();
|
||||||
|
bool ctrlAlt = ((mask & (KeyModifierControl | KeyModifierAlt)) ==
|
||||||
|
(KeyModifierControl | KeyModifierAlt));
|
||||||
|
if (down && ctrlAlt &&
|
||||||
|
isKeyDown(m_keyState->virtualKeyToButton(VK_DELETE))) {
|
||||||
|
m_keyState->setKeyDown(
|
||||||
|
m_keyState->virtualKeyToButton(VK_LCONTROL), false);
|
||||||
|
m_keyState->setKeyDown(
|
||||||
|
m_keyState->virtualKeyToButton(VK_RCONTROL), false);
|
||||||
|
m_keyState->setKeyDown(
|
||||||
|
m_keyState->virtualKeyToButton(VK_LMENU), false);
|
||||||
|
m_keyState->setKeyDown(
|
||||||
|
m_keyState->virtualKeyToButton(VK_RMENU), false);
|
||||||
|
m_keyState->setKeyDown(
|
||||||
|
m_keyState->virtualKeyToButton(VK_DELETE), false);
|
||||||
|
}
|
||||||
|
|
||||||
// ignore message if posted prior to last mark change
|
// ignore message if posted prior to last mark change
|
||||||
if (!ignore()) {
|
if (!ignore()) {
|
||||||
// check for ctrl+alt+del emulation
|
// check for ctrl+alt+del emulation
|
||||||
UINT virtKey = (wParam & 0xffu);
|
UINT virtKey = (wParam & 0xffu);
|
||||||
if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) &&
|
if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) && ctrlAlt) {
|
||||||
(m_keyState->getActiveModifiers() &
|
|
||||||
(KeyModifierControl | KeyModifierAlt)) != 0) {
|
|
||||||
LOG((CLOG_DEBUG "emulate ctrl+alt+del"));
|
LOG((CLOG_DEBUG "emulate ctrl+alt+del"));
|
||||||
// switch wParam and lParam to be as if VK_DELETE was
|
// switch wParam and lParam to be as if VK_DELETE was
|
||||||
// pressed or released
|
// pressed or released
|
||||||
|
@ -870,9 +906,41 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
KeyID key = m_keyState->mapKeyFromEvent(wParam, lParam, &mask);
|
KeyID key = m_keyState->mapKeyFromEvent(wParam, lParam, &mask);
|
||||||
button = static_cast<KeyButton>((lParam & 0x01ff0000u) >> 16);
|
button = static_cast<KeyButton>((lParam & 0x01ff0000u) >> 16);
|
||||||
if (key != kKeyNone) {
|
if (key != kKeyNone) {
|
||||||
|
// fix up key. if the key isn't down according to
|
||||||
|
// our table then we never got the key press event
|
||||||
|
// for it. if it's not a modifier key then we'll
|
||||||
|
// synthesize the press first. only do this on
|
||||||
|
// the windows 95 family, which eats certain special
|
||||||
|
// keys like alt+tab, ctrl+esc, etc.
|
||||||
|
if (m_is95Family && !wasDown && up) {
|
||||||
|
switch (virtKey) {
|
||||||
|
case VK_LSHIFT:
|
||||||
|
case VK_RSHIFT:
|
||||||
|
case VK_SHIFT:
|
||||||
|
case VK_LCONTROL:
|
||||||
|
case VK_RCONTROL:
|
||||||
|
case VK_CONTROL:
|
||||||
|
case VK_LMENU:
|
||||||
|
case VK_RMENU:
|
||||||
|
case VK_MENU:
|
||||||
|
case VK_CAPITAL:
|
||||||
|
case VK_NUMLOCK:
|
||||||
|
case VK_SCROLL:
|
||||||
|
case VK_LWIN:
|
||||||
|
case VK_RWIN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
m_keyState->sendKeyEvent(getEventTarget(),
|
||||||
|
true, false, key, mask, 1, button);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do it
|
||||||
m_keyState->sendKeyEvent(getEventTarget(),
|
m_keyState->sendKeyEvent(getEventTarget(),
|
||||||
((lParam & 0x80000000) == 0),
|
((lParam & 0x80000000u) == 0),
|
||||||
((lParam & 0x40000000) == 1),
|
((lParam & 0x40000000u) == 1),
|
||||||
key, mask, (SInt32)(lParam & 0xffff), button);
|
key, mask, (SInt32)(lParam & 0xffff), button);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1225,6 +1293,58 @@ CMSWindowsScreen::mapButtonFromEvent(WPARAM msg, LPARAM button) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsScreen::fixKeys()
|
||||||
|
{
|
||||||
|
// fake key releases for the windows keys if we think they're
|
||||||
|
// down but they're really up. we have to do this because if the
|
||||||
|
// user presses and releases a windows key without pressing any
|
||||||
|
// other key while it's down then the system will eat the key
|
||||||
|
// release. if we don't detect that and synthesize the release
|
||||||
|
// then the client won't take the usual windows key release action
|
||||||
|
// (which on windows is to show the start menu).
|
||||||
|
//
|
||||||
|
// only check on the windows 95 family since the NT family reports
|
||||||
|
// the key releases as usual.
|
||||||
|
if (m_is95Family) {
|
||||||
|
m_keyState->fixKey(getEventTarget(), VK_LWIN);
|
||||||
|
m_keyState->fixKey(getEventTarget(), VK_RWIN);
|
||||||
|
|
||||||
|
// check if we need the fix timer anymore
|
||||||
|
scheduleFixKeys();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsScreen::scheduleFixKeys()
|
||||||
|
{
|
||||||
|
if (m_is95Family) {
|
||||||
|
// see if any keys that need fixing are down
|
||||||
|
bool fix =
|
||||||
|
(m_keyState->isKeyDown(m_keyState->virtualKeyToButton(VK_LWIN)) ||
|
||||||
|
m_keyState->isKeyDown(m_keyState->virtualKeyToButton(VK_RWIN)));
|
||||||
|
|
||||||
|
// start or stop fix timer
|
||||||
|
if (fix && m_fixTimer == NULL) {
|
||||||
|
m_fixTimer = EVENTQUEUE->newTimer(0.1, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_fixTimer,
|
||||||
|
new TMethodEventJob<CMSWindowsScreen>(
|
||||||
|
this, &CMSWindowsScreen::handleFixKeys));
|
||||||
|
}
|
||||||
|
else if (!fix && m_fixTimer != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer);
|
||||||
|
EVENTQUEUE->deleteTimer(m_fixTimer);
|
||||||
|
m_fixTimer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsScreen::handleFixKeys(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
fixKeys();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CMSWindowsScreen::updateKeysCB(void*)
|
CMSWindowsScreen::updateKeysCB(void*)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
class CEventQueueTimer;
|
||||||
class CMSWindowsDesks;
|
class CMSWindowsDesks;
|
||||||
class CMSWindowsKeyState;
|
class CMSWindowsKeyState;
|
||||||
class CMSWindowsScreenSaver;
|
class CMSWindowsScreenSaver;
|
||||||
|
@ -156,6 +157,16 @@ private:
|
||||||
// map a button event to a button ID
|
// map a button event to a button ID
|
||||||
ButtonID mapButtonFromEvent(WPARAM msg, LPARAM button) const;
|
ButtonID mapButtonFromEvent(WPARAM msg, LPARAM button) const;
|
||||||
|
|
||||||
|
// fix the key state, synthesizing fake key releases for keys
|
||||||
|
// that aren't down anymore.
|
||||||
|
void fixKeys();
|
||||||
|
|
||||||
|
// (un)schedule a later call to fixKeys
|
||||||
|
void scheduleFixKeys();
|
||||||
|
|
||||||
|
// event handler to fix the key state
|
||||||
|
void handleFixKeys(const CEvent&, void*);
|
||||||
|
|
||||||
// job to update the key state
|
// job to update the key state
|
||||||
void updateKeysCB(void*);
|
void updateKeysCB(void*);
|
||||||
|
|
||||||
|
@ -200,6 +211,9 @@ private:
|
||||||
// the keyboard layout to use when off primary screen
|
// the keyboard layout to use when off primary screen
|
||||||
HKL m_keyLayout;
|
HKL m_keyLayout;
|
||||||
|
|
||||||
|
// the timer used to check for fixing key state
|
||||||
|
CEventQueueTimer* m_fixTimer;
|
||||||
|
|
||||||
// screen saver stuff
|
// screen saver stuff
|
||||||
CMSWindowsScreenSaver* m_screensaver;
|
CMSWindowsScreenSaver* m_screensaver;
|
||||||
bool m_screensaverNotify;
|
bool m_screensaverNotify;
|
||||||
|
|
|
@ -94,6 +94,7 @@ static SInt32 g_wScreen = 0;
|
||||||
static SInt32 g_hScreen = 0;
|
static SInt32 g_hScreen = 0;
|
||||||
static WPARAM g_deadVirtKey = 0;
|
static WPARAM g_deadVirtKey = 0;
|
||||||
static LPARAM g_deadLParam = 0;
|
static LPARAM g_deadLParam = 0;
|
||||||
|
static WPARAM g_oldDeadVirtKey = 0;
|
||||||
static BYTE g_deadKeyState[256] = { 0 };
|
static BYTE g_deadKeyState[256] = { 0 };
|
||||||
static DWORD g_hookThread = 0;
|
static DWORD g_hookThread = 0;
|
||||||
static DWORD g_attachedThread = 0;
|
static DWORD g_attachedThread = 0;
|
||||||
|
@ -185,21 +186,44 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
// check for dead keys. we don't forward those to our window.
|
// check for dead keys. we don't forward those to our window.
|
||||||
// instead we'll leave the key in the keyboard layout (a buffer
|
// instead we'll leave the key in the keyboard layout (a buffer
|
||||||
// internal to the system) for translation when the next key is
|
// internal to the system) for translation when the next key is
|
||||||
// pressed.
|
// pressed. note that some systems set bit 31 to indicate a
|
||||||
|
// dead key and others bit 15. nice.
|
||||||
UINT c = MapVirtualKey(wParam, 2);
|
UINT c = MapVirtualKey(wParam, 2);
|
||||||
if ((c & 0x80000000u) != 0) {
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
wParam | 0x00000000, c);
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
wParam | (c << 8) | 0x01000000, lParam);
|
||||||
|
if ((c & 0x80008000u) != 0) {
|
||||||
if ((lParam & 0x80000000u) == 0) {
|
if ((lParam & 0x80000000u) == 0) {
|
||||||
if (g_deadVirtKey == 0) {
|
if (g_deadVirtKey == 0) {
|
||||||
// dead key press, no dead key in the buffer
|
// dead key press, no dead key in the buffer
|
||||||
g_deadVirtKey = wParam;
|
g_deadVirtKey = wParam;
|
||||||
g_deadLParam = lParam;
|
g_deadLParam = lParam;
|
||||||
keyboardGetState(g_deadKeyState);
|
keyboardGetState(g_deadKeyState);
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
wParam | 0x02000000, lParam);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// second dead key press in a row so let it pass
|
// second dead key press in a row so let it pass
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
wParam | 0x03000000, lParam);
|
||||||
|
}
|
||||||
|
else if (wParam == g_oldDeadVirtKey) {
|
||||||
|
// dead key release for second dead key in a row. discard
|
||||||
|
// because we've already handled it. also take it out of
|
||||||
|
// the keyboard buffer.
|
||||||
|
g_oldDeadVirtKey = 0;
|
||||||
|
WORD c;
|
||||||
|
UINT scanCode = ((lParam & 0x00ff0000u) >> 16);
|
||||||
|
ToAscii(wParam, scanCode, g_deadKeyState, &c, 0);
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
wParam | 0x09000000, lParam);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// dead key release
|
// dead key release
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
wParam | 0x04000000, lParam);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,6 +280,8 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
// alt are being used as individual modifiers rather than AltGr.
|
// alt are being used as individual modifiers rather than AltGr.
|
||||||
// we have to put the dead key back first, if there was one.
|
// we have to put the dead key back first, if there was one.
|
||||||
if (n == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) {
|
if (n == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) {
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
wParam | 0x05000000, lParam);
|
||||||
if (g_deadVirtKey != 0) {
|
if (g_deadVirtKey != 0) {
|
||||||
ToAscii(g_deadVirtKey, (g_deadLParam & 0x00ff0000u) >> 16,
|
ToAscii(g_deadVirtKey, (g_deadLParam & 0x00ff0000u) >> 16,
|
||||||
g_deadKeyState, &c, flags);
|
g_deadKeyState, &c, flags);
|
||||||
|
@ -269,6 +295,9 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
n = ToAscii(wParam, scanCode, keys, &c, flags);
|
n = ToAscii(wParam, scanCode, keys, &c, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
wParam | (c << 8) | ((n & 0xff) << 16) | 0x06000000,
|
||||||
|
lParam);
|
||||||
switch (n) {
|
switch (n) {
|
||||||
default:
|
default:
|
||||||
// key is a dead key; we're not expecting this since we
|
// key is a dead key; we're not expecting this since we
|
||||||
|
@ -307,6 +336,9 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
if (g_deadVirtKey != 0) {
|
if (g_deadVirtKey != 0) {
|
||||||
ToAscii(g_deadVirtKey, (g_deadLParam & 0x00ff0000u) >> 16,
|
ToAscii(g_deadVirtKey, (g_deadLParam & 0x00ff0000u) >> 16,
|
||||||
g_deadKeyState, &c, flags);
|
g_deadKeyState, &c, flags);
|
||||||
|
for (int i = 0; i < 256; ++i) {
|
||||||
|
g_deadKeyState[i] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear out old dead key state
|
// clear out old dead key state
|
||||||
|
@ -318,12 +350,17 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
// forwarding events to clients because this'll keep our thread's
|
// forwarding events to clients because this'll keep our thread's
|
||||||
// key state table up to date. that's important for querying
|
// key state table up to date. that's important for querying
|
||||||
// the scroll lock toggle state.
|
// the scroll lock toggle state.
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
charAndVirtKey | 0x07000000, lParam);
|
||||||
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, charAndVirtKey, lParam);
|
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, charAndVirtKey, lParam);
|
||||||
|
|
||||||
// send fake key release if the user just pressed two dead keys
|
// send fake key release if the user just pressed two dead keys
|
||||||
// in a row, otherwise we'll lose the release because we always
|
// in a row, otherwise we'll lose the release because we always
|
||||||
// return from the top of this function for all dead key releases.
|
// return from the top of this function for all dead key releases.
|
||||||
if ((c & 0x80000000u) != 0) {
|
if ((c & 0x80008000u) != 0) {
|
||||||
|
g_oldDeadVirtKey = wParam;
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG,
|
||||||
|
wParam | 0x08000000, lParam);
|
||||||
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY,
|
PostThreadMessage(g_threadID, SYNERGY_MSG_KEY,
|
||||||
charAndVirtKey, lParam | 0x80000000u);
|
charAndVirtKey, lParam | 0x80000000u);
|
||||||
}
|
}
|
||||||
|
@ -342,6 +379,14 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
case VK_SHIFT:
|
case VK_SHIFT:
|
||||||
case VK_LSHIFT:
|
case VK_LSHIFT:
|
||||||
case VK_RSHIFT:
|
case VK_RSHIFT:
|
||||||
|
// pass the shift modifiers. if we don't do this
|
||||||
|
// we may not get the right dead key when caps lock
|
||||||
|
// is on. for example, on the french layout (with
|
||||||
|
// english keycaps) on caps lock then press shift + [
|
||||||
|
// and q. instead of an A with ^ above it you get an
|
||||||
|
// A with dots above it.
|
||||||
|
break;
|
||||||
|
|
||||||
case VK_CONTROL:
|
case VK_CONTROL:
|
||||||
case VK_LCONTROL:
|
case VK_LCONTROL:
|
||||||
case VK_RCONTROL:
|
case VK_RCONTROL:
|
||||||
|
@ -349,8 +394,8 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
case VK_LMENU:
|
case VK_LMENU:
|
||||||
case VK_RMENU:
|
case VK_RMENU:
|
||||||
case VK_HANGUL:
|
case VK_HANGUL:
|
||||||
// always pass the shift modifiers
|
// discard the control and alt modifiers
|
||||||
break;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// discard
|
// discard
|
||||||
|
@ -787,12 +832,14 @@ install()
|
||||||
g_hinstance,
|
g_hinstance,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
#if !NO_GRAB_KEYBOARD
|
||||||
if (g_keyboardLL == NULL) {
|
if (g_keyboardLL == NULL) {
|
||||||
g_keyboard = SetWindowsHookEx(WH_KEYBOARD,
|
g_keyboard = SetWindowsHookEx(WH_KEYBOARD,
|
||||||
&keyboardHook,
|
&keyboardHook,
|
||||||
g_hinstance,
|
g_hinstance,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// check that we got all the hooks we wanted
|
// check that we got all the hooks we wanted
|
||||||
if ((g_getMessage == NULL && g_wheelSupport == kWheelOld) ||
|
if ((g_getMessage == NULL && g_wheelSupport == kWheelOld) ||
|
||||||
|
|
|
@ -38,9 +38,10 @@
|
||||||
#define SYNERGY_MSG_POST_WARP WM_APP + 0x0016 // <unused>; <unused>
|
#define SYNERGY_MSG_POST_WARP WM_APP + 0x0016 // <unused>; <unused>
|
||||||
#define SYNERGY_MSG_PRE_WARP WM_APP + 0x0017 // x; y
|
#define SYNERGY_MSG_PRE_WARP WM_APP + 0x0017 // x; y
|
||||||
#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; <unused>
|
#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; <unused>
|
||||||
|
#define SYNERGY_MSG_DEBUG WM_APP + 0x0019 // data, data
|
||||||
#define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY
|
#define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY
|
||||||
#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP
|
#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP
|
||||||
#define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_SCREEN_SAVER
|
#define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_DEBUG
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,9 @@ public:
|
||||||
|
|
||||||
//! Mark key as being down
|
//! Mark key as being down
|
||||||
/*!
|
/*!
|
||||||
Sets the state of \p button to down or up. If this is overridden
|
Sets the state of \p button to down or up.
|
||||||
it must forward to the superclass.
|
|
||||||
*/
|
*/
|
||||||
virtual void setKeyDown(KeyButton button, bool down);
|
void setKeyDown(KeyButton button, bool down);
|
||||||
|
|
||||||
//! Mark modifier as being toggled on
|
//! Mark modifier as being toggled on
|
||||||
/*!
|
/*!
|
||||||
|
|
Loading…
Reference in New Issue