Updated keyboard handling on win32. Still needs some work to
avoid shadowing key state in multiple places. Also got locked to screen and reported key appeared to be wrong.
This commit is contained in:
parent
20ba10bfa8
commit
19559d4b4e
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "CMSWindowsKeyMapper.h"
|
#include "CMSWindowsKeyMapper.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
|
|
||||||
// multimedia keys
|
// multimedia keys
|
||||||
#if !defined(VK_BROWSER_BACK)
|
#if !defined(VK_BROWSER_BACK)
|
||||||
|
@ -41,22 +42,6 @@
|
||||||
// CMSWindowsKeyMapper
|
// CMSWindowsKeyMapper
|
||||||
//
|
//
|
||||||
|
|
||||||
// table of modifier keys. note that VK_RMENU shows up under the Alt
|
|
||||||
// key and ModeSwitch. when simulating AltGr we need to use the right
|
|
||||||
// alt key so we use KeyModifierModeSwitch to get it.
|
|
||||||
const CMSWindowsKeyMapper::CModifierKeys
|
|
||||||
CMSWindowsKeyMapper::s_modifiers[] =
|
|
||||||
{
|
|
||||||
KeyModifierShift, { VK_LSHIFT, VK_RSHIFT },
|
|
||||||
KeyModifierControl, { VK_LCONTROL, VK_RCONTROL | 0x100 },
|
|
||||||
KeyModifierAlt, { VK_LMENU, VK_RMENU | 0x100 },
|
|
||||||
KeyModifierSuper, { VK_LWIN | 0x100, VK_RWIN | 0x100 },
|
|
||||||
KeyModifierModeSwitch, { VK_RMENU | 0x100, 0 },
|
|
||||||
KeyModifierCapsLock, { VK_CAPITAL, 0 },
|
|
||||||
KeyModifierNumLock, { VK_NUMLOCK | 0x100, 0 },
|
|
||||||
KeyModifierScrollLock, { VK_SCROLL, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* CMSWindowsKeyMapper::s_vkToName[] =
|
const char* CMSWindowsKeyMapper::s_vkToName[] =
|
||||||
{
|
{
|
||||||
"vk 0x00",
|
"vk 0x00",
|
||||||
|
@ -578,10 +563,8 @@ const KeyID CMSWindowsKeyMapper::s_virtualKey[][2] =
|
||||||
/* 0xff */ kKeyNone, kKeyNone // reserved
|
/* 0xff */ kKeyNone, kKeyNone // reserved
|
||||||
};
|
};
|
||||||
|
|
||||||
// map special KeyID keys to virtual key codes. if the key is an
|
// map special KeyID keys to virtual key codes
|
||||||
// extended key then the entry is the virtual key code | 0x100.
|
const UINT CMSWindowsKeyMapper::s_mapE000[] =
|
||||||
// unmapped keys have a 0 entry.
|
|
||||||
const KeyButton CMSWindowsKeyMapper::s_mapE000[] =
|
|
||||||
{
|
{
|
||||||
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
@ -604,15 +587,15 @@ const KeyButton CMSWindowsKeyMapper::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|0x100, VK_BROWSER_FORWARD|0x100,
|
/* 0xa4 */ 0, 0, VK_BROWSER_BACK, VK_BROWSER_FORWARD,
|
||||||
/* 0xa8 */ VK_BROWSER_REFRESH|0x100, VK_BROWSER_STOP|0x100,
|
/* 0xa8 */ VK_BROWSER_REFRESH, VK_BROWSER_STOP,
|
||||||
/* 0xaa */ VK_BROWSER_SEARCH|0x100, VK_BROWSER_FAVORITES|0x100,
|
/* 0xaa */ VK_BROWSER_SEARCH, VK_BROWSER_FAVORITES,
|
||||||
/* 0xac */ VK_BROWSER_HOME|0x100, VK_VOLUME_MUTE|0x100,
|
/* 0xac */ VK_BROWSER_HOME, VK_VOLUME_MUTE,
|
||||||
/* 0xae */ VK_VOLUME_DOWN|0x100, VK_VOLUME_UP|0x100,
|
/* 0xae */ VK_VOLUME_DOWN, VK_VOLUME_UP,
|
||||||
/* 0xb0 */ VK_MEDIA_NEXT_TRACK|0x100, VK_MEDIA_PREV_TRACK|0x100,
|
/* 0xb0 */ VK_MEDIA_NEXT_TRACK, VK_MEDIA_PREV_TRACK,
|
||||||
/* 0xb2 */ VK_MEDIA_STOP|0x100, VK_MEDIA_PLAY_PAUSE|0x100,
|
/* 0xb2 */ VK_MEDIA_STOP, VK_MEDIA_PLAY_PAUSE,
|
||||||
/* 0xb4 */ VK_LAUNCH_MAIL|0x100, VK_LAUNCH_MEDIA_SELECT|0x100,
|
/* 0xb4 */ VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT,
|
||||||
/* 0xb6 */ VK_LAUNCH_APP1|0x100, VK_LAUNCH_APP2|0x100,
|
/* 0xb6 */ VK_LAUNCH_APP1, VK_LAUNCH_APP2,
|
||||||
/* 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,
|
||||||
|
@ -623,7 +606,7 @@ const KeyButton CMSWindowsKeyMapper::s_mapE000[] =
|
||||||
/* 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, 0
|
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
};
|
};
|
||||||
const KeyButton CMSWindowsKeyMapper::s_mapEE00[] =
|
const UINT CMSWindowsKeyMapper::s_mapEE00[] =
|
||||||
{
|
{
|
||||||
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
@ -661,7 +644,7 @@ const KeyButton CMSWindowsKeyMapper::s_mapEE00[] =
|
||||||
/* in g_mapEF00, 0xac is VK_DECIMAL not VK_SEPARATOR because win32
|
/* in g_mapEF00, 0xac is VK_DECIMAL not VK_SEPARATOR because win32
|
||||||
* doesn't seem to use VK_SEPARATOR but instead maps VK_DECIMAL to
|
* doesn't seem to use VK_SEPARATOR but instead maps VK_DECIMAL to
|
||||||
* the same meaning. */
|
* the same meaning. */
|
||||||
const KeyButton CMSWindowsKeyMapper::s_mapEF00[] =
|
const UINT CMSWindowsKeyMapper::s_mapEF00[] =
|
||||||
{
|
{
|
||||||
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0x08 */ VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,
|
/* 0x08 */ VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,
|
||||||
|
@ -673,22 +656,22 @@ const KeyButton CMSWindowsKeyMapper::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|0x100, VK_LEFT|0x100, VK_UP|0x100, VK_RIGHT|0x100,
|
/* 0x50 */ VK_HOME, VK_LEFT, VK_UP, VK_RIGHT,
|
||||||
/* 0x54 */ VK_DOWN|0x100, VK_PRIOR|0x100, VK_NEXT|0x100, VK_END|0x100,
|
/* 0x54 */ VK_DOWN, VK_PRIOR, VK_NEXT, VK_END,
|
||||||
/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
/* 0x60 */ VK_SELECT|0x100, VK_SNAPSHOT|0x100, VK_EXECUTE|0x100, VK_INSERT|0x100,
|
/* 0x60 */ VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT,
|
||||||
/* 0x64 */ 0, 0, 0, VK_APPS|0x100,
|
/* 0x64 */ 0, 0, 0, VK_APPS,
|
||||||
/* 0x68 */ 0, 0, VK_HELP|0x100, VK_CANCEL|0x100, 0, 0, 0, 0,
|
/* 0x68 */ 0, 0, VK_HELP, VK_CANCEL, 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|0x100,
|
/* 0x78 */ 0, 0, 0, 0, 0, 0, 0, VK_NUMLOCK,
|
||||||
/* 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|0x100, 0, 0,
|
/* 0x88 */ 0, VK_TAB, 0, 0, 0, VK_RETURN, 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|0x100,
|
/* 0xac */ VK_DECIMAL, VK_SUBTRACT, VK_DECIMAL, VK_DIVIDE,
|
||||||
/* 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,
|
||||||
|
@ -697,11 +680,11 @@ const KeyButton CMSWindowsKeyMapper::s_mapEF00[] =
|
||||||
/* 0xd0 */ VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 0, 0,
|
/* 0xd0 */ VK_F19, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, 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, VK_LCONTROL,
|
||||||
/* 0xe4 */ VK_RCONTROL|0x100, VK_CAPITAL, 0, 0,
|
/* 0xe4 */ VK_RCONTROL, VK_CAPITAL, 0, 0,
|
||||||
/* 0xe8 */ 0, VK_LMENU, VK_RMENU|0x100, VK_LWIN|0x100,
|
/* 0xe8 */ 0, VK_LMENU, VK_RMENU, VK_LWIN,
|
||||||
/* 0xec */ VK_RWIN|0x100, 0, 0, 0,
|
/* 0xec */ VK_RWIN, 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|0x100
|
/* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, VK_DELETE
|
||||||
};
|
};
|
||||||
|
|
||||||
CMSWindowsKeyMapper::CMSWindowsKeyMapper() : m_deadKey(0)
|
CMSWindowsKeyMapper::CMSWindowsKeyMapper() : m_deadKey(0)
|
||||||
|
@ -717,156 +700,169 @@ CMSWindowsKeyMapper::~CMSWindowsKeyMapper()
|
||||||
void
|
void
|
||||||
CMSWindowsKeyMapper::update(IKeyState* keyState)
|
CMSWindowsKeyMapper::update(IKeyState* keyState)
|
||||||
{
|
{
|
||||||
static const size_t numModifiers = sizeof(s_modifiers) /
|
|
||||||
sizeof(s_modifiers[0]);
|
|
||||||
|
|
||||||
// clear shadow state
|
// clear shadow state
|
||||||
memset(m_keys, 0, sizeof(m_keys));
|
memset(m_keys, 0, sizeof(m_keys));
|
||||||
|
|
||||||
// add modifiers
|
// clear scan code to/from virtual key mapping
|
||||||
|
memset(m_scanCodeToVirtKey, 0, sizeof(m_scanCodeToVirtKey));
|
||||||
|
memset(m_virtKeyToScanCode, 0, sizeof(m_virtKeyToScanCode));
|
||||||
|
|
||||||
|
// add modifiers. note that VK_RMENU shows up under the Alt key
|
||||||
|
// and ModeSwitch. when simulating AltGr we need to use the right
|
||||||
|
// alt key so we use KeyModifierModeSwitch to get it.
|
||||||
if (keyState != NULL) {
|
if (keyState != NULL) {
|
||||||
for (size_t i = 0; i < numModifiers; ++i) {
|
IKeyState::KeyButtons keys;
|
||||||
IKeyState::KeyButtons keys;
|
keys.push_back((KeyButton)MapVirtualKey(VK_LSHIFT, 0));
|
||||||
for (size_t j = 0; j < CModifierKeys::s_maxKeys; ++j) {
|
keys.push_back((KeyButton)MapVirtualKey(VK_RSHIFT, 0));
|
||||||
if (s_modifiers[i].m_keys[j] != 0) {
|
keyState->addModifier(KeyModifierShift, keys);
|
||||||
keys.push_back(s_modifiers[i].m_keys[j]);
|
keys.clear();
|
||||||
}
|
keys.push_back((KeyButton)MapVirtualKey(VK_LCONTROL, 0));
|
||||||
}
|
keys.push_back((KeyButton)(MapVirtualKey(VK_RCONTROL, 0) | 0x100));
|
||||||
keyState->addModifier(s_modifiers[i].m_mask, keys);
|
keyState->addModifier(KeyModifierControl, keys);
|
||||||
}
|
keys.clear();
|
||||||
|
keys.push_back((KeyButton)MapVirtualKey(VK_LMENU, 0));
|
||||||
|
keys.push_back((KeyButton)(MapVirtualKey(VK_RMENU, 0) | 0x100));
|
||||||
|
keyState->addModifier(KeyModifierAlt, keys);
|
||||||
|
keys.clear();
|
||||||
|
keys.push_back((KeyButton)(MapVirtualKey(VK_LWIN, 0) | 0x100));
|
||||||
|
keys.push_back((KeyButton)(MapVirtualKey(VK_RWIN, 0) | 0x100));
|
||||||
|
keyState->addModifier(KeyModifierSuper, keys);
|
||||||
|
keys.clear();
|
||||||
|
keys.push_back((KeyButton)(MapVirtualKey(VK_RMENU, 0) | 0x100));
|
||||||
|
keyState->addModifier(KeyModifierModeSwitch, keys);
|
||||||
|
keys.clear();
|
||||||
|
keys.push_back((KeyButton)MapVirtualKey(VK_CAPITAL, 0));
|
||||||
|
keyState->addModifier(KeyModifierCapsLock, keys);
|
||||||
|
keys.clear();
|
||||||
|
keys.push_back((KeyButton)(MapVirtualKey(VK_NUMLOCK, 0) | 0x100));
|
||||||
|
keyState->addModifier(KeyModifierNumLock, keys);
|
||||||
|
keys.clear();
|
||||||
|
keys.push_back((KeyButton)MapVirtualKey(VK_SCROLL, 0));
|
||||||
|
keyState->addModifier(KeyModifierScrollLock, keys);
|
||||||
|
keys.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// save current state of modifiers
|
/* FIXME -- potential problem here on win me
|
||||||
for (size_t i = 0; i < numModifiers; ++i) {
|
// win me (sony vaio laptop):
|
||||||
for (size_t j = 0; j < CModifierKeys::s_maxKeys; ++j) {
|
// MapVirtualKey(vk, 0):
|
||||||
if (s_modifiers[i].m_keys[j] != 0) {
|
// VK_SHIFT mapped; VK_LSHIFT, VK_RSHIFT not mapped
|
||||||
SHORT s = GetKeyState(s_modifiers[i].m_keys[j]);
|
// VK_CONTROL mapped; VK_LCONTROL, VK_RCONTROL not mapped
|
||||||
m_keys[s_modifiers[i].m_keys[j] & 0xffu] = static_cast<BYTE>(s);
|
// VK_MENU mapped; VK_LMENU, VK_RMENU not mapped
|
||||||
|
// MapVirtualKey(sc, 3):
|
||||||
|
// all scan codes unmapped (function apparently unimplemented)
|
||||||
|
*/
|
||||||
|
BYTE keys[256];
|
||||||
|
GetKeyboardState(keys);
|
||||||
|
for (UINT i = 1; i < 256; ++i) {
|
||||||
|
// skip certain virtual keys (the ones for the mouse buttons)
|
||||||
|
if (i < VK_BACK && i != VK_CANCEL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// map to a scancode and back to a virtual key
|
||||||
|
UINT scancode = MapVirtualKey(i, 0);
|
||||||
|
UINT virtKey = MapVirtualKey(scancode, 3);
|
||||||
|
if (scancode == 0 || virtKey == 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.
|
||||||
|
// 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.
|
||||||
|
// save the key state.
|
||||||
|
m_scanCodeToVirtKey[scancode] = i;
|
||||||
|
m_virtKeyToScanCode[i] = (KeyButton)scancode;
|
||||||
|
m_keys[scancode] = (BYTE)(keys[i] & 0x80);
|
||||||
|
if (keyState != NULL) {
|
||||||
|
keyState->setKeyDown((KeyButton)scancode, (keys[i] & 0x80) != 0);
|
||||||
|
}
|
||||||
|
// toggle state applies to all keys but we only want it for
|
||||||
|
// the modifier keys with corresponding lights.
|
||||||
|
if ((keys[i] & 0x01) != 0) {
|
||||||
|
switch (i) {
|
||||||
|
case VK_CAPITAL:
|
||||||
|
m_keys[scancode] |= 0x01;
|
||||||
if (keyState != NULL) {
|
if (keyState != NULL) {
|
||||||
if ((s & 0x01) != 0) {
|
keyState->setToggled(KeyModifierCapsLock);
|
||||||
keyState->setToggled(s_modifiers[i].m_mask);
|
|
||||||
}
|
|
||||||
if ((s & 0x80) != 0) {
|
|
||||||
keyState->setKeyDown(s_modifiers[i].m_keys[j]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_NUMLOCK:
|
||||||
|
m_keys[scancode] |= 0x01;
|
||||||
|
if (keyState != NULL) {
|
||||||
|
keyState->setToggled(KeyModifierNumLock);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_SCROLL:
|
||||||
|
m_keys[scancode] |= 0x01;
|
||||||
|
if (keyState != NULL) {
|
||||||
|
keyState->setToggled(KeyModifierScrollLock);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CMSWindowsKeyMapper::updateKey(KeyButton key, bool pressed)
|
CMSWindowsKeyMapper::updateKey(LPARAM eventLParam)
|
||||||
{
|
{
|
||||||
|
bool pressed = ((eventLParam & 0x80000000u) == 0);
|
||||||
|
UINT scanCode = ((eventLParam & 0x01ff0000u) >> 16);
|
||||||
|
UINT virtKey = m_scanCodeToVirtKey[scanCode];
|
||||||
|
if (virtKey == 0) {
|
||||||
|
// unmapped key
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
switch (key) {
|
m_keys[scanCode] |= 0x80;
|
||||||
case 0:
|
|
||||||
case VK_LBUTTON:
|
|
||||||
case VK_MBUTTON:
|
|
||||||
case VK_RBUTTON:
|
|
||||||
// ignore bogus key
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_LSHIFT:
|
|
||||||
case VK_RSHIFT:
|
|
||||||
case VK_SHIFT:
|
|
||||||
m_keys[key] |= 0x80;
|
|
||||||
m_keys[VK_SHIFT] |= 0x80;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_LCONTROL:
|
|
||||||
case VK_RCONTROL:
|
|
||||||
case VK_CONTROL:
|
|
||||||
m_keys[key] |= 0x80;
|
|
||||||
m_keys[VK_CONTROL] |= 0x80;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_LMENU:
|
|
||||||
case VK_RMENU:
|
|
||||||
case VK_MENU:
|
|
||||||
m_keys[key] |= 0x80;
|
|
||||||
m_keys[VK_MENU] |= 0x80;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_CAPITAL:
|
|
||||||
case VK_NUMLOCK:
|
|
||||||
case VK_SCROLL:
|
|
||||||
// toggle keys
|
|
||||||
m_keys[key] |= 0x80;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
case VK_LWIN:
|
|
||||||
case VK_RWIN:
|
|
||||||
case VK_APPS:
|
|
||||||
m_keys[key] |= 0x80;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// special case: we detect ctrl+alt+del being pressed on some
|
// special case: we detect ctrl+alt+del being pressed on some
|
||||||
// systems but we don't detect the release of those keys. so
|
// systems but we don't detect the release of those keys. so
|
||||||
// if ctrl, alt, and del are down then mark them up.
|
// if ctrl, alt, and del are down then mark them up.
|
||||||
if ((m_keys[VK_CONTROL] & 0x80) != 0 &&
|
if (isPressed(VK_CONTROL) &&
|
||||||
(m_keys[VK_MENU] & 0x80) != 0 &&
|
isPressed(VK_MENU) &&
|
||||||
(m_keys[VK_DELETE] & 0x80) != 0) {
|
isPressed(VK_DELETE)) {
|
||||||
m_keys[VK_LCONTROL] &= ~0x80;
|
m_keys[m_virtKeyToScanCode[VK_LCONTROL]] &= ~0x80;
|
||||||
m_keys[VK_RCONTROL] &= ~0x80;
|
m_keys[m_virtKeyToScanCode[VK_RCONTROL]] &= ~0x80;
|
||||||
m_keys[VK_CONTROL] &= ~0x80;
|
m_keys[m_virtKeyToScanCode[VK_LMENU]] &= ~0x80;
|
||||||
m_keys[VK_LMENU] &= ~0x80;
|
m_keys[m_virtKeyToScanCode[VK_RMENU]] &= ~0x80;
|
||||||
m_keys[VK_RMENU] &= ~0x80;
|
m_keys[m_virtKeyToScanCode[VK_DELETE]] &= ~0x80;
|
||||||
m_keys[VK_MENU] &= ~0x80;
|
|
||||||
m_keys[VK_DELETE] &= ~0x80;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch (key) {
|
m_keys[scanCode] &= ~0x80;
|
||||||
case 0:
|
|
||||||
case VK_LBUTTON:
|
|
||||||
case VK_MBUTTON:
|
|
||||||
case VK_RBUTTON:
|
|
||||||
// ignore bogus key
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_LSHIFT:
|
|
||||||
case VK_RSHIFT:
|
|
||||||
case VK_SHIFT:
|
|
||||||
m_keys[key] &= ~0x80;
|
|
||||||
if (((m_keys[VK_LSHIFT] | m_keys[VK_RSHIFT]) & 0x80) == 0) {
|
|
||||||
m_keys[VK_SHIFT] &= ~0x80;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_LCONTROL:
|
|
||||||
case VK_RCONTROL:
|
|
||||||
case VK_CONTROL:
|
|
||||||
m_keys[key] &= ~0x80;
|
|
||||||
if (((m_keys[VK_LCONTROL] | m_keys[VK_RCONTROL]) & 0x80) == 0) {
|
|
||||||
m_keys[VK_CONTROL] &= ~0x80;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_LMENU:
|
|
||||||
case VK_RMENU:
|
|
||||||
case VK_MENU:
|
|
||||||
m_keys[key] &= ~0x80;
|
|
||||||
if (((m_keys[VK_LMENU] | m_keys[VK_RMENU]) & 0x80) == 0) {
|
|
||||||
m_keys[VK_MENU] &= ~0x80;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
// handle toggle keys
|
||||||
|
switch (virtKey) {
|
||||||
case VK_CAPITAL:
|
case VK_CAPITAL:
|
||||||
case VK_NUMLOCK:
|
case VK_NUMLOCK:
|
||||||
case VK_SCROLL:
|
case VK_SCROLL:
|
||||||
// toggle keys
|
m_keys[scanCode] ^= 0x01;
|
||||||
m_keys[key] &= ~0x80;
|
|
||||||
m_keys[key] ^= 0x01;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
case VK_LWIN:
|
|
||||||
case VK_RWIN:
|
|
||||||
case VK_APPS:
|
|
||||||
m_keys[key] &= ~0x80;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -883,7 +879,7 @@ CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||||
const IKeyState& keyState, KeyID id,
|
const IKeyState& keyState, KeyID id,
|
||||||
KeyModifierMask mask, bool isAutoRepeat) const
|
KeyModifierMask mask, bool isAutoRepeat) const
|
||||||
{
|
{
|
||||||
KeyButton virtualKey = 0;
|
UINT virtualKey = 0;
|
||||||
|
|
||||||
// check for special keys
|
// check for special keys
|
||||||
if ((id & 0xfffff000u) == 0xe000u) {
|
if ((id & 0xfffff000u) == 0xe000u) {
|
||||||
|
@ -898,20 +894,14 @@ CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||||
}
|
}
|
||||||
if (virtualKey == 0) {
|
if (virtualKey == 0) {
|
||||||
LOG((CLOG_DEBUG2 "unknown special key"));
|
LOG((CLOG_DEBUG2 "unknown special key"));
|
||||||
return virtualKey;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// special handling of VK_SNAPSHOT
|
// special handling of VK_SNAPSHOT
|
||||||
if ((virtualKey & 0xffu) == VK_SNAPSHOT) {
|
if (virtualKey == VK_SNAPSHOT) {
|
||||||
// ignore key repeats on print screen
|
// ignore key repeats on print screen
|
||||||
if (!isAutoRepeat) {
|
if (!isAutoRepeat) {
|
||||||
// get event flags
|
|
||||||
DWORD flags = 0;
|
|
||||||
if (isExtendedKey(virtualKey)) {
|
|
||||||
flags |= KEYEVENTF_EXTENDEDKEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// active window (with alt) or fullscreen (without alt)?
|
// active window (with alt) or fullscreen (without alt)?
|
||||||
BYTE scan = 0;
|
BYTE scan = 0;
|
||||||
if ((mask & KeyModifierAlt) != 0) {
|
if ((mask & KeyModifierAlt) != 0) {
|
||||||
|
@ -919,9 +909,8 @@ CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||||
}
|
}
|
||||||
|
|
||||||
// send events
|
// send events
|
||||||
keybd_event(static_cast<BYTE>(virtualKey & 0xffu), scan, flags, 0);
|
keybd_event(VK_SNAPSHOT, scan, 0, 0);
|
||||||
flags |= KEYEVENTF_KEYUP;
|
keybd_event(VK_SNAPSHOT, scan, KEYEVENTF_KEYUP, 0);
|
||||||
keybd_event(static_cast<BYTE>(virtualKey & 0xffu), scan, flags, 0);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -932,16 +921,13 @@ CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||||
KeyModifierMask requiredMask = 0;
|
KeyModifierMask requiredMask = 0;
|
||||||
KeyModifierMask outMask = 0;
|
KeyModifierMask outMask = 0;
|
||||||
|
|
||||||
// strip out extended key flag
|
|
||||||
UINT virtualKey2 = (virtualKey & 0xffu);
|
|
||||||
|
|
||||||
// check numeric keypad. note that virtual keys do not distinguish
|
// check numeric keypad. note that virtual keys do not distinguish
|
||||||
// between the keypad and non-keypad movement keys. however, the
|
// between the keypad and non-keypad movement keys. however, the
|
||||||
// virtual keys do distinguish between keypad numbers and operators
|
// virtual keys do distinguish between keypad numbers and operators
|
||||||
// (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.
|
||||||
if (virtualKey2 >= VK_NUMPAD0 && virtualKey2 <= VK_DIVIDE) {
|
if (virtualKey >= VK_NUMPAD0 && virtualKey <= VK_DIVIDE) {
|
||||||
requiredMask |= KeyModifierNumLock;
|
requiredMask |= KeyModifierNumLock;
|
||||||
if (!keyState.isModifierActive(KeyModifierNumLock)) {
|
if (!keyState.isModifierActive(KeyModifierNumLock)) {
|
||||||
LOG((CLOG_DEBUG2 "turn on num lock for keypad key"));
|
LOG((CLOG_DEBUG2 "turn on num lock for keypad key"));
|
||||||
|
@ -956,8 +942,9 @@ CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||||
}
|
}
|
||||||
|
|
||||||
// now generate the keystrokes and return the resulting modifier mask
|
// now generate the keystrokes and return the resulting modifier mask
|
||||||
LOG((CLOG_DEBUG2 "KeyID 0x%08x to virtual key %d mask 0x%04x", id, virtualKey2, outMask));
|
KeyButton scanCode = m_virtKeyToScanCode[virtualKey];
|
||||||
return mapToKeystrokes(keys, keyState, virtualKey,
|
LOG((CLOG_DEBUG2 "KeyID 0x%08x to virtual key %d scan code 0x%04x mask 0x%04x", id, virtualKey, scanCode, outMask));
|
||||||
|
return mapToKeystrokes(keys, keyState, scanCode,
|
||||||
outMask, requiredMask, isAutoRepeat);
|
outMask, requiredMask, isAutoRepeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,15 +991,16 @@ CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||||
LOG((CLOG_DEBUG2 "KeyID 0x%08x not in code page", id));
|
LOG((CLOG_DEBUG2 "KeyID 0x%08x not in code page", id));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
virtualKey = mapCharacter(keys, keyState, multiByte[0], hkl, isAutoRepeat);
|
KeyButton button = mapCharacter(keys, keyState,
|
||||||
if (virtualKey != 0) {
|
multiByte[0], hkl, isAutoRepeat);
|
||||||
|
if (button != 0) {
|
||||||
LOG((CLOG_DEBUG2 "KeyID 0x%08x maps to character %u", id, (unsigned char)multiByte[0]));
|
LOG((CLOG_DEBUG2 "KeyID 0x%08x maps to character %u", id, (unsigned char)multiByte[0]));
|
||||||
if (isDeadChar(multiByte[0], hkl, false)) {
|
if (isDeadChar(multiByte[0], hkl, false)) {
|
||||||
// character mapped to a dead key but we want the
|
// character mapped to a dead key but we want the
|
||||||
// character for real so send a space key afterwards.
|
// character for real so send a space key afterwards.
|
||||||
LOG((CLOG_DEBUG2 "character mapped to dead key"));
|
LOG((CLOG_DEBUG2 "character mapped to dead key"));
|
||||||
IKeyState::Keystroke keystroke;
|
IKeyState::Keystroke keystroke;
|
||||||
keystroke.m_key = VK_SPACE;
|
keystroke.m_key = m_virtKeyToScanCode[VK_SPACE];
|
||||||
keystroke.m_press = true;
|
keystroke.m_press = true;
|
||||||
keystroke.m_repeat = false;
|
keystroke.m_repeat = false;
|
||||||
keys.push_back(keystroke);
|
keys.push_back(keystroke);
|
||||||
|
@ -1021,9 +1009,9 @@ CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||||
|
|
||||||
// ignore the release of this key since we already
|
// ignore the release of this key since we already
|
||||||
// handled it.
|
// handled it.
|
||||||
virtualKey = 0;
|
button = 0;
|
||||||
}
|
}
|
||||||
return virtualKey;
|
return button;
|
||||||
}
|
}
|
||||||
nChars = MultiByteToWideChar(codePage,
|
nChars = MultiByteToWideChar(codePage,
|
||||||
MB_COMPOSITE | MB_ERR_INVALID_CHARS,
|
MB_COMPOSITE | MB_ERR_INVALID_CHARS,
|
||||||
|
@ -1057,9 +1045,7 @@ CMSWindowsKeyMapper::mapKey(IKeyState::Keystrokes& keys,
|
||||||
|
|
||||||
// process character
|
// process character
|
||||||
LOG((CLOG_DEBUG2 "KeyID 0x%08x maps to character %u", id, (unsigned char)multiByte[0]));
|
LOG((CLOG_DEBUG2 "KeyID 0x%08x maps to character %u", id, (unsigned char)multiByte[0]));
|
||||||
virtualKey = mapCharacter(keys, keyState, multiByte[0], hkl, isAutoRepeat);
|
return mapCharacter(keys, keyState, multiByte[0], hkl, isAutoRepeat);
|
||||||
|
|
||||||
return virtualKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyID
|
KeyID
|
||||||
|
@ -1129,8 +1115,7 @@ CMSWindowsKeyMapper::mapKeyFromEvent(WPARAM charAndVirtKey,
|
||||||
else if (LOBYTE(virtualKeyAndModifierState) != vkCode) {
|
else if (LOBYTE(virtualKeyAndModifierState) != vkCode) {
|
||||||
// we didn't get the key that was actually pressed
|
// we didn't get the key that was actually pressed
|
||||||
LOG((CLOG_DEBUG1 "VkKeyScan() mismatch"));
|
LOG((CLOG_DEBUG1 "VkKeyScan() mismatch"));
|
||||||
if ((m_keys[VK_CONTROL] & 0x80) != 0 &&
|
if (isPressed(VK_CONTROL) && isPressed(VK_MENU)) {
|
||||||
(m_keys[VK_MENU] & 0x80) != 0) {
|
|
||||||
needAltGr = true;
|
needAltGr = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1147,121 +1132,31 @@ CMSWindowsKeyMapper::mapKeyFromEvent(WPARAM charAndVirtKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
// map modifier key
|
// map modifier key
|
||||||
KeyModifierMask mask = 0;
|
|
||||||
if (((m_keys[VK_LSHIFT] |
|
|
||||||
m_keys[VK_RSHIFT] |
|
|
||||||
m_keys[VK_SHIFT]) & 0x80) != 0) {
|
|
||||||
mask |= KeyModifierShift;
|
|
||||||
}
|
|
||||||
if (needAltGr) {
|
|
||||||
mask |= KeyModifierModeSwitch;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (((m_keys[VK_LCONTROL] |
|
|
||||||
m_keys[VK_RCONTROL] |
|
|
||||||
m_keys[VK_CONTROL]) & 0x80) != 0) {
|
|
||||||
mask |= KeyModifierControl;
|
|
||||||
}
|
|
||||||
if (((m_keys[VK_LMENU] |
|
|
||||||
m_keys[VK_RMENU] |
|
|
||||||
m_keys[VK_MENU]) & 0x80) != 0) {
|
|
||||||
mask |= KeyModifierAlt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (((m_keys[VK_LWIN] |
|
|
||||||
m_keys[VK_RWIN]) & 0x80) != 0) {
|
|
||||||
mask |= KeyModifierSuper;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (maskOut != NULL) {
|
if (maskOut != NULL) {
|
||||||
*maskOut = mask;
|
*maskOut = getShadowModifiers(needAltGr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CMSWindowsKeyMapper::isPressed(KeyButton key) const
|
CMSWindowsKeyMapper::isModifier(UINT virtKey) const
|
||||||
{
|
{
|
||||||
return ((m_keys[key & 0xffu] & 0x80) != 0);
|
switch (virtKey) {
|
||||||
}
|
|
||||||
|
|
||||||
UINT
|
|
||||||
CMSWindowsKeyMapper::keyToScanCode(KeyButton* virtualKey) const
|
|
||||||
{
|
|
||||||
// try mapping given virtual key
|
|
||||||
UINT code = MapVirtualKeyEx((*virtualKey) & 0xffu, 0, m_keyLayout);
|
|
||||||
if (code != 0) {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no dice. if the virtual key distinguishes between left/right
|
|
||||||
// then try the one that doesn't distinguish sides. windows (or
|
|
||||||
// keyboard drivers) are inconsistent in their treatment of these
|
|
||||||
// virtual keys. the following behaviors have been observed:
|
|
||||||
//
|
|
||||||
// win2k (gateway desktop):
|
|
||||||
// MapVirtualKey(vk, 0):
|
|
||||||
// VK_SHIFT == VK_LSHIFT != VK_RSHIFT
|
|
||||||
// VK_CONTROL == VK_LCONTROL == VK_RCONTROL
|
|
||||||
// VK_MENU == VK_LMENU == VK_RMENU
|
|
||||||
// MapVirtualKey(sc, 3):
|
|
||||||
// VK_LSHIFT and VK_RSHIFT mapped independently
|
|
||||||
// VK_LCONTROL is mapped but not VK_RCONTROL
|
|
||||||
// VK_LMENU is mapped but not VK_RMENU
|
|
||||||
//
|
|
||||||
// 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)
|
|
||||||
switch ((*virtualKey) & 0xffu) {
|
|
||||||
case VK_LSHIFT:
|
case VK_LSHIFT:
|
||||||
case VK_RSHIFT:
|
case VK_RSHIFT:
|
||||||
*virtualKey = VK_SHIFT;
|
case VK_SHIFT:
|
||||||
return MapVirtualKeyEx(VK_SHIFT, 0, m_keyLayout);
|
|
||||||
|
|
||||||
case VK_LCONTROL:
|
case VK_LCONTROL:
|
||||||
case VK_RCONTROL:
|
case VK_RCONTROL:
|
||||||
*virtualKey = VK_CONTROL;
|
case VK_CONTROL:
|
||||||
return MapVirtualKeyEx(VK_CONTROL, 0, m_keyLayout);
|
|
||||||
|
|
||||||
case VK_LMENU:
|
case VK_LMENU:
|
||||||
case VK_RMENU:
|
case VK_RMENU:
|
||||||
*virtualKey = VK_MENU;
|
case VK_MENU:
|
||||||
return MapVirtualKeyEx(VK_MENU, 0, m_keyLayout);
|
case VK_CAPITAL:
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CMSWindowsKeyMapper::isExtendedKey(KeyButton virtualKey) const
|
|
||||||
{
|
|
||||||
// see if we've already encoded the extended flag
|
|
||||||
if ((virtualKey & 0x100u) != 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check known virtual keys
|
|
||||||
switch (virtualKey & 0xffu) {
|
|
||||||
case VK_NUMLOCK:
|
case VK_NUMLOCK:
|
||||||
case VK_RCONTROL:
|
case VK_SCROLL:
|
||||||
case VK_RMENU:
|
|
||||||
case VK_LWIN:
|
case VK_LWIN:
|
||||||
case VK_RWIN:
|
case VK_RWIN:
|
||||||
case VK_APPS:
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1269,10 +1164,134 @@ CMSWindowsKeyMapper::isExtendedKey(KeyButton virtualKey) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CMSWindowsKeyMapper::isPressed(UINT virtKey) const
|
||||||
|
{
|
||||||
|
switch (virtKey) {
|
||||||
|
case VK_SHIFT:
|
||||||
|
return ((m_keys[m_virtKeyToScanCode[VK_LSHIFT]] & 0x80) != 0 ||
|
||||||
|
(m_keys[m_virtKeyToScanCode[VK_RSHIFT]] & 0x80) != 0);
|
||||||
|
|
||||||
|
case VK_CONTROL:
|
||||||
|
return ((m_keys[m_virtKeyToScanCode[VK_LCONTROL]] & 0x80) != 0 ||
|
||||||
|
(m_keys[m_virtKeyToScanCode[VK_RCONTROL]] & 0x80) != 0);
|
||||||
|
|
||||||
|
case VK_MENU:
|
||||||
|
return ((m_keys[m_virtKeyToScanCode[VK_LMENU]] & 0x80) != 0 ||
|
||||||
|
(m_keys[m_virtKeyToScanCode[VK_RMENU]] & 0x80) != 0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ((m_keys[m_virtKeyToScanCode[virtKey & 0xffu]] & 0x80) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CMSWindowsKeyMapper::isToggled(UINT virtKey) const
|
||||||
|
{
|
||||||
|
return ((m_keys[m_virtKeyToScanCode[virtKey & 0xffu]] & 0x01) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT
|
||||||
|
CMSWindowsKeyMapper::buttonToVirtualKey(KeyButton button) const
|
||||||
|
{
|
||||||
|
return m_scanCodeToVirtKey[button & 0x1ffu];
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyButton
|
||||||
|
CMSWindowsKeyMapper::virtualKeyToButton(UINT virtKey) const
|
||||||
|
{
|
||||||
|
return m_virtKeyToScanCode[virtKey & 0xffu];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CMSWindowsKeyMapper::isExtendedKey(KeyButton button) const
|
||||||
|
{
|
||||||
|
return ((button & 0x100u) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyModifierMask
|
||||||
|
CMSWindowsKeyMapper::getActiveModifiers() const
|
||||||
|
{
|
||||||
|
KeyModifierMask mask = 0;
|
||||||
|
if (GetKeyState(VK_SHIFT) < 0 ||
|
||||||
|
GetKeyState(VK_LSHIFT) < 0 ||
|
||||||
|
GetKeyState(VK_RSHIFT) < 0) {
|
||||||
|
mask |= KeyModifierShift;
|
||||||
|
}
|
||||||
|
if (GetKeyState(VK_CONTROL) < 0 ||
|
||||||
|
GetKeyState(VK_LCONTROL) < 0 ||
|
||||||
|
GetKeyState(VK_RCONTROL) < 0) {
|
||||||
|
mask |= KeyModifierControl;
|
||||||
|
}
|
||||||
|
if (GetKeyState(VK_MENU) < 0 ||
|
||||||
|
GetKeyState(VK_LMENU) < 0 ||
|
||||||
|
GetKeyState(VK_RMENU) < 0) {
|
||||||
|
mask |= KeyModifierAlt;
|
||||||
|
}
|
||||||
|
if (GetKeyState(VK_LWIN) < 0 ||
|
||||||
|
GetKeyState(VK_RWIN) < 0) {
|
||||||
|
mask |= KeyModifierSuper;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyModifierMask
|
||||||
|
CMSWindowsKeyMapper::getShadowModifiers(bool needAltGr) const
|
||||||
|
{
|
||||||
|
KeyModifierMask mask = 0;
|
||||||
|
if (isPressed(VK_SHIFT)) {
|
||||||
|
mask |= KeyModifierShift;
|
||||||
|
}
|
||||||
|
if (needAltGr) {
|
||||||
|
mask |= KeyModifierModeSwitch;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isPressed(VK_CONTROL)) {
|
||||||
|
mask |= KeyModifierControl;
|
||||||
|
}
|
||||||
|
if (isPressed(VK_MENU)) {
|
||||||
|
mask |= KeyModifierAlt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isPressed(VK_LWIN) || isPressed(VK_RWIN)) {
|
||||||
|
mask |= KeyModifierSuper;
|
||||||
|
}
|
||||||
|
if (isToggled(VK_CAPITAL)) {
|
||||||
|
mask |= KeyModifierCapsLock;
|
||||||
|
}
|
||||||
|
if (isToggled(VK_NUMLOCK)) {
|
||||||
|
mask |= KeyModifierNumLock;
|
||||||
|
}
|
||||||
|
if (isToggled(VK_SCROLL)) {
|
||||||
|
mask |= KeyModifierScrollLock;
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
CMSWindowsKeyMapper::getKeyName(KeyButton key) const
|
CMSWindowsKeyMapper::getKeyName(KeyButton key) const
|
||||||
{
|
{
|
||||||
return s_vkToName[key & 0xffu];
|
char keyName[100];
|
||||||
|
CMSWindowsKeyMapper* self = const_cast<CMSWindowsKeyMapper*>(this);
|
||||||
|
if (GetKeyNameText((key & 0x01ffu) << 16, keyName, sizeof(keyName)) != 0) {
|
||||||
|
self->m_keyName = keyName;
|
||||||
|
}
|
||||||
|
else if (m_scanCodeToVirtKey[key] != 0) {
|
||||||
|
self->m_keyName = s_vkToName[m_scanCodeToVirtKey[key]];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self->m_keyName = CStringUtil::print("scan code 0x%03x", key & 0x01ffu);
|
||||||
|
}
|
||||||
|
return m_keyName.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT
|
UINT
|
||||||
|
@ -1310,7 +1329,7 @@ CMSWindowsKeyMapper::mapCharacter(IKeyState::Keystrokes& keys,
|
||||||
SHORT virtualKeyAndModifierState = VkKeyScanEx(c, hkl);
|
SHORT virtualKeyAndModifierState = VkKeyScanEx(c, hkl);
|
||||||
|
|
||||||
// get virtual key
|
// get virtual key
|
||||||
KeyButton virtualKey = LOBYTE(virtualKeyAndModifierState);
|
UINT virtualKey = LOBYTE(virtualKeyAndModifierState);
|
||||||
if (virtualKey == 0xffu) {
|
if (virtualKey == 0xffu) {
|
||||||
LOG((CLOG_DEBUG2 "cannot map character %d", static_cast<unsigned char>(c)));
|
LOG((CLOG_DEBUG2 "cannot map character %d", static_cast<unsigned char>(c)));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1370,16 +1389,15 @@ CMSWindowsKeyMapper::mapCharacter(IKeyState::Keystrokes& keys,
|
||||||
// now generate the keystrokes. ignore the resulting modifier
|
// now generate the keystrokes. ignore the resulting modifier
|
||||||
// mask since it can't have changed (because we don't call this
|
// mask since it can't have changed (because we don't call this
|
||||||
// method for modifier keys).
|
// method for modifier keys).
|
||||||
LOG((CLOG_DEBUG2 "character %d to virtual key %d mask 0x%08x", (unsigned char)c, virtualKey, desiredMask));
|
KeyButton scanCode = m_virtKeyToScanCode[virtualKey];
|
||||||
mapToKeystrokes(keys, keyState, virtualKey,
|
LOG((CLOG_DEBUG2 "character %d to virtual key %d scan code 0x%04x mask 0x%08x", (unsigned char)c, virtualKey, scanCode, desiredMask));
|
||||||
|
return mapToKeystrokes(keys, keyState, scanCode,
|
||||||
desiredMask, requiredMask, isAutoRepeat);
|
desiredMask, requiredMask, isAutoRepeat);
|
||||||
|
|
||||||
return virtualKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyButton
|
KeyButton
|
||||||
CMSWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys,
|
CMSWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys,
|
||||||
const IKeyState& keyState, KeyButton virtualKey,
|
const IKeyState& keyState, KeyButton button,
|
||||||
KeyModifierMask desiredMask, KeyModifierMask requiredMask,
|
KeyModifierMask desiredMask, KeyModifierMask requiredMask,
|
||||||
bool isAutoRepeat) const
|
bool isAutoRepeat) const
|
||||||
{
|
{
|
||||||
|
@ -1393,7 +1411,7 @@ CMSWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys,
|
||||||
|
|
||||||
// add the key event
|
// add the key event
|
||||||
IKeyState::Keystroke keystroke;
|
IKeyState::Keystroke keystroke;
|
||||||
keystroke.m_key = virtualKey;
|
keystroke.m_key = button;
|
||||||
keystroke.m_press = true;
|
keystroke.m_press = true;
|
||||||
keystroke.m_repeat = isAutoRepeat;
|
keystroke.m_repeat = isAutoRepeat;
|
||||||
keys.push_back(keystroke);
|
keys.push_back(keystroke);
|
||||||
|
@ -1404,7 +1422,7 @@ CMSWindowsKeyMapper::mapToKeystrokes(IKeyState::Keystrokes& keys,
|
||||||
undo.pop_back();
|
undo.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
return virtualKey;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1425,7 +1443,6 @@ CMSWindowsKeyMapper::adjustModifiers(IKeyState::Keystrokes& keys,
|
||||||
requiredMask ^= mask;
|
requiredMask ^= mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define CMSWINDOWSKEYMAPPER_H
|
#define CMSWINDOWSKEYMAPPER_H
|
||||||
|
|
||||||
#include "IKeyState.h"
|
#include "IKeyState.h"
|
||||||
|
#include "CString.h"
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ public:
|
||||||
/*!
|
/*!
|
||||||
Updates the shadow keyboard state.
|
Updates the shadow keyboard state.
|
||||||
*/
|
*/
|
||||||
void updateKey(KeyButton key, bool pressed);
|
void updateKey(LPARAM eventLParam);
|
||||||
|
|
||||||
//! Set the active keyboard layout
|
//! Set the active keyboard layout
|
||||||
/*!
|
/*!
|
||||||
|
@ -77,23 +78,41 @@ public:
|
||||||
KeyID mapKeyFromEvent(WPARAM charAndVirtKey, LPARAM info,
|
KeyID mapKeyFromEvent(WPARAM charAndVirtKey, LPARAM info,
|
||||||
KeyModifierMask* maskOut, bool* altgr) const;
|
KeyModifierMask* maskOut, bool* altgr) const;
|
||||||
|
|
||||||
|
//! Check if virtual key is a modifier
|
||||||
|
/*!
|
||||||
|
Returns true iff \p virtKey refers to a modifier key.
|
||||||
|
*/
|
||||||
|
bool isModifier(UINT virtKey) const;
|
||||||
|
|
||||||
//! Test shadow key state
|
//! Test shadow key state
|
||||||
/*!
|
/*!
|
||||||
Returns true iff the shadow state indicates the key is pressed.
|
Returns true iff the shadow state indicates the key is pressed.
|
||||||
*/
|
*/
|
||||||
bool isPressed(KeyButton key) const;
|
bool isPressed(UINT virtKey) const;
|
||||||
|
|
||||||
//! Map key to a scan code
|
//! Map button to a virtual key
|
||||||
/*!
|
/*!
|
||||||
Returns the scan code for \c key and possibly adjusts \c key.
|
Returns the virtual key for \c button.
|
||||||
*/
|
*/
|
||||||
UINT keyToScanCode(KeyButton* key) const;
|
UINT buttonToVirtualKey(KeyButton button) const;
|
||||||
|
|
||||||
|
//! Map virtual key to a button
|
||||||
|
/*!
|
||||||
|
Returns the button for virtual key \c virtKey.
|
||||||
|
*/
|
||||||
|
KeyButton virtualKeyToButton(UINT virtKey) const;
|
||||||
|
|
||||||
//! Check for extended key
|
//! Check for extended key
|
||||||
/*!
|
/*!
|
||||||
Returns true iff \c key is an extended key
|
Returns true iff \c key is an extended key
|
||||||
*/
|
*/
|
||||||
bool isExtendedKey(KeyButton key) const;
|
bool isExtendedKey(KeyButton button) const;
|
||||||
|
|
||||||
|
//! Get current modifier key state
|
||||||
|
/*!
|
||||||
|
Returns the current modifier key state.
|
||||||
|
*/
|
||||||
|
KeyModifierMask getActiveModifiers() const;
|
||||||
|
|
||||||
//! Get name of key
|
//! Get name of key
|
||||||
/*!
|
/*!
|
||||||
|
@ -116,7 +135,7 @@ private:
|
||||||
// map \c virtualKey to the keystrokes to generate it, along with
|
// map \c virtualKey to the keystrokes to generate it, along with
|
||||||
// keystrokes to update and restore the modifier state.
|
// keystrokes to update and restore the modifier state.
|
||||||
KeyButton mapToKeystrokes(IKeyState::Keystrokes& keys,
|
KeyButton mapToKeystrokes(IKeyState::Keystrokes& keys,
|
||||||
const IKeyState& keyState, KeyButton virtualKey,
|
const IKeyState& keyState, KeyButton button,
|
||||||
KeyModifierMask desiredMask,
|
KeyModifierMask desiredMask,
|
||||||
KeyModifierMask requiredMask,
|
KeyModifierMask requiredMask,
|
||||||
bool isAutoRepeat) const;
|
bool isAutoRepeat) const;
|
||||||
|
@ -128,6 +147,18 @@ private:
|
||||||
KeyModifierMask desiredMask,
|
KeyModifierMask desiredMask,
|
||||||
KeyModifierMask requiredMask) const;
|
KeyModifierMask requiredMask) const;
|
||||||
|
|
||||||
|
//! Test shadow key toggle state
|
||||||
|
/*!
|
||||||
|
Returns true iff the shadow state indicates the key is toggled on.
|
||||||
|
*/
|
||||||
|
bool isToggled(UINT virtKey) const;
|
||||||
|
|
||||||
|
//! Get shadow modifier key state
|
||||||
|
/*!
|
||||||
|
Returns the shadow modifier key state.
|
||||||
|
*/
|
||||||
|
KeyModifierMask getShadowModifiers(bool needAltGr) const;
|
||||||
|
|
||||||
// pass character to ToAsciiEx(), returning what it returns
|
// pass character to ToAsciiEx(), returning what it returns
|
||||||
int toAscii(TCHAR c, HKL hkl, bool menu, WORD* chars) const;
|
int toAscii(TCHAR c, HKL hkl, bool menu, WORD* chars) const;
|
||||||
|
|
||||||
|
@ -142,16 +173,24 @@ private:
|
||||||
KeyButton m_keys[s_maxKeys];
|
KeyButton m_keys[s_maxKeys];
|
||||||
};
|
};
|
||||||
|
|
||||||
BYTE m_keys[256];
|
// map of key state for each scan code. this would be 8 bits
|
||||||
|
// except windows reuses some scan codes for "extended" keys
|
||||||
|
// we actually need 9 bits. an example is the left and right
|
||||||
|
// alt keys; they share the same scan code but the right key
|
||||||
|
// is "extended".
|
||||||
|
BYTE m_keys[512];
|
||||||
|
UINT m_scanCodeToVirtKey[512];
|
||||||
|
KeyButton m_virtKeyToScanCode[256];
|
||||||
mutable TCHAR m_deadKey;
|
mutable TCHAR m_deadKey;
|
||||||
HKL m_keyLayout;
|
HKL m_keyLayout;
|
||||||
|
CString m_keyName;
|
||||||
|
|
||||||
static const CModifierKeys s_modifiers[];
|
static const CModifierKeys s_modifiers[];
|
||||||
static const char* s_vkToName[];
|
static const char* s_vkToName[];
|
||||||
static const KeyID s_virtualKey[][2];
|
static const KeyID s_virtualKey[][2];
|
||||||
static const KeyButton s_mapE000[];
|
static const UINT s_mapE000[];
|
||||||
static const KeyButton s_mapEE00[];
|
static const UINT s_mapEE00[];
|
||||||
static const KeyButton s_mapEF00[];
|
static const UINT s_mapEF00[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -84,28 +84,6 @@
|
||||||
#define XBUTTON2 0x0002
|
#define XBUTTON2 0x0002
|
||||||
#endif
|
#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
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CMSWindowsScreen
|
// CMSWindowsScreen
|
||||||
//
|
//
|
||||||
|
@ -231,8 +209,7 @@ void
|
||||||
CMSWindowsScreen::setKeyState(IKeyState* keyState)
|
CMSWindowsScreen::setKeyState(IKeyState* keyState)
|
||||||
{
|
{
|
||||||
m_keyState = keyState;
|
m_keyState = keyState;
|
||||||
m_keyMapper.update(m_keyState);
|
updateKeys();
|
||||||
memset(m_buttons, 0, sizeof(m_buttons));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -336,6 +313,7 @@ CMSWindowsScreen::leave()
|
||||||
|
|
||||||
// tell the key mapper about the keyboard layout
|
// tell the key mapper about the keyboard layout
|
||||||
m_keyMapper.setKeyLayout(m_keyLayout);
|
m_keyMapper.setKeyLayout(m_keyLayout);
|
||||||
|
sendDeskMessage(SYNERGY_MSG_SYNC_KEYS, 0, 0);
|
||||||
|
|
||||||
// tell desk that we're leaving and tell it the keyboard layout
|
// tell desk that we're leaving and tell it the keyboard layout
|
||||||
sendDeskMessage(SYNERGY_MSG_LEAVE, (WPARAM)m_keyLayout, 0);
|
sendDeskMessage(SYNERGY_MSG_LEAVE, (WPARAM)m_keyLayout, 0);
|
||||||
|
@ -464,6 +442,7 @@ CMSWindowsScreen::updateKeys()
|
||||||
{
|
{
|
||||||
sendDeskMessage(SYNERGY_MSG_SYNC_KEYS, 0, 0);
|
sendDeskMessage(SYNERGY_MSG_SYNC_KEYS, 0, 0);
|
||||||
memset(m_buttons, 0, sizeof(m_buttons));
|
memset(m_buttons, 0, sizeof(m_buttons));
|
||||||
|
// FIXME -- get the button state
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -568,6 +547,12 @@ CMSWindowsScreen::isAnyMouseButtonDown() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyModifierMask
|
||||||
|
CMSWindowsScreen::getActiveModifiers() const
|
||||||
|
{
|
||||||
|
return m_keyMapper.getActiveModifiers();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CMSWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
|
CMSWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const
|
||||||
{
|
{
|
||||||
|
@ -582,19 +567,19 @@ CMSWindowsScreen::getKeyName(KeyButton virtualKey) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CMSWindowsScreen::fakeKeyEvent(KeyButton virtualKey, bool press) const
|
CMSWindowsScreen::fakeKeyEvent(KeyButton id, bool press) const
|
||||||
{
|
{
|
||||||
DWORD flags = 0;
|
DWORD flags = 0;
|
||||||
if (m_keyMapper.isExtendedKey(virtualKey)) {
|
if (m_keyMapper.isExtendedKey(id)) {
|
||||||
flags |= KEYEVENTF_EXTENDEDKEY;
|
flags |= KEYEVENTF_EXTENDEDKEY;
|
||||||
}
|
}
|
||||||
if (!press) {
|
if (!press) {
|
||||||
flags |= KEYEVENTF_KEYUP;
|
flags |= KEYEVENTF_KEYUP;
|
||||||
}
|
}
|
||||||
UINT code = m_keyMapper.keyToScanCode(&virtualKey);
|
UINT vk = m_keyMapper.buttonToVirtualKey(id);
|
||||||
sendDeskMessage(SYNERGY_MSG_FAKE_KEY, flags,
|
sendDeskMessage(SYNERGY_MSG_FAKE_KEY, flags,
|
||||||
MAKEWORD(static_cast<BYTE>(code),
|
MAKEWORD(static_cast<BYTE>(id & 0xffu),
|
||||||
static_cast<BYTE>(virtualKey & 0xffu)));
|
static_cast<BYTE>(vk & 0xffu)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -870,9 +855,8 @@ CMSWindowsScreen::onPreDispatchPrimary(HWND,
|
||||||
// if the user presses and releases a windows key without pressing
|
// if the user presses and releases a windows key without pressing
|
||||||
// any other key while it's down then windows will eat the key
|
// any other key while it's down then windows will eat the key
|
||||||
// release. if we don't detect that and synthesize the release
|
// release. if we don't detect that and synthesize the release
|
||||||
// then the user will be locked to the screen and the client won't
|
// then the cclient won't take the usual windows key release action
|
||||||
// take the usual windows key release action (which on windows is
|
// (which on windows is to show the start menu).
|
||||||
// to show the start menu).
|
|
||||||
//
|
//
|
||||||
// we can use GetKeyState() to check the state of the windows keys
|
// we can use GetKeyState() to check the state of the windows keys
|
||||||
// because, event though the key release is not reported to us,
|
// because, event though the key release is not reported to us,
|
||||||
|
@ -881,42 +865,12 @@ CMSWindowsScreen::onPreDispatchPrimary(HWND,
|
||||||
// state on every event. only check on windows 95 family since
|
// state on every event. only check on windows 95 family since
|
||||||
// NT family reports the key release as usual. obviously we skip
|
// NT family reports the key release as usual. obviously we skip
|
||||||
// this if the event is for the windows key itself.
|
// this if the event is for the windows key itself.
|
||||||
if (m_is95Family) {
|
if (m_is95Family && message != SYNERGY_MSG_KEY) {
|
||||||
if (m_keyMapper.isPressed(VK_LWIN) &&
|
if (wParam != VK_LWIN) {
|
||||||
(GetAsyncKeyState(VK_LWIN) & 0x8000) == 0 &&
|
fixKey(VK_LWIN);
|
||||||
!(message == SYNERGY_MSG_KEY && wParam == VK_LWIN)) {
|
|
||||||
// compute appropriate parameters for fake event
|
|
||||||
WPARAM wParam = VK_LWIN;
|
|
||||||
LPARAM lParam = 0xc1000000;
|
|
||||||
lParam |= (0x00ff0000 & (MapVirtualKey(wParam, 0) << 24));
|
|
||||||
|
|
||||||
// process as if it were a key up
|
|
||||||
KeyModifierMask mask;
|
|
||||||
KeyButton button = static_cast<KeyButton>(
|
|
||||||
(lParam & 0x00ff0000u) >> 16);
|
|
||||||
KeyID key = m_keyMapper.mapKeyFromEvent(wParam,
|
|
||||||
lParam, &mask, NULL);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
|
||||||
sendEvent(getKeyUpEvent(), CKeyInfo::alloc(key, mask, button, 1));
|
|
||||||
m_keyMapper.updateKey(static_cast<KeyButton>(wParam), false);
|
|
||||||
}
|
}
|
||||||
if (m_keyMapper.isPressed(VK_RWIN) &&
|
if (wParam != VK_RWIN) {
|
||||||
(GetAsyncKeyState(VK_RWIN) & 0x8000) == 0 &&
|
fixKey(VK_RWIN);
|
||||||
!(message == SYNERGY_MSG_KEY && wParam == VK_RWIN)) {
|
|
||||||
// compute appropriate parameters for fake event
|
|
||||||
WPARAM wParam = VK_RWIN;
|
|
||||||
LPARAM lParam = 0xc1000000;
|
|
||||||
lParam |= (0x00ff0000 & (MapVirtualKey(wParam, 0) << 24));
|
|
||||||
|
|
||||||
// process as if it were a key up
|
|
||||||
KeyModifierMask mask;
|
|
||||||
KeyButton button = static_cast<KeyButton>(
|
|
||||||
(lParam & 0x00ff0000u) >> 16);
|
|
||||||
KeyID key = m_keyMapper.mapKeyFromEvent(wParam,
|
|
||||||
lParam, &mask, NULL);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
|
||||||
sendEvent(getKeyUpEvent(), CKeyInfo::alloc(key, mask, button, 1));
|
|
||||||
m_keyMapper.updateKey(static_cast<KeyButton>(wParam), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1047,6 +1001,16 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
WPARAM charAndVirtKey = wParam;
|
WPARAM charAndVirtKey = wParam;
|
||||||
wParam &= 0xffu;
|
wParam &= 0xffu;
|
||||||
|
|
||||||
|
// update key state. ignore key repeats.
|
||||||
|
if ((lParam & 0xc0000000u) == 0x00000000) {
|
||||||
|
KeyButton scancode = (KeyButton)((lParam & 0x01ff0000) >> 16);
|
||||||
|
m_keyState->setKeyDown(scancode, true);
|
||||||
|
}
|
||||||
|
else if ((lParam & 0xc0000000u) == 0xc0000000) {
|
||||||
|
KeyButton scancode = (KeyButton)((lParam & 0x01ff0000) >> 16);
|
||||||
|
m_keyState->setKeyDown(scancode, 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
|
||||||
|
@ -1054,9 +1018,11 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
(m_keyMapper.isPressed(VK_CONTROL) &&
|
(m_keyMapper.isPressed(VK_CONTROL) &&
|
||||||
m_keyMapper.isPressed(VK_MENU))) {
|
m_keyMapper.isPressed(VK_MENU))) {
|
||||||
LOG((CLOG_DEBUG "emulate ctrl+alt+del"));
|
LOG((CLOG_DEBUG "emulate ctrl+alt+del"));
|
||||||
wParam = VK_DELETE;
|
wParam = VK_DELETE;
|
||||||
lParam &= 0xffff0000;
|
lParam &= 0xfffe0000;
|
||||||
lParam |= 0x00000001;
|
lParam |= m_keyMapper.virtualKeyToButton(wParam) << 16;
|
||||||
|
lParam |= 0x00000001;
|
||||||
|
charAndVirtKey = wParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
// process key normally
|
// process key normally
|
||||||
|
@ -1065,7 +1031,7 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
const KeyID key = m_keyMapper.mapKeyFromEvent(
|
const KeyID key = m_keyMapper.mapKeyFromEvent(
|
||||||
charAndVirtKey, lParam, &mask, &altgr);
|
charAndVirtKey, lParam, &mask, &altgr);
|
||||||
KeyButton button = static_cast<KeyButton>(
|
KeyButton button = static_cast<KeyButton>(
|
||||||
(lParam & 0x00ff0000u) >> 16);
|
(lParam & 0x01ff0000u) >> 16);
|
||||||
if (key != kKeyNone && key != kKeyMultiKey) {
|
if (key != kKeyNone && key != kKeyMultiKey) {
|
||||||
if ((lParam & 0x80000000) == 0) {
|
if ((lParam & 0x80000000) == 0) {
|
||||||
// key press
|
// key press
|
||||||
|
@ -1085,43 +1051,34 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
if (altgr) {
|
if (altgr) {
|
||||||
KeyID key;
|
KeyID key;
|
||||||
KeyButton button;
|
KeyButton button;
|
||||||
UINT scanCode;
|
|
||||||
KeyModifierMask mask2 = (mask &
|
KeyModifierMask mask2 = (mask &
|
||||||
~(KeyModifierControl |
|
~(KeyModifierControl |
|
||||||
KeyModifierAlt |
|
KeyModifierAlt |
|
||||||
KeyModifierModeSwitch));
|
KeyModifierModeSwitch));
|
||||||
if (ctrlL) {
|
if (ctrlL) {
|
||||||
key = kKeyControl_L;
|
key = kKeyControl_L;
|
||||||
button = VK_LCONTROL;
|
button = m_keyMapper.virtualKeyToButton(VK_LCONTROL);
|
||||||
scanCode = m_keyMapper.keyToScanCode(&button);
|
|
||||||
button = static_cast<KeyButton>(scanCode);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
||||||
sendEvent(getKeyUpEvent(),
|
sendEvent(getKeyUpEvent(),
|
||||||
CKeyInfo::alloc(key, mask2, button, 1));
|
CKeyInfo::alloc(key, mask2, button, 1));
|
||||||
}
|
}
|
||||||
if (ctrlR) {
|
if (ctrlR) {
|
||||||
key = kKeyControl_R;
|
key = kKeyControl_R;
|
||||||
button = VK_RCONTROL;
|
button = m_keyMapper.virtualKeyToButton(VK_RCONTROL);
|
||||||
scanCode = m_keyMapper.keyToScanCode(&button);
|
|
||||||
button = static_cast<KeyButton>(scanCode);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
||||||
sendEvent(getKeyUpEvent(),
|
sendEvent(getKeyUpEvent(),
|
||||||
CKeyInfo::alloc(key, mask2, button, 1));
|
CKeyInfo::alloc(key, mask2, button, 1));
|
||||||
}
|
}
|
||||||
if (altL) {
|
if (altL) {
|
||||||
key = kKeyAlt_L;
|
key = kKeyAlt_L;
|
||||||
button = VK_LMENU;
|
button = m_keyMapper.virtualKeyToButton(VK_LMENU);
|
||||||
scanCode = m_keyMapper.keyToScanCode(&button);
|
|
||||||
button = static_cast<KeyButton>(scanCode);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
||||||
sendEvent(getKeyUpEvent(),
|
sendEvent(getKeyUpEvent(),
|
||||||
CKeyInfo::alloc(key, mask2, button, 1));
|
CKeyInfo::alloc(key, mask2, button, 1));
|
||||||
}
|
}
|
||||||
if (altR) {
|
if (altR) {
|
||||||
key = kKeyAlt_R;
|
key = kKeyAlt_R;
|
||||||
button = VK_RMENU;
|
button = m_keyMapper.virtualKeyToButton(VK_RMENU);
|
||||||
scanCode = m_keyMapper.keyToScanCode(&button);
|
|
||||||
button = static_cast<KeyButton>(scanCode);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
||||||
sendEvent(getKeyUpEvent(),
|
sendEvent(getKeyUpEvent(),
|
||||||
CKeyInfo::alloc(key, mask2, button, 1));
|
CKeyInfo::alloc(key, mask2, button, 1));
|
||||||
|
@ -1149,16 +1106,13 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
if (altgr) {
|
if (altgr) {
|
||||||
KeyID key;
|
KeyID key;
|
||||||
KeyButton button;
|
KeyButton button;
|
||||||
UINT scanCode;
|
|
||||||
KeyModifierMask mask2 = (mask &
|
KeyModifierMask mask2 = (mask &
|
||||||
~(KeyModifierControl |
|
~(KeyModifierControl |
|
||||||
KeyModifierAlt |
|
KeyModifierAlt |
|
||||||
KeyModifierModeSwitch));
|
KeyModifierModeSwitch));
|
||||||
if (ctrlL) {
|
if (ctrlL) {
|
||||||
key = kKeyControl_L;
|
key = kKeyControl_L;
|
||||||
button = VK_LCONTROL;
|
button = m_keyMapper.virtualKeyToButton(VK_LCONTROL);
|
||||||
scanCode = m_keyMapper.keyToScanCode(&button);
|
|
||||||
button = static_cast<KeyButton>(scanCode);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
||||||
sendEvent(getKeyDownEvent(),
|
sendEvent(getKeyDownEvent(),
|
||||||
CKeyInfo::alloc(key, mask2, button, 1));
|
CKeyInfo::alloc(key, mask2, button, 1));
|
||||||
|
@ -1166,9 +1120,7 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
if (ctrlR) {
|
if (ctrlR) {
|
||||||
key = kKeyControl_R;
|
key = kKeyControl_R;
|
||||||
button = VK_RCONTROL;
|
button = m_keyMapper.virtualKeyToButton(VK_RCONTROL);
|
||||||
scanCode = m_keyMapper.keyToScanCode(&button);
|
|
||||||
button = static_cast<KeyButton>(scanCode);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
||||||
sendEvent(getKeyDownEvent(),
|
sendEvent(getKeyDownEvent(),
|
||||||
CKeyInfo::alloc(key, mask2, button, 1));
|
CKeyInfo::alloc(key, mask2, button, 1));
|
||||||
|
@ -1176,9 +1128,7 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
if (altL) {
|
if (altL) {
|
||||||
key = kKeyAlt_L;
|
key = kKeyAlt_L;
|
||||||
button = VK_LMENU;
|
button = m_keyMapper.virtualKeyToButton(VK_LMENU);
|
||||||
scanCode = m_keyMapper.keyToScanCode(&button);
|
|
||||||
button = static_cast<KeyButton>(scanCode);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
||||||
sendEvent(getKeyDownEvent(),
|
sendEvent(getKeyDownEvent(),
|
||||||
CKeyInfo::alloc(key, mask2, button, 1));
|
CKeyInfo::alloc(key, mask2, button, 1));
|
||||||
|
@ -1186,9 +1136,7 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
if (altR) {
|
if (altR) {
|
||||||
key = kKeyAlt_R;
|
key = kKeyAlt_R;
|
||||||
button = VK_RMENU;
|
button = m_keyMapper.virtualKeyToButton(VK_RMENU);
|
||||||
scanCode = m_keyMapper.keyToScanCode(&button);
|
|
||||||
button = static_cast<KeyButton>(scanCode);
|
|
||||||
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask2, button));
|
||||||
sendEvent(getKeyDownEvent(),
|
sendEvent(getKeyDownEvent(),
|
||||||
CKeyInfo::alloc(key, mask2, button, 1));
|
CKeyInfo::alloc(key, mask2, button, 1));
|
||||||
|
@ -1203,12 +1151,13 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
// synthesize the press first. only do this on
|
// synthesize the press first. only do this on
|
||||||
// the windows 95 family, which eats certain special
|
// the windows 95 family, which eats certain special
|
||||||
// keys like alt+tab, ctrl+esc, etc.
|
// keys like alt+tab, ctrl+esc, etc.
|
||||||
if (m_is95Family && !isModifier(wParam) &&
|
if (m_is95Family &&
|
||||||
m_keyMapper.isPressed(static_cast<KeyButton>(wParam))) {
|
!m_keyMapper.isModifier(wParam) &&
|
||||||
|
m_keyMapper.isPressed(wParam)) {
|
||||||
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
LOG((CLOG_DEBUG1 "event: fake key press key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
||||||
sendEvent(getKeyDownEvent(),
|
sendEvent(getKeyDownEvent(),
|
||||||
CKeyInfo::alloc(key, mask, button, 1));
|
CKeyInfo::alloc(key, mask, button, 1));
|
||||||
m_keyMapper.updateKey(static_cast<KeyButton>(wParam), true);
|
m_keyMapper.updateKey(lParam & 0x3fffffffu);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do key up
|
// do key up
|
||||||
|
@ -1223,8 +1172,7 @@ CMSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep our shadow key state up to date
|
// keep our shadow key state up to date
|
||||||
m_keyMapper.updateKey(static_cast<KeyButton>(wParam),
|
m_keyMapper.updateKey(lParam);
|
||||||
((lParam & 0x80000000) == 0));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1520,6 +1468,25 @@ CMSWindowsScreen::enableSpecialKeys(bool enable) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsScreen::fixKey(UINT virtualKey)
|
||||||
|
{
|
||||||
|
if (m_keyMapper.isPressed(virtualKey) &&
|
||||||
|
(GetAsyncKeyState(virtualKey) & 0x8000) == 0) {
|
||||||
|
// compute appropriate parameters for fake event
|
||||||
|
KeyButton button = m_keyMapper.virtualKeyToButton(virtualKey);
|
||||||
|
LPARAM lParam = 0xc0000000 | ((LPARAM)button << 16);
|
||||||
|
|
||||||
|
// process as if it were a key up
|
||||||
|
KeyModifierMask mask;
|
||||||
|
KeyID key = m_keyMapper.mapKeyFromEvent(virtualKey,
|
||||||
|
lParam, &mask, NULL);
|
||||||
|
LOG((CLOG_DEBUG1 "event: fake key release key=%d mask=0x%04x button=0x%04x", key, mask, button));
|
||||||
|
sendEvent(getKeyUpEvent(), CKeyInfo::alloc(key, mask, button, 1));
|
||||||
|
m_keyMapper.updateKey(lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DWORD
|
DWORD
|
||||||
CMSWindowsScreen::mapButtonToEvent(ButtonID button,
|
CMSWindowsScreen::mapButtonToEvent(ButtonID button,
|
||||||
bool press, DWORD* inData) const
|
bool press, DWORD* inData) const
|
||||||
|
@ -1616,31 +1583,6 @@ CMSWindowsScreen::mapButtonFromEvent(WPARAM msg, LPARAM button) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
CMSWindowsScreen::isModifier(UINT vkCode) const
|
|
||||||
{
|
|
||||||
switch (vkCode) {
|
|
||||||
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:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CMSWindowsScreen::ctrlAltDelThread(void*)
|
CMSWindowsScreen::ctrlAltDelThread(void*)
|
||||||
{
|
{
|
||||||
|
|
|
@ -86,6 +86,7 @@ public:
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
virtual bool isAnyMouseButtonDown() const;
|
virtual bool isAnyMouseButtonDown() const;
|
||||||
|
virtual KeyModifierMask getActiveModifiers() const;
|
||||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||||
virtual const char* getKeyName(KeyButton) const;
|
virtual const char* getKeyName(KeyButton) const;
|
||||||
|
|
||||||
|
@ -168,6 +169,10 @@ private:
|
||||||
// enable/disable special key combinations so we can catch/pass them
|
// enable/disable special key combinations so we can catch/pass them
|
||||||
void enableSpecialKeys(bool) const;
|
void enableSpecialKeys(bool) const;
|
||||||
|
|
||||||
|
// send fake key up if shadow state says virtualKey is down but
|
||||||
|
// system says it isn't.
|
||||||
|
void fixKey(UINT virtualKey);
|
||||||
|
|
||||||
// map a button ID and action to a mouse event
|
// map a button ID and action to a mouse event
|
||||||
DWORD mapButtonToEvent(ButtonID button,
|
DWORD mapButtonToEvent(ButtonID button,
|
||||||
bool press, DWORD* inData) const;
|
bool press, DWORD* inData) const;
|
||||||
|
|
|
@ -235,14 +235,14 @@ CScreen::keyRepeat(KeyID id,
|
||||||
// dead key. for example, a dead accent followed by 'a' will
|
// dead key. for example, a dead accent followed by 'a' will
|
||||||
// generate an 'a with accent' followed by a repeating 'a'. the
|
// generate an 'a with accent' followed by a repeating 'a'. the
|
||||||
// keycodes for the two keysyms might be different.
|
// keycodes for the two keysyms might be different.
|
||||||
key &= 0xffu;
|
key &= 0x1ffu;
|
||||||
if (key != index->second) {
|
if (key != index->second) {
|
||||||
// replace key up with previous key id but leave key down
|
// replace key up with previous key id but leave key down
|
||||||
// alone so it uses the new keycode and store that keycode
|
// alone so it uses the new keycode and store that keycode
|
||||||
// in the server key map.
|
// in the server key map.
|
||||||
for (Keystrokes::iterator index2 = keys.begin();
|
for (Keystrokes::iterator index2 = keys.begin();
|
||||||
index2 != keys.end(); ++index2) {
|
index2 != keys.end(); ++index2) {
|
||||||
if ((index2->m_key & 0xffu) == key) {
|
if ((index2->m_key & 0x1ffu) == key) {
|
||||||
index2->m_key = index->second;
|
index2->m_key = index->second;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -477,11 +477,10 @@ CScreen::updateKeys()
|
||||||
void
|
void
|
||||||
CScreen::releaseKeys()
|
CScreen::releaseKeys()
|
||||||
{
|
{
|
||||||
LOG((CLOG_INFO "releaseKeys")); // FIXME
|
|
||||||
// release keys that we've synthesized a press for and only those
|
// release keys that we've synthesized a press for and only those
|
||||||
// keys. we don't want to synthesize a release on a key the user
|
// keys. we don't want to synthesize a release on a key the user
|
||||||
// is still physically pressing.
|
// is still physically pressing.
|
||||||
for (KeyButton i = 1; i < 256; ++i) {
|
for (KeyButton i = 1; i < sizeof(m_keys) / sizeof(m_keys[0]); ++i) {
|
||||||
if ((m_fakeKeys[i] & kDown) != 0) {
|
if ((m_fakeKeys[i] & kDown) != 0) {
|
||||||
fakeKeyEvent(i, false, false);
|
fakeKeyEvent(i, false, false);
|
||||||
m_keys[i] &= ~kDown;
|
m_keys[i] &= ~kDown;
|
||||||
|
@ -495,10 +494,10 @@ CScreen::setKeyDown(KeyButton key, bool down)
|
||||||
{
|
{
|
||||||
if (!isHalfDuplex(getMaskForKey(key))) {
|
if (!isHalfDuplex(getMaskForKey(key))) {
|
||||||
if (down) {
|
if (down) {
|
||||||
m_keys[key & 0xffu] |= kDown;
|
m_keys[key & 0x1ffu] |= kDown;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_keys[key & 0xffu] &= ~kDown;
|
m_keys[key & 0x1ffu] &= ~kDown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,7 +514,7 @@ CScreen::setToggled(KeyModifierMask mask)
|
||||||
}
|
}
|
||||||
for (KeyButtons::const_iterator j = i->second.begin();
|
for (KeyButtons::const_iterator j = i->second.begin();
|
||||||
j != i->second.end(); ++j) {
|
j != i->second.end(); ++j) {
|
||||||
m_keys[(*j) & 0xffu] |= kToggled;
|
m_keys[(*j) & 0x1ffu] |= kToggled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,8 +535,9 @@ CScreen::addModifier(KeyModifierMask mask, KeyButtons& keys)
|
||||||
// index mask by keycodes
|
// index mask by keycodes
|
||||||
for (KeyButtons::iterator j = keys.begin(); j != keys.end(); ++j) {
|
for (KeyButtons::iterator j = keys.begin(); j != keys.end(); ++j) {
|
||||||
// key must be valid
|
// key must be valid
|
||||||
assert(((*j) & 0xffu) != 0);
|
if (((*j) & 0x1ffu) != 0) {
|
||||||
m_keyToMask[static_cast<KeyButton>((*j) & 0xffu)] = mask;
|
m_keyToMask[static_cast<KeyButton>((*j) & 0x1ffu)] = mask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// index keys by mask
|
// index keys by mask
|
||||||
|
@ -563,7 +563,7 @@ CScreen::setToggleState(KeyModifierMask mask)
|
||||||
KeyButton
|
KeyButton
|
||||||
CScreen::isAnyKeyDown() const
|
CScreen::isAnyKeyDown() const
|
||||||
{
|
{
|
||||||
for (UInt32 i = 1; i < 256; ++i) {
|
for (UInt32 i = 1; i < sizeof(m_keys) / sizeof(m_keys[0]); ++i) {
|
||||||
if ((m_keys[i] & kDown) != 0) {
|
if ((m_keys[i] & kDown) != 0) {
|
||||||
return static_cast<KeyButton>(i);
|
return static_cast<KeyButton>(i);
|
||||||
}
|
}
|
||||||
|
@ -574,7 +574,7 @@ CScreen::isAnyKeyDown() const
|
||||||
bool
|
bool
|
||||||
CScreen::isKeyDown(KeyButton key) const
|
CScreen::isKeyDown(KeyButton key) const
|
||||||
{
|
{
|
||||||
key &= 0xffu;
|
key &= 0x1ffu;
|
||||||
return (key != 0 && ((m_keys[key] & kDown) != 0));
|
return (key != 0 && ((m_keys[key] & kDown) != 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -867,7 +867,7 @@ void
|
||||||
CScreen::updateKeyState(KeyButton button, KeyButton key, bool press)
|
CScreen::updateKeyState(KeyButton button, KeyButton key, bool press)
|
||||||
{
|
{
|
||||||
// ignore bogus keys
|
// ignore bogus keys
|
||||||
key &= 0xffu;
|
key &= 0x1ffu;
|
||||||
if (button == 0 || key == 0) {
|
if (button == 0 || key == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -931,13 +931,13 @@ CScreen::toggleKey(KeyModifierMask mask)
|
||||||
|
|
||||||
// toggle shadow state
|
// toggle shadow state
|
||||||
m_mask ^= mask;
|
m_mask ^= mask;
|
||||||
key &= 0xffu;
|
key &= 0x1ffu;
|
||||||
m_keys[key] ^= kToggled;
|
m_keys[key] ^= kToggled;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CScreen::isKeyToggled(KeyButton key) const
|
CScreen::isKeyToggled(KeyButton key) const
|
||||||
{
|
{
|
||||||
key &= 0xffu;
|
key &= 0x1ffu;
|
||||||
return (key != 0 && ((m_keys[key] & kToggled) != 0));
|
return (key != 0 && ((m_keys[key] & kToggled) != 0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,10 +298,10 @@ private:
|
||||||
ServerKeyMap m_serverKeyMap;
|
ServerKeyMap m_serverKeyMap;
|
||||||
|
|
||||||
// system key states as set by us or the user
|
// system key states as set by us or the user
|
||||||
KeyState m_keys[256];
|
KeyState m_keys[512];
|
||||||
|
|
||||||
// system key states as set by us
|
// system key states as set by us
|
||||||
KeyState m_fakeKeys[256];
|
KeyState m_fakeKeys[512];
|
||||||
|
|
||||||
// modifier info
|
// modifier info
|
||||||
MaskToKeys m_maskToKeys;
|
MaskToKeys m_maskToKeys;
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
example, if buttons 5 and 23 were mapped to KeyModifierShift (perhaps
|
example, if buttons 5 and 23 were mapped to KeyModifierShift (perhaps
|
||||||
as left and right shift keys) then the mask would be KeyModifierShift
|
as left and right shift keys) then the mask would be KeyModifierShift
|
||||||
and \c keys would contain 5 and 23. A modifier with no keys is
|
and \c keys would contain 5 and 23. A modifier with no keys is
|
||||||
ignored. All keys must be valid (not zero). \c keys may be modified
|
ignored. Keys that are zero are ignored. \c keys may be modified
|
||||||
by the call.
|
by the call.
|
||||||
*/
|
*/
|
||||||
virtual void addModifier(KeyModifierMask, KeyButtons& keys) = 0;
|
virtual void addModifier(KeyModifierMask, KeyButtons& keys) = 0;
|
||||||
|
|
|
@ -107,7 +107,7 @@ SOURCE=.\IClipboard.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\IPlatformScreen.cpp
|
SOURCE=.\IPrimaryScreen.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue