Skip to content

Commit b554c9b

Browse files
committed
Added preliminary support for long press on inputs
1 parent 025382f commit b554c9b

File tree

11 files changed

+144
-31
lines changed

11 files changed

+144
-31
lines changed

Format/InputConfig.cs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,26 +46,19 @@ public enum InputFlag
4646
Shift = 1 << 0,
4747
Control = 1 << 1,
4848
Alt = 1 << 2,
49-
// supports up to 32 entries
50-
}
49+
LongPress = 1 << 3,
50+
// supports up to 32 entries
51+
}
5152

5253
/// <summary>
5354
/// Constructor for an InputConfig
5455
/// </summary>
5556
/// <param name="byFlags">The flags defining the input</param>
5657
/// <param name="byVirtualKey">The value of the input</param>
5758
/// <param name="eKeyArgs">The input key arguments from user input</param>
58-
public InputConfig(byte byVirtualKey, KeyEventArgs eKeyArgs)
59+
public InputConfig(byte byVirtualKey)
5960
{
6061
VirtualKey = byVirtualKey;
61-
62-
if (null != eKeyArgs)
63-
{
64-
Flags |= (int)(
65-
(eKeyArgs.Shift ? (int)InputFlag.Shift : (byte)0) |
66-
(eKeyArgs.Alt ? (int)InputFlag.Alt : (byte)0) |
67-
(eKeyArgs.Control ? (int)InputFlag.Control : (byte)0));
68-
}
6962
}
7063

7164
public InputConfig(Stream zStream) : base(zStream) { }
@@ -77,6 +70,7 @@ public override string GetDescription()
7770
(IsFlaggedAs(InputFlag.Shift) ? "+Shift" : string.Empty) +
7871
(IsFlaggedAs(InputFlag.Alt) ? "+Alt" : string.Empty) +
7972
(IsFlaggedAs(InputFlag.Control) ? "+Control" : string.Empty) +
73+
(IsFlaggedAs(InputFlag.LongPress) ? "+LongPress" : string.Empty) +
8074
"]";
8175
}
8276
}

Forms/KeyCaptureConfig.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public partial class KeyCaptureConfig
4747
private readonly List<string> m_listRecentFiles = new List<string>();
4848
private readonly KeyCapInstanceState m_zInstanceState;
4949
private readonly IniManager m_zIniManager = new IniManager(Application.ProductName, false, true, false);
50+
private HashSet<Control> m_setInputControls = new HashSet<Control>();
5051
private HashSet<Control> m_setOutputControls = new HashSet<Control>();
5152

5253
private FormWindowState m_ePrevWindowState = FormWindowState.Normal;
@@ -103,7 +104,7 @@ private void KeyCaptureConfig_Load(object sender, EventArgs e)
103104
}
104105
}
105106

106-
InitOutputControlsSet();
107+
InitControlSets();
107108
ConfigureToolTips();
108109

109110
// load the command line specified file
@@ -120,8 +121,15 @@ private void KeyCaptureConfig_Load(object sender, EventArgs e)
120121
}
121122
}
122123

123-
private void InitOutputControlsSet()
124+
private void InitControlSets()
124125
{
126+
m_setInputControls = new HashSet<Control>(new Control[]
127+
{
128+
checkInputAlt,
129+
checkInputControl,
130+
checkInputShift,
131+
checkInputLongPress
132+
});
125133
m_setOutputControls = new HashSet<Control>(new Control[]
126134
{
127135
checkOutputAlt,
@@ -254,7 +262,7 @@ private void txtKeyIn_KeyDown(object sender, KeyEventArgs e)
254262
#if LOG_KEYS
255263
Console.Out.WriteLine("Key Input: {0} 0x{1}".FormatString(e.KeyCode, e.KeyCode.ToString("x")));
256264
#endif
257-
UpdateTextBox((TextBox)sender, e, new InputConfig((byte)e.KeyCode, e));
265+
UpdateTextBox((TextBox)sender, e, new InputConfig((byte)e.KeyCode));
258266
}
259267

260268
private void txtKeyOut_KeyDown(object sender, KeyEventArgs e)
@@ -482,6 +490,15 @@ private void btnStart_Click(object sender, EventArgs e)
482490

483491
#region Input / Output Settings Control Events
484492

493+
private void checkInputLongPress_CheckedChanged(object sender, EventArgs e)
494+
{
495+
ToggleControlsEnabled(m_setInputControls, !checkInputLongPress.Checked, (Control)sender);
496+
if (checkInputLongPress.Checked)
497+
{
498+
ToggleCheckboxesChecked(false, checkInputAlt, checkInputControl, checkInputShift);
499+
}
500+
}
501+
485502
private void comboBoxMouseOut_SelectedIndexChanged(object sender, EventArgs e)
486503
{
487504
SetOutKeyConfig(comboBoxOutMouse.SelectedIndex == 0 ? null : new OutputConfig(
@@ -628,11 +645,13 @@ private InputConfig UpdateInputFlags(InputConfig zInputConfig)
628645
var bAlt = checkInputAlt.Checked;
629646
var bControl = checkInputControl.Checked;
630647
var bShift = checkInputShift.Checked;
648+
var bLongPress = checkInputLongPress.Checked;
631649

632650
var nFlags = 0;
633651
nFlags = BitUtil.UpdateFlag(nFlags, bAlt, InputConfig.InputFlag.Alt);
634652
nFlags = BitUtil.UpdateFlag(nFlags, bControl, InputConfig.InputFlag.Control);
635653
nFlags = BitUtil.UpdateFlag(nFlags, bShift, InputConfig.InputFlag.Shift);
654+
nFlags = BitUtil.UpdateFlag(nFlags, bLongPress, InputConfig.InputFlag.LongPress);
636655
zInputConfig.Flags = nFlags;
637656
return zInputConfig;
638657
}

Forms/KeyCaptureConfig.designer.cs

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

KeyCapLib/KeyCaptureUtil.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,22 @@ char* GetBoolString(BYTE nValue)
6666
char* GetInputConfigDescription(InputConfig inputConfig)
6767
{
6868
char* pDescription = (char*)malloc(DESCRIPTION_BUFFER_SIZE);
69-
sprintf_s(pDescription, DESCRIPTION_BUFFER_SIZE, "InputConfig [Key: %d 0x%02x][Alt: %s][Ctrl: %s][Shift: %s]",
70-
inputConfig.virtualKey,
71-
inputConfig.virtualKey,
72-
GetBoolString(inputConfig.inputFlag.bAlt),
73-
GetBoolString(inputConfig.inputFlag.bControl),
74-
GetBoolString(inputConfig.inputFlag.bShift));
69+
if(inputConfig.inputFlag.bLongPress)
70+
{
71+
sprintf_s(pDescription, DESCRIPTION_BUFFER_SIZE, "InputConfig [Key: %d 0x%02x][LongPress: %s]",
72+
inputConfig.virtualKey,
73+
inputConfig.virtualKey,
74+
GetBoolString(inputConfig.inputFlag.bLongPress));
75+
}
76+
else
77+
{
78+
sprintf_s(pDescription, DESCRIPTION_BUFFER_SIZE, "InputConfig [Key: %d 0x%02x][Alt: %s][Ctrl: %s][Shift: %s]",
79+
inputConfig.virtualKey,
80+
inputConfig.virtualKey,
81+
GetBoolString(inputConfig.inputFlag.bAlt),
82+
GetBoolString(inputConfig.inputFlag.bControl),
83+
GetBoolString(inputConfig.inputFlag.bShift));
84+
}
7585
return pDescription;
7686
}
7787

KeyCapLib/keyboardproc.cpp

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
extern RemapEntryContainerListItem* g_KeyTranslationTable[WIN_KEY_COUNT];
2626

27+
ULONGLONG g_KeyDownTime[WIN_KEY_COUNT];
28+
2729
/*
2830
Implementation of the win32 LowLevelKeyboardProc (see docs for information)
2931
@@ -33,7 +35,7 @@ created to send out the key(s) to send to the os.
3335
*/
3436
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
3537
{
36-
KBDLLHOOKSTRUCT *pHook = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
38+
KBDLLHOOKSTRUCT *pHook = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
3739
bool bSentInput = false;
3840

3941
bool bAlt = 0 != (GetAsyncKeyState(VK_MENU) & 0x8000);
@@ -51,13 +53,16 @@ LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
5153
case WM_SYSKEYDOWN:
5254
// 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)
5355
{
54-
RemapEntryContainerListItem* pKeyListItem = g_KeyTranslationTable[pHook->vkCode];
56+
// NOTE: key down events will come in while a key is being held
57+
58+
const RemapEntryContainerListItem* pKeyListItem = g_KeyTranslationTable[pHook->vkCode];
5559
while (NULL != pKeyListItem)
5660
{
57-
InputConfig* pKeyDef = &pKeyListItem->pEntryContainer->pEntry->inputConfig;
61+
const InputConfig* pKeyDef = &pKeyListItem->pEntryContainer->pEntry->inputConfig;
5862
if ((bAlt == pKeyDef->inputFlag.bAlt) &&
5963
(bControl == pKeyDef->inputFlag.bControl) &&
60-
(bShift == pKeyDef->inputFlag.bShift))
64+
(bShift == pKeyDef->inputFlag.bShift)
65+
&& !pKeyDef->inputFlag.bLongPress)
6166
{
6267
#ifdef _DEBUG
6368
char* pInputConfigDescription = GetInputConfigDescription(*pKeyDef);
@@ -69,7 +74,24 @@ LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
6974
{
7075
pKeyListItem->pEntryContainer->pEntryState->threadHandle = CreateThread(NULL, 0, SendInputThread, pKeyListItem->pEntryContainer, 0, NULL);
7176
}
72-
// no matter if a new SendInputThread was started or not block further processing with the inputs
77+
// block further processing with the inputs
78+
bSentInput = true;
79+
break;
80+
}
81+
if(!bAlt
82+
&& !bControl
83+
&& !bShift
84+
&& pKeyDef->inputFlag.bLongPress)
85+
{
86+
if (g_KeyDownTime[pKeyDef->virtualKey] == 0) // ignore all keydown events on this key after recording the initial key down time
87+
{
88+
const ULONGLONG tickCount = GetTickCount64();
89+
g_KeyDownTime[pKeyDef->virtualKey] = tickCount;
90+
#ifdef _DEBUG
91+
LogDebugMessage("Detected LONGPRESS Key Down: %d Tick: %d", pKeyDef->virtualKey, tickCount);
92+
#endif
93+
}
94+
// block further processing with the inputs
7395
bSentInput = true;
7496
break;
7597
}
@@ -85,10 +107,42 @@ LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
85107
while (NULL != pKeyListItem)
86108
{
87109
InputConfig* pKeyDef = &pKeyListItem->pEntryContainer->pEntry->inputConfig;
88-
if ((bAlt == pKeyDef->inputFlag.bAlt) &&
89-
(bControl == pKeyDef->inputFlag.bControl) &&
90-
(bShift == pKeyDef->inputFlag.bShift))
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)
91123
{
124+
ULONGLONG tickCount = GetTickCount64();
125+
if (tickCount - g_KeyDownTime[pKeyDef->virtualKey] > 1000)
126+
{
127+
#ifdef _DEBUG
128+
char* pInputConfigDescription = GetInputConfigDescription(*pKeyDef);
129+
LogDebugMessage("Detected LONGPRESS Key Up: %s Outputs: %d", pInputConfigDescription, pKeyListItem->pEntryContainer->pEntry->outputCount);
130+
free(pInputConfigDescription);
131+
#endif
132+
// If there is NOT an existing thread OR the existing thread is running a repeat another key press is allowed
133+
if (NULL == pKeyListItem->pEntryContainer->pEntryState->threadHandle || pKeyListItem->pEntryContainer->pEntryState->bRepeating)
134+
{
135+
pKeyListItem->pEntryContainer->pEntryState->threadHandle = CreateThread(NULL, 0, SendInputThread, pKeyListItem->pEntryContainer, 0, NULL);
136+
}
137+
}
138+
else
139+
{
140+
LogDebugMessage("Detected LONGPRESS Key UP (too short): %d Tick: %d (Old Tick: %d)", pKeyDef->virtualKey, tickCount, g_KeyDownTime[pKeyDef->virtualKey]);
141+
// when a longpress "fails" just send the normal keypress
142+
CreateThread(NULL, 0, SendInputKeypress, pKeyDef, 0, NULL);
143+
}
144+
g_KeyDownTime[pKeyDef->virtualKey] = 0;
145+
// block further processing with the inputs
92146
bSentInput = true;
93147
break;
94148
}

KeyCapLib/keycapturestructs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ struct InputFlag
3434
const int KEYCAP_SHIFT = 1 << 0;
3535
const int KEYCAP_CONTROL = 1 << 1;
3636
const int KEYCAP_ALT = 1 << 2;
37+
const int KEYCAP_LONGPRESS = 1 << 3;
3738
#endif
3839
BYTE bShift : 1;
3940
BYTE bControl : 1;
4041
BYTE bAlt : 1;
41-
BYTE padOne : 5;
42+
BYTE bLongPress : 1;
43+
BYTE padOne : 4;
4244
BYTE padTwo : 8;
4345
BYTE padThree : 8;
4446
BYTE padFour : 8;

KeyCapLib/sendinputthread.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,20 @@ DWORD InitiateSendInput(RemapEntry* pRemapEntry, RemapEntryState* pRemapEntrySta
180180
free(pInputConfigDescription);
181181
#endif
182182
return 0;
183+
}
184+
185+
/*
186+
* Thread entry point for simple keypress (used for longpress configured keys to send the normal input key on key up)
187+
*/
188+
DWORD WINAPI SendInputKeypress(LPVOID lpParam)
189+
{
190+
InputConfig* inputConfig = static_cast<InputConfig*>(lpParam);
191+
int nIndex = 0;
192+
INPUT inputBuffer[MAX_KEY_INPUT_PER_STROKE];
193+
memset(&inputBuffer, 0, sizeof(INPUT) * MAX_KEY_INPUT_PER_STROKE);
194+
AppendSingleKey(inputConfig->virtualKey, &inputBuffer[nIndex++], 0);
195+
AppendSingleKey(inputConfig->virtualKey, &inputBuffer[nIndex++], KEYEVENTF_KEYUP);
196+
LogDebugMessage("[Sending Input Keypress][virtualKey: %d]", inputConfig->virtualKey);
197+
SendInput(nIndex, inputBuffer, sizeof(INPUT));
198+
return 0;
183199
}

KeyCapLib/sendinputthread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
#include "stdafx.h"
2929

3030
DWORD WINAPI SendInputThread(LPVOID lpParam);
31+
DWORD WINAPI SendInputKeypress(LPVOID lpParam);
3132

3233
#endif

Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,5 @@
5555
// You can specify all the values or you can default the Build and Revision Numbers
5656
// by using the '*' as shown below:
5757
// [assembly: AssemblyVersion("1.0.*")]
58-
[assembly: AssemblyVersion("2.0.0.4")]
59-
[assembly: AssemblyFileVersion("2.0.0.4")]
58+
[assembly: AssemblyVersion("2.0.0.5")]
59+
[assembly: AssemblyFileVersion("2.0.0.5")]

bin/Release/History.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
KeyCap Version History
22
--------------------------
3+
2.0.0.5
4+
- Added long press as an input option (at this time it requires being held for about 1 second)
5+
36
2.0.0.4
47
- Refactors and improvements with the output controls (blocking unsupported configurations)
58
- Updated all delays/repeats to operate on increments of 100ms

0 commit comments

Comments
 (0)