Fixes for win32 key handling.

This commit is contained in:
crs 2002-05-04 18:08:22 +00:00
parent f3c70dc300
commit 4d11079095
4 changed files with 187 additions and 71 deletions

View File

@ -5,6 +5,7 @@
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include <assert.h> #include <assert.h>
#include <ctype.h>
// //
// CMSWindowsSecondaryScreen // CMSWindowsSecondaryScreen
@ -40,7 +41,7 @@ static BOOL CALLBACK WINAPI debugProc(HWND, UINT msg, WPARAM wParam, LPARAM lPar
case WM_APP: case WM_APP:
if (!s_logMore.empty()) { if (!s_logMore.empty()) {
if (s_log.size() > 20000) if (s_log.size() > 40000)
s_log = s_logMore; s_log = s_logMore;
else else
s_log += s_logMore; s_log += s_logMore;
@ -189,15 +190,12 @@ void CMSWindowsSecondaryScreen::keyDown(
// get the sequence of keys to simulate key press and the final // get the sequence of keys to simulate key press and the final
// modifier state. // modifier state.
m_mask = mapKey(keys, virtualKey, key, mask, true); m_mask = mapKey(keys, virtualKey, key, mask, kPress);
if (keys.empty()) if (keys.empty())
return; return;
// generate key events // generate key events
for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ++k) { doKeystrokes(keys, 1);
const UINT code = MapVirtualKey(k->first, 0);
keybd_event(k->first, code, k->second ? 0 : KEYEVENTF_KEYUP, 0);
}
// note that key is now down // note that key is now down
m_keys[virtualKey] |= 0x80; m_keys[virtualKey] |= 0x80;
@ -209,22 +207,14 @@ void CMSWindowsSecondaryScreen::keyRepeat(
Keystrokes keys; Keystrokes keys;
UINT virtualKey; UINT virtualKey;
// get the sequence of keys to simulate key release and the final // get the sequence of keys to simulate key repeat and the final
// modifier state. // modifier state.
m_mask = mapKey(keys, virtualKey, key, mask, true); m_mask = mapKey(keys, virtualKey, key, mask, kRepeat);
if (keys.empty()) if (keys.empty())
return; return;
// generate key events // generate key events
// YYY -- need to know which code in Keystrokes should be repeated; doKeystrokes(keys, count);
// then repeat only that key count times
for (SInt32 i = 0; i < count; ++i) {
for (Keystrokes::const_iterator k = keys.begin();
k != keys.end(); ++k) {
const UINT code = MapVirtualKey(k->first, 0);
keybd_event(k->first, code, k->second ? 0 : KEYEVENTF_KEYUP, 0);
}
}
} }
void CMSWindowsSecondaryScreen::keyUp( void CMSWindowsSecondaryScreen::keyUp(
@ -235,15 +225,12 @@ void CMSWindowsSecondaryScreen::keyUp(
// get the sequence of keys to simulate key release and the final // get the sequence of keys to simulate key release and the final
// modifier state. // modifier state.
m_mask = mapKey(keys, virtualKey, key, mask, false); m_mask = mapKey(keys, virtualKey, key, mask, kRelease);
if (keys.empty()) if (keys.empty())
return; return;
// generate key events // generate key events
for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ++k) { doKeystrokes(keys, 1);
const UINT code = MapVirtualKey(k->first, 0);
keybd_event(k->first, code, k->second ? 0 : KEYEVENTF_KEYUP, 0);
}
// note that key is now up // note that key is now up
m_keys[virtualKey] &= ~0x80; m_keys[virtualKey] &= ~0x80;
@ -252,7 +239,7 @@ void CMSWindowsSecondaryScreen::keyUp(
void CMSWindowsSecondaryScreen::mouseDown(ButtonID button) void CMSWindowsSecondaryScreen::mouseDown(ButtonID button)
{ {
// map button id to button flag // map button id to button flag
DWORD flags = mapButton(button); DWORD flags = mapButton(button, true);
// send event // send event
if (flags != 0) if (flags != 0)
@ -262,7 +249,7 @@ void CMSWindowsSecondaryScreen::mouseDown(ButtonID button)
void CMSWindowsSecondaryScreen::mouseUp(ButtonID button) void CMSWindowsSecondaryScreen::mouseUp(ButtonID button)
{ {
// map button id to button flag // map button id to button flag
DWORD flags = mapButton(button); DWORD flags = mapButton(button, false);
// send event // send event
if (flags != 0) if (flags != 0)
@ -786,7 +773,7 @@ static const UINT g_function[] =
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x18 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x18 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ VK_TAB, 0, 0, 0, 0, 0, 0, 0,
/* 0x28 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0,
@ -815,10 +802,6 @@ static const UINT g_function[] =
/* 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
}; };
// FIXME -- will this work?
// 0x100 + = shift
// 0x200 + = ctrl
// 0x400 + = alt
/* XK_KP_Space to XK_KP_Equal */ /* XK_KP_Space to XK_KP_Equal */
static const UINT g_miscellany[] = static const UINT g_miscellany[] =
{ {
@ -919,18 +902,18 @@ static const UINT* g_mapTable[] =
}; };
DWORD CMSWindowsSecondaryScreen::mapButton( DWORD CMSWindowsSecondaryScreen::mapButton(
ButtonID button) const ButtonID button, bool press) const
{ {
// map button id to button flag // map button id to button flag
switch (button) { switch (button) {
case kButtonLeft: case kButtonLeft:
return MOUSEEVENTF_LEFTDOWN; return press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
case kButtonMiddle: case kButtonMiddle:
return MOUSEEVENTF_MIDDLEDOWN; return press ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
case kButtonRight: case kButtonRight:
return MOUSEEVENTF_RIGHTDOWN; return press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
default: default:
return 0; return 0;
@ -941,7 +924,7 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
Keystrokes& keys, Keystrokes& keys,
UINT& virtualKey, UINT& virtualKey,
KeyID id, KeyModifierMask mask, KeyID id, KeyModifierMask mask,
bool press) const EKeyAction action) const
{ {
// lookup the key table // lookup the key table
const UInt32 mapID = ((id >> 8) & 0xff); const UInt32 mapID = ((id >> 8) & 0xff);
@ -959,17 +942,20 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
(KeyModifierCapsLock | (KeyModifierCapsLock |
KeyModifierNumLock | KeyModifierNumLock |
KeyModifierScrollLock)); KeyModifierScrollLock));
log((CLOG_DEBUG2 "key id %d -> virtual key %d", id, virtualKey));
// if not in map then ask system to convert ascii character // if not in map then ask system to convert ascii character
if (virtualKey == 0) { if (virtualKey == 0) {
if (mapID != 0) { if (mapID != 0) {
// not ascii // not ascii
log((CLOG_DEBUG2 "not ascii"));
return m_mask; return m_mask;
} }
// translate. return no keys if unknown key. // translate. return no keys if unknown key.
SHORT vk = VkKeyScan(code); SHORT vk = VkKeyScan(code);
if (vk == 0xffff) { if (vk == 0xffff) {
log((CLOG_DEBUG2 "no virtual key for character %d", code));
return m_mask; return m_mask;
} }
@ -980,11 +966,30 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
outMask |= KeyModifierControl; outMask |= KeyModifierControl;
if (HIBYTE(vk) & 4) if (HIBYTE(vk) & 4)
outMask |= KeyModifierAlt; outMask |= KeyModifierAlt;
log((CLOG_DEBUG2 "character %d to virtual key %d mask 0x%04x", code, LOBYTE(vk), outMask));
// if caps-lock is on and so is shift then turn off caps-lock // handle combination of caps-lock and shift. if caps-lock is
if (outMask & (KeyModifierShift | KeyModifierCapsLock) == // off locally then use shift as necessary. if caps-lock is on
(KeyModifierShift | KeyModifierCapsLock)) // locally then shift reverses its meaning (for keys that are
outMask &= ~KeyModifierCapsLock; // subject to case conversion).
if ((m_mask & KeyModifierCapsLock) != 0) {
// caps-lock is on. note if shift is required.
log((CLOG_DEBUG2 "caps-lock is on"));
const bool needShift = ((outMask & KeyModifierShift) != 0);
// if needShift is true then see if the key is subject to
// case conversion. if it is then caps-lock and shift
// cancel out. if not then caps-lock is ignored and shift
// is required.
if (needShift) {
// FIXME -- there should be some system call to test
// if a key is subject to case conversion.
if (tolower(code) != toupper(code)) {
log((CLOG_DEBUG2 "turn off shift"));
outMask &= ~KeyModifierShift;
}
}
}
// get virtual key // get virtual key
virtualKey = LOBYTE(vk); virtualKey = LOBYTE(vk);
@ -1001,11 +1006,22 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
// virtual keys but not for numeric keys. // virtual keys but not for numeric keys.
if (virtualKey >= VK_NUMPAD0 && virtualKey <= VK_DIVIDE) { if (virtualKey >= VK_NUMPAD0 && virtualKey <= VK_DIVIDE) {
// set required shift state based on current numlock state // set required shift state based on current numlock state
if ((outMask & KeyModifierNumLock) == 0) if ((outMask & KeyModifierNumLock) == 0) {
if ((m_mask & KeyModifierNumLock) == 0) {
log((CLOG_DEBUG2 "turn on num lock for keypad key"));
outMask |= KeyModifierNumLock;
}
else {
log((CLOG_DEBUG2 "turn on shift for keypad key"));
outMask |= KeyModifierShift; outMask |= KeyModifierShift;
} }
}
}
// FIXME -- should check for LeftTab KeySym // check for ISO_Left_Tab
else if (id == 0xfe20) {
outMask |= KeyModifierShift;
}
} }
// a list of modifier key info // a list of modifier key info
@ -1078,6 +1094,7 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
// a modifier key then skip this because modifiers should not // a modifier key then skip this because modifiers should not
// modify modifiers. // modify modifiers.
Keystrokes undo; Keystrokes undo;
Keystroke keystroke;
if (outMask != m_mask && !isModifier) { if (outMask != m_mask && !isModifier) {
for (unsigned int i = 0; i < s_numModifiers; ++i) { for (unsigned int i = 0; i < s_numModifiers; ++i) {
KeyModifierMask bit = s_modifier[i].mask; KeyModifierMask bit = s_modifier[i].mask;
@ -1087,15 +1104,20 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
// modifier is a toggle then toggle it on with a // modifier is a toggle then toggle it on with a
// press/release, otherwise activate it with a // press/release, otherwise activate it with a
// press. // press.
const UINT modifierKey = s_modifier[i].virtualKey; keystroke.m_virtualKey = s_modifier[i].virtualKey;
keys.push_back(std::make_pair(modifierKey, true)); keystroke.m_press = true;
keystroke.m_repeat = false;
keys.push_back(keystroke);
if (s_modifier[i].isToggle) { if (s_modifier[i].isToggle) {
keys.push_back(std::make_pair(modifierKey, false)); keystroke.m_press = false;
undo.push_back(std::make_pair(modifierKey, false)); keys.push_back(keystroke);
undo.push_back(std::make_pair(modifierKey, true)); undo.push_back(keystroke);
keystroke.m_press = true;
undo.push_back(keystroke);
} }
else { else {
undo.push_back(std::make_pair(modifierKey, false)); keystroke.m_press = false;
undo.push_back(keystroke);
} }
} }
@ -1106,22 +1128,34 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
// release. we must check each keycode for the // release. we must check each keycode for the
// modifier if not a toggle. // modifier if not a toggle.
if (s_modifier[i].isToggle) { if (s_modifier[i].isToggle) {
const UINT modifierKey = s_modifier[i].virtualKey; keystroke.m_virtualKey = s_modifier[i].virtualKey;
keys.push_back(std::make_pair(modifierKey, true)); keystroke.m_press = true;
keys.push_back(std::make_pair(modifierKey, false)); keystroke.m_repeat = false;
undo.push_back(std::make_pair(modifierKey, false)); keys.push_back(keystroke);
undo.push_back(std::make_pair(modifierKey, true)); keystroke.m_press = false;
keys.push_back(keystroke);
undo.push_back(keystroke);
keystroke.m_press = true;
undo.push_back(keystroke);
} }
else { else {
UINT key = s_modifier[i].virtualKey; UINT key = s_modifier[i].virtualKey;
if ((m_keys[key] & 0x80) != 0) { if ((m_keys[key] & 0x80) != 0) {
keys.push_back(std::make_pair(key, false)); keystroke.m_virtualKey = key;
undo.push_back(std::make_pair(key, true)); keystroke.m_press = false;
keystroke.m_repeat = false;
keys.push_back(keystroke);
keystroke.m_press = true;
undo.push_back(keystroke);
} }
key = s_modifier[i].virtualKey2; key = s_modifier[i].virtualKey2;
if ((m_keys[key] & 0x80) != 0) { if (key != 0 && (m_keys[key] & 0x80) != 0) {
keys.push_back(std::make_pair(key, false)); keystroke.m_virtualKey = key;
undo.push_back(std::make_pair(key, true)); keystroke.m_press = false;
keystroke.m_repeat = false;
keys.push_back(keystroke);
keystroke.m_press = true;
undo.push_back(keystroke);
} }
} }
} }
@ -1130,7 +1164,26 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
} }
// add the key event // add the key event
keys.push_back(std::make_pair(virtualKey, press)); keystroke.m_virtualKey = virtualKey;
switch (action) {
case kPress:
keystroke.m_press = true;
keystroke.m_repeat = false;
keys.push_back(keystroke);
break;
case kRelease:
keystroke.m_press = false;
keystroke.m_repeat = false;
keys.push_back(keystroke);
break;
case kRepeat:
keystroke.m_press = true;
keystroke.m_repeat = true;
keys.push_back(keystroke);
break;
}
// add key events to restore the modifier state. apply events in // add key events to restore the modifier state. apply events in
// the reverse order that they're stored in undo. // the reverse order that they're stored in undo.
@ -1142,16 +1195,15 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
// if the key is a modifier key then compute the modifier mask after // if the key is a modifier key then compute the modifier mask after
// this key is pressed. // this key is pressed.
mask = m_mask; mask = m_mask;
if (isModifier) { if (isModifier && action != kRepeat) {
// toggle keys modify the state on press if toggling on and on // toggle keys modify the state on release. other keys set
// release if toggling off. other keys set the bit on press // the bit on press and clear the bit on release.
// and clear the bit on release.
// FIXME -- verify if that's true on win32
if (s_modifier[modifierIndex].isToggle) { if (s_modifier[modifierIndex].isToggle) {
if (((mask & s_modifier[modifierIndex].mask) == 0) == press) if (action == kRelease) {
mask ^= s_modifier[modifierIndex].mask; mask ^= s_modifier[modifierIndex].mask;
} }
else if (press) { }
else if (action == kPress) {
mask |= s_modifier[modifierIndex].mask; mask |= s_modifier[modifierIndex].mask;
} }
else { else {
@ -1161,7 +1213,8 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
if ((m_keys[s_modifier[modifierIndex].virtualKey] & 0x80) != 0) { if ((m_keys[s_modifier[modifierIndex].virtualKey] & 0x80) != 0) {
down = true; down = true;
} }
if ((m_keys[s_modifier[modifierIndex].virtualKey2] & 0x80) != 0) { if (s_modifier[modifierIndex].virtualKey2 != 0 &&
(m_keys[s_modifier[modifierIndex].virtualKey2] & 0x80) != 0) {
down = true; down = true;
} }
if (!down) if (!down)
@ -1169,12 +1222,65 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
} }
} }
log((CLOG_DEBUG2 "previous modifiers 0x%04x, final modifiers 0x%04x", m_mask, mask));
return mask; return mask;
} }
void CMSWindowsSecondaryScreen::doKeystrokes(
const Keystrokes& keys, SInt32 count)
{
// do nothing if no keys or no repeats
if (count < 1 || keys.empty())
return;
// generate key events
for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) {
if (k->m_repeat) {
// repeat from here up to but not including the next key
// with m_repeat == false count times.
Keystrokes::const_iterator start = k;
for (; count > 0; --count) {
// send repeating events
for (k = start; k != keys.end() && k->m_repeat; ++k) {
const UINT code = MapVirtualKey(k->m_virtualKey, 0);
keybd_event(k->m_virtualKey, code,
k->m_press ? 0 : KEYEVENTF_KEYUP, 0);
}
}
// note -- k is now on the first non-repeat key after the
// repeat keys, exactly where we'd like to continue from.
}
else {
// send event
const UINT code = MapVirtualKey(k->m_virtualKey, 0);
keybd_event(k->m_virtualKey, code,
k->m_press ? 0 : KEYEVENTF_KEYUP, 0);
// next key
++k;
}
}
}
void CMSWindowsSecondaryScreen::updateKeys() void CMSWindowsSecondaryScreen::updateKeys()
{ {
GetKeyboardState(m_keys); // GetKeyboardKeys() doesn't seem to do the expected thing
memset(m_keys, 0, sizeof(m_keys));
m_keys[VK_LSHIFT] = GetKeyState(VK_LSHIFT);
m_keys[VK_RSHIFT] = GetKeyState(VK_RSHIFT);
m_keys[VK_SHIFT] = GetKeyState(VK_SHIFT);
m_keys[VK_LCONTROL] = GetKeyState(VK_LCONTROL);
m_keys[VK_RCONTROL] = GetKeyState(VK_RCONTROL);
m_keys[VK_CONTROL] = GetKeyState(VK_CONTROL);
m_keys[VK_LMENU] = GetKeyState(VK_LMENU);
m_keys[VK_RMENU] = GetKeyState(VK_RMENU);
m_keys[VK_MENU] = GetKeyState(VK_MENU);
m_keys[VK_LWIN] = GetKeyState(VK_LWIN);
m_keys[VK_RWIN] = GetKeyState(VK_RWIN);
m_keys[VK_CAPITAL] = GetKeyState(VK_CAPITAL);
m_keys[VK_NUMLOCK] = GetKeyState(VK_NUMLOCK);
m_keys[VK_SCROLL] = GetKeyState(VK_SCROLL);
} }
void CMSWindowsSecondaryScreen::updateModifiers() void CMSWindowsSecondaryScreen::updateModifiers()
@ -1195,6 +1301,7 @@ void CMSWindowsSecondaryScreen::updateModifiers()
m_mask |= KeyModifierNumLock; m_mask |= KeyModifierNumLock;
if ((m_keys[VK_SCROLL] & 0x01) != 0) if ((m_keys[VK_SCROLL] & 0x01) != 0)
m_mask |= KeyModifierScrollLock; m_mask |= KeyModifierScrollLock;
log((CLOG_DEBUG2 "modifiers on update: 0x%04x", m_mask));
} }
void CMSWindowsSecondaryScreen::toggleKey( void CMSWindowsSecondaryScreen::toggleKey(

View File

@ -40,12 +40,19 @@ protected:
virtual void onCloseDisplay(); virtual void onCloseDisplay();
private: private:
typedef std::pair<UINT, bool> Keystroke; enum EKeyAction { kPress, kRelease, kRepeat };
class Keystroke {
public:
UINT m_virtualKey;
bool m_press;
bool m_repeat;
};
typedef std::vector<Keystroke> Keystrokes; typedef std::vector<Keystroke> Keystrokes;
DWORD mapButton(ButtonID button) const; DWORD mapButton(ButtonID button, bool press) const;
KeyModifierMask mapKey(Keystrokes&, UINT& virtualKey, KeyID, KeyModifierMask mapKey(Keystrokes&, UINT& virtualKey, KeyID,
KeyModifierMask, bool press) const; KeyModifierMask, EKeyAction) const;
void doKeystrokes(const Keystrokes&, SInt32 count);
void updateKeys(); void updateKeys();
void updateModifiers(); void updateModifiers();

View File

@ -135,9 +135,11 @@ void CTCPSocket::init()
CNetwork::TCPNoDelayType flag = 1; CNetwork::TCPNoDelayType flag = 1;
CNetwork::setsockopt(m_fd, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag)); CNetwork::setsockopt(m_fd, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag));
#if !defined(CONFIG_PLATFORM_WIN32)
// don't buffer sends, we merge messages ourself // don't buffer sends, we merge messages ourself
int data = 0; int data = 0;
CNetwork::setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &data, sizeof(data)); CNetwork::setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &data, sizeof(data));
#endif
} }
void CTCPSocket::ioThread(void*) void CTCPSocket::ioThread(void*)

View File

@ -252,7 +252,7 @@ void CMSWindowsPrimaryScreen::getClipboard(
CClipboard::copy(dst, &src); CClipboard::copy(dst, &src);
} }
KeyModifierMask CXWindowsPrimaryScreen::getToggleMask() const KeyModifierMask CMSWindowsPrimaryScreen::getToggleMask() const
{ {
KeyModifierMask mask; KeyModifierMask mask;
if ((m_keys[VK_CAPITAL] & 0x01) != 0) if ((m_keys[VK_CAPITAL] & 0x01) != 0)