houmain / keymapper

A cross-platform context-aware key remapper.
GNU General Public License v3.0
257 stars 21 forks source link

Feature Request: key mapping changed notifications #91

Closed G-M0N3Y-2503 closed 2 months ago

G-M0N3Y-2503 commented 6 months ago

It would be good to be able to configure a system notification to pop up that helps explain the key map that is active.

For me the notible key maps change when any of the virtual keys are pressed or when a context change matches a new block.

Perhaps a good first step for the notification message would be the virtual keys alias and the context values.

Linux Workaround

[class=/chrome/i title=/some website/i device="Razer Razer Basilisk V3 Pro"]
Modified = Virtual0
!Modified ControlLeft   >> Modified $(notify-send -t 500 -a "keymapper" "Not Modified") ^
Modified{ControlLeft}   >> Modified $(notify-send -t 500 -a "keymapper" "Modified") ^
!Modified ButtonForward >> A
Modified{ButtonForward} >> B
G-M0N3Y-2503 commented 6 months ago

Maybe for the Virtual key senario more thought is required. What works for me on Linux is the following:

[device="Razer Razer Basilisk V3 Pro"]
VolumeProfile = Virtual1
MediaProfile = Virtual2
Profiles = MediaProfile | VolumeProfile

[system="Linux" device="Razer Razer Basilisk V3 Pro"]
SetNoneProfile      =               $(notify-send -t 500 -a "keymapper" "Profile:\n [None] Volume  Media") ^
SetVolumeProfile    = VolumeProfile $(notify-send -t 500 -a "keymapper" "Profile:\n  None [Volume] Media") ^
SetMedifProfile     = MediaProfile  $(notify-send -t 500 -a "keymapper" "Profile:\n  None  Volume [Media]") ^

# Reddit

[modifier="!Profiles" class=/chrome/i title=/reddit/i device="Razer Razer Basilisk V3 Pro"]
ButtonForward   >> J
ButtonBack      >> K

# Default

[device="Razer Razer Basilisk V3 Pro"]
!Profiles ControlLeft       >> SetVolumeProfile
VolumeProfile{ControlLeft}  >> VolumeProfile SetMedifProfile
MediaProfile{ControlLeft}   >> MediaProfile SetNoneProfile

[modifier="VolumeProfile" device="Razer Razer Basilisk V3 Pro"]
ButtonForward   >> AudioVolumeUp
ButtonBack      >> AudioVolumeDown
AltLeft         >> (Meta){AudioVolumeMute}

[modifier="MediaProfile" device="Razer Razer Basilisk V3 Pro"]
ButtonForward   >> MediaTrackNext
ButtonBack      >> MediaTrackPrevious
AltLeft         >> MediaPlayPause

[device="Razer Razer Basilisk V3 Pro"]
AltLeft >> LaunchApp1
Any     >> Any

So It notifies me exactly what mapping I have for the virtual keys but not when I am on Reddit vs some other site.

ristomatti commented 6 months ago

@G-M0N3Y-2503 Cool trick, thanks for sharing!

G-M0N3Y-2503 commented 5 months ago

For Windows and Linux the following gets across the line for the notification part at least.

MediaProfileMsg  = "Profile:  None  Volume [Media]"
VolumeProfileMsg = "Profile:  None [Volume] Media"
NoneProfileMsg   = "Profile: [None] Volume  Media"

[system="Linux" device="Razer Razer Basilisk V3 Pro"]
MediaProfileNotify  = $(notify-send -t 500 -a "keymapper" MediaProfileMsg) ^
VolumeProfileNotify = $(notify-send -t 500 -a "keymapper" VolumeProfileMsg) ^
NoneProfileNotify   = $(notify-send -t 500 -a "keymapper" NoneProfileMsg) ^

[system="Windows"]
MediaProfileNotify  = $(msg.exe * /TIME:1 MediaProfileMsg) ^
VolumeProfileNotify = $(msg.exe * /TIME:1 VolumeProfileMsg) ^
NoneProfileNotify   = $(msg.exe * /TIME:1 NoneProfileMsg) ^

No device filter on Windows which makes it difficult for cross-platform.

houmain commented 5 months ago

Hi, I am planning to implement a few new features to simplify this:

With these something like the following configuration should be possible:

[system="Linux"]
notify(TEXT) = $(notify-send -t 500 -a "keymapper" TEXT)

[system="Windows"]
notify(TEXT) = $(msg.exe * /TIME:1 TEXT)

[default]
context(NAME) = notify("entered NAME") ^ notify("left NAME")

[class=/chrome/i title=/reddit/i]
ContextActive >> context("Reddit")
G-M0N3Y-2503 commented 5 months ago

That sounds awesome! It'd be good to explicitly know when you're changing context!

But to avoid conflation on one part of my shown config, just to be safe. It allows me to change the map tempararily while in a different context, like changing music while in VSCode where I more often use the default map. These changes will help clean that up a and let me have context specific maps to cycle through. But just noting it is different.

houmain commented 4 months ago

This is already testable, if you are willing to build the next branch from source. It is not yet documented but this is the config I used for testing:

log = $(print "$0" >> ~/keymapper.log)
context = 50ms log["entered $0"] ^ log["left $0"]

[title="GPUpad"]
ContextActive >> context["GPUpad"]

[title="Thunar"]
ContextActive >> context["Thunar"]

It should be quite self-explanatory. It logs whenever one of the applications gets/loses focus to a file.

ristomatti commented 4 months ago

@houmain I tried building it on my Ubuntu Focal based system but the build fails. I guess my toolchain is too obsolete?

$ cmake --version
cmake version 3.25.0

$ gcc --version
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0

Error:

+ cmake -B ./build -DCMAKE_INSTALL_PREFIX=dist
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ristomatti/src/keymapper/build
+ cmake --build ./build --config Release
[  3%] Building CXX object CMakeFiles/keymapper.dir/src/config/ParseConfig.cpp.o
/home/ristomatti/src/keymapper/src/config/ParseConfig.cpp: In member function ‘std::string ParseConfig::preprocess_ident(std::string) const’:
/home/ristomatti/src/keymapper/src/config/ParseConfig.cpp:466:65: error: could not convert ‘{ident.std::__cxx11::basic_string<char>::begin().__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >::operator+(((__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >::difference_type)pos)).__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >::operator+(1), ident.std::__cxx11::basic_string<char>::end()}’ from ‘<brace-enclosed initializer list>’ to ‘std::string_view’ {aka ‘std::basic_string_view<char>’}
  466 |       get_argument_list({ ident.begin() + pos + 1, ident.end() }));
      |                                                                 ^
      |                                                                 |
      |                                                                 <brace-enclosed initializer list>
In file included from /usr/include/x86_64-linux-gnu/c++/9/bits/c++allocator.h:33,
                 from /usr/include/c++/9/bits/allocator.h:46,
                 from /usr/include/c++/9/string:41,
                 from /home/ristomatti/src/keymapper/src/runtime/Key.h:3,
                 from /home/ristomatti/src/keymapper/src/runtime/KeyEvent.h:3,
                 from /home/ristomatti/src/keymapper/src/config/ParseConfig.h:3,
                 from /home/ristomatti/src/keymapper/src/config/ParseConfig.cpp:2:
/usr/include/c++/9/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::basic_string_view<char>; _Args = {const char*&, const char*}; _Tp = std::basic_string_view<char>]’:
/usr/include/c++/9/bits/alloc_traits.h:483:4:   required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::basic_string_view<char>; _Args = {const char*&, const char*}; _Tp = std::basic_string_view<char>; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::basic_string_view<char> >]’
/usr/include/c++/9/bits/vector.tcc:115:30:   required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {const char*&, const char*}; _Tp = std::basic_string_view<char>; _Alloc = std::allocator<std::basic_string_view<char> >; std::vector<_Tp, _Alloc>::reference = std::basic_string_view<char>&]’
/home/ristomatti/src/keymapper/src/config/ParseConfig.cpp:80:62:   required from here
/usr/include/c++/9/ext/new_allocator.h:146:4: error: invalid conversion from ‘const char*’ to ‘std::basic_string_view<char>::size_type’ {aka ‘long unsigned int’} [-fpermissive]
  146 |  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
      |    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |    |
      |    const char*
In file included from /usr/include/c++/9/bits/basic_string.h:48,
                 from /usr/include/c++/9/string:55,
                 from /home/ristomatti/src/keymapper/src/runtime/Key.h:3,
                 from /home/ristomatti/src/keymapper/src/runtime/KeyEvent.h:3,
                 from /home/ristomatti/src/keymapper/src/config/ParseConfig.h:3,
                 from /home/ristomatti/src/keymapper/src/config/ParseConfig.cpp:2:
/usr/include/c++/9/string_view:129:56: note:   initializing argument 2 of ‘constexpr std::basic_string_view<_CharT, _Traits>::basic_string_view(const _CharT*, std::basic_string_view<_CharT, _Traits>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_string_view<_CharT, _Traits>::size_type = long unsigned int]’
  129 |       basic_string_view(const _CharT* __str, size_type __len) noexcept
      |                                              ~~~~~~~~~~^~~~~
make[2]: *** [CMakeFiles/keymapper.dir/build.make:272: CMakeFiles/keymapper.dir/src/config/ParseConfig.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:85: CMakeFiles/keymapper.dir/all] Error 2
make: *** [Makefile:156: all] Error 2
houmain commented 4 months ago

Oops, I unintentionally used a C++20 feature. This is fixed now. Please try again.

houmain commented 4 months ago

Here is another example, with multiple arguments:

modify = $0{ $1 }
A >> modify[ShiftLeft, X]
ristomatti commented 4 months ago

So nice! This will definitely help with debugging. I can get ContextActive to trigger on class, title and modifier scoped contexts but not on a device scoped context. Is this a bug or expected behavior

Test config below. When the window gets focused "entered kitty default", but if I press F12, "k15" gets typed.

log = $(echo "$0" >> ~/tmp/keymapper.log)
context = 50ms log["entered $0"] ^ log["left $0"]

KeyboardK15Pro = /Keychron K15 Pro Keyboard$/i

[device=KeyboardK15Pro class="kitty"]
  ContextActive >> context["kitty k15 pro"]
  F12 >> 'k15'

[class="kitty"]
  ContextActive >> context["kitty default"]
  F12 >> 'default'
ristomatti commented 4 months ago

Here is another example, with multiple arguments:

modify = $0{ $1 }
A >> modify[ShiftLeft, X]

Multiple arguments seems to work also, perfect.

I see this example uncovered another yet undocumented and also rather unexpected feature! Do you have a specific use case in mind for this? My imagination is lacking with this one. :thinking:

houmain commented 4 months ago

... but not on a device scoped context. Is this a bug or expected behavior?

That is not intentional. I will fix that soon. Thanks!

I see this example uncovered another yet undocumented and also rather unexpected feature!

It is actually not another new feature. Just the possibility to pass arguments to aliases/macros.

Do you have a specific use case in mind for this? My imagination is lacking with this one. 🤔

Not yet, maybe someone finds another use case beside debugging. 😄

ristomatti commented 4 months ago

@houmain I came across a bug with the parameterized aliases. The parameter apparently cannot be an alias itself.

Repro with some context of what I'm doing:

log = $(echo "$0" >> ~/tmp/keymapper.log)

# Logitech G502 X
ButtonSide      = 277

DoubleTap       = $0 !250ms $0

[default]
  ButtonSideDouble  = ButtonSide !200ms ButtonSide

  ButtonForward{150ms}    >> log["mouse_drag"]
  ButtonBack{150ms}       >> log["mouse_drag_resize"]
  # ButtonSideDouble      >> log["wm_float_window"]       # OK
  # DoubleTap[277]        >> log["wm_float_window"]       # OK
  DoubleTap[ButtonSide]   >> log["wm_float_window"]       # Invalid key "ButtonSide"
  ButtonSide              >>

[modifier="ButtonSide"]
  DoubleTap[ButtonLeft]   >> log["wm_resize_window"]      # OK
  ButtonLeft              >> log["wm_center_window"]
  DoubleTap[ButtonRight]  >> log["wm_close_window"]       # OK
  ButtonRight             >> log["wm_resize_window_wide"]
  ButtonMiddle            >> log["wm_sticky_toggle"]
houmain commented 3 months ago

Hi ristomatti, Aliases should work now as parameters. Also the ContextActive in device contexts should work now. This will be available in the upcoming 4.0.0 release which is already documented and testable in the next branch. I incremented the major version since I refactored the code a lot. So it would be great if you could try it out with your sophisticated configuration, thanks!

ristomatti commented 3 months ago

Sorry to report but the fix doesn't seem to work fully and the changes caused some regression with the mappings the above example config was based on. The actual snippet from my config:

MouseG502X      = /Logitech USB Receiver|G502 X LIGHTSPEED/i
ButtonSide      = 277

[device=MouseG502X]
  ButtonSideDouble  = ButtonSide !200ms ButtonSide

  ButtonForward{150ms}    >> mouse_drag
  ButtonBack{150ms}       >> mouse_drag_resize
  # ButtonSideDouble        >> wm_float_window
  ButtonSideDouble        >> log["wm_float_window"]       # <- modified for testing
  ButtonSide              >>

[device=MouseG502X modifier="ButtonSide"]
  # Added as a test
  ContextActive           >> log["MouseG502X ButtonSide"] # <- added for testing

  DoubleTap[ButtonLeft]   >> wm_resize_window
  ButtonLeft              >> wm_center_window
  # DoubleTap[ButtonRight]  >> wm_close_window
  DoubleTap[ButtonRight]  >> log["wm_close_window"]       # <- modified for testing

  ButtonRight             >> wm_resize_window_wide
  ButtonMiddle            >> wm_sticky_toggle

# ... lots of other config ...

[default]
  mouse_drag                  >> (AltLeft ButtonLeft)
  mouse_drag_resize           >> (AltLeft ButtonRight)

  wm_resize_window            >> $(i3-msg "resize set 1000px 1200px") ^
  wm_resize_window_wide       >> $(i3-msg "resize set 1800px 1200px") ^
  wm_center_window            >> $(i3-msg "move absolute position center") ^
  wm_close_window             >> $(i3-msg '[con_id="__focused__"] kill') ^
  wm_float_window             >> $(i3-msg "floating toggle") ^
  wm_sticky_toggle            >> $(i3-msg "sticky toggle") ^

These mappings stopped working:

[device=MouseG502X modifier="ButtonSide"]
  ButtonSideDouble        >> wm_float_window
  ButtonForward{150ms}    >> mouse_drag
  ButtonBack{150ms}       >> mouse_drag_resize

Neither of these seem to trigger:

[device=MouseG502X]
  ButtonSideDouble        >> log["wm_float_window"]

[device=MouseG502X modifier="ButtonSide"]
  ContextActive           >> log["MouseG502X ButtonSide"]

This however does work as expected but it did previously as well:

[device=MouseG502X modifier="ButtonSide"]
  DoubleTap[ButtonRight]  >> log["wm_close_window"]
ristomatti commented 3 months ago

I incremented the major version since I refactored the code a lot

I can see that. https://github.com/houmain/keymapper/compare/3.5.3...next :exploding_head:

houmain commented 3 months ago

Thanks for trying it out so quickly. I am glad I did not release it yet. I will analyze this asap!

ristomatti commented 3 months ago

I tried this again with the new updates you mentioned here https://github.com/houmain/keymapper/issues/105#issuecomment-2008003564.

I was able to get ContextActive to trigger from this:

[device=MouseG502X modifier="ButtonSide"]
  ContextActive           >> log["MouseG502X ButtonSide"]

I don't know if it's got anything to do with the changes but I got it to trigger by a slight modification below. It seemed to have the downside I couldn't get a mapping like ButtonSide !200ms ButtonSide >> do_stuff to work.

ButtonSideMod   = Virtual7

[device=MouseG502X]
  ContextActive >> context["MouseG502X"]
  ButtonSide    >> ButtonSideMod ^ ButtonSideMod

[device=MouseG502X modifier="ButtonSideMod"]
  ContextActive >> context["MouseG502X ButtonSide"]

I did some more testing/debugging around the mouse button mappings. The remaining issue is that my mappings for window move/drag from any part of the window when holding mouse back/forward buttons does not work anymore:

# [device=MouseG502X]  <- commented out for this to work as a test config 
[default]
  ButtonForward{150ms}    >> mouse_drag
  ButtonBack{150ms}       >> mouse_drag_resize

  # This would work but it'd break normal use as back/forward buttons 
  # ButtonForward         >> mouse_drag
  # ButtonBack            >> mouse_drag_resize

[default]
  mouse_drag              >> (AltLeft ButtonLeft)
  mouse_drag_resize       >> (AltLeft ButtonRight)
houmain commented 3 months ago

I think I could reproduce it with this configuration. There is still a problem when a key is used at the same time in a context modifier and has a timeout:

X{!1000ms} >> B

[modifier="X"]
  ContextActive >> A ^
ristomatti commented 3 months ago

We're you able to reproduce the last example about the mouse keys held down? I forgot to include this minimum config I was able to reproduce it. It seems to be affect any mapping that relies on holding a button down:

1{250ms} >> 2

Previously this would allow using 1 as normal but act as if 2 was held down if kept pressed longer than 150ms.

houmain commented 3 months ago

Hi ristomatti, With the latest commits I can no longer reproduce any problem. I tested it with the configurations above and this one:

log = $(notify-send -t 2000 -a "keymapper" "$0")

MouseG502X      = /G300/i
ButtonSide      = ButtonBack

[device=MouseG502X]

  ButtonSideDouble  = ButtonSide !200ms ButtonSide
  ButtonSideDouble        >> log["wm_float_window"]

[device=MouseG502X modifier="ButtonBack"]
  ContextActive           >> log["ButtonSide"]

Could you please also give the latest version an try?

ristomatti commented 3 months ago

Could you please also give the latest version an try?

For sure. Luckily it's a 4 days weekend due to Easter as I see my inbox is full with notifications from this repo. 😁

ristomatti commented 3 months ago

I'm still seeing a change with the mouse handling, e.g. my old config doesn't work. I have not yet pinpointed if it's due to relying on some undocumented behavior. Here's an example config with only the bits of config affected:

# Debug logging
log        = $(echo "$0" >> ~/tmp/keymapper.log)
context    = 50ms log["entered $0"] ^ log["left $0"]

# Custom keys
ButtonSide = 277

# Context matchers
Mouse      = /Mouse|Logitech USB Receiver|G502/i
MouseG502X = /Logitech USB Receiver|G502 X LIGHTSPEED/i

# Pameterized aliases
DoubleTap  = $0 !250ms $0{!250ms}
Hold       = $0{200ms}

[device=Mouse]
  ContextActive           >> context["Mouse"]              # triggers, previosly didn't

  ButtonForward{150ms}    >> mouse_drag                    # doesn't trigger
  ButtonBack{150ms}       >> mouse_drag_resize             # doesn't trigger

[device=MouseG502X modifier="ButtonSide"]
  ContextActive           >> context["G502X ButtonSide"]   # triggers, previosly didn't

  DoubleTap[ButtonLeft]   >> log["wm_resize_window"]       # triggers
  DoubleTap[ButtonRight]  >> log["wm_close_window"]        # triggers
  Hold[ButtonMiddle]      >> log["wm_sticky_toggle"]       # doesn't trigger

  ButtonLeft              >> log["wm_center_window"]       # doesn't trigger
  ButtonRight             >> log["wm_resize_window_wide"]  # doesn't trigger
  ButtonMiddle            >> log["wm_float_window"]        # triggers

[default]
  mouse_drag              >> (AltLeft ButtonLeft)
  mouse_drag_resize       >> (AltLeft ButtonRight)

Previously all worked except the device context ContextActive logs.

ristomatti commented 3 months ago

I just noticed that that if I don't define a separate ButtonSide context, these both trigger.

[device=MouseG502X]
  ButtonSide{DoubleTap[ButtonLeft]}  >> log["wm_resize_window"]
  ButtonSide{ButtonLeft}             >> log["wm_center_window"] 
ristomatti commented 3 months ago

Further findings, this config doesn't work either for me:

log  = $(echo "$0" >> ~/tmp/keymapper.log)

Hold = $0{200ms}

Hold[F4] >> log["F4 held"]  # doesn't trigger
ristomatti commented 3 months ago

Actually it seems key hold mappings do not work at all. Even this does not work on my system. :thinking:

A{200ms} >> B
ristomatti commented 3 months ago

@houmain Out of curiosity, I traced back the commit after which X{200ms} >> Y mappings stop working. It's this one https://github.com/houmain/keymapper/commit/0979310df0264afefab40ce0f85fd623da9394c3 which first introduced keymapperctl.

houmain commented 3 months ago

Sorry for the late reply! I was AFK this week. The last commit should fix the problem.

ristomatti commented 3 months ago

@houmain No sweat! Unfortunately the change didn't seem to have any effect. Here's the test config I used:

# Debug logging
log        = $(echo "$0" >> ~/tmp/keymapper.log)
context    = 50ms log["entered $0"] ^ log["left $0"]

# Custom keys
ButtonSide = 277

# Context matchers
MouseG502X = /Logitech USB Receiver|G502 X LIGHTSPEED/i

# Pameterized aliases
DoubleTap  = $0 !250ms $0{!250ms}
Hold       = $0{200ms}

[device=MouseG502X]
  ContextActive           >> context["MouseG502X"]

  # ❌ - no trigger
  ButtonForward{150ms}    >> mouse_drag
  ButtonBack{150ms}       >> mouse_drag_resize

[device=MouseG502X modifier="ButtonSide"]
  # ✅ - logs "entered X" when button held down, "left X" when released
  ContextActive           >> context["MouseG502X ButtonSide"]

  # ✅ - both trigger consistently
  DoubleTap[ButtonLeft]   >> log["wm_resize_window"]
  DoubleTap[ButtonRight]  >> log["wm_close_window"]

  # ❌ - no trigger
  Hold[ButtonMiddle]      >> log["wm_sticky_toggle"]

  # ❌ - these two behave similarly as "A{!100ms} B", e.g. in sequence, but not
  # when ButtonSide held down
  ButtonLeft              >> log["wm_center_window"]            
  ButtonRight             >> log["wm_resize_window_wide"]

  # ✅ - triggers consistently
  ButtonMiddle            >> log["wm_float_window"]

[default]
  mouse_drag              >> (AltLeft ButtonLeft)
  mouse_drag_resize       >> (AltLeft ButtonRight)
$ inxi -SGx  
System:    Host: x1e Kernel: 5.15.0-94-generic x86_64 bits: 64 compiler: N/A Desktop: Gnome 3.36.9 
           Distro: Linux Mint 20 Ulyana base: Ubuntu 20.04 focal 
Graphics:  Device-1: NVIDIA vendor: Lenovo driver: nvidia v: 520.61.05 bus ID: 01:00.0 
           Display: x11 server: X.Org 1.20.13 driver: nvidia unloaded: fbdev,modesetting,nouveau,vesa 
           resolution: 3440x1440~60Hz 
           OpenGL: renderer: NVIDIA GeForce GTX 1650 Ti with Max-Q Design/PCIe/SSE2 v: 4.6.0 NVIDIA 520.61.05 
           direct render: Yes 
houmain commented 3 months ago

I tested your configuration and found another bug, thanks! I am again quite confident that it should work now.

ristomatti commented 3 months ago

Great work! Everything the above config works and so does every other mapping I've tried so far. I found one regression though unless it's by design in the new version. Aliases don't work within shell commands. E.g.

LOG_FILE = "$HOME/tmp/keymapper.log"

log = $(echo "$0" >> LOG_FILE)
# ...various other commands that log to the same file

Now the logs go to ~/LOG_FILE. I don't have that many aliases I use as variables on the commands so I can just inline them. I have a vague memory you at some point added a workaround to prevent alias substitution within quotes(?)

ristomatti commented 3 months ago

Similarly I had this state indicator logic (which I'm definitely going to redo using keymapperctl)

# Create state directory if it doesn't exist
ensureStateDirExists       = test -f STATE_DIR || mkdir -p STATE_DIR

# Status bar input mode indicator handling
auto_shift_status_on       = $(ensureStateDirExists && touch AUTO_SHIFT_FILE)
auto_shift_status_off      = $(test -f AUTO_SHIFT_FILE && rm AUTO_SHIFT_FILE)

direct_umlauts_status_on   = $(ensureStateDirExists && touch DIRECT_UMLAUTS_FILE)
direct_umlauts_status_off  = $(test -f DIRECT_UMLAUTS_FILE && rm DIRECT_UMLAUTS_FILE)

caps_word_status_on        = $(ensureStateDirExists && touch CAPS_WORD_FILE)
caps_word_status_off       = $(test -f CAPS_WORD_FILE && rm CAPS_WORD_FILE)

Here ensureStateDirExists gives "command not found" error when running with verbose logging.

ristomatti commented 3 months ago

Now with everything inlined, the indicators work as well. 🙂

houmain commented 3 months ago

I restored the substitution within terminal commands.

ristomatti commented 3 months ago

Confirm working again. Your reaction times are insane! :zap: