00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "CArchMiscWindows.h"
00016 #include "CMSWindowsKeyState.h"
00017 #include "CConfig.h"
00018 #include "CHotkeyOptions.h"
00019 #include "CStringUtil.h"
00020 #include "LaunchUtil.h"
00021 #include "resource.h"
00022
00023 #if !defined(WM_XBUTTONDOWN)
00024 #define WM_XBUTTONDOWN 0x020B
00025 #define WM_XBUTTONUP 0x020C
00026 #define WM_XBUTTONDBLCLK 0x020D
00027 #define XBUTTON1 0x0001
00028 #define XBUTTON2 0x0002
00029 #endif
00030
00031
00032
00033
00034
00035 CHotkeyOptions* CHotkeyOptions::s_singleton = NULL;
00036
00037 CHotkeyOptions::CHotkeyOptions(HWND parent, CConfig* config) :
00038 m_parent(parent),
00039 m_config(config)
00040 {
00041 assert(s_singleton == NULL);
00042 s_singleton = this;
00043 }
00044
00045 CHotkeyOptions::~CHotkeyOptions()
00046 {
00047 s_singleton = NULL;
00048 }
00049
00050 void
00051 CHotkeyOptions::doModal()
00052 {
00053
00054 m_inputFilter = m_config->getInputFilter();
00055 DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_HOTKEY_OPTIONS),
00056 m_parent, (DLGPROC)dlgProc, (LPARAM)this);
00057 }
00058
00059 void
00060 CHotkeyOptions::doInit(HWND hwnd)
00061 {
00062 m_activeRuleIndex = (UInt32)-1;
00063 fillHotkeys(hwnd);
00064 openRule(hwnd);
00065 }
00066
00067 void
00068 CHotkeyOptions::fillHotkeys(HWND hwnd, UInt32 select)
00069 {
00070 HWND rules = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
00071
00072 SendMessage(rules, LB_RESETCONTENT, 0, 0);
00073 for (UInt32 i = 0, n = m_inputFilter->getNumRules(); i < n; ++i) {
00074 CInputFilter::CRule& rule = m_inputFilter->getRule(i);
00075 SendMessage(rules, LB_INSERTSTRING, (WPARAM)-1,
00076 (LPARAM)rule.getCondition()->format().c_str());
00077 }
00078
00079 if (select < m_inputFilter->getNumRules()) {
00080 SendMessage(rules, LB_SETCURSEL, select, 0);
00081 }
00082
00083 updateHotkeysControls(hwnd);
00084 }
00085
00086 void
00087 CHotkeyOptions::updateHotkeysControls(HWND hwnd)
00088 {
00089 HWND child = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
00090 bool selected = (SendMessage(child, LB_GETCURSEL, 0, 0) != LB_ERR);
00091
00092 enableItem(hwnd, IDC_HOTKEY_ADD_HOTKEY, TRUE);
00093 enableItem(hwnd, IDC_HOTKEY_EDIT_HOTKEY, selected);
00094 enableItem(hwnd, IDC_HOTKEY_REMOVE_HOTKEY, selected);
00095 }
00096
00097 void
00098 CHotkeyOptions::addHotkey(HWND hwnd)
00099 {
00100 closeRule(hwnd);
00101 CInputFilter::CCondition* condition = NULL;
00102 if (editCondition(hwnd, condition)) {
00103 m_inputFilter->addFilterRule(CInputFilter::CRule(condition));
00104 fillHotkeys(hwnd, m_inputFilter->getNumRules() - 1);
00105 }
00106 else {
00107 delete condition;
00108 }
00109 openRule(hwnd);
00110 }
00111
00112 void
00113 CHotkeyOptions::removeHotkey(HWND hwnd)
00114 {
00115 UInt32 ruleIndex = m_activeRuleIndex;
00116 closeRule(hwnd);
00117
00118 m_inputFilter->removeFilterRule(ruleIndex);
00119 UInt32 n = m_inputFilter->getNumRules();
00120 if (n > 0 && ruleIndex >= n) {
00121 ruleIndex = n - 1;
00122 }
00123 fillHotkeys(hwnd, ruleIndex);
00124
00125 openRule(hwnd);
00126 }
00127
00128 void
00129 CHotkeyOptions::editHotkey(HWND hwnd)
00130 {
00131
00132 HWND actions = getItem(hwnd, IDC_HOTKEY_ACTIONS);
00133 LRESULT aIndex = SendMessage(actions, LB_GETCURSEL, 0, 0);
00134
00135 UInt32 index = m_activeRuleIndex;
00136 closeRule(hwnd);
00137
00138 CInputFilter::CRule& rule = m_inputFilter->getRule(index);
00139 CInputFilter::CCondition* condition = rule.getCondition()->clone();
00140 if (editCondition(hwnd, condition)) {
00141 rule.setCondition(condition);
00142 fillHotkeys(hwnd, index);
00143 }
00144 else {
00145 delete condition;
00146 }
00147
00148 openRule(hwnd);
00149
00150
00151 if (aIndex != LB_ERR) {
00152 SendMessage(actions, LB_SETCURSEL, aIndex, 0);
00153 }
00154 }
00155
00156 void
00157 CHotkeyOptions::fillActions(HWND hwnd, UInt32 select)
00158 {
00159 HWND actions = getItem(hwnd, IDC_HOTKEY_ACTIONS);
00160 SendMessage(actions, LB_RESETCONTENT, 0, 0);
00161 if (m_activeRuleIndex != (UInt32)-1) {
00162 UInt32 n = m_activeRule.getNumActions(true);
00163 UInt32 n2 = m_activeRule.getNumActions(false);
00164 for (UInt32 i = 0; i < n; ++i) {
00165 const CInputFilter::CAction& action =
00166 m_activeRule.getAction(true, i);
00167 CString line("A ");
00168 line += action.format();
00169 SendMessage(actions, LB_INSERTSTRING, (WPARAM)-1,
00170 (LPARAM)line.c_str());
00171 SendMessage(actions, LB_SETITEMDATA, (WPARAM)i, (LPARAM)i);
00172 }
00173 for (UInt32 i = 0; i < n2; ++i) {
00174 const CInputFilter::CAction& action =
00175 m_activeRule.getAction(false, i);
00176 CString line("D ");
00177 line += action.format();
00178 SendMessage(actions, LB_INSERTSTRING, (WPARAM)-1,
00179 (LPARAM)line.c_str());
00180 SendMessage(actions, LB_SETITEMDATA, (WPARAM)i + n,
00181 (LPARAM)(i | 0x80000000u));
00182 }
00183
00184 if (select < n + n2) {
00185 SendMessage(actions, LB_SETCURSEL, select, 0);
00186 }
00187 }
00188
00189 updateActionsControls(hwnd);
00190 }
00191
00192 void
00193 CHotkeyOptions::updateActionsControls(HWND hwnd)
00194 {
00195 HWND child = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
00196 bool active = (m_activeRuleIndex != (UInt32)-1);
00197
00198 child = getItem(hwnd, IDC_HOTKEY_ACTIONS);
00199 bool selected =
00200 (active && (SendMessage(child, LB_GETCURSEL, 0, 0) != LB_ERR));
00201
00202 enableItem(hwnd, IDC_HOTKEY_ADD_ACTION, active);
00203 enableItem(hwnd, IDC_HOTKEY_EDIT_ACTION, selected);
00204 enableItem(hwnd, IDC_HOTKEY_REMOVE_ACTION, selected);
00205 }
00206
00207 void
00208 CHotkeyOptions::addAction(HWND hwnd)
00209 {
00210 CInputFilter::CAction* action = NULL;
00211 bool onActivate = true;
00212 if (editAction(hwnd, action, onActivate)) {
00213 m_activeRule.adoptAction(action, onActivate);
00214
00215 UInt32 actionIndex = m_activeRule.getNumActions(true) - 1;
00216 if (!onActivate) {
00217 actionIndex += m_activeRule.getNumActions(false);
00218 }
00219 fillActions(hwnd, actionIndex);
00220 }
00221 else {
00222 delete action;
00223 }
00224 }
00225
00226 void
00227 CHotkeyOptions::removeAction(HWND hwnd)
00228 {
00229 HWND child = getItem(hwnd, IDC_HOTKEY_ACTIONS);
00230 LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
00231 if (index != LB_ERR) {
00232 UInt32 actionIndex =
00233 (UInt32)SendMessage(child, LB_GETITEMDATA, index, 0);
00234 bool onActivate = ((actionIndex & 0x80000000u) == 0);
00235 actionIndex &= ~0x80000000u;
00236
00237 m_activeRule.removeAction(onActivate, actionIndex);
00238
00239 actionIndex = static_cast<UInt32>(index);
00240 UInt32 n = m_activeRule.getNumActions(true) +
00241 m_activeRule.getNumActions(false);
00242 if (n > 0 && actionIndex >= n) {
00243 actionIndex = n - 1;
00244 }
00245 fillActions(hwnd, actionIndex);
00246 }
00247 }
00248
00249 void
00250 CHotkeyOptions::editAction(HWND hwnd)
00251 {
00252 HWND child = getItem(hwnd, IDC_HOTKEY_ACTIONS);
00253 LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
00254 if (index != LB_ERR) {
00255 UInt32 actionIndex =
00256 (UInt32)SendMessage(child, LB_GETITEMDATA, index, 0);
00257 bool onActivate = ((actionIndex & 0x80000000u) == 0);
00258 actionIndex &= ~0x80000000u;
00259
00260 CInputFilter::CAction* action =
00261 m_activeRule.getAction(onActivate, actionIndex).clone();
00262 bool newOnActivate = onActivate;
00263 if (editAction(hwnd, action, newOnActivate)) {
00264 if (onActivate == newOnActivate) {
00265 m_activeRule.replaceAction(action, onActivate, actionIndex);
00266 actionIndex = static_cast<UInt32>(index);
00267 }
00268 else {
00269 m_activeRule.removeAction(onActivate, actionIndex);
00270 m_activeRule.adoptAction(action, newOnActivate);
00271 actionIndex = m_activeRule.getNumActions(true) - 1;
00272 if (!newOnActivate) {
00273 actionIndex += m_activeRule.getNumActions(false);
00274 }
00275 }
00276 fillActions(hwnd, actionIndex);
00277 }
00278 else {
00279 delete action;
00280 }
00281 }
00282 }
00283
00284 bool
00285 CHotkeyOptions::editCondition(HWND hwnd, CInputFilter::CCondition*& condition)
00286 {
00287 return CConditionDialog::doModal(hwnd, condition);
00288 }
00289
00290 bool
00291 CHotkeyOptions::editAction(HWND hwnd, CInputFilter::CAction*& action,
00292 bool& onActivate)
00293 {
00294 return CActionDialog::doModal(hwnd, m_config, action, onActivate);
00295 }
00296
00297 void
00298 CHotkeyOptions::openRule(HWND hwnd)
00299 {
00300
00301
00302
00303 HWND rules = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
00304 LRESULT index = SendMessage(rules, LB_GETCURSEL, 0, 0);
00305 if (index != LB_ERR) {
00306
00307 m_activeRuleIndex = (SInt32)index;
00308 m_activeRule = m_inputFilter->getRule(m_activeRuleIndex);
00309
00310
00311 for (UInt32 i = 0, n = m_activeRule.getNumActions(true); i < n; ++i) {
00312
00313 const CInputFilter::CAction* action =
00314 &m_activeRule.getAction(true, i);
00315
00316
00317 const CInputFilter::CKeystrokeAction* keyAction =
00318 dynamic_cast<const CInputFilter::CKeystrokeAction*>(action);
00319 const CInputFilter::CMouseButtonAction* mouseAction =
00320 dynamic_cast<const CInputFilter::CMouseButtonAction*>(action);
00321 if (keyAction == NULL && mouseAction == NULL) {
00322 continue;
00323 }
00324
00325
00326 UInt32 j = (UInt32)-1;
00327 CInputFilter::CAction* newAction = NULL;
00328 if (keyAction != NULL) {
00329 j = findMatchingAction(keyAction);
00330 if (j != (UInt32)-1) {
00331
00332 const IPlatformScreen::CKeyInfo* oldInfo =
00333 keyAction->getInfo();
00334 IPlatformScreen::CKeyInfo* newInfo =
00335 IKeyState::CKeyInfo::alloc(*oldInfo);
00336 newAction = new CKeystrokeDownUpAction(newInfo);
00337 }
00338 }
00339 else if (mouseAction != NULL) {
00340 j = findMatchingAction(mouseAction);
00341 if (j != (UInt32)-1) {
00342
00343 const IPlatformScreen::CButtonInfo* oldInfo =
00344 mouseAction->getInfo();
00345 IPlatformScreen::CButtonInfo* newInfo =
00346 IPrimaryScreen::CButtonInfo::alloc(*oldInfo);
00347 newAction = new CMouseButtonDownUpAction(newInfo);
00348 }
00349 }
00350
00351
00352 if (newAction != NULL) {
00353 m_activeRule.replaceAction(newAction, true, i);
00354 m_activeRule.removeAction(false, j);
00355 }
00356 }
00357 }
00358 else {
00359 m_activeRuleIndex = (UInt32)-1;
00360 }
00361 fillActions(hwnd);
00362 }
00363
00364 void
00365 CHotkeyOptions::closeRule(HWND)
00366 {
00367
00368
00369 if (m_activeRuleIndex != (UInt32)-1) {
00370
00371 for (UInt32 i = 0, n = m_activeRule.getNumActions(true); i < n; ++i) {
00372
00373 const CInputFilter::CAction* action =
00374 &m_activeRule.getAction(true, i);
00375
00376
00377 const CKeystrokeDownUpAction* keyAction =
00378 dynamic_cast<const CKeystrokeDownUpAction*>(action);
00379 const CMouseButtonDownUpAction* mouseAction =
00380 dynamic_cast<const CMouseButtonDownUpAction*>(action);
00381 if (keyAction == NULL && mouseAction == NULL) {
00382 continue;
00383 }
00384
00385
00386 if (keyAction != NULL) {
00387 const IPlatformScreen::CKeyInfo* oldInfo =
00388 keyAction->getInfo();
00389 IPlatformScreen::CKeyInfo* newInfo =
00390 IKeyState::CKeyInfo::alloc(*oldInfo);
00391 CInputFilter::CKeystrokeAction* downAction =
00392 new CInputFilter::CKeystrokeAction(newInfo, true);
00393 newInfo = IKeyState::CKeyInfo::alloc(*oldInfo);
00394 CInputFilter::CKeystrokeAction* upAction =
00395 new CInputFilter::CKeystrokeAction(newInfo, false);
00396 m_activeRule.replaceAction(downAction, true, i);
00397 m_activeRule.adoptAction(upAction, false);
00398 }
00399 else if (mouseAction != NULL) {
00400 const IPlatformScreen::CButtonInfo* oldInfo =
00401 mouseAction->getInfo();
00402 IPlatformScreen::CButtonInfo* newInfo =
00403 IPrimaryScreen::CButtonInfo::alloc(*oldInfo);
00404 CInputFilter::CMouseButtonAction* downAction =
00405 new CInputFilter::CMouseButtonAction(newInfo, true);
00406 newInfo = IPrimaryScreen::CButtonInfo::alloc(*oldInfo);
00407 CInputFilter::CMouseButtonAction* upAction =
00408 new CInputFilter::CMouseButtonAction(newInfo, false);
00409 m_activeRule.replaceAction(downAction, true, i);
00410 m_activeRule.adoptAction(upAction, false);
00411 }
00412 }
00413
00414
00415 m_inputFilter->getRule(m_activeRuleIndex) = m_activeRule;
00416 }
00417 m_activeRuleIndex = (UInt32)-1;
00418 }
00419
00420 UInt32
00421 CHotkeyOptions::findMatchingAction(
00422 const CInputFilter::CKeystrokeAction* src) const
00423 {
00424 for (UInt32 i = 0, n = m_activeRule.getNumActions(false); i < n; ++i) {
00425 const CInputFilter::CKeystrokeAction* dst =
00426 dynamic_cast<const CInputFilter::CKeystrokeAction*>(
00427 &m_activeRule.getAction(false, i));
00428 if (dst != NULL &&
00429 IKeyState::CKeyInfo::equal(src->getInfo(), dst->getInfo())) {
00430 return i;
00431 }
00432 }
00433 return (UInt32)-1;
00434 }
00435
00436 UInt32
00437 CHotkeyOptions::findMatchingAction(
00438 const CInputFilter::CMouseButtonAction* src) const
00439 {
00440 for (UInt32 i = 0, n = m_activeRule.getNumActions(false); i < n; ++i) {
00441 const CInputFilter::CMouseButtonAction* dst =
00442 dynamic_cast<const CInputFilter::CMouseButtonAction*>(
00443 &m_activeRule.getAction(false, i));
00444 if (dst != NULL &&
00445 IPrimaryScreen::CButtonInfo::equal(
00446 src->getInfo(), dst->getInfo())) {
00447 return i;
00448 }
00449 }
00450 return (UInt32)-1;
00451 }
00452
00453 BOOL
00454 CHotkeyOptions::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
00455 {
00456 switch (message) {
00457 case WM_INITDIALOG:
00458 doInit(hwnd);
00459 return TRUE;
00460
00461 case WM_COMMAND:
00462 switch (LOWORD(wParam)) {
00463 case IDOK:
00464 case IDCANCEL:
00465 closeRule(hwnd);
00466 EndDialog(hwnd, 0);
00467 return TRUE;
00468
00469 case IDC_HOTKEY_HOTKEYS:
00470 switch (HIWORD(wParam)) {
00471 case LBN_DBLCLK:
00472 editHotkey(hwnd);
00473 return TRUE;
00474
00475 case LBN_SELCHANGE: {
00476 HWND rules = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
00477 LRESULT index = SendMessage(rules, LB_GETCURSEL, 0, 0);
00478 if (m_activeRuleIndex != (UInt32)index) {
00479 closeRule(hwnd);
00480 updateHotkeysControls(hwnd);
00481 openRule(hwnd);
00482 }
00483 return TRUE;
00484 }
00485 }
00486 break;
00487
00488 case IDC_HOTKEY_ADD_HOTKEY:
00489 addHotkey(hwnd);
00490 return TRUE;
00491
00492 case IDC_HOTKEY_REMOVE_HOTKEY:
00493 removeHotkey(hwnd);
00494 return TRUE;
00495
00496 case IDC_HOTKEY_EDIT_HOTKEY:
00497 editHotkey(hwnd);
00498 return TRUE;
00499
00500 case IDC_HOTKEY_ACTIONS:
00501 switch (HIWORD(wParam)) {
00502 case LBN_DBLCLK:
00503 editAction(hwnd);
00504 return TRUE;
00505
00506 case LBN_SELCHANGE:
00507 updateActionsControls(hwnd);
00508 return TRUE;
00509 }
00510 break;
00511
00512 case IDC_HOTKEY_ADD_ACTION:
00513 addAction(hwnd);
00514 return TRUE;
00515
00516 case IDC_HOTKEY_REMOVE_ACTION:
00517 removeAction(hwnd);
00518 return TRUE;
00519
00520 case IDC_HOTKEY_EDIT_ACTION:
00521 editAction(hwnd);
00522 return TRUE;
00523 }
00524 break;
00525
00526 default:
00527 break;
00528 }
00529
00530 return FALSE;
00531 }
00532
00533 BOOL CALLBACK
00534 CHotkeyOptions::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
00535 {
00536 return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
00537 }
00538
00539
00540
00541
00542
00543
00544 CInputFilter::CCondition*
00545 CHotkeyOptions::CConditionDialog::s_condition = NULL;
00546 CInputFilter::CCondition*
00547 CHotkeyOptions::CConditionDialog::s_lastGoodCondition = NULL;
00548 WNDPROC CHotkeyOptions::CConditionDialog::s_editWndProc = NULL;
00549
00550 bool
00551 CHotkeyOptions::CConditionDialog::doModal(HWND parent,
00552 CInputFilter::CCondition*& condition)
00553 {
00554 s_condition = condition;
00555 if (s_condition != NULL) {
00556 s_lastGoodCondition = s_condition->clone();
00557 }
00558 else {
00559 s_lastGoodCondition = NULL;
00560 }
00561 int n = DialogBox(s_instance, MAKEINTRESOURCE(IDD_HOTKEY_CONDITION),
00562 parent, (DLGPROC) dlgProc);
00563
00564 condition = s_condition;
00565 delete s_lastGoodCondition;
00566 s_condition = NULL;
00567 s_lastGoodCondition = NULL;
00568
00569
00570 if (condition == NULL) {
00571 n = 0;
00572 }
00573
00574 return (n == 1);
00575 }
00576
00577 void
00578 CHotkeyOptions::CConditionDialog::doInit(HWND hwnd)
00579 {
00580
00581 HWND child = getItem(hwnd, IDC_HOTKEY_CONDITION_HOTKEY);
00582 s_editWndProc = (WNDPROC)GetWindowLongPtr(child, GWLP_WNDPROC);
00583 SetWindowLongPtr(child, GWLP_WNDPROC, (LONG_PTR) editProc);
00584
00585
00586 fillHotkey(hwnd);
00587 }
00588
00589 void
00590 CHotkeyOptions::CConditionDialog::fillHotkey(HWND hwnd)
00591 {
00592 HWND child = getItem(hwnd, IDC_HOTKEY_CONDITION_HOTKEY);
00593 if (s_condition != NULL) {
00594 setWindowText(child, s_condition->format().c_str());
00595 }
00596 else {
00597 setWindowText(child, "");
00598 }
00599 }
00600
00601 void
00602 CHotkeyOptions::CConditionDialog::onButton(HWND hwnd, ButtonID button)
00603 {
00604 delete s_condition;
00605 s_condition =
00606 new CInputFilter::CMouseButtonCondition(button, getModifiers());
00607
00608 fillHotkey(GetParent(hwnd));
00609 }
00610
00611 void
00612 CHotkeyOptions::CConditionDialog::onKey(HWND hwnd, WPARAM wParam, LPARAM lParam)
00613 {
00614
00615 if ((lParam & 0xc0000000u) == 0x40000000u) {
00616 return;
00617 }
00618
00619
00620
00621 if ((lParam & 0x80000000u) != 0) {
00622 if (isGoodCondition() || wParam == VK_TAB) {
00623 return;
00624 }
00625 }
00626
00627 KeyID key = kKeyNone;
00628 KeyModifierMask mask = getModifiers();
00629 switch (wParam) {
00630 case VK_SHIFT:
00631 case VK_LSHIFT:
00632 case VK_RSHIFT:
00633 case VK_CONTROL:
00634 case VK_LCONTROL:
00635 case VK_RCONTROL:
00636 case VK_MENU:
00637 case VK_LMENU:
00638 case VK_RMENU:
00639 case VK_LWIN:
00640 case VK_RWIN:
00641 break;
00642
00643 case VK_TAB:
00644
00645 if ((mask & (KeyModifierControl |
00646 KeyModifierAlt | KeyModifierSuper)) == 0) {
00647 HWND next = hwnd;
00648 if ((mask & KeyModifierShift) == 0) {
00649 do {
00650 next = GetWindow(next, GW_HWNDNEXT);
00651 if (next == NULL) {
00652 next = GetWindow(hwnd, GW_HWNDFIRST);
00653 }
00654 } while (next != hwnd &&
00655 (!IsWindowVisible(next) ||
00656 (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP) == 0));
00657 }
00658 else {
00659 do {
00660 next = GetWindow(next, GW_HWNDPREV);
00661 if (next == NULL) {
00662 next = GetWindow(hwnd, GW_HWNDLAST);
00663 }
00664 } while (next != hwnd &&
00665 (!IsWindowVisible(next) ||
00666 (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP) == 0));
00667 }
00668 SetFocus(next);
00669 return;
00670 }
00671
00672
00673 default:
00674 key = CMSWindowsKeyState::getKeyID(wParam,
00675 static_cast<KeyButton>((lParam & 0x1ff0000u) >> 16));
00676 switch (key) {
00677 case kKeyNone:
00678
00679 key = getChar(wParam, lParam);
00680 if (key == kKeyNone) {
00681 return;
00682 }
00683 break;
00684
00685 case kKeyShift_L:
00686 case kKeyShift_R:
00687 case kKeyControl_L:
00688 case kKeyControl_R:
00689 case kKeyAlt_L:
00690 case kKeyAlt_R:
00691 case kKeyMeta_L:
00692 case kKeyMeta_R:
00693 case kKeySuper_L:
00694 case kKeySuper_R:
00695 case kKeyCapsLock:
00696 case kKeyNumLock:
00697 case kKeyScrollLock:
00698
00699 return;
00700 }
00701 break;
00702 }
00703
00704 delete s_condition;
00705 s_condition = new CInputFilter::CKeystrokeCondition(key, mask);
00706
00707 fillHotkey(GetParent(hwnd));
00708 }
00709
00710 KeyID
00711 CHotkeyOptions::CConditionDialog::getChar(WPARAM wParam, LPARAM lParam)
00712 {
00713 BYTE keyState[256];
00714 UINT virtualKey = (UINT)wParam;
00715 UINT scanCode = (UINT)((lParam & 0x0ff0000u) >> 16);
00716 GetKeyboardState(keyState);
00717
00718
00719 keyState[VK_SHIFT] = 0;
00720 keyState[VK_LSHIFT] = 0;
00721 keyState[VK_RSHIFT] = 0;
00722 keyState[VK_CONTROL] = 0;
00723 keyState[VK_LCONTROL] = 0;
00724 keyState[VK_RCONTROL] = 0;
00725 keyState[VK_MENU] = 0;
00726 keyState[VK_LMENU] = 0;
00727 keyState[VK_RMENU] = 0;
00728 keyState[VK_LWIN] = 0;
00729 keyState[VK_RWIN] = 0;
00730
00731
00732 int n;
00733 KeyID id;
00734 if (CArchMiscWindows::isWindows95Family()) {
00735
00736 WORD ascii;
00737 n = ToAscii(virtualKey, scanCode, keyState, &ascii, 0);
00738 id = static_cast<KeyID>(ascii & 0xffu);
00739 }
00740 else {
00741 typedef int (WINAPI *ToUnicode_t)(UINT wVirtKey,
00742 UINT wScanCode,
00743 PBYTE lpKeyState,
00744 LPWSTR pwszBuff,
00745 int cchBuff,
00746 UINT wFlags);
00747 ToUnicode_t s_ToUnicode = NULL;
00748 if (s_ToUnicode == NULL) {
00749 HMODULE userModule = GetModuleHandle("user32.dll");
00750 s_ToUnicode =
00751 (ToUnicode_t)GetProcAddress(userModule, "ToUnicode");
00752 }
00753
00754 WCHAR unicode[2];
00755 n = s_ToUnicode(virtualKey, scanCode, keyState,
00756 unicode, sizeof(unicode) / sizeof(unicode[0]),
00757 0);
00758 id = static_cast<KeyID>(unicode[0]);
00759 }
00760 switch (n) {
00761 case -1:
00762
00763 return kKeyNone;
00764
00765 default:
00766 case 0:
00767
00768 return kKeyNone;
00769
00770 case 1:
00771 return id;
00772 }
00773 }
00774
00775 KeyModifierMask
00776 CHotkeyOptions::CConditionDialog::getModifiers()
00777 {
00778 KeyModifierMask mask = 0;
00779 if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) {
00780 mask |= KeyModifierShift;
00781 }
00782 if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) {
00783 mask |= KeyModifierControl;
00784 }
00785 if ((GetKeyState(VK_MENU) & 0x8000) != 0) {
00786 mask |= KeyModifierAlt;
00787 }
00788 if ((GetKeyState(VK_LWIN) & 0x8000) != 0 ||
00789 (GetKeyState(VK_RWIN) & 0x8000) != 0) {
00790 mask |= KeyModifierSuper;
00791 }
00792 return mask;
00793 }
00794
00795 bool
00796 CHotkeyOptions::CConditionDialog::isGoodCondition()
00797 {
00798 CInputFilter::CKeystrokeCondition* keyCondition =
00799 dynamic_cast<CInputFilter::CKeystrokeCondition*>(s_condition);
00800 return (keyCondition == NULL || keyCondition->getKey() != kKeyNone);
00801 }
00802
00803 BOOL CALLBACK
00804 CHotkeyOptions::CConditionDialog::dlgProc(HWND hwnd,
00805 UINT message, WPARAM wParam, LPARAM)
00806 {
00807 switch (message) {
00808 case WM_INITDIALOG:
00809 doInit(hwnd);
00810 return TRUE;
00811
00812 case WM_COMMAND:
00813 switch (LOWORD(wParam)) {
00814 case IDOK:
00815 EndDialog(hwnd, 1);
00816 return TRUE;
00817
00818 case IDCANCEL:
00819 EndDialog(hwnd, 0);
00820 return TRUE;
00821 }
00822 break;
00823
00824 default:
00825 break;
00826 }
00827
00828 return FALSE;
00829 }
00830
00831 LRESULT CALLBACK
00832 CHotkeyOptions::CConditionDialog::editProc(HWND hwnd,
00833 UINT message, WPARAM wParam, LPARAM lParam)
00834 {
00835 switch (message) {
00836 case WM_LBUTTONDOWN:
00837 if (GetFocus() == hwnd) {
00838 onButton(hwnd, kButtonLeft);
00839 }
00840 else {
00841 SetFocus(hwnd);
00842 }
00843 return 0;
00844
00845 case WM_MBUTTONDOWN:
00846 if (GetFocus() == hwnd) {
00847 onButton(hwnd, kButtonMiddle);
00848 }
00849 return 0;
00850
00851 case WM_RBUTTONDOWN:
00852 if (GetFocus() == hwnd) {
00853 onButton(hwnd, kButtonRight);
00854 }
00855 return 0;
00856
00857 case WM_XBUTTONDOWN:
00858 if (GetFocus() == hwnd) {
00859 switch (HIWORD(wParam)) {
00860 case XBUTTON1:
00861 onButton(hwnd, kButtonExtra0 + 0);
00862 break;
00863
00864 case XBUTTON2:
00865 onButton(hwnd, kButtonExtra0 + 1);
00866 break;
00867 }
00868 }
00869 return 0;
00870
00871 case WM_KEYDOWN:
00872 case WM_SYSKEYDOWN:
00873 case WM_KEYUP:
00874 case WM_SYSKEYUP:
00875 onKey(hwnd, wParam, lParam);
00876 return 0;
00877
00878 case WM_LBUTTONUP:
00879 case WM_MBUTTONUP:
00880 case WM_RBUTTONUP:
00881 case WM_XBUTTONUP:
00882 case WM_CHAR:
00883 case WM_SYSCHAR:
00884 case WM_DEADCHAR:
00885 case WM_SYSDEADCHAR:
00886 return 0;
00887
00888 case WM_SETFOCUS:
00889 if (s_condition != NULL) {
00890 delete s_lastGoodCondition;
00891 s_lastGoodCondition = s_condition->clone();
00892 }
00893 break;
00894
00895 case WM_KILLFOCUS:
00896 if (!isGoodCondition()) {
00897 delete s_condition;
00898 if (s_lastGoodCondition != NULL) {
00899 s_condition = s_lastGoodCondition->clone();
00900 }
00901 else {
00902 s_condition = NULL;
00903 }
00904 }
00905 fillHotkey(GetParent(hwnd));
00906 break;
00907
00908 case WM_GETDLGCODE:
00909 return DLGC_WANTALLKEYS;
00910
00911 default:
00912 break;
00913 }
00914 return CallWindowProc(s_editWndProc, hwnd, message, wParam, lParam);
00915 }
00916
00917
00918
00919
00920
00921
00922 CConfig* CHotkeyOptions::CActionDialog::s_config = NULL;
00923 bool CHotkeyOptions::CActionDialog::s_onActivate = false;
00924 CInputFilter::CAction*
00925 CHotkeyOptions::CActionDialog::s_action = NULL;
00926 CInputFilter::CAction*
00927 CHotkeyOptions::CActionDialog::s_lastGoodAction = NULL;
00928 std::set<CString>
00929 CHotkeyOptions::CActionDialog::s_screens;
00930 WNDPROC CHotkeyOptions::CActionDialog::s_editWndProc = NULL;
00931
00932 bool
00933 CHotkeyOptions::CActionDialog::doModal(HWND parent, CConfig* config,
00934 CInputFilter::CAction*& action, bool& onActivate)
00935 {
00936 s_config = config;
00937 s_onActivate = onActivate;
00938 s_action = action;
00939 if (s_action != NULL) {
00940 s_lastGoodAction = s_action->clone();
00941 }
00942 else {
00943 s_lastGoodAction = NULL;
00944 }
00945
00946 int n = DialogBox(s_instance, MAKEINTRESOURCE(IDD_HOTKEY_ACTION),
00947 parent, (DLGPROC) dlgProc);
00948
00949 onActivate = s_onActivate;
00950 action = s_action;
00951 delete s_lastGoodAction;
00952 s_action = NULL;
00953 s_lastGoodAction = NULL;
00954
00955 return (n == 1);
00956 }
00957
00958 void
00959 CHotkeyOptions::CActionDialog::doInit(HWND hwnd)
00960 {
00961
00962 HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY);
00963 s_editWndProc = (WNDPROC)GetWindowLongPtr(child, GWLP_WNDPROC);
00964 SetWindowLongPtr(child, GWLP_WNDPROC, (LONG_PTR)editProc);
00965 setWindowText(getItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY), "");
00966 fillHotkey(hwnd);
00967
00968
00969 child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST);
00970 SendMessage(child, CB_RESETCONTENT, 0, 0);
00971 for (CConfig::const_iterator index = s_config->begin();
00972 index != s_config->end(); ) {
00973 const CString& name = *index;
00974 ++index;
00975 if (index != s_config->end()) {
00976 SendMessage(child, CB_INSERTSTRING,
00977 (WPARAM)-1, (LPARAM)name.c_str());
00978 }
00979 else {
00980 SendMessage(child, CB_ADDSTRING, 0, (LPARAM)name.c_str());
00981 }
00982 }
00983 SendMessage(child, CB_SETCURSEL, 0, 0);
00984
00985
00986 child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST);
00987 SendMessage(child, CB_ADDSTRING, 0,
00988 (LPARAM)getString(IDS_EDGE_LEFT).c_str());
00989 SendMessage(child, CB_ADDSTRING, 0,
00990 (LPARAM)getString(IDS_EDGE_RIGHT).c_str());
00991 SendMessage(child, CB_ADDSTRING, 0,
00992 (LPARAM)getString(IDS_EDGE_TOP).c_str());
00993 SendMessage(child, CB_ADDSTRING, 0,
00994 (LPARAM)getString(IDS_EDGE_BOTTOM).c_str());
00995 SendMessage(child, CB_SETCURSEL, 0, 0);
00996
00997
00998 child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST);
00999 SendMessage(child, CB_ADDSTRING, 0,
01000 (LPARAM)getString(IDS_MODE_OFF).c_str());
01001 SendMessage(child, CB_ADDSTRING, 0,
01002 (LPARAM)getString(IDS_MODE_ON).c_str());
01003 SendMessage(child, CB_ADDSTRING, 0,
01004 (LPARAM)getString(IDS_MODE_TOGGLE).c_str());
01005 SendMessage(child, CB_SETCURSEL, 0, 0);
01006
01007
01008 child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST);
01009 SendMessage(child, CB_ADDSTRING, 0,
01010 (LPARAM)getString(IDS_MODE_OFF).c_str());
01011 SendMessage(child, CB_ADDSTRING, 0,
01012 (LPARAM)getString(IDS_MODE_ON).c_str());
01013 SendMessage(child, CB_ADDSTRING, 0,
01014 (LPARAM)getString(IDS_MODE_TOGGLE).c_str());
01015 SendMessage(child, CB_SETCURSEL, 0, 0);
01016
01017
01018 if (s_onActivate) {
01019 child = getItem(hwnd, IDC_HOTKEY_ACTION_ON_ACTIVATE);
01020 }
01021 else {
01022 child = getItem(hwnd, IDC_HOTKEY_ACTION_ON_DEACTIVATE);
01023 }
01024 setItemChecked(child, true);
01025
01026
01027 s_screens.clear();
01028
01029
01030 child = NULL;
01031 CInputFilter::CKeystrokeAction* keyAction =
01032 dynamic_cast<CInputFilter::CKeystrokeAction*>(s_action);
01033 CInputFilter::CMouseButtonAction* mouseAction =
01034 dynamic_cast<CInputFilter::CMouseButtonAction*>(s_action);
01035 CInputFilter::CLockCursorToScreenAction* lockAction =
01036 dynamic_cast<CInputFilter::CLockCursorToScreenAction*>(s_action);
01037 CInputFilter::CSwitchToScreenAction* switchToAction =
01038 dynamic_cast<CInputFilter::CSwitchToScreenAction*>(s_action);
01039 CInputFilter::CSwitchInDirectionAction* switchInAction =
01040 dynamic_cast<CInputFilter::CSwitchInDirectionAction*>(s_action);
01041 CInputFilter::CKeyboardBroadcastAction* keyboardBroadcastAction=
01042 dynamic_cast<CInputFilter::CKeyboardBroadcastAction*>(s_action);
01043 if (keyAction != NULL) {
01044 if (dynamic_cast<CKeystrokeDownUpAction*>(s_action) != NULL) {
01045 child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP);
01046 }
01047 else if (keyAction->isOnPress()) {
01048 child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWN);
01049 }
01050 else {
01051 child = getItem(hwnd, IDC_HOTKEY_ACTION_UP);
01052 }
01053 }
01054 else if (mouseAction != NULL) {
01055 if (dynamic_cast<CMouseButtonDownUpAction*>(s_action) != NULL) {
01056 child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP);
01057 }
01058 else if (keyAction->isOnPress()) {
01059 child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWN);
01060 }
01061 else {
01062 child = getItem(hwnd, IDC_HOTKEY_ACTION_UP);
01063 }
01064 }
01065 else if (lockAction != NULL) {
01066 child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST);
01067 SendMessage(child, CB_SETCURSEL, lockAction->getMode(), 0);
01068 child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK);
01069 }
01070 else if (switchToAction != NULL) {
01071 child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST);
01072 DWORD i = SendMessage(child, CB_FINDSTRINGEXACT, (WPARAM)-1,
01073 (LPARAM)switchToAction->getScreen().c_str());
01074 if (i == CB_ERR) {
01075 i = 0;
01076 }
01077 SendMessage(child, CB_SETCURSEL, i, 0);
01078 child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO);
01079 }
01080 else if (switchInAction != NULL) {
01081 child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST);
01082 SendMessage(child, CB_SETCURSEL,
01083 switchInAction->getDirection() - kLeft, 0);
01084 child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN);
01085 }
01086 else if (keyboardBroadcastAction != NULL) {
01087
01088 s_screens = keyboardBroadcastAction->getScreens();
01089
01090 child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST);
01091 SendMessage(child, CB_SETCURSEL, keyboardBroadcastAction->getMode(), 0);
01092 child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST);
01093 }
01094 if (child != NULL) {
01095 setItemChecked(child, true);
01096 }
01097
01098 updateControls(hwnd);
01099 }
01100
01101 void
01102 CHotkeyOptions::CActionDialog::fillHotkey(HWND hwnd)
01103 {
01104 HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY);
01105 CInputFilter::CKeystrokeAction* keyAction =
01106 dynamic_cast<CInputFilter::CKeystrokeAction*>(s_action);
01107 CInputFilter::CMouseButtonAction* mouseAction =
01108 dynamic_cast<CInputFilter::CMouseButtonAction*>(s_action);
01109 if (keyAction != NULL || mouseAction != NULL) {
01110 setWindowText(child, s_action->format().c_str());
01111 }
01112 else {
01113 setWindowText(child, "");
01114 }
01115
01116
01117 enableItem(hwnd, IDC_HOTKEY_ACTION_SCREENS, keyAction != NULL);
01118 }
01119
01120 void
01121 CHotkeyOptions::CActionDialog::updateControls(HWND hwnd)
01122 {
01123
01124 UInt32 mode = 0;
01125 if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP)) ||
01126 isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWN)) ||
01127 isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_UP))) {
01128 mode = 1;
01129 }
01130 else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO))) {
01131 mode = 2;
01132 }
01133 else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN))) {
01134 mode = 3;
01135 }
01136 else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_LOCK))) {
01137 mode = 4;
01138 }
01139 else if (isItemChecked(getItem(hwnd,
01140 IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST))) {
01141 mode = 5;
01142 }
01143
01144
01145 enableItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY, mode == 1);
01146 enableItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST, mode == 2);
01147 enableItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST, mode == 3);
01148 enableItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST, mode == 4);
01149 enableItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST, mode == 5);
01150 enableItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS, mode == 5);
01151
01152
01153 CInputFilter::CKeystrokeAction* keyAction =
01154 dynamic_cast<CInputFilter::CKeystrokeAction*>(s_action);
01155 enableItem(hwnd, IDC_HOTKEY_ACTION_SCREENS, keyAction != NULL);
01156 }
01157
01158 void
01159 CHotkeyOptions::CActionDialog::onButton(HWND hwnd, ButtonID button)
01160 {
01161 IPlatformScreen::CButtonInfo* info =
01162 IPrimaryScreen::CButtonInfo::alloc(button, getModifiers());
01163 delete s_action;
01164 HWND parent = GetParent(hwnd);
01165 if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_DOWNUP))) {
01166 s_action = new CMouseButtonDownUpAction(info);
01167 }
01168 else if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_DOWN))) {
01169 s_action = new CInputFilter::CMouseButtonAction(info, true);
01170 }
01171 else if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_UP))) {
01172 s_action = new CInputFilter::CMouseButtonAction(info, false);
01173 }
01174 else {
01175 s_action = NULL;
01176 }
01177
01178 fillHotkey(parent);
01179 }
01180
01181 void
01182 CHotkeyOptions::CActionDialog::onKey(HWND hwnd, WPARAM wParam, LPARAM lParam)
01183 {
01184
01185 if ((lParam & 0xc0000000u) == 0x40000000u) {
01186 return;
01187 }
01188
01189
01190
01191 if ((lParam & 0x80000000u) != 0) {
01192 if (isGoodAction() || wParam == VK_TAB) {
01193 return;
01194 }
01195 }
01196
01197 KeyID key = kKeyNone;
01198 KeyModifierMask mask = getModifiers();
01199 switch (wParam) {
01200 case VK_SHIFT:
01201 case VK_LSHIFT:
01202 case VK_RSHIFT:
01203 case VK_CONTROL:
01204 case VK_LCONTROL:
01205 case VK_RCONTROL:
01206 case VK_MENU:
01207 case VK_LMENU:
01208 case VK_RMENU:
01209 case VK_LWIN:
01210 case VK_RWIN:
01211 break;
01212
01213 case VK_TAB:
01214
01215 if ((mask & (KeyModifierControl |
01216 KeyModifierAlt | KeyModifierSuper)) == 0) {
01217 HWND next = hwnd;
01218 if ((mask & KeyModifierShift) == 0) {
01219 do {
01220 next = GetWindow(next, GW_HWNDNEXT);
01221 if (next == NULL) {
01222 next = GetWindow(hwnd, GW_HWNDFIRST);
01223 }
01224 } while (next != hwnd &&
01225 (!IsWindowVisible(next) ||
01226 (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP) == 0));
01227 }
01228 else {
01229 do {
01230 next = GetWindow(next, GW_HWNDPREV);
01231 if (next == NULL) {
01232 next = GetWindow(hwnd, GW_HWNDLAST);
01233 }
01234 } while (next != hwnd &&
01235 (!IsWindowVisible(next) ||
01236 (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP) == 0));
01237 }
01238 SetFocus(next);
01239 return;
01240 }
01241
01242
01243 default:
01244 key = CMSWindowsKeyState::getKeyID(wParam,
01245 static_cast<KeyButton>((lParam & 0x1ff0000u) >> 16));
01246 switch (key) {
01247 case kKeyNone:
01248
01249 key = getChar(wParam, lParam);
01250 if (key == kKeyNone) {
01251 return;
01252 }
01253 break;
01254
01255 case kKeyShift_L:
01256 case kKeyShift_R:
01257 case kKeyControl_L:
01258 case kKeyControl_R:
01259 case kKeyAlt_L:
01260 case kKeyAlt_R:
01261 case kKeyMeta_L:
01262 case kKeyMeta_R:
01263 case kKeySuper_L:
01264 case kKeySuper_R:
01265 case kKeyCapsLock:
01266 case kKeyNumLock:
01267 case kKeyScrollLock:
01268
01269 return;
01270 }
01271 break;
01272 }
01273
01274
01275 std::set<CString> screens;
01276 CInputFilter::CKeystrokeAction* keyAction =
01277 dynamic_cast<CInputFilter::CKeystrokeAction*>(s_action);
01278 if (keyAction == NULL) {
01279 keyAction =
01280 dynamic_cast<CInputFilter::CKeystrokeAction*>(s_lastGoodAction);
01281 }
01282 if (keyAction != NULL) {
01283 IKeyState::CKeyInfo::split(keyAction->getInfo()->m_screens, screens);
01284 }
01285
01286
01287 IPlatformScreen::CKeyInfo* info =
01288 IKeyState::CKeyInfo::alloc(key, mask, 0, 0, screens);
01289 delete s_action;
01290 HWND parent = GetParent(hwnd);
01291 if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_DOWNUP))) {
01292 s_action = new CKeystrokeDownUpAction(info);
01293 }
01294 else if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_DOWN))) {
01295 s_action = new CInputFilter::CKeystrokeAction(info, true);
01296 }
01297 else if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_UP))) {
01298 s_action = new CInputFilter::CKeystrokeAction(info, false);
01299 }
01300 else {
01301 s_action = NULL;
01302 }
01303
01304 fillHotkey(parent);
01305 }
01306
01307 void
01308 CHotkeyOptions::CActionDialog::onLockAction(HWND hwnd)
01309 {
01310 HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST);
01311 LRESULT index = SendMessage(child, CB_GETCURSEL, 0, 0);
01312 if (index != CB_ERR) {
01313 delete s_action;
01314 s_action = new CInputFilter::CLockCursorToScreenAction(
01315 (CInputFilter::CLockCursorToScreenAction::Mode)index);
01316 }
01317 }
01318
01319 void
01320 CHotkeyOptions::CActionDialog::onSwitchToAction(HWND hwnd)
01321 {
01322 HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST);
01323 CString screen = getWindowText(child);
01324 delete s_action;
01325 s_action = new CInputFilter::CSwitchToScreenAction(screen);
01326 }
01327
01328 void
01329 CHotkeyOptions::CActionDialog::onSwitchInAction(HWND hwnd)
01330 {
01331 HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST);
01332 LRESULT index = SendMessage(child, CB_GETCURSEL, 0, 0);
01333 if (index != CB_ERR) {
01334 delete s_action;
01335 s_action = new CInputFilter::CSwitchInDirectionAction(
01336 (EDirection)(index + kLeft));
01337 }
01338 }
01339
01340 void
01341 CHotkeyOptions::CActionDialog::onKeyboardBroadcastAction(HWND hwnd)
01342 {
01343 HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST);
01344 LRESULT index = SendMessage(child, CB_GETCURSEL, 0, 0);
01345 if (index != CB_ERR) {
01346 delete s_action;
01347 s_action = new CInputFilter::CKeyboardBroadcastAction(
01348 (CInputFilter::CKeyboardBroadcastAction::Mode)index, s_screens);
01349 }
01350 }
01351
01352 KeyID
01353 CHotkeyOptions::CActionDialog::getChar(WPARAM wParam, LPARAM lParam)
01354 {
01355 BYTE keyState[256];
01356 UINT virtualKey = (UINT)wParam;
01357 UINT scanCode = (UINT)((lParam & 0x0ff0000u) >> 16);
01358 GetKeyboardState(keyState);
01359
01360
01361 keyState[VK_SHIFT] = 0;
01362 keyState[VK_LSHIFT] = 0;
01363 keyState[VK_RSHIFT] = 0;
01364 keyState[VK_CONTROL] = 0;
01365 keyState[VK_LCONTROL] = 0;
01366 keyState[VK_RCONTROL] = 0;
01367 keyState[VK_MENU] = 0;
01368 keyState[VK_LMENU] = 0;
01369 keyState[VK_RMENU] = 0;
01370 keyState[VK_LWIN] = 0;
01371 keyState[VK_RWIN] = 0;
01372
01373
01374 int n;
01375 KeyID id;
01376 if (CArchMiscWindows::isWindows95Family()) {
01377
01378 WORD ascii;
01379 n = ToAscii(virtualKey, scanCode, keyState, &ascii, 0);
01380 id = static_cast<KeyID>(ascii & 0xffu);
01381 }
01382 else {
01383 typedef int (WINAPI *ToUnicode_t)(UINT wVirtKey,
01384 UINT wScanCode,
01385 PBYTE lpKeyState,
01386 LPWSTR pwszBuff,
01387 int cchBuff,
01388 UINT wFlags);
01389 ToUnicode_t s_ToUnicode = NULL;
01390 if (s_ToUnicode == NULL) {
01391 HMODULE userModule = GetModuleHandle("user32.dll");
01392 s_ToUnicode =
01393 (ToUnicode_t)GetProcAddress(userModule, "ToUnicode");
01394 }
01395
01396 WCHAR unicode[2];
01397 n = s_ToUnicode(virtualKey, scanCode, keyState,
01398 unicode, sizeof(unicode) / sizeof(unicode[0]),
01399 0);
01400 id = static_cast<KeyID>(unicode[0]);
01401 }
01402 switch (n) {
01403 case -1:
01404
01405 return kKeyNone;
01406
01407 default:
01408 case 0:
01409
01410 return kKeyNone;
01411
01412 case 1:
01413 return id;
01414 }
01415 }
01416
01417 KeyModifierMask
01418 CHotkeyOptions::CActionDialog::getModifiers()
01419 {
01420 KeyModifierMask mask = 0;
01421 if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) {
01422 mask |= KeyModifierShift;
01423 }
01424 if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) {
01425 mask |= KeyModifierControl;
01426 }
01427 if ((GetKeyState(VK_MENU) & 0x8000) != 0) {
01428 mask |= KeyModifierAlt;
01429 }
01430 if ((GetKeyState(VK_LWIN) & 0x8000) != 0 ||
01431 (GetKeyState(VK_RWIN) & 0x8000) != 0) {
01432 mask |= KeyModifierSuper;
01433 }
01434 return mask;
01435 }
01436
01437 bool
01438 CHotkeyOptions::CActionDialog::isGoodAction()
01439 {
01440 CInputFilter::CMouseButtonAction* mouseAction =
01441 dynamic_cast<CInputFilter::CMouseButtonAction*>(s_action);
01442 CInputFilter::CKeystrokeAction* keyAction =
01443 dynamic_cast<CInputFilter::CKeystrokeAction*>(s_action);
01444 return (mouseAction == NULL || keyAction == NULL ||
01445 keyAction->getInfo()->m_key != kKeyNone);
01446 }
01447
01448 void
01449 CHotkeyOptions::CActionDialog::convertAction(HWND hwnd)
01450 {
01451 if (s_lastGoodAction != NULL) {
01452 CInputFilter::CMouseButtonAction* mouseAction =
01453 dynamic_cast<CInputFilter::CMouseButtonAction*>(s_lastGoodAction);
01454 CInputFilter::CKeystrokeAction* keyAction =
01455 dynamic_cast<CInputFilter::CKeystrokeAction*>(s_lastGoodAction);
01456 if (mouseAction != NULL) {
01457 IPlatformScreen::CButtonInfo* info =
01458 IPrimaryScreen::CButtonInfo::alloc(*mouseAction->getInfo());
01459 delete s_action;
01460 if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP))) {
01461 s_action = new CMouseButtonDownUpAction(info);
01462 }
01463 else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWN))) {
01464 s_action = new CInputFilter::CMouseButtonAction(info, true);
01465 }
01466 else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_UP))) {
01467 s_action = new CInputFilter::CMouseButtonAction(info, false);
01468 }
01469 else {
01470 free(info);
01471 s_action = NULL;
01472 }
01473 }
01474 else if (keyAction != NULL) {
01475 IPlatformScreen::CKeyInfo* info =
01476 IKeyState::CKeyInfo::alloc(*keyAction->getInfo());
01477 delete s_action;
01478 if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP))) {
01479 s_action = new CKeystrokeDownUpAction(info);
01480 }
01481 else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWN))) {
01482 s_action = new CInputFilter::CKeystrokeAction(info, true);
01483 }
01484 else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_UP))) {
01485 s_action = new CInputFilter::CKeystrokeAction(info, false);
01486 }
01487 else {
01488 free(info);
01489 s_action = NULL;
01490 }
01491 }
01492 }
01493 }
01494
01495 bool
01496 CHotkeyOptions::CActionDialog::isDownUpAction()
01497 {
01498 return (dynamic_cast<CKeystrokeDownUpAction*>(s_action) != NULL ||
01499 dynamic_cast<CMouseButtonDownUpAction*>(s_action) != NULL);
01500 }
01501
01502 BOOL CALLBACK
01503 CHotkeyOptions::CActionDialog::dlgProc(HWND hwnd,
01504 UINT message, WPARAM wParam, LPARAM)
01505 {
01506 switch (message) {
01507 case WM_INITDIALOG:
01508 doInit(hwnd);
01509 return TRUE;
01510
01511 case WM_COMMAND:
01512 switch (LOWORD(wParam)) {
01513 case IDOK:
01514 if (isDownUpAction()) {
01515 s_onActivate = true;
01516 }
01517 EndDialog(hwnd, 1);
01518 return TRUE;
01519
01520 case IDCANCEL:
01521 EndDialog(hwnd, 0);
01522 return TRUE;
01523
01524 case IDC_HOTKEY_ACTION_ON_ACTIVATE:
01525 s_onActivate = true;
01526 return TRUE;
01527
01528 case IDC_HOTKEY_ACTION_ON_DEACTIVATE:
01529 s_onActivate = false;
01530 return TRUE;
01531
01532 case IDC_HOTKEY_ACTION_DOWNUP:
01533 case IDC_HOTKEY_ACTION_DOWN:
01534 case IDC_HOTKEY_ACTION_UP:
01535 convertAction(hwnd);
01536 fillHotkey(hwnd);
01537 updateControls(hwnd);
01538 return TRUE;
01539
01540 case IDC_HOTKEY_ACTION_LOCK:
01541 onLockAction(hwnd);
01542 updateControls(hwnd);
01543 return TRUE;
01544
01545 case IDC_HOTKEY_ACTION_SWITCH_TO:
01546 onSwitchToAction(hwnd);
01547 updateControls(hwnd);
01548 return TRUE;
01549
01550 case IDC_HOTKEY_ACTION_SWITCH_IN:
01551 onSwitchInAction(hwnd);
01552 updateControls(hwnd);
01553 return TRUE;
01554
01555 case IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST:
01556 onKeyboardBroadcastAction(hwnd);
01557 updateControls(hwnd);
01558 return TRUE;
01559
01560 case IDC_HOTKEY_ACTION_LOCK_LIST:
01561 switch (HIWORD(wParam)) {
01562 case LBN_SELCHANGE:
01563 onLockAction(hwnd);
01564 return TRUE;
01565 }
01566 break;
01567
01568 case IDC_HOTKEY_ACTION_SWITCH_TO_LIST:
01569 switch (HIWORD(wParam)) {
01570 case LBN_SELCHANGE:
01571 onSwitchToAction(hwnd);
01572 return TRUE;
01573 }
01574 break;
01575
01576 case IDC_HOTKEY_ACTION_SWITCH_IN_LIST:
01577 switch (HIWORD(wParam)) {
01578 case LBN_SELCHANGE:
01579 onSwitchInAction(hwnd);
01580 return TRUE;
01581 }
01582 break;
01583
01584 case IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST:
01585 switch (HIWORD(wParam)) {
01586 case LBN_SELCHANGE:
01587 onKeyboardBroadcastAction(hwnd);
01588 return TRUE;
01589 }
01590 break;
01591
01592 case IDC_HOTKEY_ACTION_SCREENS:
01593 CScreensDialog::doModal(hwnd, s_config,
01594 dynamic_cast<CInputFilter::CKeystrokeAction*>(s_action));
01595 fillHotkey(hwnd);
01596 return TRUE;
01597
01598 case IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS: {
01599
01600 IPlatformScreen::CKeyInfo* tmpInfo =
01601 IPlatformScreen::CKeyInfo::alloc(0, 0, 0, 1, s_screens);
01602 CInputFilter::CKeystrokeAction tmpAction(tmpInfo, true);
01603
01604
01605 CScreensDialog::doModal(hwnd, s_config, &tmpAction);
01606
01607
01608 IPlatformScreen::CKeyInfo::split(
01609 tmpAction.getInfo()->m_screens, s_screens);
01610
01611
01612 onKeyboardBroadcastAction(hwnd);
01613 return TRUE;
01614 }
01615 }
01616 break;
01617
01618 default:
01619 break;
01620 }
01621
01622 return FALSE;
01623 }
01624
01625 LRESULT CALLBACK
01626 CHotkeyOptions::CActionDialog::editProc(HWND hwnd,
01627 UINT message, WPARAM wParam, LPARAM lParam)
01628 {
01629 switch (message) {
01630 case WM_LBUTTONDOWN:
01631 if (GetFocus() == hwnd) {
01632 onButton(hwnd, kButtonLeft);
01633 }
01634 else {
01635 SetFocus(hwnd);
01636 }
01637 return 0;
01638
01639 case WM_MBUTTONDOWN:
01640 if (GetFocus() == hwnd) {
01641 onButton(hwnd, kButtonMiddle);
01642 }
01643 return 0;
01644
01645 case WM_RBUTTONDOWN:
01646 if (GetFocus() == hwnd) {
01647 onButton(hwnd, kButtonRight);
01648 }
01649 return 0;
01650
01651 case WM_XBUTTONDOWN:
01652 if (GetFocus() == hwnd) {
01653 switch (HIWORD(wParam)) {
01654 case XBUTTON1:
01655 onButton(hwnd, kButtonExtra0 + 0);
01656 break;
01657
01658 case XBUTTON2:
01659 onButton(hwnd, kButtonExtra0 + 1);
01660 break;
01661 }
01662 }
01663 return 0;
01664
01665 case WM_KEYDOWN:
01666 case WM_SYSKEYDOWN:
01667 case WM_KEYUP:
01668 case WM_SYSKEYUP:
01669 onKey(hwnd, wParam, lParam);
01670 return 0;
01671
01672 case WM_LBUTTONUP:
01673 case WM_MBUTTONUP:
01674 case WM_RBUTTONUP:
01675 case WM_XBUTTONUP:
01676 case WM_CHAR:
01677 case WM_SYSCHAR:
01678 case WM_DEADCHAR:
01679 case WM_SYSDEADCHAR:
01680 return 0;
01681
01682 case WM_SETFOCUS:
01683 if (s_action != NULL) {
01684 delete s_lastGoodAction;
01685 s_lastGoodAction = s_action->clone();
01686 }
01687 break;
01688
01689 case WM_KILLFOCUS:
01690 if (!isGoodAction()) {
01691 delete s_action;
01692 if (s_lastGoodAction != NULL) {
01693 s_action = s_lastGoodAction->clone();
01694 }
01695 else {
01696 s_action = NULL;
01697 }
01698 }
01699 else if (s_action != NULL) {
01700 delete s_lastGoodAction;
01701 s_lastGoodAction = s_action->clone();
01702 }
01703 fillHotkey(GetParent(hwnd));
01704 break;
01705
01706 case WM_GETDLGCODE:
01707 return DLGC_WANTALLKEYS;
01708
01709 default:
01710 break;
01711 }
01712 return CallWindowProc(s_editWndProc, hwnd, message, wParam, lParam);
01713 }
01714
01715
01716
01717
01718
01719
01720 CConfig* CHotkeyOptions::CScreensDialog::s_config = NULL;
01721 CInputFilter::CKeystrokeAction*
01722 CHotkeyOptions::CScreensDialog::s_action = NULL;
01723 CHotkeyOptions::CScreensDialog::CScreens
01724 CHotkeyOptions::CScreensDialog::s_nonTargets;
01725 CHotkeyOptions::CScreensDialog::CScreens
01726 CHotkeyOptions::CScreensDialog::s_targets;
01727 CString CHotkeyOptions::CScreensDialog::s_allScreens;
01728
01729 void
01730 CHotkeyOptions::CScreensDialog::doModal(HWND parent, CConfig* config,
01731 CInputFilter::CKeystrokeAction* action)
01732 {
01733 s_allScreens = getString(IDS_ALL_SCREENS);
01734 s_config = config;
01735 s_action = action;
01736 DialogBox(s_instance, MAKEINTRESOURCE(IDD_HOTKEY_SCREENS),
01737 parent, (DLGPROC) dlgProc);
01738 s_config = NULL;
01739 s_action = NULL;
01740 }
01741
01742 void
01743 CHotkeyOptions::CScreensDialog::doInit(HWND hwnd)
01744 {
01745 s_nonTargets.clear();
01746 s_targets.clear();
01747
01748
01749 s_nonTargets.insert("*");
01750 for (CConfig::const_iterator i = s_config->begin();
01751 i != s_config->end(); ++i) {
01752 s_nonTargets.insert(*i);
01753 }
01754
01755
01756 IKeyState::CKeyInfo::split(s_action->getInfo()->m_screens, s_targets);
01757
01758
01759 for (CScreens::const_iterator i = s_targets.begin();
01760 i != s_targets.end(); ++i) {
01761 s_nonTargets.erase(*i);
01762 }
01763
01764
01765 fillScreens(hwnd);
01766 updateControls(hwnd);
01767 }
01768
01769 void
01770 CHotkeyOptions::CScreensDialog::doFini(HWND)
01771 {
01772
01773 const IPlatformScreen::CKeyInfo* oldInfo = s_action->getInfo();
01774 IPlatformScreen::CKeyInfo* newInfo =
01775 IKeyState::CKeyInfo::alloc(oldInfo->m_key,
01776 oldInfo->m_mask, 0, 0, s_targets);
01777 s_action->adoptInfo(newInfo);
01778 }
01779
01780 void
01781 CHotkeyOptions::CScreensDialog::fillScreens(HWND hwnd)
01782 {
01783 HWND child = getItem(hwnd, IDC_HOTKEY_SCREENS_SRC);
01784 SendMessage(child, LB_RESETCONTENT, 0, 0);
01785 for (CScreens::const_iterator i = s_nonTargets.begin();
01786 i != s_nonTargets.end(); ++i) {
01787 CString name = *i;
01788 if (name == "*") {
01789 name = s_allScreens;
01790 }
01791 SendMessage(child, LB_INSERTSTRING, (WPARAM)-1,
01792 (LPARAM)name.c_str());
01793 }
01794
01795 child = getItem(hwnd, IDC_HOTKEY_SCREENS_DST);
01796 SendMessage(child, LB_RESETCONTENT, 0, 0);
01797 for (CScreens::const_iterator i = s_targets.begin();
01798 i != s_targets.end(); ++i) {
01799 CString name = *i;
01800 if (name == "*") {
01801 name = s_allScreens;
01802 }
01803 SendMessage(child, LB_INSERTSTRING, (WPARAM)-1,
01804 (LPARAM)name.c_str());
01805 }
01806 if (s_targets.empty()) {
01807
01808
01809 CString activeScreenLabel = getString(IDS_ACTIVE_SCREEN);
01810 SendMessage(child, LB_INSERTSTRING, (WPARAM)-1,
01811 (LPARAM)activeScreenLabel.c_str());
01812 }
01813 }
01814
01815 void
01816 CHotkeyOptions::CScreensDialog::updateControls(HWND hwnd)
01817 {
01818 HWND child = getItem(hwnd, IDC_HOTKEY_SCREENS_SRC);
01819 bool canAdd = (SendMessage(child, LB_GETSELCOUNT, 0, 0) != 0);
01820 child = getItem(hwnd, IDC_HOTKEY_SCREENS_DST);
01821 bool canRemove = (!s_targets.empty() &&
01822 (SendMessage(child, LB_GETSELCOUNT, 0, 0) != 0));
01823
01824 enableItem(hwnd, IDC_HOTKEY_SCREENS_ADD, canAdd);
01825 enableItem(hwnd, IDC_HOTKEY_SCREENS_REMOVE, canRemove);
01826 }
01827
01828 void
01829 CHotkeyOptions::CScreensDialog::add(HWND hwnd)
01830 {
01831 CScreens selected;
01832 getSelected(hwnd, IDC_HOTKEY_SCREENS_SRC, s_nonTargets, selected);
01833 for (CScreens::const_iterator i = selected.begin();
01834 i != selected.end(); ++i) {
01835 s_targets.insert(*i);
01836 s_nonTargets.erase(*i);
01837 }
01838 fillScreens(hwnd);
01839 updateControls(hwnd);
01840 }
01841
01842 void
01843 CHotkeyOptions::CScreensDialog::remove(HWND hwnd)
01844 {
01845 CScreens selected;
01846 getSelected(hwnd, IDC_HOTKEY_SCREENS_DST, s_targets, selected);
01847 for (CScreens::const_iterator i = selected.begin();
01848 i != selected.end(); ++i) {
01849 s_nonTargets.insert(*i);
01850 s_targets.erase(*i);
01851 }
01852 fillScreens(hwnd);
01853 updateControls(hwnd);
01854 }
01855
01856 void
01857 CHotkeyOptions::CScreensDialog::getSelected(HWND hwnd, UINT id,
01858 const CScreens& inScreens, CScreens& outScreens)
01859 {
01860
01861 HWND child = getItem(hwnd, id);
01862 UInt32 n = (UInt32)SendMessage(child, LB_GETSELCOUNT, 0, 0);
01863 int* index = new int[n];
01864 SendMessage(child, LB_GETSELITEMS, (WPARAM)n, (LPARAM)index);
01865
01866
01867 std::vector<CString> tmpList;
01868 for (CScreens::const_iterator i = inScreens.begin();
01869 i != inScreens.end(); ++i) {
01870 tmpList.push_back(*i);
01871 }
01872
01873
01874 outScreens.clear();
01875 for (UInt32 i = 0; i < n; ++i) {
01876 outScreens.insert(tmpList[index[i]]);
01877 }
01878
01879
01880 delete[] index;
01881 }
01882
01883 BOOL CALLBACK
01884 CHotkeyOptions::CScreensDialog::dlgProc(HWND hwnd,
01885 UINT message, WPARAM wParam, LPARAM lParam)
01886 {
01887 switch (message) {
01888 case WM_INITDIALOG:
01889 doInit(hwnd);
01890 return TRUE;
01891
01892 case WM_COMMAND:
01893 switch (LOWORD(wParam)) {
01894 case IDOK:
01895 doFini(hwnd);
01896 EndDialog(hwnd, 0);
01897 return TRUE;
01898
01899 case IDCANCEL:
01900 EndDialog(hwnd, 0);
01901 return TRUE;
01902
01903 case IDC_HOTKEY_SCREENS_ADD:
01904 add(hwnd);
01905 return TRUE;
01906
01907 case IDC_HOTKEY_SCREENS_REMOVE:
01908 remove(hwnd);
01909 return TRUE;
01910
01911 case IDC_HOTKEY_SCREENS_SRC:
01912 case IDC_HOTKEY_SCREENS_DST:
01913 switch (HIWORD(wParam)) {
01914 case LBN_SELCANCEL:
01915 case LBN_SELCHANGE:
01916 updateControls(hwnd);
01917 return TRUE;
01918 }
01919 break;
01920 }
01921 break;
01922
01923 case WM_CTLCOLORLISTBOX:
01924 if (s_targets.empty() &&
01925 (HWND)lParam == getItem(hwnd, IDC_HOTKEY_SCREENS_DST)) {
01926
01927 HDC dc = (HDC)wParam;
01928 SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
01929 return (BOOL)GetSysColorBrush(COLOR_WINDOW);
01930 }
01931 break;
01932
01933 default:
01934 break;
01935 }
01936
01937 return FALSE;
01938 }