source: trunk/synergy/lib/platform/CPMKeyState.cpp@ 2768

Last change on this file since 2768 was 2768, checked in by bird, 19 years ago

Expanded m_client to 64-bit. Finally managed to hack together a getKeyMap and fakeKey for PM.

File size: 40.9 KB
Line 
1/*
2 * synergy -- mouse and keyboard sharing utility
3 * Copyright (C) 2003 Chris Schoeneman
4 * Copyright (C) 2006 Knut St. Osmundsen
5 *
6 * This package is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * found in the file COPYING that should have accompanied this file.
9 *
10 * This package is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include "CPMKeyState.h"
17#include "CThread.h"
18#include "CFunctionJob.h"
19#include "CLog.h"
20#include "CStringUtil.h"
21#include "CPMUtil.h"
22#include "IEventQueue.h"
23#include "TMethodEventJob.h"
24
25//
26// CPMKeyState
27//
28
29// map virtual keys to synergy key enumeration
30const CPMKeyState::VirtualKey CPMKeyState::s_virtualKey[0x42] =
31{
32{ /* 0x000 */ kKeyNone, 0, 0, 0 }, // reserved
33{ /* 0x001 */ kKeyNone, 0, 0, 0 }, // VK_BUTTON1
34{ /* 0x002 */ kKeyNone, 0, 0, 0 }, // VK_BUTTON2
35{ /* 0x003 */ kKeyNone, 0, 0, 0 }, // VK_BUTTON3
36{ /* 0x004 */ kKeyBreak, 0, 0, 0 }, // VK_BREAK
37{ /* 0x005 */ kKeyBackSpace, 8, 0, 0 }, // VK_BACKSPACE
38{ /* 0x006 */ kKeyTab, 9, 0, 0 }, // VK_TAB
39{ /* 0x007 */ kKeyLeftTab, 9, 0, 1 }, // VK_BACKTAB
40{ /* 0x008 */ kKeyReturn, 0x0d, 0, 0 }, // VK_NEWLINE
41{ /* 0x009 */ kKeyShift_L, 0, 0, 0 }, // VK_SHIFT
42{ /* 0x00a */ kKeyControl_L, 0, 0, 0 }, // VK_CTRL
43{ /* 0x00b */ kKeyAlt_L, 0, 0, 0 }, // VK_ALT
44{ /* 0x00c */ kKeyAltGr, 0, 0, 0 }, // VK_ALTGRAF
45{ /* 0x00d */ kKeyPause, 0, 0, 0 }, // VK_PAUSE
46{ /* 0x00e */ kKeyCapsLock, 0, 0, 0 }, // VK_CAPSLOCK
47{ /* 0x00f */ kKeyEscape, 0x1b, 0, 0 }, // VK_ESC
48{ /* 0x010 */ ' ', 0x20, 0, 0 }, // VK_SPACE
49{ /* 0x011 */ kKeyPageUp, 0xe0, 1, -1 }, // VK_PAGEUP
50{ /* 0x012 */ kKeyPageDown, 0xe0, 1, -1 }, // VK_PAGEDOWN
51{ /* 0x013 */ kKeyEnd, 0xe0, 1, -1 }, // VK_END
52{ /* 0x014 */ kKeyHome, 0xe0, 1, -1 }, // VK_HOME
53{ /* 0x015 */ kKeyLeft, 0xe0, 1, -1 }, // VK_LEFT
54{ /* 0x016 */ kKeyUp, 0xe0, 1, -1 }, // VK_UP
55{ /* 0x017 */ kKeyRight, 0xe0, 1, -1 }, // VK_RIGHT
56{ /* 0x018 */ kKeyDown, 0xe0, 1, -1 }, // VK_DOWN
57{ /* 0x019 */ kKeyNone, 0xe0, 0, 0 }, // VK_PRINTSCRN
58{ /* 0x01a */ kKeyInsert, 0xe0, 1, 1 }, // VK_INSERT
59{ /* 0x01b */ kKeyDelete, 0xe0, 1, 1 }, // VK_DELETE
60{ /* 0x01c */ kKeyScrollLock, 0, 0, 0 }, // VK_SCRLLOCK
61{ /* 0x01d */ kKeyNumLock, 0, 0, 0 }, // VK_NUMLOCK
62{ /* 0x01e */ kKeyKP_Enter, 0x0d, 1, 1 }, // VK_ENTER
63{ /* 0x01f */ kKeySysReq, 0, 0, 0 }, // VK_SYSRQ
64{ /* 0x020 */ kKeyF1, 0, 0, 1 }, // VK_F1
65{ /* 0x021 */ kKeyF2, 0, 0, 1 }, // VK_F2
66{ /* 0x022 */ kKeyF3, 0, 0, 1 }, // VK_F3
67{ /* 0x023 */ kKeyF4, 0, 0, 1 }, // VK_F4
68{ /* 0x024 */ kKeyF5, 0, 0, 1 }, // VK_F5
69{ /* 0x025 */ kKeyF6, 0, 0, 1 }, // VK_F6
70{ /* 0x026 */ kKeyF7, 0, 0, 1 }, // VK_F7
71{ /* 0x027 */ kKeyF8, 0, 0, 1 }, // VK_F8
72{ /* 0x028 */ kKeyF9, 0, 0, 1 }, // VK_F9
73{ /* 0x029 */ kKeyF10, 0, 0, 1 }, // VK_F10
74{ /* 0x02a */ kKeyF11, 0, 0, 1 }, // VK_F11
75{ /* 0x02b */ kKeyF12, 0, 0, 1 }, // VK_F12
76{ /* 0x02c */ kKeyF13, 0, 0, 1 }, // VK_F13
77{ /* 0x02d */ kKeyF14, 0, 0, 1 }, // VK_F14
78{ /* 0x02e */ kKeyF15, 0, 0, 1 }, // VK_F15
79{ /* 0x02f */ kKeyF16, 0, 0, 1 }, // VK_F16
80{ /* 0x030 */ kKeyF17, 0, 0, 1 }, // VK_F17
81{ /* 0x031 */ kKeyF18, 0, 0, 1 }, // VK_F18
82{ /* 0x032 */ kKeyF19, 0, 0, 1 }, // VK_F19
83{ /* 0x033 */ kKeyF20, 0, 0, 1 }, // VK_F20
84{ /* 0x034 */ kKeyF21, 0, 0, 1 }, // VK_F21
85{ /* 0x035 */ kKeyF22, 0, 0, 1 }, // VK_F22
86{ /* 0x036 */ kKeyF23, 0, 0, 1 }, // VK_F23
87{ /* 0x037 */ kKeyF24, 0, 0, 1 }, // VK_F24
88{ /* 0x038 */ kKeyNone, 0, 0, 0 }, // VK_ENDDRAG
89{ /* 0x039 */ kKeyNone, 0, 0, 0 }, // VK_CLEAR
90{ /* 0x03a */ kKeyNone, 0, 0, 0 }, // VK_EREOF
91{ /* 0x03b */ kKeyNone, 0, 0, 0 }, // VK_PA1
92{ /* 0x03c */ kKeyNone, 0, 0, 0 }, // VK_ATTN
93{ /* 0x03d */ kKeyNone, 0, 0, 0 }, // VK_CRSEL
94{ /* 0x03e */ kKeyNone, 0, 0, 0 }, // VK_EXSEL
95{ /* 0x03f */ kKeyNone, 0, 0, 0 }, // VK_COPY
96{ /* 0x040 */ kKeyNone, 0, 0, 0 }, // VK_BLK1
97{ /* 0x041 */ kKeyNone, 0, 0, 0 }, // VK_BLK2
98};
99
100struct CWin32Modifiers {
101public:
102 ULONG m_vk;
103 KeyModifierMask m_mask;
104};
105
106static const CWin32Modifiers s_modifiers[] =
107{
108 { VK_SHIFT, KeyModifierShift },
109 { VK_CTRL, KeyModifierControl },
110 { VK_ALT, KeyModifierAlt },
111 { VK_ALTGRAF, KeyModifierAltGr },
112};
113
114CPMKeyState::CPMKeyState(void* eventTarget, FakeMsgFunc fakeMsg) :
115 m_eventTarget(eventTarget),
116 m_fakeMsg(fakeMsg),
117 m_lastButton(0),
118 m_fixTimer(NULL),
119 m_lastDown(kKeyNone),
120 m_useSavedModifiers(false),
121 m_savedModifiers(0),
122 m_originalSavedModifiers(0)
123{
124 LOG((CLOG_DEBUG "CPMKeyState:"));
125}
126
127CPMKeyState::~CPMKeyState()
128{
129 LOG((CLOG_DEBUG "~CPMKeyState:"));
130 disable();
131}
132
133void
134CPMKeyState::disable()
135{
136 LOG((CLOG_DEBUG "disable:"));
137 if (m_fixTimer != NULL) {
138 EVENTQUEUE->removeHandler(CEvent::kTimer, m_fixTimer);
139 EVENTQUEUE->deleteTimer(m_fixTimer);
140 m_fixTimer = NULL;
141 }
142 m_lastDown = kKeyNone;
143}
144
145KeyButton
146CPMKeyState::virtualKeyToButton(ULONG virtualKey) const
147{
148 LOG((CLOG_DEBUG "virtualKeyToButton:"));
149 return m_virtualKeyToButton[virtualKey & 0xffu];
150}
151
152bool
153CPMKeyState::testAutoRepeat(bool press, bool isRepeat, KeyButton button)
154{
155 LOG((CLOG_DEBUG "testAutoRepeat:"));
156 if (!isRepeat)
157 isRepeat = press && button == m_lastDown && button != kKeyNone;
158 m_lastDown = press ? button : kKeyNone;
159 return isRepeat;
160}
161
162void
163CPMKeyState::saveModifiers()
164{
165 LOG((CLOG_DEBUG "saveModifiers:"));
166 m_savedModifiers = getActiveModifiers();
167 m_originalSavedModifiers = m_savedModifiers;
168}
169
170void
171CPMKeyState::useSavedModifiers(bool enable)
172{
173 LOG((CLOG_DEBUG "useSavedModifiers:"));
174 if (enable != m_useSavedModifiers) {
175 m_useSavedModifiers = enable;
176 if (!m_useSavedModifiers) {
177 // transfer any modifier state changes to CKeyState's state
178 KeyModifierMask mask = m_originalSavedModifiers ^ m_savedModifiers;
179 getActiveModifiersRValue() = (getActiveModifiers() & ~mask) | (m_savedModifiers & mask);
180 }
181 }
182}
183
184KeyID
185CPMKeyState::mapKeyFromEvent(USHORT fsFlags, UCHAR ucRepeat, UCHAR ucScanCode, USHORT usch, USHORT usvk, KeyModifierMask* maskOut) const
186{
187 LOG((CLOG_DEBUG "mapKeyFromEvent:"));
188#if 0 /** @todo */
189 static const KeyModifierMask s_controlAlt = KeyModifierControl | KeyModifierAlt;
190
191 // extract character, virtual key, and if we didn't use AltGr
192 char c = (char)((charAndVirtKey & 0xff00u) >> 8);
193 ULONG vkCode = (charAndVirtKey & 0xffu);
194 bool noAltGr = ((charAndVirtKey & 0xff0000u) != 0);
195
196 // handle some keys via table lookup
197 KeyID id = getKeyID(vkCode, (KeyButton)((info >> 16) & 0x1ffu));
198
199 // check if not in table; map character to key id
200 if (id == kKeyNone && c != 0) {
201 if ((c & 0x80u) == 0) {
202 // ASCII
203 id = static_cast<KeyID>(c) & 0xffu;
204 }
205 else {
206 // character is not really ASCII. instead it's some
207 // character in the current ANSI code page. try to
208 // convert that to a Unicode character. if we fail
209 // then use the single byte character as is.
210 char src = c;
211 wchar_t unicode;
212 if (MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED,
213 &src, 1, &unicode, 1) > 0) {
214 id = static_cast<KeyID>(unicode);
215 }
216 else {
217 id = static_cast<KeyID>(c) & 0xffu;
218 }
219 }
220 }
221
222 // set modifier mask
223 if (maskOut != NULL) {
224 KeyModifierMask active = getActiveModifiers();
225 if (!noAltGr && (active & s_controlAlt) == s_controlAlt) {
226 // if !noAltGr then we're only interested in matching the
227 // key, not the AltGr. AltGr is down (i.e. control and alt
228 // are down) but we don't want the client to have to match
229 // that so we clear it.
230 active &= ~s_controlAlt;
231 }
232 *maskOut = active;
233 }
234 return id;
235#else
236 return kKeyNone;
237#endif
238}
239
240ULONG
241CPMKeyState::mapKeyToVirtualKey(KeyID key) const
242{
243 LOG((CLOG_DEBUG "mapKeyToVirtualKey:"));
244 if (key == kKeyNone)
245 return 0;
246 KeyToVKMap::const_iterator i = m_keyToVKMap.find(key);
247 if (i == m_keyToVKMap.end())
248 return 0;
249 return i->second;
250}
251
252void
253CPMKeyState::sendKeyEvent(void* target,
254 bool press, bool isAutoRepeat,
255 KeyID key, KeyModifierMask mask,
256 SInt32 count, KeyButton button)
257{
258 LOG((CLOG_DEBUG "sendKeyEvent:"));
259 if (press || isAutoRepeat) {
260 // send key
261 if (press && !isAutoRepeat) {
262 CKeyState::sendKeyEvent(target, true, false, key, mask, 1, button);
263 if (count > 0) {
264 --count;
265 }
266 }
267 if (count >= 1) {
268 CKeyState::sendKeyEvent(target, true, true, key, mask, count, button);
269 }
270 }
271 else {
272 // do key up
273 CKeyState::sendKeyEvent(target, false, false, key, mask, 1, button);
274 }
275}
276
277void
278CPMKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button)
279{
280 LOG((CLOG_DEBUG "fakeKeyDown: id=%#x mask=%#x button=%#x", id, mask, button));
281 CKeyState::fakeKeyDown(id, mask, button);
282}
283
284void
285CPMKeyState::fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button)
286{
287 LOG((CLOG_DEBUG "fakeKeyRepeat: id=%#x mask=%#x count=%d button=%#x", id, mask, count, button));
288 CKeyState::fakeKeyRepeat(id, mask, count, button);
289}
290
291bool
292CPMKeyState::fakeCtrlAltDel()
293{
294 LOG((CLOG_DEBUG "fakeCtrlAltDel:"));
295 fakeKeyDown(kKeyDelete, KeyModifierControl | KeyModifierAlt, virtualKeyToButton(VK_DELETE));
296}
297
298KeyModifierMask
299CPMKeyState::pollActiveModifiers() const
300{
301 LOG((CLOG_DEBUG "pollActiveModifiers:"));
302 KeyModifierMask state = 0;
303
304 // get non-toggle modifiers from our own shadow key state
305 for (size_t i = 0; i < sizeof(s_modifiers) / sizeof(s_modifiers[0]); ++i) {
306 KeyButton button = virtualKeyToButton(s_modifiers[i].m_vk);
307 if (button != 0 && isKeyDown(button)) {
308 state |= s_modifiers[i].m_mask;
309 }
310 }
311
312 // we can get toggle modifiers from the system
313 if (WinGetKeyState(HWND_DESKTOP, VK_CAPSLOCK) & 1)
314 state |= KeyModifierCapsLock;
315 if (WinGetKeyState(HWND_DESKTOP, VK_NUMLOCK) & 1)
316 state |= KeyModifierNumLock;
317 if (WinGetKeyState(HWND_DESKTOP, VK_SCRLLOCK) & 1)
318 state |= KeyModifierScrollLock;
319 return state;
320}
321
322SInt32
323CPMKeyState::pollActiveGroup() const
324{
325 LOG((CLOG_DEBUG "pollActiveGroup:"));
326#if 0
327 HKL hkl = GetKeyboardLayout(targetThread);
328
329 // get group
330 GroupMap::const_iterator i = m_groupMap.find(hkl);
331 if (i == m_groupMap.end()) {
332 LOG((CLOG_DEBUG1 "can't find keyboard layout %08x", hkl));
333 return 0;
334 }
335
336 return i->second;
337#else
338 return 0;
339#endif
340}
341
342void
343CPMKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const
344{
345 LOG((CLOG_DEBUG "pollPressedKeys:"));
346 BYTE keyState[256];
347 if (WinSetKeyboardStateTable(HWND_DESKTOP, keyState, FALSE)) {
348 for (KeyButton i = 1; i < 256; ++i) {
349 if ((keyState[i] & 0x80) != 0) {
350 pressedKeys.insert(i);
351 }
352 }
353 }
354}
355
356static USHORT
357convertKeyModiferMaskToTCF(const KeyModifierMask mask)
358{
359 USHORT fShiftState = 0;
360 if (mask & KeyModifierShift) fShiftState |= TCF_SHIFT;
361 if (mask & KeyModifierControl) fShiftState |= TCF_CONTROL;
362 if (mask & KeyModifierAlt) fShiftState |= TCF_ALT;
363 if (mask & KeyModifierAltGr) fShiftState |= TCF_ALTGR;
364 if (mask & KeyModifierCapsLock) fShiftState |= TCF_CAPSLOCK;
365 if (mask & KeyModifierNumLock) fShiftState |= TCF_NUMLOCK;
366 return fShiftState;
367}
368
369static KeyModifierMask
370convertTCFToKeyModiferMask(const USHORT fShiftState)
371{
372 KeyModifierMask mask = 0;
373 if (fShiftState & TCF_SHIFT) mask |= KeyModifierShift;
374 if (fShiftState & TCF_CONTROL) mask |= KeyModifierControl;
375 if (fShiftState & TCF_ALT) mask |= KeyModifierAlt;
376 if (fShiftState & TCF_ALTGR) mask |= KeyModifierAltGr;
377 if (fShiftState & TCF_CAPSLOCK) mask |= KeyModifierCapsLock;
378 if (fShiftState & TCF_NUMLOCK) mask |= KeyModifierNumLock;
379 return mask;
380}
381
382static bool
383isASCIIControlChar(const USHORT usChar)
384{
385 switch (usChar) {
386 /* Skip the ones with virtual keys. */
387 case 0x08 + 0x40: case 0x08 + 0x60: // backspace
388 case 0x09 + 0x40: case 0x09 + 0x60: // horizontal tab
389 case 0x1b + 0x40: case 0x1b + 0x60: // escape
390 case 0x0d + 0x40: case 0x0d + 0x60: // return
391 return false;
392 default:
393 return (usChar >= 'A' && usChar <= '_')
394 || (usChar >= 'a' && usChar <= 'z');
395 }
396}
397
398void
399CPMKeyState::convertScancodes(ClientData *pData)
400{
401 /*
402 * This is a bit tricky / hackish, but what we have to do here is to
403 * deal with extended keys and the keypad stuff. The scancode
404 * translation tables doesn't seem to be 100% correct for these
405 * keys, and these keys are the ones we need them the most. sigh.
406 */
407
408 //
409 // navigation and insert/delete buttons left of the numpad:
410 // home, up, pgup, left, right, end, down, pgdn, insert, delete
411 //
412 // The pm and translated scancodes are mixed up in these cases.
413 // The keys are all extended and secondary.
414 //
415 if ( pData->s.xlatScan >= 0x60 /* VK_HOME */
416 && pData->s.xlatScan <= 0x69 /* VK_DELETE */
417 && pData->s.virtualKey != 0) {
418 pData->s.scan = pData->s.xlatScan;
419 pData->s.xlatScan = m_pmScanToOemScanExt[pData->s.xlatScan];
420 pData->s.fExtendedKey = true;
421 pData->s.fNeedNumUnlockKey = true;
422 pData->s.fSecondary = true;
423 return;
424 }
425
426 //
427 // There are some virtual keys we know are extended, mark them so (like the Fxx keys).
428 //
429 if ( pData->s.virtualKey < sizeof(s_virtualKey) / sizeof(s_virtualKey[0])
430 && !pData->s.fExtendedKey) {
431 if ( s_virtualKey[pData->s.virtualKey].extended == 1
432 || ( s_virtualKey[pData->s.virtualKey].extended == -1
433 && ( pData->s.xlatChar == 0
434 || pData->s.xlatChar == s_virtualKey[pData->s.virtualKey].ch))) {
435 pData->s.fExtendedKey = true;
436 }
437 }
438
439 //
440 // Do the translating.
441 //
442 if (pData->s.xlatScan == pData->s.scan) {
443 pData->s.scan = m_pmScanToOemScan[pData->s.xlatScan];
444 //if (pData->s.fExtendedKey) {
445 // pData->s.scan = m_pmScanToOemScanExt[pData->s.xlatScan];
446 //} else {
447 // pData->s.scan = m_pmScanToOemScan[pData->s.xlatScan];
448 //}
449 }
450}
451
452
453void
454CPMKeyState::getKeyMap(CKeyMap& keyMap)
455{
456 LOG((CLOG_DEBUG "getKeyMap:"));
457#if 0
458 // update keyboard groups
459 if (getGroups(m_groups)) {
460 m_groupMap.clear();
461 SInt32 numGroups = (SInt32)m_groups.size();
462 for (SInt32 g = 0; g < numGroups; ++g) {
463 m_groupMap[m_groups[g]] = g;
464 }
465 }
466 HKL activeLayout = GetKeyboardLayout(0);
467#endif
468
469 // clear table
470 memset(m_virtualKeyToButton, 0, sizeof(m_virtualKeyToButton));
471 m_keyToVKMap.clear();
472
473 CKeyMap::KeyItem item;
474 for (SInt32 g = 0; g < 1; ++g) {
475 item.m_group = g;
476
477 //
478 // Fill the scan code conversion tables.
479 //
480 for (unsigned i = 0; i < sizeof(m_pmScanToOemScan) / sizeof(m_pmScanToOemScan[0]); i++) {
481 USHORT us = i;
482 USHORT fShiftState = 0;
483 WinTranslateChar2(0, &us, NULL, TC_SCANTOOEMSCAN, &fShiftState);
484 m_pmScanToOemScan[i] = us;
485 }
486 for (unsigned i = 0; i < sizeof(m_pmScanToOemScanExt) / sizeof(m_pmScanToOemScanExt[0]); i++) {
487 USHORT us = i;
488 USHORT fShiftState = TCF_EXTENDEDKEY;
489 WinTranslateChar2(0, &us, NULL, TC_SCANTOOEMSCAN, &fShiftState);
490 m_pmScanToOemScanExt[i] = us;
491 }
492 for (unsigned i = 0; i < sizeof(m_oemScanToPmScan) / sizeof(m_oemScanToPmScan[0]); i++) {
493 USHORT us = i;
494 USHORT fShiftState = 0;
495 WinTranslateChar2(0, &us, NULL, TC_OEMSCANTOSCAN, &fShiftState);
496 m_oemScanToPmScan[i] = us;
497 }
498 for (unsigned i = 0; i < sizeof(m_oemScanToPmScanExt) / sizeof(m_oemScanToPmScanExt[0]); i++) {
499 USHORT us = i;
500 USHORT fShiftState = TCF_EXTENDEDKEY;
501 WinTranslateChar2(0, &us, NULL, TC_OEMSCANTOSCAN, &fShiftState);
502 m_oemScanToPmScanExt[i] = us;
503 }
504
505
506 //
507 // map buttons (scancodes) to virtual keys
508 //
509 memset(m_buttonToVK, 0, sizeof(m_buttonToVK));
510 for (KeyButton i = 1; i < 256; ++i) {
511 USHORT usVirtualKey = i;
512 USHORT fShiftState = 0;
513 WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
514 if ( usVirtualKey != 0
515 && m_buttonToVK[i] == 0) {
516 m_buttonToVK[i] = usVirtualKey;
517 }
518 }
519
520/// @todo the stuff down to the button loop isn't really done yet.
521
522 // now map virtual keys to buttons. multiple virtual keys may map
523 // to a single button. if the virtual key matches the one in
524 // m_buttonToVK then we use the button as is. if not then it's
525 // either a numpad key and we use the button as is or it's an
526 // extended button.
527 for (ULONG i = 1; i < 255; ++i) {
528 // skip virtual keys we don't want
529 switch (i) {
530 case VK_BUTTON1:
531 case VK_BUTTON2:
532 case VK_BUTTON3:
533 case VK_MENU:
534 continue;
535 }
536
537 // get the button
538 USHORT usButton = i;
539 USHORT fShiftState = 0;
540 WinTranslateChar2(0, &usButton, NULL, TC_VIRTUALKEYTOSCANCODE, &fShiftState);
541
542 // add extended key if virtual keys don't match
543 if ( usButton != 0
544 && m_buttonToVK[usButton] != i) {
545 m_buttonToVK[usButton | 0x100u] = i;
546 }
547 }
548
549 // set virtual key to button table
550// if (GetKeyboardLayout(0) == m_groups[g]) {
551 for (KeyButton i = 0; i < 512; ++i) {
552 if (m_buttonToVK[i] != 0) {
553 if (m_virtualKeyToButton[m_buttonToVK[i]] == 0) {
554 m_virtualKeyToButton[m_buttonToVK[i]] = i;
555 }
556 }
557 }
558// }
559
560 //
561 // Add the keys to the map.
562 //
563 //for (KeyButton i = 0; i < 256; ++i) {
564 for (KeyButton i = 0; i < 256; ++i) {
565 //
566 // Does this translate to a virtual key or character?
567 //
568 USHORT usChar = i;
569 USHORT fShiftState = 0;
570 USHORT fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
571 USHORT usVirtualKey = i;
572 USHORT fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
573 if (!usChar && !usVirtualKey) {
574 // try with control down.
575 usChar = i;
576 fShiftState = TCF_CONTROL;
577 fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
578 usVirtualKey = i;
579 fShiftState = TCF_CONTROL;
580 fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
581 }
582 if (!usChar && !usVirtualKey) {
583 // try with altgr down.
584 usChar = i;
585 fShiftState = TCF_ALTGR;
586 fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
587 usVirtualKey = i;
588 fShiftState = TCF_ALTGR;
589 fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
590 }
591 if (!usChar && !usVirtualKey) {
592 // try with numlock toggled.
593 usChar = i;
594 fShiftState = TCF_NUMLOCK;
595 fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
596 usVirtualKey = i;
597 fShiftState = TCF_NUMLOCK;
598 fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
599 }
600 if ( usChar
601 || usVirtualKey) {
602 // initialize the item
603 item.m_id = getKeyID(m_buttonToVK[i], i, false, usChar);
604 item.m_button = i;
605 item.m_required = 0;
606 item.m_sensitive = 0;
607 item.m_dead = false;
608 item.m_lock = false;
609
610 // get flags for modifier keys
611 CKeyMap::initModifierKey(item);
612 if (item.m_generates != 0) {
613 // it's a modifier key.
614 item.m_lock = usVirtualKey == VK_NUMLOCK
615 || usVirtualKey == VK_SCRLLOCK
616 || usVirtualKey == VK_CAPSLOCK;
617 ClientData data;
618 data.u = 0;
619 data.s.scan = i;
620 data.s.xlatScan = i;
621 data.s.fShiftKey = true;
622 data.s.xlatChar = usChar;
623 data.s.virtualKey = usVirtualKey;
624 convertScancodes(&data);
625 item.m_client = data.u;
626 addKeyEntry(keyMap, item);
627 } else {
628 //
629 // Check which keys it might be sensitive to.
630 // We assume (possibly incorrectly) that combinations doesn't matter... :)
631 //
632 static const struct {
633 KeyModifierMask mask;
634 unsigned fShiftState;
635 } modifiers[] = {
636 { KeyModifierShift, TCF_SHIFT},
637 { KeyModifierControl, TCF_CONTROL },
638 { KeyModifierAlt, TCF_ALT },
639 { KeyModifierAltGr, TCF_ALTGR },
640 { KeyModifierCapsLock, TCF_CAPSLOCK },
641 { KeyModifierNumLock, TCF_NUMLOCK }
642 };
643 usChar = i;
644 fShiftState = 0;
645 fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
646 usVirtualKey = i;
647 fShiftState = 0;
648 fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
649 for (unsigned j = 0; j < sizeof(modifiers) / sizeof(modifiers[0]); j++) {
650 USHORT usCh = i;
651 fShiftState = modifiers[j].fShiftState;
652 if ( WinTranslateChar2(0, &usCh, NULL, TC_SCANCODETOCHAR, &fShiftState) != 0
653 && usCh != 0
654 && usCh != usChar) {
655 item.m_sensitive |= modifiers[j].mask;
656 continue;
657 }
658 usCh = i;
659 fShiftState = modifiers[j].fShiftState;
660 WinTranslateChar2(0, &usCh, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
661 if ( usCh != 0
662 && usCh != usVirtualKey) {
663 item.m_sensitive |= modifiers[j].mask;
664 continue;
665 }
666 }
667 if (isASCIIControlChar(usChar)) {
668 item.m_sensitive |= KeyModifierControl;
669 }
670
671 //
672 // Check for numpad keys. We need to adjust stuff then.
673 // It think this test should be sufficient.
674 //
675 bool numpad = (item.m_sensitive & KeyModifierNumLock) != 0;
676
677 //
678 // Unoptimized brute force algorithm for determining the
679 // possible combinations and adding them to the key map.
680 //
681 struct
682 {
683 UCHAR uchChar;
684 UCHAR uchVirtualKey;
685 } combinations[1 << TCF_MAX_BITS];
686
687 for (unsigned j = 0; j < sizeof(combinations) / sizeof(combinations[0]); j++) {
688 const KeyModifierMask mask = convertTCFToKeyModiferMask(j);
689 if ((mask & item.m_sensitive) != mask /*|| j>3*/) {
690 combinations[j].uchChar = combinations[j].uchVirtualKey = 0;
691 continue;
692 }
693 // get any character value
694 USHORT us = i;
695 fShiftState = j;
696 if (WinTranslateChar2(0, &us, NULL, TC_SCANCODETOCHAR, &fShiftState) == 0) {
697 us = 0;
698 }
699 combinations[j].uchChar = us;
700
701 // get any virtual key value
702 us = i;
703 fShiftState = j;
704 WinTranslateChar2(0, &us, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
705 combinations[j].uchVirtualKey = us;
706
707 // deal with missing character translations
708 if ( combinations[j].uchChar == 0
709 && us != 0
710 && us < sizeof(s_virtualKey) / sizeof(s_virtualKey[0])) {
711 combinations[j].uchChar = s_virtualKey[us].ch;
712 }
713 }
714
715 // 2. Eliminate duplicates.
716 for (unsigned j = 0; j < sizeof(combinations) / sizeof(combinations[0]); j++) {
717 unsigned best = j;
718 KeyModifierMask bestMask = convertTCFToKeyModiferMask(j);
719 for (unsigned k = j + 1; k < sizeof(combinations) / sizeof(combinations[0]); k++) {
720 if ( combinations[best].uchChar == combinations[k].uchChar
721 && combinations[best].uchVirtualKey == combinations[k].uchVirtualKey) {
722 const KeyModifierMask mask = convertTCFToKeyModiferMask(k);
723 // drop L/R mixes.
724 if (mask == bestMask) {
725 combinations[k].uchChar = combinations[k].uchVirtualKey = 0;
726 }
727 }
728 }
729 }
730
731 // 3. Add the remainders.
732 for (unsigned j = 0; j < sizeof(combinations) / sizeof(combinations[0]); j++) {
733 if (combinations[j].uchChar || combinations[j].uchVirtualKey) {
734 USHORT usChar = combinations[j].uchChar;
735 USHORT usVirtualKey = combinations[j].uchVirtualKey;
736
737 // update the changing item members
738 item.m_required = convertTCFToKeyModiferMask(j);
739 if (usVirtualKey) {
740 switch (usVirtualKey) {
741 case VK_BACKTAB:
742 item.m_required |= KeyModifierShift;
743 item.m_sensitive |= KeyModifierShift;
744 usChar = 0; // this one is translated incorrectly
745 break;
746 }
747 item.m_id = getKeyID(usVirtualKey, i, numpad, usChar);
748 } else {
749 item.m_id = usChar; /// @todo translate to unicode!
750 }
751 ClientData data;
752 data.u = 0;
753 data.s.scan = i;
754 data.s.xlatScan = i;
755 data.s.xlatChar = usChar;
756 data.s.virtualKey = usVirtualKey;
757 convertScancodes(&data);
758 item.m_client = data.u;
759 addKeyEntry(keyMap, item);
760 }
761 }
762
763 // 4. ASCII Control Character variants. (ARG! this doesn't work, fakeMsg hacks it.)
764 if (isASCIIControlChar(usChar)) {
765 /* add key */
766 item.m_id = usChar - (usChar >= 'a' ? 0x60 : 0x40);
767 item.m_required = KeyModifierControl;
768 ClientData data;
769 data.u = 0;
770 data.s.scan = i;
771 data.s.xlatScan = i;
772 data.s.xlatChar = item.m_id;
773 convertScancodes(&data);
774 item.m_client = data.u;
775 addKeyEntry(keyMap, item);
776 item.m_id = usChar;
777 addKeyEntry(keyMap, item);
778 }
779 }
780 }
781 } // for buttons 0 thru 254
782
783 //
784 // Various other keys for which we don't expect the above loops to catch.
785 //
786 item.m_id = kKeyMenu;
787 item.m_button = 0xee;
788 item.m_required = 0;
789 item.m_sensitive = 0;
790 item.m_dead = false;
791 item.m_lock = false;
792 ClientData data;
793 data.u = 0;
794 data.s.scan = 0x7c;
795 data.s.xlatScan = 0xee;
796 data.s.fSecondary = true;
797 data.s.fExtendedKey = true;
798 data.s.fNeedNumUnlockKey = true;
799 item.m_client = data.u;
800 CKeyMap::initModifierKey(item);
801 addKeyEntry(keyMap, item);
802
803 item.m_id = kKeySuper_L;
804 item.m_button = 0xec;
805 data.s.xlatScan = 0xec;
806 data.s.scan = 0x7e;
807 item.m_client = data.u;
808 CKeyMap::initModifierKey(item);
809 addKeyEntry(keyMap, item);
810
811 item.m_id = kKeySuper_R;
812 item.m_button = 0xed;
813 data.s.xlatScan = 0xed;
814 data.s.scan = 0x7f;
815 item.m_client = data.u;
816 CKeyMap::initModifierKey(item);
817 addKeyEntry(keyMap, item);
818
819 }
820
821#if 0
822 // restore keyboard layout
823 ActivateKeyboardLayout(activeLayout, 0);
824#endif
825}
826
827void
828CPMKeyState::fakeKey(const Keystroke& keystroke)
829{
830 LOG((CLOG_DEBUG "fakeKey:"));
831 switch (keystroke.m_type) {
832 case Keystroke::kButton: {
833 LOG((CLOG_DEBUG1 " %03x (%08llx) %s%s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client,
834 keystroke.m_data.m_button.m_press ? "down" : "up", keystroke.m_data.m_button.m_repeat ? " repeate" : ""));
835 KeyButton button = keystroke.m_data.m_button.m_button;
836
837 // OS/2 doesn't send key ups for key repeats
838 if (keystroke.m_data.m_button.m_repeat &&
839 !keystroke.m_data.m_button.m_press) {
840 LOG((CLOG_DEBUG " discard key repeat release"));
841 break;
842 }
843
844 // unpack the m_client packet.
845 ClientData data;
846 data.u = keystroke.m_data.m_button.m_client;
847
848 //
849 // synthesize message
850 // There are two options at this point, WM_CHAR or WM_VIOCHAR. It seems
851 // like WM_VIOCHAR is the better choice since that's the form in which
852 // keyboard events normally arrive in the system queue.
853 //
854 // WM_VIOCHAR:
855 // mp1.s1: KC_ flags.
856 // mp1.c3: repeat
857 // mp1.c4: scancode
858 // mp2.c1: translated char
859 // mp2.c2: translated scancode
860 // mp2.s2: KDD_ flags.
861 //
862
863 // the standard bits.
864 HAB hab = CPMUtil::getHAB();/// @todo fix this
865 QMSG qmsg;
866 qmsg.hwnd = NULLHANDLE;
867 qmsg.msg = WM_VIOCHAR;
868 qmsg.ptl.x = 0;
869 qmsg.ptl.y = 0;
870 qmsg.time = WinGetCurrentTime(hab);
871 qmsg.reserved = 0;
872
873 //
874 // calc the key code flags.
875 // PM deals with: KC_TOGGLE, KC_VIRTUALKEY, KC_CHAR, (WM_CHAR: also KC_CTRL, KC_ALT, KC_SHIFT).
876 //
877 USHORT fKC = 0;
878 if (data.s.scan)
879 fKC |= KC_SCANCODE;
880 if (!keystroke.m_data.m_button.m_press)
881 fKC |= KC_KEYUP;
882 /// @todo check that PM does KC_INVALIDCOMP
883 if (data.s.fDeadKey)
884 fKC |= KC_DEADKEY;
885 if (data.s.fComposite)
886 fKC |= KC_COMPOSITE;
887 if (!keystroke.m_data.m_button.m_press && m_lastButton == data.s.scan)
888 fKC |= KC_LONEKEY;
889
890 // we need these for calcing fKDD, so just put them in even if PM can do it for us.
891 KeyModifierMask modifierMask = this->getActiveModifiers();
892 if (modifierMask & KeyModifierShift)
893 fKC |= KC_SHIFT;
894 if (modifierMask & KeyModifierControl)
895 fKC |= KC_CTRL;
896 if (modifierMask & KeyModifierAlt)
897 fKC |= KC_ALT;
898
899 //
900 // Calc the keyboard device driver flags.
901 //
902 USHORT fKDD;
903 // the action
904 if (data.s.fShiftKey)
905 fKDD = KDD_SHIFTKEY;
906/** @todo Determin the KDD_ACTIONMASK value.
907KDD_PREFIXKEY
908KDD_PAUSEKEY
909KDD_PSEUDOPAUSE
910KDD_WAKEUPKEY
911KDD_BREAKKEY
912KDD_PSEUDOBREAK
913KDD_PRTECHOKEY
914KDD_PSEUDOPRECH */
915 else
916 fKDD = KDD_PUTINKIB;
917#if 0
918 if (fKC & KC_LONEKEY) fKDD |= KDD_KC_LONEKEY;
919 if (fKC & KC_PREVDOWN) fKDD |= KDD_KC_PREVDOWN;
920 if (fKC & KC_KEYUP) fKDD |= KDD_KC_KEYUP | KDD_BREAK;
921 if (fKC & KC_ALT) fKDD |= KDD_KC_ALT;
922 if (fKC & KC_CTRL) fKDD |= KDD_KC_CTRL;
923 if (fKC & KC_SHIFT) fKDD |= KDD_KC_SHIFT;
924#else
925 if (fKC & KC_KEYUP) fKDD |= KDD_BREAK;
926#endif
927 if (data.s.fSecondary) fKDD |= KDD_SECONDARY;
928 if (data.s.fExtendedKey) fKDD |= KDD_EXTENDEDKEY;
929
930 //
931 // Adjust char for ASCII control keys. (Ctrl+C and stuff)
932 //
933 if ( (fKC & KC_CTRL)
934 && isASCIIControlChar(data.s.xlatChar)) {
935 data.s.xlatChar -= (data.s.xlatChar >= 'a' ? 0x60 : 0x40);
936 }
937
938 //
939 // For some keys (navigation and edit keys left to the numpad),
940 // any numlock or shift needs to be 'canceled'.
941 // (At least this happens with my logitech diNovo keyboards.)
942 //
943 if ( data.s.fNeedNumUnlockKey
944 && ( (modifierMask & (KeyModifierShift | KeyModifierNumLock)) == KeyModifierNumLock
945 || (modifierMask & (KeyModifierShift | KeyModifierNumLock)) == KeyModifierShift)) {
946 // need to insert a key nullifying the numlock/shift.
947 QMSG qmsg0 = qmsg;
948 qmsg0.mp1 = MPFROMSH2CH(fKC & KC_KEYUP, 1, 0);
949 qmsg0.mp2 = MPFROM2SHORT(MAKESHORT(0, 0x2a), (fKDD & KDD_BREAK) | KDD_UNDEFINED | KDD_SECONDARY | KDD_EXTENDEDKEY);
950
951 // this message comes first on keydown and last on keyup.
952 if (fKC & KC_KEYUP) {
953 QMSG tmp = qmsg;
954 qmsg = qmsg0;
955 qmsg0 = tmp;
956 }
957
958 LOG((CLOG_INFO "WM_VIOCHAR: fKC=%04x rep=%02x scan=%02x xlch=%02x(%c) xlscan=%02x fKDD=%04x ",
959 SHORT1FROMMP(qmsg0.mp1), CHAR3FROMMP(qmsg0.mp1), CHAR4FROMMP(qmsg0.mp1), CHAR1FROMMP(qmsg0.mp2),
960 isprint(CHAR1FROMMP(qmsg0.mp2)) ? CHAR1FROMMP(qmsg0.mp2) : '.', CHAR2FROMMP(qmsg0.mp2), SHORT2FROMMP(qmsg0.mp2)));
961 const char *pszError = m_fakeMsg(hab, &qmsg0);
962 if (pszError) {
963 LOG((CLOG_ERR " fakeMsg failed to inject msg=%#lx mp1=%#lx mp2=%#lx: %s", qmsg0.msg, qmsg0.mp1, qmsg0.mp2, pszError));
964 }
965 }
966
967 //
968 // Inject the (last) message.
969 //
970 qmsg.mp1 = MPFROMSH2CH(fKC, 1, data.s.scan);
971 qmsg.mp2 = MPFROM2SHORT(MAKESHORT(data.s.xlatChar, data.s.xlatScan), fKDD);
972 LOG((CLOG_INFO "WM_VIOCHAR: fKC=%04x rep=%02x scan=%02x xlch=%02x(%c) xlscan=%02x fKDD=%04x ",
973 SHORT1FROMMP(qmsg.mp1), CHAR3FROMMP(qmsg.mp1), CHAR4FROMMP(qmsg.mp1), CHAR1FROMMP(qmsg.mp2),
974 isprint(CHAR1FROMMP(qmsg.mp2)) ? CHAR1FROMMP(qmsg.mp2) : '.', CHAR2FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2)));
975 const char *pszError = m_fakeMsg(hab, &qmsg);
976 if (pszError) {
977 LOG((CLOG_ERR " fakeMsg failed to inject msg=%#lx mp1=%#lx mp2=%#lx: %s", qmsg.msg, qmsg.mp1, qmsg.mp2, pszError));
978 }
979
980 // remember the previous key for KC_LONEKEY.
981 if (keystroke.m_data.m_button.m_press && !keystroke.m_data.m_button.m_repeat)
982 m_lastButton = data.s.scan;
983 break;
984 }
985
986 case Keystroke::kGroup:
987#if 0
988 // we don't restore the group. we'd like to but we can't be
989 // sure the restoring group change will be processed after the
990 // key events.
991 if (!keystroke.m_data.m_group.m_restore) {
992 if (keystroke.m_data.m_group.m_absolute) {
993 LOG((CLOG_DEBUG1 " group %d", keystroke.m_data.m_group.m_group));
994 setWindowGroup(keystroke.m_data.m_group.m_group);
995 }
996 else {
997 LOG((CLOG_DEBUG1 " group %+d", keystroke.m_data.m_group.m_group));
998 setWindowGroup(getEffectiveGroup(pollActiveGroup(),
999 keystroke.m_data.m_group.m_group));
1000 }
1001 }
1002#endif
1003 break;
1004 }
1005}
1006
1007KeyModifierMask&
1008CPMKeyState::getActiveModifiersRValue()
1009{
1010 LOG((CLOG_DEBUG "getActiveModifiersRValue:"));
1011 if (m_useSavedModifiers) {
1012 return m_savedModifiers;
1013 }
1014 return CKeyState::getActiveModifiersRValue();
1015}
1016
1017KeyID
1018CPMKeyState::getKeyID(ULONG virtualKey, KeyButton button, bool numpad, USHORT usChar)
1019{
1020 LOG((CLOG_DEBUG "getKeyID:"));
1021 if (virtualKey < sizeof(s_virtualKey) / sizeof(s_virtualKey[0])) {
1022
1023 //
1024 // Numpad kludge.
1025 //
1026 if (numpad && s_virtualKey[virtualKey].numpad) {
1027 switch (usChar) {
1028 case '=': return kKeyKP_Equal;
1029 case '*': return kKeyKP_Multiply;
1030 case '+': return kKeyKP_Add;
1031 //case ',':
1032 //case '.': return kKeyKP_Separator ? kKeyKP_Decimal;
1033 case '-': return kKeyKP_Subtract;
1034 case '/': return kKeyKP_Divide;
1035 case '0': return kKeyKP_0;
1036 case '1': return kKeyKP_1;
1037 case '2': return kKeyKP_2;
1038 case '3': return kKeyKP_3;
1039 case '4': return kKeyKP_4;
1040 case '5': return kKeyKP_5;
1041 case '6': return kKeyKP_6;
1042 case '7': return kKeyKP_7;
1043 case '8': return kKeyKP_8;
1044 case '9': return kKeyKP_9;
1045 case ' ': return kKeyKP_Space;
1046 }
1047 switch (s_virtualKey[virtualKey].key) {
1048 case kKeyHome: return kKeyKP_Home;
1049 case kKeyLeft: return kKeyKP_Left;
1050 case kKeyUp: return kKeyKP_Up;
1051 case kKeyRight: return kKeyKP_Right;
1052 case kKeyDown: return kKeyKP_Down;
1053 case kKeyPageUp: return kKeyKP_PageUp;
1054 case kKeyPageDown: return kKeyKP_PageDown;
1055 case kKeyEnd: return kKeyKP_End;
1056 case kKeyBegin: return kKeyKP_Begin;
1057 case kKeyInsert: return kKeyKP_Insert;
1058 case kKeyDelete: return kKeyKP_Delete;
1059 }
1060 } else {
1061 //
1062 // Left/right shift and control kludge.
1063 //