summaryrefslogtreecommitdiff
path: root/plugins/HwHotKeys/src/HwHotKeys_KbdHook.cpp
blob: e6ecf195ca6b8613d805bb26d156cc313f346a4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* ============================================================================
Hardware HotKeys plugin for Miranda NG.
Copyright © Eugene f2065, http://f2065.narod.ru, f2065 mail.ru, ICQ 35078112

This program is free software; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111 - 1307, USA.
============================================================================ */

#include "stdafx.h"

LRESULT CALLBACK key_hook(int nCode, WPARAM wParam, LPARAM lParam)  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644985%28v=vs.85%29.aspx
{
	KBDLLHOOKSTRUCT *pKbdLLHookStruct = (KBDLLHOOKSTRUCT *)lParam;
	if (nCode >= 0) {
		if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) // при отпускании любой кнопки - сбрасываем всю накопленную комбинацию
			key_code = 0;

		else if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
			// 0xFFFFFF00 фильтр для странных двойных сканкодов например перед L_Alt/AltGr, 
			// 0xFF фильтр для нулевых сканкодов(приходят при всякой там эмуляции нажатий и т.п.)
			// LLKHF_INJECTED фильтр для эмулируемых нажатий, но есть проблема с некоторыми клавами
			if (!(pKbdLLHookStruct->scanCode & 0xFFFFFF00) && (pKbdLLHookStruct->scanCode & 0xFF)) {
				// строим комплексный код(сканкод + доп.флаг LLKHF_EXTENDED), от 0 до 1FF
				key_code_raw = (LOBYTE(pKbdLLHookStruct->scanCode) | ((LOBYTE(pKbdLLHookStruct->flags) & 1) << 8));

				if (hDialogWnd) { // если диалог настроек открыт - выводим в него нажимаемые кнопоки
					StringCbPrintfA(key_name_buffer, sizeof(key_name_buffer), "%03X %s", key_code_raw, key_tab[(key_code_raw & 0x1FF)]);
					SetDlgItemTextA(hDialogWnd, dlg_scancode_edit, key_name_buffer);
				}

				switch (key_code_raw) { // проверяем кнопки модификаторов
				case 0x01D: // L_Ctrl
					key_code |= key_flag_cl;
					break;   // после модификаторов - ничего не делаем, выход из хука.
				case 0x11D: // R_Ctrl
					key_code |= key_flag_cr;
					break;
				case 0x038: // L_Alt
					key_code |= key_flag_al;
					break;
				case 0x138: // R_Alt
					key_code |= key_flag_ar;
					break;
				case 0x15B: // L_Win
					key_code |= key_flag_wl;
					break;
				case 0x15C: // R_Win
					key_code |= key_flag_wr;
					break;
				case 0x02A: // L_Shift
					key_code |= key_flag_sl;
					break;
				case 0x036: // R_Shift
					key_code |= key_flag_sr;
					break;
				case 0x12A: // L_Shift_fake
					key_code |= key_flag_sl;
					break;
				case 0x136: // R_Shift_fake
					key_code |= key_flag_sr;
					break;
				
				default:  // если это не кнопка модификатора - то дальнейшая обработка
					key_code = (LOWORD(key_code_raw)) | (key_code & 0xFFFF0000); // в старшей половине там лежат биты модификаторов - их оставляем (они там могут быть от предыдущего раза)
					if (hDialogWnd) { // если диалог настроек открыт - выводим в него комплексную комбинацию (типа Shift+Key), которую потом можно назначить;
						if (IsDlgButtonChecked(hDialogWnd, dlg_combine)) { // левые/правые модификаторы объединять в один?
							uint32_t tmp1, tmp2;
							tmp1 = ((key_code >> 4) | (key_code >> 8)) & 0x00F00000;
							tmp2 = LOWORD(key_code) | tmp1;
							tmp2 &= 0x00F001FF;
							key_code_assign = tmp2;
						}
						else key_code_assign = key_code;

						HwHotKeys_PrintFullKeyname(key_code_assign);
						SetDlgItemTextA(hDialogWnd, dlg_keyname_edit, key_name_buffer);
					}
					else { // хоткей выполняют действия только если закрыт диалог настроек (чтобы не мешал настраивать)
						if (HwHotKeys_CompareCurrentScancode(code_Close)) { // хоткей полного закрытия Miranda
							// Beep(300, 200);
							CallService("CloseAction", 0, 0);
							return 1;
						}
						
						if (HwHotKeys_CompareCurrentScancode(code_HideShow)) { // хоткей сворачивания/разворачивания главного окна Miranda
							// Beep(700, 200);
							g_clistApi.pfnShowHide(); // есть варианты
							return 1;
						}
						
						if (HwHotKeys_CompareCurrentScancode(code_ReadMsg)) { // хоткей чтения сообщения
							// Beep(1500, 200);
							if (Clist_EventsProcessTrayDoubleClick(0) != 0) { // клик по трею для стандартного открытия сообщения
								// иначе - окно чата уже открыто и надо его вытащить наверх...
								SetForegroundWindow(g_clistApi.hwndContactList);
								SetFocus(g_clistApi.hwndContactList);
								// хотя всЄ равно это не очень работает в новой винде
								// надо http://www.rsdn.ru/article/qna/ui/wndsetfg.xml
								// но пока незнаю где тут взять хэндл окна чата(причём именно для
								// выбранного контакта, их же несколько может быть если простой srmm)
								// у миранды в hkRead такие же проблемы
							}
							return 1; // возврат 1 запрещает дальнейшую работу кнопки, т.е. кнопка после нашего плагина никому более не достанется
						}
					}
				}
			}
		}
	}
	
	return CallNextHookEx(hHook, nCode, wParam, lParam);
}