Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Features for momentary and toggle layers, properly held keys, more combo triggers, etc #101

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
d608a4c
add hold() function for momentary layer effect
Dregu Jan 26, 2024
4fb7e48
what happened to these
Dregu Jan 26, 2024
eba421d
fix replacing holdkeys twice, oops
Dregu Jan 26, 2024
a278164
support multiple keys in hold()
Dregu Jan 26, 2024
8d82c41
use combo() syntax instead of _ in hold()
Dregu Jan 27, 2024
6ce854d
block physical modifier up when included in hold, add moddedhold to r…
Dregu Jan 27, 2024
ff53a40
support modifier strings in hold functions
Dregu Jan 27, 2024
d2b0f0a
make most functions accept any key/combo format
Dregu Jan 27, 2024
1ed5982
fix .... modstrings breaking old behavior, silently ignore invalid ke…
Dregu Jan 27, 2024
997b19f
add option HoldRepeatsAllKeys and repeat only last key by default
Dregu Jan 27, 2024
c7f530c
fix hold with rewired keys
Dregu Jan 27, 2024
912b487
add more tap/hold modstrings
Dregu Jan 27, 2024
5bc79b3
add pretty labels for virtual keys
Dregu Jan 27, 2024
f88ffe8
add holdmods() to hold combo modifiers with physical mod and keys wit…
Dregu Jan 28, 2024
878f0a6
add type modifiers for key() function to clear the mess
Dregu Jan 28, 2024
839f7e5
support multiple functions per combo
Dregu Jan 28, 2024
7870942
some convenience functions
Dregu Jan 28, 2024
fa1f95a
add nop()
Dregu Jan 28, 2024
933c8bd
add up/tap combo triggers and toggleable modifiers
Dregu Jan 28, 2024
a460470
fixes
Dregu Jan 28, 2024
1e87ebf
rename combo to down
Dregu Jan 29, 2024
3d13037
add F24
Dregu Jan 29, 2024
3507b82
fix hold repeat
Dregu Jan 29, 2024
520862b
add exe() to run programs directly
Dregu Jan 29, 2024
cbc06b0
exe fixes, add kill() too
Dregu Jan 29, 2024
994a8b9
32 mods
Dregu Jan 29, 2024
0d35620
expand env variables in exe
Dregu Jan 29, 2024
b64b2da
fix modstring parser
Dregu Jan 30, 2024
0e5afa7
make modstring optional
Dregu Jan 30, 2024
ce1df40
add simple fallback function for combos
Dregu Jan 30, 2024
a40c9e7
add options to disable or forward Esc combos
Dregu Jan 30, 2024
605f7e5
fixes
Dregu Jan 30, 2024
aceacac
where did this go?
Dregu Jan 30, 2024
57e9591
support multiple keys in down etc
Dregu Jan 30, 2024
93efc4e
Load AutoHotkey_H as DLL, define and call functions directly in the ini
Dregu Jan 31, 2024
c4ed395
fix
Dregu Feb 1, 2024
e2fb5ae
hope that wasn't important
Dregu Feb 1, 2024
d8f1191
add deviceid filter to combos
Dregu Feb 1, 2024
65cfcd1
initial mouse support
Dregu Feb 1, 2024
2d68bb1
mouse fixes
Dregu Feb 1, 2024
970030b
add option to enable mouse support
Dregu Feb 1, 2024
08eb82b
device filter optimization, fixes
Dregu Feb 2, 2024
7c72b9e
fix the fixes
Dregu Feb 2, 2024
22bddba
add Esc+M to toggle mouse input support
Dregu Feb 3, 2024
bcc25d4
handle multiple mouse buttons per stroke
Dregu Feb 6, 2024
2e6f407
add REPEAT combo trigger
Dregu Feb 6, 2024
8d5c4ad
fix mouse wheel events getting stuck?
Dregu Feb 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,431 changes: 1,100 additions & 331 deletions capsicain/capsicain.cpp

Large diffs are not rendered by default.

33 changes: 30 additions & 3 deletions capsicain/capsicain.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#define PROGRAM_NAME_AHK "autohotkey.exe"
#include <string>
#include <map>

#include "interception.h"
#include "utils.h"
#include "configUtils.h"
Expand All @@ -8,6 +10,23 @@
#define IFTRACE if(false)
#define IFPROF if(false) //measuring time takes some time

struct Executable
{
std::string verb;
std::string path;
std::string args;
std::string dir;
int mode;
HANDLE proc;
DWORD pid;
HWND hwnd;
};

struct Device {
std::string id;
bool keyboard;
bool apple;
};

enum KEYSTATE
{
Expand Down Expand Up @@ -39,15 +58,15 @@ void playKeyEventSequence(std::vector<VKeyEvent> keyEventSequence);

void printOptions();

void sendVKeyEvent(VKeyEvent keyEvent);
void sendVKeyEvent(VKeyEvent keyEvent, bool hold = true);

void sendResultingKeyOrSequence();

VKeyEvent convertIkstroke2VKeyEvent(InterceptionKeyStroke ikStroke);

void normalizeIKStroke(InterceptionKeyStroke &ikstroke);
InterceptionKeyStroke convertVkeyEvent2ikstroke(VKeyEvent keyEvent);
void getHardwareId();
std::map<uint8_t, Device>* getHardwareId(bool refresh = true);

bool initConsoleWindow();
void parseIniGlobals();
Expand All @@ -73,3 +92,11 @@ void resetCapsNumScrollLock();
int obfuscateVKey(int vk);
int deObfuscateVKey(int vk);

int getKeyHolding(int vcode);
bool runExecutable(Executable &exe);
void killExecutable(Executable &exe);
void killExecutableByPath(std::string path);

void loadAHK();
void unloadAHK();
void sendAHK(std::string msg);
178 changes: 178 additions & 0 deletions capsicain/capsicain.newfeatures.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# This is not a complete working ini, it just has random examples of the
# new features in https://github.com/cajhin/capsicain/pull/101

# Forward some Esc keys to combos or OS, but also do the default Esc action, unless disabled
GLOBAL forwardEscKey A

# Disable some Esc actions you don't need and don't want to end up in some weird mode accidentally
# Disabled keys can also be forwarded to OS
GLOBAL disableEscKey Q W E Y U P A S H J K L ; Z B , .

# Repeat all held keys in combos, instead of the last key only.
# Standard keyboard behavior is to only repeat the last key pressed.
#OPTION holdRepeatsAllKeys

# Set default formatter to wrap around combo parameters when no function is specified
# This is the default default already
#OPTION defaultFunction key(%s, m)

# Modstring is also optional, so this is the simplest form for combos
DOWN A > LSHF+B # Equivalent to: COMBO A [] > key(LSHF+B, m)

REWIRE RCTRL MOD9
REWIRE LWIN MOD11 LWIN

# You can rewire the Esc key and use it in combos if the combo key is included in forwardEscKey
REWIRE ESC MOD12 ESC
DOWN A [&^^^ ^^^^ ^^^^] > B

# Simple example with RCTRL emulating the Fn layer on a 65%
# with no physical INS,HOME,END keys and a horrible real Fn layer
COMBO DEL [...& .... ....] > hold(INS)
COMBO PGUP [...& .... ....] > hold(HOME)
COMBO PGDOWN [...& .... ....] > hold(END)

# More confusing examples with real modifiers
COMBO Z [.&] > hold(LSHF + A) # Shift+Z will hold Shift+A until Z is released and also block physical Shift release
COMBO Z [&.] > hold(LSHF + A) # Ctrl+Z will hold Shift+A until Z is released, but not touch Ctrl
COMBO X [&.] > moddedhold(LSHF + A) # Ctrl+X will release Ctrl and hold Shift+A until X is released
# After pressing MOD11+SPACE, MOD11 holds LWIN, SPACE holds SPACE, cause language switcher demands it
COMBO SPACE [^&^^ ^^^^ ^^^^] > holdmods(LWIN + SPACE)

# This is just weird, but still works
COMBO C [...& .... ....] > hold(A + ..&& + LWIN + X) # RCtrl+C will hold Shift+Ctrl+A+Win+X until C is released

# key(combo, type) can be used as an alias for different functions, where type is any of
# 42: repeat combo 42 times, can be combined with r but not h or m
# r: release all keys (temporarily, unless combined with hold) before the combo
# h: hold all keys in the combo until triggering main physical key is released
# m: hold modifiers with physical modifier and other keys with other keys separately

# key(LSHF+X) == combo(LSHF+X)
# key(LSHF+X, r) == moddedkey(X + ...&)
# key(LSHF+X, 10) == combontimes(LSHF+X, 10)
# key(LSHF+X, h) == hold(LSHF+X)
# key(LSHF+X, m) == holdmods(LSHF+X)
# key(LSHF+X, hr) == moddedhold(LSHF+X)
# key(LSHF+X, rm) == moddedholdmods(LSHF+X)

# h is great for simple one-to-one momentary Fn layer keys that should be held
# Example: MOD11+DEL will hold INS until DEL is released
COMBO DEL [...& .... ....] > key(INS, h)
# Example: MOD11+UP will hold LCTRL+UP until UP is released
COMBO UP [...& .... ....] > key(LCTRL+UP, h)

# use m when pressing MOD+X opens and cycles something, but releasing MOD closes it
# perfect for the language switcher or cycling windows of pinned taskbar items
# Example: when MOD11+. is pressed, send LWIN + SPACE,
# hold LWIN until MOD11 is released,
# hold SPACE until . is released
COMBO . [^&^^ ^^^^ ^^^^] > key(LWIN + SPACE, m)

# Use r with real modifiers that shouldn't be included in the resulting combo
# Example: when LSHF+A is pressed, release LSHF, but
# hold LCTRL until physical LSHF is released,
# hold A until A is released
COMBO A [^^^^ ^^^^ ^^^&] > key(LCTRL + A, rm)

# Example: LCTRL+UP will release LCTRL, press UP 10 times and press LCTRL again
COMBO UP [^^^^ ^^^^ ^^&^] > key(UP, 10r)

# Support multiple functions per combo, and some new functions to go with that
COMBO 1 [^^^^ ^^^^ ^^&^] > release() altchar(0169) key(SPACE) sequence(&LSHF_d_^LSHF_r_e_g_u)
COMBO 2 [^^^^ ^^^^ ^^&^] > release() delay(33) sequence(h_e_l_l_o_SPACE_delay:0_w_o_r_l_d)


# Tap OR Hold MOD9+4 to F4, without adding two combos for & and t
# DOWN == COMBO, I aliased it when I added UP to make it clear which event triggers it
DOWN 4 [.../ .... ....] > hold(F4)
# TapAndHold Alt+4 to Alt+F4
DOWN 4 [.... .... *...] > key(F4)
# Press B after releasing A
# Note that you have to specifically release keys with release() or up(key) if you hijack their UP/TAP/SLOW events
UP A [.... .... ....] > up(A) key(B)


# Set MOD9 down with slow tap (one long enough to trigger repeat)
# Modifiers are forced down even if pressed and released physically, you have to specifically up() them
# Normal keys will pop back up when pressed once
SLOW MOD9 [.... ^^^^ ^^^^] > down(MOD9)
# Set MOD9 up with tap if it's forced down, but also mark it untapped,
# cause we don't want the tap to trigger on the next key, as this tap was to disable the mod
TAP MOD9 [...& ^^^^ ^^^^] > up(MOD9) untap(MOD9)


# Add executables to run with exe(num) function
# The params are passed to ShellExecute(lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd) as is
EXE 1 open,wt,,,10
EXE 2 open,WindowsTerminal.exe
# Launch terminal with MOD11+RET
DOWN RET [^&^^ ^^^^ ^^^^] > exe(1)
# Kill previously launched program if we still have a valid handle to it, or any process matching the filename
# kill(1) wouldn't work here, cause wt is not the name of the process, nor is the handle from ShellExecute valid any more
DOWN RET [^&^^ ^^^| ^^^|] > kill(2)


# "Mod-Tap", send small m when tapping fast, and big M when tapping slow enough to trigger key repeat
# The repeat delay depends on your Windows keyboard settings and can't be changed here
DOWN M > nop()
TAP M > key(M)
SLOW M > key(LSHF+M)


# Block repeat strokes for a key
REPEAT A > nop()


# Add {&deviceid} on combos to trigger only on matching devices
DOWN A {&003d} [&.] > B
# Add {^deviceid} on combos to exclude all matching devices
DOWN A {^003d} [&.] > C


# Enable experimental mouse support for a config, otherwise mouse is ignored
# Mouse has some limitations atm, like skipping events if you release two buttons at exactly the same time...
# M->KB and KB->M combos are sent through the last seen device of the other kind
OPTION enableMouse
# Ctrl + left click releases Ctrl and sends right click
DOWN MOUSE1 [&.] > key(MOUSE2, r)
# PGDOWN sends wheel down
DOWN PGDOWN [] > MWDOWN
# Middle mouse sends Return
DOWN MOUSE3 [] > RET
# Toggle thumb buttons to keys with MOD9+M,
# cause it's *checks calendar* 2024(!) and games still don't support thumb buttons
DOWN M [^^.^ ^^^& ^^^^ ^^^^] > toggle(MOD14)
DOWN MOUSE4 [^^&^ ^^^^ .... ....] > PGDOWN
DOWN MOUSE5 [^^&^ ^^^^ .... ....] > PGUP
# Or you could just do this and switch configs I guess
#REWIRE MOUSE4 PGDOWN
#REWIRE MOUSE5 PGUP


# Load AutoHotkey_H 2.0+ as DLL and call AHK functions directly (or use cryptic hotkeys if you really want to)
# Get AutoHotkey64.dll from https://github.com/thqby/AutoHotkey_H and put next to capsicain.exe
GLOBAL startAHK
# Run some AHK functions
DOWN T [^^^& ^^^^ ^^^^] > ahk(test, 42, 27)
DOWN X [^^^& ^^^^ ^^^^] > ahk(maximize)

# Everything after [ahk] will be loaded as an AHK script and reloaded on Esc+A/R
# This has to be the last section in the ini
[ahk]

; Remember to add Persistent if you don't have real hotkeys in here, AHK won't run without hotkeys by default
Persistent

test(a, b) {
c := a + b
MsgBox "Quick maths: " . a . " + " . b . " = " . c
}

maximize() {
If (WinGetMinMax("A")) {
WinRestore "A"
} else {
WinMaximize "A"
}
}
Loading