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 "CLog.h"
#include <assert.h>
#include <ctype.h>
//
// CMSWindowsSecondaryScreen
@ -40,7 +41,7 @@ static BOOL CALLBACK WINAPI debugProc(HWND, UINT msg, WPARAM wParam, LPARAM lPar
case WM_APP:
if (!s_logMore.empty()) {
if (s_log.size() > 20000)
if (s_log.size() > 40000)
s_log = s_logMore;
else
s_log += s_logMore;
@ -189,15 +190,12 @@ void CMSWindowsSecondaryScreen::keyDown(
// get the sequence of keys to simulate key press and the final
// modifier state.
m_mask = mapKey(keys, virtualKey, key, mask, true);
m_mask = mapKey(keys, virtualKey, key, mask, kPress);
if (keys.empty())
return;
// generate key events
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);
}
doKeystrokes(keys, 1);
// note that key is now down
m_keys[virtualKey] |= 0x80;
@ -209,22 +207,14 @@ void CMSWindowsSecondaryScreen::keyRepeat(
Keystrokes keys;
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.
m_mask = mapKey(keys, virtualKey, key, mask, true);
m_mask = mapKey(keys, virtualKey, key, mask, kRepeat);
if (keys.empty())
return;
// generate key events
// YYY -- need to know which code in Keystrokes should be repeated;
// 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);
}
}
doKeystrokes(keys, count);
}
void CMSWindowsSecondaryScreen::keyUp(
@ -235,15 +225,12 @@ void CMSWindowsSecondaryScreen::keyUp(
// get the sequence of keys to simulate key release and the final
// modifier state.
m_mask = mapKey(keys, virtualKey, key, mask, false);
m_mask = mapKey(keys, virtualKey, key, mask, kRelease);
if (keys.empty())
return;
// generate key events
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);
}
doKeystrokes(keys, 1);
// note that key is now up
m_keys[virtualKey] &= ~0x80;
@ -252,7 +239,7 @@ void CMSWindowsSecondaryScreen::keyUp(
void CMSWindowsSecondaryScreen::mouseDown(ButtonID button)
{
// map button id to button flag
DWORD flags = mapButton(button);
DWORD flags = mapButton(button, true);
// send event
if (flags != 0)
@ -262,7 +249,7 @@ void CMSWindowsSecondaryScreen::mouseDown(ButtonID button)
void CMSWindowsSecondaryScreen::mouseUp(ButtonID button)
{
// map button id to button flag
DWORD flags = mapButton(button);
DWORD flags = mapButton(button, false);
// send event
if (flags != 0)
@ -786,7 +773,7 @@ static const UINT g_function[] =
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x18 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x20 */ VK_TAB, 0, 0, 0, 0, 0, 0, 0,
/* 0x28 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0,
@ -815,10 +802,6 @@ static const UINT g_function[] =
/* 0xf0 */ 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 */
static const UINT g_miscellany[] =
{
@ -919,18 +902,18 @@ static const UINT* g_mapTable[] =
};
DWORD CMSWindowsSecondaryScreen::mapButton(
ButtonID button) const
ButtonID button, bool press) const
{
// map button id to button flag
switch (button) {
case kButtonLeft:
return MOUSEEVENTF_LEFTDOWN;
return press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
case kButtonMiddle:
return MOUSEEVENTF_MIDDLEDOWN;
return press ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
case kButtonRight:
return MOUSEEVENTF_RIGHTDOWN;
return press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
default:
return 0;
@ -941,7 +924,7 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
Keystrokes& keys,
UINT& virtualKey,
KeyID id, KeyModifierMask mask,
bool press) const
EKeyAction action) const
{
// lookup the key table
const UInt32 mapID = ((id >> 8) & 0xff);
@ -959,17 +942,20 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
(KeyModifierCapsLock |
KeyModifierNumLock |
KeyModifierScrollLock));
log((CLOG_DEBUG2 "key id %d -> virtual key %d", id, virtualKey));
// if not in map then ask system to convert ascii character
if (virtualKey == 0) {
if (mapID != 0) {
// not ascii
log((CLOG_DEBUG2 "not ascii"));
return m_mask;
}
// translate. return no keys if unknown key.
SHORT vk = VkKeyScan(code);
if (vk == 0xffff) {
log((CLOG_DEBUG2 "no virtual key for character %d", code));
return m_mask;
}
@ -980,11 +966,30 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
outMask |= KeyModifierControl;
if (HIBYTE(vk) & 4)
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
if (outMask & (KeyModifierShift | KeyModifierCapsLock) ==
(KeyModifierShift | KeyModifierCapsLock))
outMask &= ~KeyModifierCapsLock;
// handle combination of caps-lock and shift. if caps-lock is
// off locally then use shift as necessary. if caps-lock is on
// locally then shift reverses its meaning (for keys that are
// 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
virtualKey = LOBYTE(vk);
@ -1001,11 +1006,22 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
// virtual keys but not for numeric keys.
if (virtualKey >= VK_NUMPAD0 && virtualKey <= VK_DIVIDE) {
// set required shift state based on current numlock state
if ((outMask & KeyModifierNumLock) == 0)
outMask |= KeyModifierShift;
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;
}
}
}
// FIXME -- should check for LeftTab KeySym
// check for ISO_Left_Tab
else if (id == 0xfe20) {
outMask |= KeyModifierShift;
}
}
// a list of modifier key info
@ -1078,6 +1094,7 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
// a modifier key then skip this because modifiers should not
// modify modifiers.
Keystrokes undo;
Keystroke keystroke;
if (outMask != m_mask && !isModifier) {
for (unsigned int i = 0; i < s_numModifiers; ++i) {
KeyModifierMask bit = s_modifier[i].mask;
@ -1087,15 +1104,20 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
// modifier is a toggle then toggle it on with a
// press/release, otherwise activate it with a
// press.
const UINT modifierKey = s_modifier[i].virtualKey;
keys.push_back(std::make_pair(modifierKey, true));
keystroke.m_virtualKey = s_modifier[i].virtualKey;
keystroke.m_press = true;
keystroke.m_repeat = false;
keys.push_back(keystroke);
if (s_modifier[i].isToggle) {
keys.push_back(std::make_pair(modifierKey, false));
undo.push_back(std::make_pair(modifierKey, false));
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 {
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
// modifier if not a toggle.
if (s_modifier[i].isToggle) {
const UINT modifierKey = s_modifier[i].virtualKey;
keys.push_back(std::make_pair(modifierKey, true));
keys.push_back(std::make_pair(modifierKey, false));
undo.push_back(std::make_pair(modifierKey, false));
undo.push_back(std::make_pair(modifierKey, true));
keystroke.m_virtualKey = s_modifier[i].virtualKey;
keystroke.m_press = true;
keystroke.m_repeat = false;
keys.push_back(keystroke);
keystroke.m_press = false;
keys.push_back(keystroke);
undo.push_back(keystroke);
keystroke.m_press = true;
undo.push_back(keystroke);
}
else {
UINT key = s_modifier[i].virtualKey;
if ((m_keys[key] & 0x80) != 0) {
keys.push_back(std::make_pair(key, false));
undo.push_back(std::make_pair(key, true));
keystroke.m_virtualKey = key;
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;
if ((m_keys[key] & 0x80) != 0) {
keys.push_back(std::make_pair(key, false));
undo.push_back(std::make_pair(key, true));
if (key != 0 && (m_keys[key] & 0x80) != 0) {
keystroke.m_virtualKey = key;
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
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
// 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
// this key is pressed.
mask = m_mask;
if (isModifier) {
// toggle keys modify the state on press if toggling on and on
// release if toggling off. other keys set the bit on press
// and clear the bit on release.
// FIXME -- verify if that's true on win32
if (isModifier && action != kRepeat) {
// toggle keys modify the state on release. other keys set
// the bit on press and clear the bit on release.
if (s_modifier[modifierIndex].isToggle) {
if (((mask & s_modifier[modifierIndex].mask) == 0) == press)
if (action == kRelease) {
mask ^= s_modifier[modifierIndex].mask;
}
}
else if (press) {
else if (action == kPress) {
mask |= s_modifier[modifierIndex].mask;
}
else {
@ -1161,7 +1213,8 @@ KeyModifierMask CMSWindowsSecondaryScreen::mapKey(
if ((m_keys[s_modifier[modifierIndex].virtualKey] & 0x80) != 0) {
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;
}
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;
}
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()
{
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()
@ -1195,6 +1301,7 @@ void CMSWindowsSecondaryScreen::updateModifiers()
m_mask |= KeyModifierNumLock;
if ((m_keys[VK_SCROLL] & 0x01) != 0)
m_mask |= KeyModifierScrollLock;
log((CLOG_DEBUG2 "modifiers on update: 0x%04x", m_mask));
}
void CMSWindowsSecondaryScreen::toggleKey(

View File

@ -40,12 +40,19 @@ protected:
virtual void onCloseDisplay();
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;
DWORD mapButton(ButtonID button) const;
DWORD mapButton(ButtonID button, bool press) const;
KeyModifierMask mapKey(Keystrokes&, UINT& virtualKey, KeyID,
KeyModifierMask, bool press) const;
KeyModifierMask, EKeyAction) const;
void doKeystrokes(const Keystrokes&, SInt32 count);
void updateKeys();
void updateModifiers();

View File

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

View File

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