HotKeys.cpp 8.5 KB

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