HotKeys.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. #include "stdafx.h"
  2. #include "HotKeys.h"
  3. #include "Options.h"
  4. #include "Misc.h"
  5. #include "SendKeys.h"
  6. #include "Accels.h"
  7. CHotKeys g_HotKeys;
  8. int CHotKey::m_nextId = 0;
  9. CHotKey::CHotKey(CString name, DWORD defKey, bool bUnregOnShowDitto, HotKeyType hkType, CString description)
  10. : m_Name(name),
  11. m_description(description),
  12. m_bIsRegistered(false),
  13. m_bUnRegisterOnShowDitto(bUnregOnShowDitto),
  14. m_clipId(0)
  15. {
  16. m_Atom = ::GlobalAddAtom(StrF(_T("%s_%d"), m_Name, hkType));
  17. ASSERT(m_Atom);
  18. m_Key = (DWORD)CGetSetOptions::GetProfileLong(m_Name, (long) defKey);
  19. m_globalId = m_nextId;
  20. m_nextId++;
  21. m_hkType = hkType;
  22. g_HotKeys.Add(this);
  23. }
  24. CHotKey::~CHotKey()
  25. {
  26. Unregister();
  27. ::GlobalDeleteAtom(m_Atom);
  28. }
  29. CString CHotKey::GetHotKeyDisplay()
  30. {
  31. return GetHotKeyDisplayStatic(m_Key);
  32. }
  33. CString CHotKey::GetHotKeyDisplayStatic(DWORD dwHotKey)
  34. {
  35. WORD vk = LOBYTE(dwHotKey);
  36. CString keyDisplay;
  37. UINT modifiers = GetModifier(HIBYTE(dwHotKey));
  38. if(modifiers & MOD_SHIFT)
  39. {
  40. keyDisplay += _T("Shift + ");
  41. }
  42. if(modifiers & MOD_CONTROL)
  43. {
  44. keyDisplay += _T("Ctrl + ");
  45. }
  46. if(modifiers & MOD_ALT)
  47. {
  48. keyDisplay += _T("Alt + ");
  49. }
  50. if(modifiers & MOD_WIN)
  51. {
  52. keyDisplay += _T("Win + ");
  53. }
  54. switch (vk)
  55. {
  56. case VK_MOUSE_CLICK:
  57. keyDisplay += "Click";
  58. break;
  59. case VK_MOUSE_DOUBLE_CLICK:
  60. keyDisplay += "Double Click";
  61. break;
  62. case VK_MOUSE_RIGHT_CLICK:
  63. keyDisplay += "Right Click";
  64. break;
  65. case VK_MOUSE_MIDDLE_CLICK:
  66. keyDisplay += "Middle Click";
  67. break;
  68. default:
  69. keyDisplay += GetVirKeyName(vk);
  70. break;
  71. }
  72. return keyDisplay;
  73. }
  74. //http://www.ffuts.org/blog/mapvirtualkey-getkeynametext-and-a-story-of-how-to/
  75. CString CHotKey::GetVirKeyName(unsigned int virtualKey)
  76. {
  77. // MapVirtualKey/GetKeyNameText does not return a name for F13-F24
  78. // even though these keys can be registered as global hotkeys. If we
  79. // detect one of these virtual key codes then manually return the
  80. // appropriate string.
  81. if(virtualKey >= VK_F13 && virtualKey <= VK_F24)
  82. {
  83. return StrF(_T("F%d"), (virtualKey - VK_F1) + 1);
  84. }
  85. // Provide friendly names for multimedia and browser keys which
  86. // otherwise return an empty string from GetKeyNameText.
  87. switch (virtualKey)
  88. {
  89. case VK_VOLUME_MUTE: return _T("Volume Mute");
  90. case VK_VOLUME_DOWN: return _T("Volume Down");
  91. case VK_VOLUME_UP: return _T("Volume Up");
  92. case VK_MEDIA_NEXT_TRACK: return _T("Next Track");
  93. case VK_MEDIA_PREV_TRACK: return _T("Prev Track");
  94. case VK_MEDIA_PLAY_PAUSE: return _T("Play/Pause");
  95. case VK_MEDIA_STOP: return _T("Stop");
  96. case VK_BROWSER_BACK: return _T("Browser Back");
  97. case VK_BROWSER_FORWARD: return _T("Browser Forward");
  98. case VK_BROWSER_REFRESH: return _T("Browser Refresh");
  99. case VK_BROWSER_STOP: return _T("Browser Stop");
  100. case VK_BROWSER_SEARCH: return _T("Browser Search");
  101. case VK_BROWSER_FAVORITES: return _T("Browser Favorites");
  102. case VK_BROWSER_HOME: return _T("Browser Home");
  103. case VK_LAUNCH_MAIL: return _T("Launch Mail");
  104. case VK_LAUNCH_MEDIA_SELECT: return _T("Launch Media");
  105. case VK_LAUNCH_APP1: return _T("Launch App1");
  106. case VK_LAUNCH_APP2: return _T("Launch App2");
  107. }
  108. unsigned int scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC);
  109. // because MapVirtualKey strips the extended bit for some keys
  110. switch (virtualKey)
  111. {
  112. case VK_LEFT:
  113. case VK_UP:
  114. case VK_RIGHT:
  115. case VK_DOWN: // arrow keys
  116. case VK_PRIOR:
  117. case VK_NEXT: // page up and page down
  118. case VK_END:
  119. case VK_HOME:
  120. case VK_INSERT:
  121. case VK_DELETE:
  122. case VK_DIVIDE: // numpad slash
  123. case VK_NUMLOCK:
  124. {
  125. scanCode |= 0x100; // set extended bit
  126. break;
  127. }
  128. }
  129. wchar_t keyName[50];
  130. if (GetKeyNameText(scanCode << 16, keyName, _countof(keyName)) != 0)
  131. {
  132. return keyName;
  133. }
  134. else
  135. {
  136. return "[Error]";
  137. }
  138. }
  139. UINT CHotKey::GetModifier(DWORD dwHotKey)
  140. {
  141. UINT uMod = 0;
  142. if(dwHotKey & HOTKEYF_SHIFT)
  143. uMod |= MOD_SHIFT;
  144. if(dwHotKey & HOTKEYF_CONTROL)
  145. uMod |= MOD_CONTROL;
  146. if(dwHotKey & HOTKEYF_ALT)
  147. uMod |= MOD_ALT;
  148. if(dwHotKey & HOTKEYF_EXT)
  149. uMod |= MOD_WIN;
  150. return uMod;
  151. }
  152. void CHotKey::SetKey( DWORD key, bool bSave )
  153. {
  154. if(m_Key == key)
  155. {
  156. return;
  157. }
  158. if(m_bIsRegistered)
  159. Unregister();
  160. m_Key = key;
  161. if(bSave)
  162. SaveKey();
  163. }
  164. void CHotKey::LoadKey()
  165. {
  166. SetKey((DWORD) CGetSetOptions::GetProfileLong(m_Name, 0));
  167. }
  168. bool CHotKey::SaveKey()
  169. {
  170. if(m_clipId <= 0)
  171. {
  172. return CGetSetOptions::SetProfileLong( m_Name, (long) m_Key ) != FALSE;
  173. }
  174. return false;
  175. }
  176. BOOL CHotKey::ValidateHotKey(DWORD dwHotKey)
  177. {
  178. ATOM id = ::GlobalAddAtom(_T("HK_VALIDATE"));
  179. BOOL bResult = ::RegisterHotKey( g_HotKeys.m_hWnd,
  180. id,
  181. GetModifier(HIBYTE(dwHotKey)),
  182. LOBYTE(dwHotKey) );
  183. if(bResult)
  184. ::UnregisterHotKey(g_HotKeys.m_hWnd, id);
  185. ::GlobalDeleteAtom(id);
  186. return bResult;
  187. }
  188. void CHotKey::CopyFromCtrl(CHotKeyCtrl& ctrl, HWND hParent, int nWindowsCBID)
  189. {
  190. long lHotKey = ctrl.GetHotKey();
  191. short sKeyKode = LOBYTE(lHotKey);
  192. short sModifers = ((HIBYTE(lHotKey)) & ~HOTKEYF_EXT);
  193. if(lHotKey && ::IsDlgButtonChecked(hParent, nWindowsCBID))
  194. {
  195. sModifers |= HOTKEYF_EXT;
  196. }
  197. SetKey(MAKEWORD(sKeyKode, sModifers));
  198. }
  199. void CHotKey::CopyToCtrl(CHotKeyCtrl& ctrl, HWND hParent, int nWindowsCBID)
  200. {
  201. DWORD shortcut = ACCEL_MAKEKEY(LOBYTE(m_Key), ((HIBYTE(m_Key)) &~HOTKEYF_EXT));
  202. switch (LOBYTE(shortcut))
  203. {
  204. case VK_LEFT:
  205. case VK_UP:
  206. case VK_RIGHT:
  207. case VK_DOWN: // arrow keys
  208. case VK_PRIOR:
  209. case VK_NEXT: // page up and page down
  210. case VK_END:
  211. case VK_HOME:
  212. case VK_INSERT:
  213. case VK_DELETE:
  214. case VK_DIVIDE: // numpad slash
  215. case VK_NUMLOCK:
  216. {
  217. shortcut = ACCEL_MAKEKEY(LOBYTE(shortcut), (HIBYTE(shortcut) | HOTKEYF_EXT));
  218. }
  219. break;
  220. }
  221. long lModifiers = HIBYTE(shortcut);
  222. long keys = LOBYTE(shortcut);
  223. ctrl.SetHotKey((WORD)keys, (WORD)lModifiers);
  224. long originalModifiers = HIBYTE(m_Key);
  225. if(originalModifiers & HOTKEYF_EXT)
  226. {
  227. ::CheckDlgButton(hParent, nWindowsCBID, BST_CHECKED);
  228. }
  229. }
  230. bool CHotKey::Register()
  231. {
  232. if(m_Key)
  233. {
  234. if(m_bIsRegistered == false)
  235. {
  236. ASSERT(g_HotKeys.m_hWnd);
  237. m_bIsRegistered = ::RegisterHotKey(g_HotKeys.m_hWnd,
  238. m_Atom,
  239. GetModifier(),
  240. LOBYTE(m_Key) ) == TRUE;
  241. }
  242. }
  243. else
  244. {
  245. m_bIsRegistered = false;
  246. }
  247. return m_bIsRegistered;
  248. }
  249. bool CHotKey::Unregister(bool bOnShowingDitto)
  250. {
  251. if(!m_bIsRegistered)
  252. return true;
  253. if(bOnShowingDitto)
  254. {
  255. if(m_bUnRegisterOnShowDitto == false)
  256. return true;
  257. }
  258. if(m_Key)
  259. {
  260. ASSERT(g_HotKeys.m_hWnd);
  261. if(::UnregisterHotKey( g_HotKeys.m_hWnd, m_Atom))
  262. {
  263. m_bIsRegistered = false;
  264. return true;
  265. }
  266. else
  267. {
  268. Log(_T("Unregister FAILED!"));
  269. ASSERT(0);
  270. }
  271. }
  272. else
  273. {
  274. m_bIsRegistered = false;
  275. return true;
  276. }
  277. return false;
  278. }
  279. CHotKeys::CHotKeys() : m_hWnd(NULL)
  280. {
  281. }
  282. CHotKeys::~CHotKeys()
  283. {
  284. CHotKey* pHotKey;
  285. INT_PTR count = GetSize();
  286. for(int i=0; i < count; i++)
  287. {
  288. pHotKey = ElementAt(i);
  289. if(pHotKey)
  290. {
  291. delete pHotKey;
  292. }
  293. }
  294. }
  295. INT_PTR CHotKeys::Find(CHotKey* pHotKey)
  296. {
  297. INT_PTR count = GetSize();
  298. for(int i=0; i < count; i++)
  299. {
  300. if(pHotKey == ElementAt(i))
  301. {
  302. return i;
  303. }
  304. }
  305. return -1;
  306. }
  307. bool CHotKeys::Remove(CHotKey* pHotKey)
  308. {
  309. INT_PTR i = Find(pHotKey);
  310. if(i >= 0)
  311. {
  312. RemoveAt(i);
  313. return true;
  314. }
  315. return false;
  316. }
  317. bool CHotKeys::Remove(int clipId, CHotKey::HotKeyType hkType)
  318. {
  319. INT_PTR count = GetSize();
  320. for(int i=0; i < count; i++)
  321. {
  322. if(ElementAt(i) != NULL &&
  323. ElementAt(i)->m_clipId == clipId &&
  324. ElementAt(i)->m_hkType == hkType)
  325. {
  326. CHotKey *pKey = ElementAt(i);
  327. RemoveAt(i);
  328. delete pKey;
  329. return true;
  330. }
  331. }
  332. return false;
  333. }
  334. BOOL CHotKeys::ValidateClip(int clipId, DWORD key, CString desc, CHotKey::HotKeyType hkType)
  335. {
  336. CHotKey *pKey = NULL;
  337. INT_PTR count = GetSize();
  338. for(int i=0; i < count; i++)
  339. {
  340. if(ElementAt(i) != NULL &&
  341. ElementAt(i)->m_clipId == clipId &&
  342. ElementAt(i)->m_hkType == hkType)
  343. {
  344. pKey = ElementAt(i);
  345. break;
  346. }
  347. }
  348. if(pKey == NULL)
  349. {
  350. pKey = new CHotKey(desc, key, true, hkType);
  351. }
  352. BOOL ret = FALSE;
  353. if(pKey != NULL)
  354. {
  355. pKey->m_Key = key;
  356. pKey->m_Name = desc;
  357. pKey->m_clipId = clipId;
  358. ret = CHotKey::ValidateHotKey(key);
  359. }
  360. return ret;
  361. }
  362. void CHotKeys::LoadAllKeys()
  363. {
  364. INT_PTR count = GetSize();
  365. for(int i=0; i < count; i++)
  366. {
  367. ElementAt(i)->LoadKey();
  368. }
  369. }
  370. void CHotKeys::SaveAllKeys()
  371. {
  372. INT_PTR count = GetSize();
  373. for(int i=0; i < count; i++)
  374. {
  375. ElementAt(i)->SaveKey();
  376. }
  377. }
  378. void CHotKeys::RegisterAll(bool bMsgOnError)
  379. {
  380. CString str;
  381. CHotKey* pHotKey;
  382. INT_PTR count = GetSize();
  383. for(int i = 0; i < count; i++)
  384. {
  385. pHotKey = ElementAt(i);
  386. if(!pHotKey->Register() && pHotKey->m_Key > 0)
  387. {
  388. str = "Error Registering ";
  389. str += pHotKey->GetName();
  390. Log(str);
  391. if(bMsgOnError)
  392. AfxMessageBox(str);
  393. }
  394. }
  395. }
  396. void CHotKeys::UnregisterAll(bool bMsgOnError, bool bOnShowDitto)
  397. {
  398. CString str;
  399. CHotKey* pHotKey;
  400. INT_PTR count = GetSize();
  401. for(int i = 0; i < count; i++)
  402. {
  403. pHotKey = ElementAt(i);
  404. if(!pHotKey->Unregister(bOnShowDitto))
  405. {
  406. str = "Error Unregistering ";
  407. str += pHotKey->GetName();
  408. Log(str);
  409. if(bMsgOnError)
  410. AfxMessageBox(str);
  411. }
  412. }
  413. }
  414. void CHotKeys::GetKeys(ARRAY& keys)
  415. {
  416. INT_PTR count = GetSize();
  417. keys.SetSize(count);
  418. for(int i=0; i < count; i++)
  419. {
  420. keys[i] = ElementAt(i)->GetKey();
  421. }
  422. }
  423. // caution! this alters hotkeys based upon corresponding indexes
  424. void CHotKeys::SetKeys(ARRAY& keys, bool bSave)
  425. {
  426. INT_PTR count = GetSize();
  427. ASSERT(count == keys.GetSize());
  428. for(int i=0; i < count; i++)
  429. {
  430. ElementAt(i)->SetKey(keys[(INT)i], bSave);
  431. }
  432. }
  433. bool CHotKeys::FindFirstConflict(ARRAY& keys, INT_PTR* pX, INT_PTR* pY)
  434. {
  435. bool bConflict = false;
  436. INT_PTR i, j;
  437. INT_PTR count = keys.GetSize();
  438. DWORD key;
  439. for(i = 0; i < count && !bConflict; i++)
  440. {
  441. key = keys.ElementAt(i);
  442. // only check valid keys
  443. if(key == 0)
  444. continue;
  445. // scan the array for a duplicate
  446. for(j = i+1; j < count; j++ )
  447. {
  448. if(keys.ElementAt(j) == key)
  449. {
  450. bConflict = true;
  451. break;
  452. }
  453. }
  454. }
  455. if(bConflict)
  456. {
  457. if(pX)
  458. *pX = i-1;
  459. if(pY)
  460. *pY = j;
  461. }
  462. return bConflict;
  463. }
  464. // if true, pX and pY (if valid) are set to the indexes of the conflicting hotkeys.
  465. bool CHotKeys::FindFirstConflict(INT_PTR* pX, INT_PTR* pY)
  466. {
  467. ARRAY keys;
  468. GetKeys(keys);
  469. return FindFirstConflict(keys, pX, pY);
  470. }