Skip to content

Commit eff1a8f

Browse files
authored
Merge pull request #10 from michelematteini/master
Added basic support for mouse special keys as input key
2 parents d971a26 + 7aac207 commit eff1a8f

File tree

4 files changed

+154
-80
lines changed

4 files changed

+154
-80
lines changed

Forms/KeyCaptureConfig.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,32 @@ private void btnMouseGeneric_Click(object sender, EventArgs e)
399399
UpdateTextBox(txtKeyOut, null, CreateOutputConfigFromUI());
400400
}
401401

402+
private void txtKeyIn_MouseDown(object sender, MouseEventArgs e)
403+
{
404+
byte keyCode = 0;
405+
switch (e.Button)
406+
{
407+
case MouseButtons.Middle:
408+
keyCode = 0x04; // VK_MBUTTON
409+
break;
410+
case MouseButtons.XButton1:
411+
keyCode = 0x05; // VK_XBUTTON1
412+
break;
413+
case MouseButtons.XButton2:
414+
keyCode = 0x06; // VK_XBUTTON2
415+
break;
416+
}
417+
418+
if (keyCode == 0)
419+
return; // unsupported
420+
421+
#if LOG_KEYS
422+
Console.Out.WriteLine("Key Input: {0} 0x{1}".FormatString(keyCode, keyCode.ToString("x")));
423+
#endif
424+
m_zActiveInputConfig.VirtualKey = keyCode;
425+
UpdateTextBox((TextBox)sender, null, CreateInputConfigFromUI());
426+
}
427+
402428
#endregion
403429

404430
#region Output String Generation
@@ -1133,6 +1159,6 @@ public override void Reset()
11331159
}
11341160
}
11351161

1136-
#endregion
1162+
#endregion
11371163
}
11381164
}

Forms/KeyCaptureConfig.designer.cs

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

KeyCapLib/KeyCapture.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ extern "C"
4242
void InitiallizeEntryContainerListItem(RemapEntryContainerListItem* pKeyItem, RemapEntry* pEntry);
4343

4444
// sweet globals
45-
HHOOK g_hookMain = NULL;
45+
HHOOK g_hookKeyboard = NULL, g_hookMouse = NULL;
4646
RemapEntryContainerListItem* g_KeyTranslationTable[WIN_KEY_COUNT];
4747
RemapEntry* g_KeyTranslationHead = NULL;
4848
void* g_KeyTranslationEnd = NULL; // pointer indicating the end of the input file data
@@ -129,8 +129,9 @@ __declspec(dllexport) int LoadAndCaptureFromFile(HINSTANCE hInstance, char* sFil
129129
if(bValidTranslationSet)
130130
{
131131
// Note: This fails in VisualStudio if managed debugging is NOT enabled in the project(!)
132-
g_hookMain = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, NULL);
133-
if(NULL != g_hookMain)
132+
g_hookKeyboard = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, NULL);
133+
g_hookMouse = SetWindowsHookEx(WH_MOUSE_LL, LowLevelKeyboardProc, hInstance, NULL);
134+
if(g_hookKeyboard && g_hookMouse)
134135
{
135136
return HOOK_CREATION_SUCCESS;
136137
}
@@ -211,12 +212,18 @@ __declspec(dllexport) void ShutdownCapture()
211212
// stop any active threads
212213
ShutdownInputThreads(true);
213214

214-
// disable the hook
215-
if(NULL != g_hookMain)
215+
// disable the hooks
216+
if(g_hookKeyboard)
216217
{
217-
LogDebugMessage("Unhooked");
218-
UnhookWindowsHookEx(g_hookMain);
219-
g_hookMain = NULL;
218+
LogDebugMessage("Unhooked keyboard");
219+
UnhookWindowsHookEx(g_hookKeyboard);
220+
g_hookKeyboard = NULL;
221+
}
222+
if (g_hookMouse)
223+
{
224+
LogDebugMessage("Unhooked mouse");
225+
UnhookWindowsHookEx(g_hookMouse);
226+
g_hookMouse = NULL;
220227
}
221228

222229
// memory clean up

KeyCapLib/keyboardproc.cpp

Lines changed: 110 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -41,98 +41,138 @@ messages (as those are the keys being captured). A separate thread is
4141
created to send out the key(s) to send to the os.
4242
*/
4343
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
44-
{
45-
KBDLLHOOKSTRUCT *pHook = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
44+
{
45+
DWORD vkCode = 0;
4646
bool bSentInput = false;
4747

4848
bool bAlt = 0 != (GetAsyncKeyState(VK_MENU) & 0x8000);
4949
bool bControl = 0 != (GetAsyncKeyState(VK_CONTROL) & 0x8000);
5050
bool bShift = 0 != (GetAsyncKeyState(VK_SHIFT) & 0x8000);
5151

52-
// don't catch injected keys
53-
if (!(pHook->flags & LLKHF_INJECTED)
54-
&& HC_ACTION == nCode)
52+
// get the correct virtual key
53+
switch (wParam)
54+
{
55+
case WM_MBUTTONDOWN:
56+
case WM_MBUTTONUP:
57+
{
58+
// mouse mid
59+
vkCode = 0x04;
60+
break;
61+
}
62+
case WM_XBUTTONDOWN:
63+
case WM_XBUTTONUP:
64+
{
65+
// mouse x
66+
MSLLHOOKSTRUCT* pMSHook = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
67+
UINT xBtn = GET_XBUTTON_WPARAM(pMSHook->mouseData);
68+
vkCode = xBtn == XBUTTON1 ? 0x05 : 0x06;
69+
break;
70+
71+
}
72+
case WM_KEYDOWN:
73+
case WM_SYSKEYDOWN:
74+
case WM_KEYUP:
75+
case WM_SYSKEYUP:
76+
{
77+
// keyboard
78+
KBDLLHOOKSTRUCT* pKBHook = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
79+
80+
// don't catch injected keys
81+
if (pKBHook->flags & LLKHF_INJECTED && HC_ACTION != nCode)
82+
return CallNextHookEx(NULL, nCode, wParam, lParam);
83+
84+
vkCode = pKBHook->vkCode;
85+
break;
86+
}
87+
}
88+
89+
if (!vkCode)
90+
return CallNextHookEx(NULL, nCode, wParam, lParam); // invalid or unsupported event
91+
92+
// NOTE: these are in while loops because a key may have multiple mappings due to the flag keys (shift/alt/ctrl)
93+
switch (wParam)
5594
{
56-
// NOTE: these are in while loops because a key may have multiple mappings due to the flag keys (shift/alt/ctrl)
57-
switch (wParam)
95+
case WM_KEYDOWN:
96+
case WM_SYSKEYDOWN:
97+
case WM_MBUTTONDOWN:
98+
case WM_XBUTTONDOWN:
99+
// detect a keydown that matches a remaped key (and start the input thread to respond accordingly then indicate to the OS that the key has been handled)
58100
{
59-
case WM_KEYDOWN:
60-
case WM_SYSKEYDOWN:
61-
// detect a keydown that matches a remaped key (and start the input thread to respond accordingly then indicate to the OS that the key has been handled)
62-
{
63-
// NOTE: key down events will come in while a key is being held
101+
// NOTE: key down events will come in while a key is being held
64102

65-
const RemapEntryContainerListItem* pKeyListItem = g_KeyTranslationTable[pHook->vkCode];
66-
while (NULL != pKeyListItem)
103+
const RemapEntryContainerListItem* pKeyListItem = g_KeyTranslationTable[vkCode];
104+
while (NULL != pKeyListItem)
105+
{
106+
const InputConfig* pKeyDef = &pKeyListItem->pEntryContainer->pEntry->inputConfig;
107+
if ((bAlt == pKeyDef->inputFlag.bAlt) &&
108+
(bControl == pKeyDef->inputFlag.bControl) &&
109+
(bShift == pKeyDef->inputFlag.bShift)
110+
&& !pKeyDef->inputFlag.bLongPress)
67111
{
68-
const InputConfig* pKeyDef = &pKeyListItem->pEntryContainer->pEntry->inputConfig;
69-
if ((bAlt == pKeyDef->inputFlag.bAlt) &&
70-
(bControl == pKeyDef->inputFlag.bControl) &&
71-
(bShift == pKeyDef->inputFlag.bShift)
72-
&& !pKeyDef->inputFlag.bLongPress)
73-
{
74112
#ifdef _DEBUG
75-
char* pInputConfigDescription = GetInputConfigDescription(*pKeyDef);
76-
LogDebugMessage("Detected Key Press: %s Outputs: %d", pInputConfigDescription, pKeyListItem->pEntryContainer->pEntry->outputCount);
77-
free(pInputConfigDescription);
113+
char* pInputConfigDescription = GetInputConfigDescription(*pKeyDef);
114+
LogDebugMessage("Detected Key Press: %s Outputs: %d", pInputConfigDescription, pKeyListItem->pEntryContainer->pEntry->outputCount);
115+
free(pInputConfigDescription);
78116
#endif
79-
// If there is NOT an existing thread OR the existing thread is running a repeat another key press is allowed
80-
if (NULL == pKeyListItem->pEntryContainer->pEntryState->threadHandle || pKeyListItem->pEntryContainer->pEntryState->bRepeating)
81-
{
82-
pKeyListItem->pEntryContainer->pEntryState->threadHandle = CreateThread(NULL, 0, SendInputThread, pKeyListItem->pEntryContainer, 0, NULL);
83-
}
84-
// block further processing with the inputs
85-
bSentInput = true;
86-
break;
87-
}
88-
if(!bAlt
89-
&& !bControl
90-
&& !bShift
91-
&& pKeyDef->inputFlag.bLongPress)
117+
// If there is NOT an existing thread OR the existing thread is running a repeat another key press is allowed
118+
if (NULL == pKeyListItem->pEntryContainer->pEntryState->threadHandle || pKeyListItem->pEntryContainer->pEntryState->bRepeating)
92119
{
93-
ProcessLongPressKeyDown(pKeyDef, pKeyListItem);
94-
// block further processing with the inputs
95-
bSentInput = true;
96-
break;
120+
pKeyListItem->pEntryContainer->pEntryState->threadHandle = CreateThread(NULL, 0, SendInputThread, pKeyListItem->pEntryContainer, 0, NULL);
97121
}
98-
pKeyListItem = pKeyListItem->pNext;
122+
// block further processing with the inputs
123+
bSentInput = true;
124+
break;
99125
}
126+
if(!bAlt
127+
&& !bControl
128+
&& !bShift
129+
&& pKeyDef->inputFlag.bLongPress)
130+
{
131+
ProcessLongPressKeyDown(pKeyDef, pKeyListItem);
132+
// block further processing with the inputs
133+
bSentInput = true;
134+
break;
135+
}
136+
pKeyListItem = pKeyListItem->pNext;
100137
}
101-
break;
102-
case WM_KEYUP:
103-
case WM_SYSKEYUP:
104-
// detect a keyup that matches a remaped key (and indicate to the OS that the key has been handled)
138+
}
139+
break;
140+
case WM_KEYUP:
141+
case WM_SYSKEYUP:
142+
case WM_MBUTTONUP:
143+
case WM_XBUTTONUP:
144+
// detect a keyup that matches a remaped key (and indicate to the OS that the key has been handled)
145+
{
146+
RemapEntryContainerListItem* pKeyListItem = g_KeyTranslationTable[vkCode];
147+
while (NULL != pKeyListItem)
105148
{
106-
RemapEntryContainerListItem* pKeyListItem = g_KeyTranslationTable[pHook->vkCode];
107-
while (NULL != pKeyListItem)
149+
InputConfig* pKeyDef = &pKeyListItem->pEntryContainer->pEntry->inputConfig;
150+
if (bAlt == pKeyDef->inputFlag.bAlt
151+
&& bControl == pKeyDef->inputFlag.bControl
152+
&& bShift == pKeyDef->inputFlag.bShift
153+
&& !pKeyDef->inputFlag.bLongPress)
108154
{
109-
InputConfig* pKeyDef = &pKeyListItem->pEntryContainer->pEntry->inputConfig;
110-
if (bAlt == pKeyDef->inputFlag.bAlt
111-
&& bControl == pKeyDef->inputFlag.bControl
112-
&& bShift == pKeyDef->inputFlag.bShift
113-
&& !pKeyDef->inputFlag.bLongPress)
114-
{
115-
// block further processing with the inputs
116-
bSentInput = true;
117-
break;
118-
}
119-
if (!bAlt
120-
&& !bControl
121-
&& !bShift
122-
&& pKeyDef->inputFlag.bLongPress)
123-
{
124-
ProcessLongPressKeyUp(pKeyDef);
125-
// block further processing with the inputs
126-
bSentInput = true;
127-
break;
128-
}
129-
pKeyListItem = pKeyListItem->pNext;
155+
// block further processing with the inputs
156+
bSentInput = true;
157+
break;
158+
}
159+
if (!bAlt
160+
&& !bControl
161+
&& !bShift
162+
&& pKeyDef->inputFlag.bLongPress)
163+
{
164+
ProcessLongPressKeyUp(pKeyDef);
165+
// block further processing with the inputs
166+
bSentInput = true;
167+
break;
130168
}
169+
pKeyListItem = pKeyListItem->pNext;
131170
}
132-
break;
133171
}
134-
LogDebugMessage("LowLevelKeyboardProc Complete");
172+
break;
135173
}
174+
LogDebugMessage("LowLevelKeyboardProc Complete");
175+
136176
return bSentInput ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam);
137177
}
138178

0 commit comments

Comments
 (0)