Skip to content

Commit 4285be7

Browse files
committed
Memory and input adjustments.
Non-repeating inputs (highlight: delayed inputs) will not allow re-execution until the existing thread is complete. The inputs keys will still be handled by the application and not passed through for further processing.
1 parent 1ff616f commit 4285be7

File tree

8 files changed

+106
-23
lines changed

8 files changed

+106
-23
lines changed

KeyCapLib/KeyCapLib.vcxproj

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,32 @@
2222
<ProjectGuid>{5637CC7B-9FFF-486B-9D51-898DEDCB908A}</ProjectGuid>
2323
<Keyword>Win32Proj</Keyword>
2424
<RootNamespace>KeyCapLib</RootNamespace>
25-
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
25+
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
2626
</PropertyGroup>
2727
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2828
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
2929
<ConfigurationType>DynamicLibrary</ConfigurationType>
3030
<UseDebugLibraries>true</UseDebugLibraries>
31-
<PlatformToolset>v141</PlatformToolset>
31+
<PlatformToolset>v142</PlatformToolset>
3232
<CharacterSet>Unicode</CharacterSet>
3333
</PropertyGroup>
3434
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
3535
<ConfigurationType>DynamicLibrary</ConfigurationType>
3636
<UseDebugLibraries>false</UseDebugLibraries>
37-
<PlatformToolset>v141</PlatformToolset>
37+
<PlatformToolset>v142</PlatformToolset>
3838
<WholeProgramOptimization>true</WholeProgramOptimization>
3939
<CharacterSet>Unicode</CharacterSet>
4040
</PropertyGroup>
4141
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
4242
<ConfigurationType>DynamicLibrary</ConfigurationType>
4343
<UseDebugLibraries>true</UseDebugLibraries>
44-
<PlatformToolset>v141</PlatformToolset>
44+
<PlatformToolset>v142</PlatformToolset>
4545
<CharacterSet>Unicode</CharacterSet>
4646
</PropertyGroup>
4747
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
4848
<ConfigurationType>DynamicLibrary</ConfigurationType>
4949
<UseDebugLibraries>false</UseDebugLibraries>
50-
<PlatformToolset>v141</PlatformToolset>
50+
<PlatformToolset>v142</PlatformToolset>
5151
<WholeProgramOptimization>true</WholeProgramOptimization>
5252
<CharacterSet>Unicode</CharacterSet>
5353
</PropertyGroup>

KeyCapLib/KeyCapture.cpp

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#include "keycapture.h"
2929
#include "keyboardproc.h"
3030
#include "mouseinput.h"
31-
#include "keyboardinput.h"
3231
#include "configfile.h"
3332

3433
// === prototypes
@@ -39,9 +38,11 @@ extern "C"
3938
__declspec(dllexport) void ShutdownCapture();
4039
}
4140

42-
HHOOK g_hookMain = NULL;
41+
// non extern functions
42+
void InitiallizeEntryContainerListItem(RemapEntryContainerListItem* pKeyItem, RemapEntry* pEntry);
4343

4444
// sweet globals
45+
HHOOK g_hookMain = NULL;
4546
RemapEntryContainerListItem* g_KeyTranslationTable[WIN_KEY_COUNT];
4647
RemapEntry* g_KeyTranslationHead = NULL;
4748
void* g_KeyTranslationEnd = NULL; // pointer indicating the end of the input file data
@@ -83,20 +84,19 @@ __declspec(dllexport) int LoadAndCaptureFromFile(HINSTANCE hInstance, char* sFil
8384
return INPUT_BAD;
8485
}
8586
// TODO: just get a pointer to g_KeyTranslationTable[pKey->inputConfig.virtualKey] ?
86-
87+
#ifdef _DEBUG
8788
char* pInputConfigDescription = GetInputConfigDescription(pEntry->inputConfig);
8889
LogDebugMessage("Loading %s Outputs: %d", pInputConfigDescription, pEntry->outputCount);
8990
free(pInputConfigDescription);
90-
91+
#endif
9192
// if the entry doesn't exist yet for the given input vkey create a new one with a null next pointer
9293
if(NULL == g_KeyTranslationTable[pEntry->inputConfig.virtualKey])
9394
{
9495
g_KeyTranslationTable[pEntry->inputConfig.virtualKey] = (RemapEntryContainerListItem*)malloc(sizeof(RemapEntryContainerListItem));
95-
g_KeyTranslationTable[pEntry->inputConfig.virtualKey]->pEntryContainer = (RemapEntryContainer*)malloc(sizeof(RemapEntryContainer));
96-
g_KeyTranslationTable[pEntry->inputConfig.virtualKey]->pEntryContainer->pEntryState = (RemapEntryState*)malloc(sizeof(RemapEntryState));
97-
g_KeyTranslationTable[pEntry->inputConfig.virtualKey]->pEntryContainer->pEntry = pEntry;
96+
InitiallizeEntryContainerListItem(g_KeyTranslationTable[pEntry->inputConfig.virtualKey], pEntry);
9897
g_KeyTranslationTable[pEntry->inputConfig.virtualKey]->pNext = NULL;
9998
}
99+
100100
// if the entry does exist create a new entry and append it to the existing linked list
101101
else
102102
{
@@ -107,9 +107,7 @@ __declspec(dllexport) int LoadAndCaptureFromFile(HINSTANCE hInstance, char* sFil
107107
}
108108
pKeyItem->pNext = (RemapEntryContainerListItem*)malloc(sizeof(RemapEntryContainerListItem));
109109
pKeyItem = pKeyItem->pNext;
110-
pKeyItem->pEntryContainer = (RemapEntryContainer*)malloc(sizeof(RemapEntryContainer));
111-
pKeyItem->pEntryContainer->pEntryState = (RemapEntryState*)malloc(sizeof(RemapEntryState));
112-
pKeyItem->pEntryContainer->pEntry = pEntry;
110+
InitiallizeEntryContainerListItem(pKeyItem, pEntry);
113111
pKeyItem->pNext = NULL;
114112
}
115113
// jump to the next entry
@@ -130,7 +128,7 @@ __declspec(dllexport) int LoadAndCaptureFromFile(HINSTANCE hInstance, char* sFil
130128
if(bValidTranslationSet)
131129
{
132130
// Note: This fails in VisualStudio if managed debugging is NOT enabled in the project(!)
133-
HHOOK g_hookMain = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, NULL);
131+
g_hookMain = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, NULL);
134132
if(NULL == g_hookMain)
135133
{
136134
ShutdownCapture();
@@ -148,11 +146,67 @@ __declspec(dllexport) int LoadAndCaptureFromFile(HINSTANCE hInstance, char* sFil
148146
}
149147
}
150148

149+
void InitiallizeEntryContainerListItem(RemapEntryContainerListItem* pKeyItem, RemapEntry* pEntry)
150+
{
151+
pKeyItem->pEntryContainer = (RemapEntryContainer*)malloc(sizeof(RemapEntryContainer));
152+
pKeyItem->pEntryContainer->pEntryState = (RemapEntryState*)calloc(1, sizeof(RemapEntryState));
153+
pKeyItem->pEntryContainer->pEntry = pEntry;
154+
}
155+
151156
/*
152157
Shuts down the key capture hook and frees any allocated memory
153158
*/
154159
__declspec(dllexport) void ShutdownCapture()
155160
{
161+
// signal shutdown for all entries with a thread handle
162+
for(int nIdx = 0; nIdx < WIN_KEY_COUNT; nIdx++)
163+
{
164+
if(NULL != g_KeyTranslationTable[nIdx])
165+
{
166+
RemapEntryContainerListItem* pListItem = g_KeyTranslationTable[nIdx];
167+
RemapEntryContainerListItem* pNextItem = NULL;
168+
while(NULL != pListItem)
169+
{
170+
pNextItem = pListItem->pNext;
171+
if (NULL != pListItem->pEntryContainer->pEntryState->threadHandle)
172+
{
173+
pListItem->pEntryContainer->pEntryState->bShutdown = true;
174+
}
175+
pListItem = pNextItem;
176+
}
177+
}
178+
}
179+
180+
// monitor and terminate threads for all entries with a thread handle
181+
for (int nIdx = 0; nIdx < WIN_KEY_COUNT; nIdx++)
182+
{
183+
if (NULL != g_KeyTranslationTable[nIdx])
184+
{
185+
RemapEntryContainerListItem* pListItem = g_KeyTranslationTable[nIdx];
186+
RemapEntryContainerListItem* pNextItem = NULL;
187+
while (NULL != pListItem)
188+
{
189+
pNextItem = pListItem->pNext;
190+
if(NULL != pListItem->pEntryContainer->pEntryState->threadHandle)
191+
{
192+
DWORD dwExitCode = WAIT_TIMEOUT;
193+
for(int shutdownIteration = 0; shutdownIteration < THREAD_SHUTDOWN_MAX_ATTEMPTS && dwExitCode != WAIT_OBJECT_0; shutdownIteration++)
194+
{
195+
// check on the state of the thread (for 100ms) (MS says not to use GetExitCodeThread unless the thread is known to be exited)
196+
dwExitCode = WaitForSingleObject(pListItem->pEntryContainer->pEntryState->threadHandle, THREAD_SHUTDOWN_ATTEMPT_DELAY_MS);
197+
}
198+
if (dwExitCode != WAIT_OBJECT_0)
199+
{
200+
LogDebugMessage("Force terminating thread!");
201+
TerminateThread(pListItem->pEntryContainer->pEntryState->threadHandle, 1);
202+
}
203+
}
204+
pListItem = pNextItem;
205+
}
206+
}
207+
}
208+
209+
156210
// disable the hook
157211
if(NULL != g_hookMain)
158212
{

KeyCapLib/KeyCapture.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@
2828
#include "keycapturestructs.h"
2929
#include "keycaptureutil.h"
3030

31+
// === consts and defines
32+
const int THREAD_SHUTDOWN_MAX_ATTEMPTS = 5;
33+
const int THREAD_SHUTDOWN_ATTEMPT_DELAY_MS = 100;
34+
3135
#endif // KEY_CAPTURE_H_

KeyCapLib/KeyboardInput.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Sends the necessary inputs to complete the trigger (modifier keys)
3030
3131
pTriggerDefinition: pointer to a key definition for the trigger
3232
*/
33-
void SendTriggerEndInputKeys(RemapEntry* pRemapEntry/*InputConfig* pInputConfig*/)
33+
void SendTriggerEndInputKeys(RemapEntry* pRemapEntry)
3434
{
3535
InputConfig* pInputConfig = &pRemapEntry->inputConfig;
3636

KeyCapLib/keyboardproc.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,17 @@ LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
5959
(bControl == pKeyDef->inputFlag.bControl) &&
6060
(bShift == pKeyDef->inputFlag.bShift))
6161
{
62+
#ifdef _DEBUG
6263
char* pInputConfigDescription = GetInputConfigDescription(*pKeyDef);
6364
LogDebugMessage("Detected Key Press: %s Outputs: %d", pInputConfigDescription, pKeyListItem->pEntryContainer->pEntry->outputCount);
6465
free(pInputConfigDescription);
65-
// TODO: get thread handle, also check for null
66-
CreateThread(NULL, 0, SendInputThread, pKeyListItem->pEntryContainer, 0, NULL);
66+
#endif
67+
// If there is NOT an existing thread OR the existing thread is running a repeat another key press is allowed
68+
if (NULL == pKeyListItem->pEntryContainer->pEntryState->threadHandle || pKeyListItem->pEntryContainer->pEntryState->bRepeating)
69+
{
70+
pKeyListItem->pEntryContainer->pEntryState->threadHandle = CreateThread(NULL, 0, SendInputThread, pKeyListItem->pEntryContainer, 0, NULL);
71+
}
72+
// no matter if a new SendInputThread was started or not block further processing with the inputs
6773
bSentInput = true;
6874
break;
6975
}

KeyCapLib/keycapturestructs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ struct RemapEntryState
9595
{
9696
BYTE bToggled : 1;
9797
BYTE bRepeating : 1;
98-
BYTE padOne : 6;
98+
BYTE bShutdown : 1;
99+
BYTE padOne : 5;
99100
BYTE padTwo : 8;
100101
BYTE padThree : 8;
101102
BYTE padFour : 8;

KeyCapLib/sendinputthread.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
6161
if (pRemapEntryState->bRepeating)
6262
{
6363
pRemapEntryState->bRepeating = false;
64+
pRemapEntryState->bShutdown = true;
6465
LogDebugMessage("SendInputThread Completed (ended Repeat)");
6566
return 0;
6667
}
@@ -92,14 +93,14 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
9293
// skip this output
9394
pOutputConfig++; // move the pointer forward one KeyDefinition
9495
}
95-
96+
#ifdef _DEBUG
9697
char* pOutputConfigDescription = GetOutputConfigDescription(*pOutputConfig);
9798
LogDebugMessage("Performing %s Output Action: %s",
9899
pOutputConfig->outputFlag.bMouseOut ? "Mouse" : "Keyboard",
99100
pOutputConfigDescription
100101
);
101102
free(pOutputConfigDescription);
102-
103+
#endif
103104
// mouse input
104105
if (pOutputConfig->outputFlag.bMouseOut)
105106
{
@@ -108,7 +109,16 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
108109
// just a delay
109110
else if (pOutputConfig->outputFlag.bDelay)
110111
{
111-
Sleep(1000 * pOutputConfig->parameter);
112+
//Want to delay break...
113+
int iterations = pOutputConfig->parameter * 10;
114+
for (int nDelayCount = 0; nDelayCount < iterations; nDelayCount++)
115+
{
116+
Sleep(100);
117+
if (pRemapEntryState->bShutdown)
118+
{
119+
break;
120+
}
121+
}
112122
}
113123
// keyboard input
114124
else
@@ -118,6 +128,12 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
118128
pOutputConfig++; // move the pointer forward one KeyDefinition
119129
}
120130

131+
// break out now
132+
if (pRemapEntryState->bShutdown)
133+
{
134+
break;
135+
}
136+
121137
// reset output pointer
122138
pOutputConfig = (OutputConfig*)(pRemapEntry + 1);
123139
firstPassComplete = true;
@@ -132,5 +148,7 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
132148
pRemapEntryState->bToggled = !pRemapEntryState->bToggled;
133149

134150
LogDebugMessage("SendInputThread Completed");
151+
// Disconnect this thread from the state
152+
pRemapEntryState->threadHandle = NULL;
135153
return 0;
136154
}

bin/Release/KeyCap.odt

1.17 KB
Binary file not shown.

0 commit comments

Comments
 (0)