Skip to content

Commit 473d2db

Browse files
committed
Added ability to cancel all active output threads
Fixed some other edge cases related to multi-out.
1 parent 4285be7 commit 473d2db

File tree

8 files changed

+131
-37
lines changed

8 files changed

+131
-37
lines changed

Format/OutputConfig.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public enum OutputFlag
5555
Down = 1 << 7,
5656
Up = 1 << 8,
5757
Repeat = 1 << 9,
58+
CancelActiveOutputs = 1 << 10,
5859
// all ThreadKill ?
5960
// supports up to 32 entries
6061
}
@@ -117,6 +118,16 @@ public override string GetDescription()
117118
return "[Delay({0}s)]".FormatString(Parameter);
118119
}
119120

121+
if (IsFlaggedAs(OutputFlag.DoNothing))
122+
{
123+
return "[Do Nothing]".FormatString(Parameter);
124+
}
125+
126+
if (IsFlaggedAs(OutputFlag.CancelActiveOutputs))
127+
{
128+
return "[Cancel Active Outputs]".FormatString(Parameter);
129+
}
130+
120131
if (IsFlaggedAs(OutputFlag.MouseOut))
121132
{
122133
return GetOutputDescriptionText((MouseButton)VirtualKey, "Mouse");

Forms/KeyCaptureConfig.cs

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ private void txtKeyOut_KeyDown(object sender, KeyEventArgs e)
191191
{
192192
// Console.Out.WriteLine("Key Input: {0} 0x{1}".FormatString(e.KeyCode, e.KeyCode.ToString("x")));
193193
UpdateTextBox((TextBox)sender, e, new OutputConfig(0, (byte)e.KeyCode, 0, e));
194+
// delay is toggled off if a key is specified
195+
checkOutputDelay.Checked = false;
194196
}
195197

196198
private void UpdateTextBox<T>(TextBox txtBox, KeyEventArgs e, T config) where T : BaseIOConfig
@@ -328,6 +330,14 @@ private void comboBoxMouseOut_SelectedIndexChanged(object sender, EventArgs e)
328330
}
329331
}
330332

333+
private void checkOutputDelay_CheckedChanged(object sender, EventArgs e)
334+
{
335+
if (checkOutputDelay.Checked)
336+
{
337+
numericUpDownDelay_ValueChanged(sender, e);
338+
}
339+
}
340+
331341
private void numericUpDownDelay_ValueChanged(object sender, EventArgs e)
332342
{
333343
var nFlag = 0;
@@ -346,9 +356,8 @@ private void numericUpDownDelay_ValueChanged(object sender, EventArgs e)
346356
0,
347357
(int) numericUpDownOutputParameter.Value);
348358

349-
var zDisplay = txtKeyOut;
350-
zDisplay.Text = zOutputConfig.GetDescription();
351-
zDisplay.Tag = zOutputConfig;
359+
txtKeyOut.Text = zOutputConfig.GetDescription();
360+
txtKeyOut.Tag = zOutputConfig;
352361
}
353362

354363
private void btnAdd_Click(object sender, EventArgs e)
@@ -452,25 +461,54 @@ private void checkOutputToggle_CheckedChanged(object sender, EventArgs e)
452461
if (checkOutputToggle.Checked)
453462
{
454463
checkOutputAlt.Checked =
455-
checkOutputShift.Checked =
456-
checkOutputControl.Checked =
457-
checkOutputRepeat.Checked =
458-
checkOutputDelay.Checked =
459-
checkOutputNothing.Checked = false;
464+
checkOutputShift.Checked =
465+
checkOutputControl.Checked =
466+
checkOutputRepeat.Checked =
467+
checkOutputDelay.Checked =
468+
checkOutputNothing.Checked = false;
460469
}
461470
}
462471

463472
private void checkOutputDoNothing_CheckedChanged(object sender, EventArgs e)
464473
{
465474
comboBoxOutMouse.Enabled =
466-
checkOutputAlt.Enabled =
467-
checkOutputShift.Enabled =
468-
checkOutputControl.Enabled =
469-
checkOutputUp.Enabled =
470-
checkOutputDown.Enabled =
471-
checkOutputToggle.Enabled =
472-
checkOutputDelay.Enabled =
473-
checkOutputRepeat.Enabled = !checkOutputNothing.Checked;
475+
checkOutputAlt.Enabled =
476+
checkOutputShift.Enabled =
477+
checkOutputControl.Enabled =
478+
checkOutputUp.Enabled =
479+
checkOutputDown.Enabled =
480+
checkOutputToggle.Enabled =
481+
checkOutputDelay.Enabled =
482+
checkOutputRepeat.Enabled =
483+
checkOutputCancel.Enabled =
484+
!checkOutputNothing.Checked;
485+
if (checkOutputNothing.Checked)
486+
{
487+
var zOutputConfig = new OutputConfig((int)OutputConfig.OutputFlag.DoNothing, 0);
488+
txtKeyOut.Text = zOutputConfig.GetDescription();
489+
txtKeyOut.Tag = zOutputConfig;
490+
}
491+
}
492+
493+
private void checkOutputCancel_CheckedChanged(object sender, EventArgs e)
494+
{
495+
comboBoxOutMouse.Enabled =
496+
checkOutputAlt.Enabled =
497+
checkOutputShift.Enabled =
498+
checkOutputControl.Enabled =
499+
checkOutputUp.Enabled =
500+
checkOutputDown.Enabled =
501+
checkOutputToggle.Enabled =
502+
checkOutputDelay.Enabled =
503+
checkOutputRepeat.Enabled =
504+
checkOutputNothing.Enabled =
505+
!checkOutputCancel.Checked;
506+
if (checkOutputCancel.Checked)
507+
{
508+
var zOutputConfig = new OutputConfig((int)OutputConfig.OutputFlag.CancelActiveOutputs, 0);
509+
txtKeyOut.Text = zOutputConfig.GetDescription();
510+
txtKeyOut.Tag = zOutputConfig;
511+
}
474512
}
475513

476514
#endregion
@@ -513,11 +551,17 @@ private InputConfig UpdateInputFlags(InputConfig zInputConfig)
513551

514552
private OutputConfig UpdateOutputFlags(OutputConfig zOutputConfig)
515553
{
554+
if (zOutputConfig.IsFlaggedAs(OutputConfig.OutputFlag.DoNothing)
555+
|| zOutputConfig.IsFlaggedAs(OutputConfig.OutputFlag.CancelActiveOutputs))
556+
{
557+
return zOutputConfig;
558+
}
559+
560+
516561
// get the flags from the check boxes (always, both mouse and keyboard support them in some fashion)
517562
var bAlt = checkOutputAlt.Checked;
518563
var bControl = checkOutputControl.Checked;
519564
var bShift = checkOutputShift.Checked;
520-
var bNone = checkOutputNothing.Checked;
521565
var bToggle = checkOutputToggle.Checked;
522566
var bRepeat = checkOutputRepeat.Checked;
523567
var bDown = checkOutputDown.Checked;
@@ -530,7 +574,6 @@ private OutputConfig UpdateOutputFlags(OutputConfig zOutputConfig)
530574
nFlags = BitUtil.UpdateFlag(nFlags, zOutputConfig.IsFlaggedAs(OutputConfig.OutputFlag.MouseOut), OutputConfig.OutputFlag.MouseOut);
531575
nFlags = BitUtil.UpdateFlag(nFlags, zOutputConfig.IsFlaggedAs(OutputConfig.OutputFlag.Delay), OutputConfig.OutputFlag.Delay);
532576

533-
nFlags = BitUtil.UpdateFlag(nFlags, bNone, OutputConfig.OutputFlag.DoNothing);
534577
nFlags = BitUtil.UpdateFlag(nFlags, bToggle, OutputConfig.OutputFlag.Toggle);
535578
nFlags = BitUtil.UpdateFlag(nFlags, bRepeat, OutputConfig.OutputFlag.Repeat);
536579
nFlags = BitUtil.UpdateFlag(nFlags, bDown, OutputConfig.OutputFlag.Down);
@@ -664,5 +707,6 @@ private bool ValidateOutputHasAction(OutputConfig zOutputConfig)
664707
}
665708

666709
#endregion
710+
667711
}
668712
}

Forms/KeyCaptureConfig.designer.cs

Lines changed: 16 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 & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -153,19 +153,16 @@ void InitiallizeEntryContainerListItem(RemapEntryContainerListItem* pKeyItem, Re
153153
pKeyItem->pEntryContainer->pEntry = pEntry;
154154
}
155155

156-
/*
157-
Shuts down the key capture hook and frees any allocated memory
158-
*/
159-
__declspec(dllexport) void ShutdownCapture()
156+
void ShutdownInputThreads()
160157
{
161158
// signal shutdown for all entries with a thread handle
162-
for(int nIdx = 0; nIdx < WIN_KEY_COUNT; nIdx++)
159+
for (int nIdx = 0; nIdx < WIN_KEY_COUNT; nIdx++)
163160
{
164-
if(NULL != g_KeyTranslationTable[nIdx])
161+
if (NULL != g_KeyTranslationTable[nIdx])
165162
{
166163
RemapEntryContainerListItem* pListItem = g_KeyTranslationTable[nIdx];
167164
RemapEntryContainerListItem* pNextItem = NULL;
168-
while(NULL != pListItem)
165+
while (NULL != pListItem)
169166
{
170167
pNextItem = pListItem->pNext;
171168
if (NULL != pListItem->pEntryContainer->pEntryState->threadHandle)
@@ -175,7 +172,7 @@ __declspec(dllexport) void ShutdownCapture()
175172
pListItem = pNextItem;
176173
}
177174
}
178-
}
175+
}
179176

180177
// monitor and terminate threads for all entries with a thread handle
181178
for (int nIdx = 0; nIdx < WIN_KEY_COUNT; nIdx++)
@@ -187,10 +184,10 @@ __declspec(dllexport) void ShutdownCapture()
187184
while (NULL != pListItem)
188185
{
189186
pNextItem = pListItem->pNext;
190-
if(NULL != pListItem->pEntryContainer->pEntryState->threadHandle)
187+
if (NULL != pListItem->pEntryContainer->pEntryState->threadHandle)
191188
{
192189
DWORD dwExitCode = WAIT_TIMEOUT;
193-
for(int shutdownIteration = 0; shutdownIteration < THREAD_SHUTDOWN_MAX_ATTEMPTS && dwExitCode != WAIT_OBJECT_0; shutdownIteration++)
190+
for (int shutdownIteration = 0; shutdownIteration < THREAD_SHUTDOWN_MAX_ATTEMPTS && dwExitCode != WAIT_OBJECT_0; shutdownIteration++)
194191
{
195192
// check on the state of the thread (for 100ms) (MS says not to use GetExitCodeThread unless the thread is known to be exited)
196193
dwExitCode = WaitForSingleObject(pListItem->pEntryContainer->pEntryState->threadHandle, THREAD_SHUTDOWN_ATTEMPT_DELAY_MS);
@@ -205,7 +202,15 @@ __declspec(dllexport) void ShutdownCapture()
205202
}
206203
}
207204
}
205+
}
208206

207+
/*
208+
Shuts down the key capture hook and frees any allocated memory
209+
*/
210+
__declspec(dllexport) void ShutdownCapture()
211+
{
212+
// stop any active threads
213+
ShutdownInputThreads();
209214

210215
// disable the hook
211216
if(NULL != g_hookMain)

KeyCapLib/KeyCapture.h

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

31+
// shared functions
32+
void ShutdownInputThreads();
33+
3134
// === consts and defines
3235
const int THREAD_SHUTDOWN_MAX_ATTEMPTS = 5;
3336
const int THREAD_SHUTDOWN_ATTEMPT_DELAY_MS = 100;

KeyCapLib/KeyCaptureUtil.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ char* GetInputConfigDescription(InputConfig inputConfig)
7171
char* GetOutputConfigDescription(OutputConfig outputConfig)
7272
{
7373
char* pDescription = (char*)malloc(DESCRIPTION_BUFFER_SIZE);
74-
sprintf_s(pDescription, DESCRIPTION_BUFFER_SIZE, "OutputConfig [Key: %d 0x%02x][Alt: %s][Ctrl: %s][Shift: %s][Nothing: %s][Mouse: %s][Delay: %s][Toggle: %s][Down: %s][Up: %s]",
74+
sprintf_s(pDescription, DESCRIPTION_BUFFER_SIZE, "OutputConfig [Key: %d 0x%02x][Alt: %s][Ctrl: %s][Shift: %s][Nothing: %s][Mouse: %s][Delay: %s][Toggle: %s][Down: %s][Up: %s][Cancel: %s]",
7575
outputConfig.virtualKey,
7676
outputConfig.virtualKey,
7777
GetBoolString(outputConfig.outputFlag.bAlt),
@@ -82,7 +82,8 @@ char* GetOutputConfigDescription(OutputConfig outputConfig)
8282
GetBoolString(outputConfig.outputFlag.bDelay),
8383
GetBoolString(outputConfig.outputFlag.bToggle),
8484
GetBoolString(outputConfig.outputFlag.bDown),
85-
GetBoolString(outputConfig.outputFlag.bUp)
85+
GetBoolString(outputConfig.outputFlag.bUp),
86+
GetBoolString(outputConfig.outputFlag.bCancelActiveOutputs)
8687
);
8788

8889
return pDescription;

KeyCapLib/keycapturestructs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ struct OutputFlag
5656
BYTE bDown : 1;
5757
BYTE bUp : 1;
5858
BYTE bRepeat : 1;
59-
BYTE padTwo : 6;
59+
BYTE bCancelActiveOutputs : 1;
60+
BYTE padTwo : 5;
6061
BYTE padThree : 8;
6162
BYTE padFour : 8;
6263
};

KeyCapLib/sendinputthread.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "keycapturestructs.h"
2626
#include "keycaptureutil.h"
27+
#include "keycapture.h"
2728
#include "sendinputthread.h"
2829
#include "keyboardinput.h"
2930
#include "mouseinput.h"
@@ -86,7 +87,7 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
8687
do
8788
{
8889
// iterate over the target inputs
89-
while (pOutputConfig < pTerminator)
90+
while (pOutputConfig < pTerminator && !pRemapEntryState->bShutdown)
9091
{
9192
if (!pOutputConfig->outputFlag.bRepeat && firstPassComplete)
9293
{
@@ -96,17 +97,28 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
9697
#ifdef _DEBUG
9798
char* pOutputConfigDescription = GetOutputConfigDescription(*pOutputConfig);
9899
LogDebugMessage("Performing %s Output Action: %s",
99-
pOutputConfig->outputFlag.bMouseOut ? "Mouse" : "Keyboard",
100+
pOutputConfig->outputFlag.bMouseOut ? "Mouse" : "Keyboard (or other)",
100101
pOutputConfigDescription
101102
);
102103
free(pOutputConfigDescription);
103104
#endif
104105
// mouse input
105-
if (pOutputConfig->outputFlag.bMouseOut)
106+
if(pOutputConfig->outputFlag.bDoNothing)
107+
{
108+
// nothing
109+
}
110+
if(pOutputConfig->outputFlag.bCancelActiveOutputs)
111+
{
112+
// HACK alert - would destroy this thread, so disassociate and exit immediately after
113+
pRemapEntryState->bShutdown = true;
114+
pRemapEntryState->threadHandle = NULL;
115+
ShutdownInputThreads();
116+
break;
117+
}
118+
else if (pOutputConfig->outputFlag.bMouseOut)
106119
{
107120
SendInputMouse(pRemapEntryState, pOutputConfig);
108121
}
109-
// just a delay
110122
else if (pOutputConfig->outputFlag.bDelay)
111123
{
112124
//Want to delay break...
@@ -116,13 +128,14 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
116128
Sleep(100);
117129
if (pRemapEntryState->bShutdown)
118130
{
131+
LogDebugMessage("Exiting delay loop due to shutdown.");
119132
break;
120133
}
121134
}
122135
}
123-
// keyboard input
124136
else
125137
{
138+
// default to keyboard input
126139
SendInputKeys(pRemapEntryState, pOutputConfig);
127140
}
128141
pOutputConfig++; // move the pointer forward one KeyDefinition
@@ -146,6 +159,7 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
146159

147160
// flip the overall toggle state
148161
pRemapEntryState->bToggled = !pRemapEntryState->bToggled;
162+
pRemapEntryState->bShutdown = false;
149163

150164
LogDebugMessage("SendInputThread Completed");
151165
// Disconnect this thread from the state

0 commit comments

Comments
 (0)