zmk icon indicating copy to clipboard operation
zmk copied to clipboard

feat: lock a momentary layer

Open ecstatic-morse opened this issue 1 year ago • 7 comments

Resolves #1299. Resolves #1771.

This adds a momentary layer lock behavior (&molock ) which causes all active momentary layers not to become deactivated on release. If no layers are active, &molock triggers a customizable fallback behavior, which defaults to &to 0.

See the newly added docs for a more complete description.

ecstatic-morse avatar Nov 02 '23 21:11 ecstatic-morse

I'm using this locally, but haven't written tests or documentation yet. When that's done, I'll mark this as ready for review.

Ultimately I want to allow arbitrary behaviors in the fallback case instead of only &to LAYER, but this seems fine for a rough draft.

ecstatic-morse avatar Nov 02 '23 21:11 ecstatic-morse

This PR is now feature complete, so I've marked it as ready for review. It would be nice to allow custom momentary layer lock behaviors to accept an arbitrary arguments, but I didn't see any prior art for that and I'm still not too proficient with devicetree/Zephyr, so for now you need to specify all the arguments when the behavior is defined.

ecstatic-morse avatar Nov 06 '23 23:11 ecstatic-morse

Maybe someone can help me out? I get Failed to build errors with no logs when running west test tests/momentary-layer-lock. Attempting to compile manually with the west build invocation from run-test.sh gives:

➜  app git:(molock) west build -d build/tests/momentary-layer -b native_posix_64 -- -DZMK_CONFIG=/home/mackendy/src/zephyr/zmk/app/tests/momentary-layer
-- west build: generating a build system
Loading Zephyr default modules (Zephyr base (cached)).
-- Application: /home/mackendy/src/zephyr/zmk/app
-- ZMK Config directory: /home/mackendy/src/zephyr/zmk/app/tests/momentary-layer
CMake Warning at cmake/ZephyrBuildConfig.cmake:199 (message):
  Failed to locate keymap file!
Call Stack (most recent call first):
  /home/mackendy/src/zephyr/zmk/zephyr/cmake/modules/zephyr_default.cmake:22 (find_package)
  /home/mackendy/src/zephyr/zmk/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake:66 (include)
  /home/mackendy/src/zephyr/zmk/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake:97 (include_boilerplate)
  CMakeLists.txt:15 (find_package)


-- Cache files will be written to: /home/mackendy/.cache/zephyr
-- Zephyr version: 3.2.0 (/home/mackendy/src/zephyr/zmk/zephyr)
-- Found west (found suitable version "1.2.0", minimum required is "0.7.1")
-- Board: native_posix_64
-- Found host-tools: zephyr 0.16.3 (/home/mackendy/.local/opt/zephyr-sdk-0.16.3)
-- Found toolchain: host (gcc/ld)
-- Found BOARD.dts: /home/mackendy/src/zephyr/zmk/zephyr/boards/posix/native_posix/native_posix_64.dts
-- Found devicetree overlay: /home/mackendy/src/zephyr/zmk/app/boards/native_posix_64.overlay
-- Found devicetree overlay: /home/mackendy/src/zephyr/zmk/app/boards/native_posix_64.overlay
-- Generated zephyr.dts: /home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer/zephyr/zephyr.dts
-- Generated devicetree_generated.h: /home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer/zephyr/include/generated/devicetree_generated.h
-- Including generated dts.cmake file: /home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer/zephyr/dts.cmake
Parsing /home/mackendy/src/zephyr/zmk/app/Kconfig
Loaded configuration '/home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer/zephyr/.config'
No change to configuration in '/home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer/zephyr/.config'
No change to Kconfig header in '/home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer/zephyr/include/generated/autoconf.h'
-- Configuring done (1.9s)
CMake Warning (dev) at /home/mackendy/src/zephyr/zmk/zephyr/cmake/linker/ld/target.cmake:75 (add_custom_command):
  Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
  add_custom_command().  Run "cmake --help-policy CMP0116" for policy
  details.  Use the cmake_policy command to set the policy and suppress this
  warning.
Call Stack (most recent call first):
  /home/mackendy/src/zephyr/zmk/zephyr/CMakeLists.txt:1099 (configure_linker_script)
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) at /home/mackendy/src/zephyr/zmk/zephyr/cmake/linker/ld/target.cmake:75 (add_custom_command):
  Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
  add_custom_command().  Run "cmake --help-policy CMP0116" for policy
  details.  Use the cmake_policy command to set the policy and suppress this
  warning.
Call Stack (most recent call first):
  /home/mackendy/src/zephyr/zmk/zephyr/CMakeLists.txt:1311 (configure_linker_script)
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Generating done (0.0s)
-- Build files have been written to: /home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer
-- west build: building application
[18/79] Building C object CMakeFiles/app.dir/src/keymap.c.obj
FAILED: CMakeFiles/app.dir/src/keymap.c.obj 
ccache /usr/lib64/ccache/gcc -DKERNEL -D_FORTIFY_SOURCE=2 -D_POSIX_C_SOURCE=200809 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED -D__ZEPHYR__=1 -I/home/mackendy/src/zephyr/zmk/app/include -I/home/mackendy/src/zephyr/zmk/zephyr/include -I/home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer/zephyr/include/generated -I/home/mackendy/src/zephyr/zmk/zephyr/soc/posix/inf_clock -I/home/mackendy/src/zephyr/zmk/zephyr/boards/posix/native_posix -I/home/mackendy/src/zephyr/zmk/app/module/include -fno-strict-aliasing -Og -imacros /home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer/zephyr/include/generated/autoconf.h -ffreestanding -fno-common -g -gdwarf-4 -fdiagnostics-color=always -Wall -Wformat -Wformat-security -Wno-format-zero-length -Wno-main -Wno-pointer-sign -Wpointer-arith -Wexpansion-to-defined -Wno-unused-but-set-variable -Werror=implicit-int -fno-pic -fno-pie -fno-asynchronous-unwind-tables -fno-reorder-functions --param=min-pagesize=0 -fno-defer-pop -fmacro-prefix-map=/home/mackendy/src/zephyr/zmk/app=CMAKE_SOURCE_DIR -fmacro-prefix-map=/home/mackendy/src/zephyr/zmk/zephyr=ZEPHYR_BASE -fmacro-prefix-map=/home/mackendy/src/zephyr/zmk=WEST_TOPDIR -ffunction-sections -fdata-sections -m64 -fPIC -include /home/mackendy/src/zephyr/zmk/zephyr/arch/posix/include/posix_cheats.h -fno-freestanding -std=c11 -Wfatal-errors -MD -MT CMakeFiles/app.dir/src/keymap.c.obj -MF CMakeFiles/app.dir/src/keymap.c.obj.d -o CMakeFiles/app.dir/src/keymap.c.obj -c /home/mackendy/src/zephyr/zmk/app/src/keymap.c
In file included from /home/mackendy/src/zephyr/zmk/zephyr/include/zephyr/device.h:38,
                 from /home/mackendy/src/zephyr/zmk/app/include/drivers/behavior.h:13,
                 from /home/mackendy/src/zephyr/zmk/app/src/keymap.c:7:
/home/mackendy/src/zephyr/zmk/zephyr/include/zephyr/devicetree.h:326:40: warning: implicit declaration of function ‘DT_N_INST_0_zmk_keymap_FOREACH_CHILD’; did you mean ‘DT_N_S_sdl_kscan_FOREACH_CHILD’? [-Wimplicit-function-declaration]
  326 | #define DT_INST(inst, compat) UTIL_CAT(DT_N_INST, DT_DASH(inst, compat))
      |                                        ^~~~~~~~~
/home/mackendy/src/zephyr/zmk/zephyr/include/zephyr/devicetree.h:3714:24: note: in definition of macro ‘DT_CAT’
 3714 | #define DT_CAT(a1, a2) a1 ## a2
      |                        ^~
/home/mackendy/src/zephyr/zmk/app/include/zmk/keymap.h:13:6: note: in expansion of macro ‘DT_FOREACH_CHILD’
   13 |     (DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0)
      |      ^~~~~~~~~~~~~~~~
/home/mackendy/src/zephyr/zmk/zephyr/include/zephyr/sys/util_internal.h:104:26: note: in expansion of macro ‘UTIL_PRIMITIVE_CAT’
  104 | #define UTIL_CAT(a, ...) UTIL_PRIMITIVE_CAT(a, __VA_ARGS__)
      |                          ^~~~~~~~~~~~~~~~~~
/home/mackendy/src/zephyr/zmk/zephyr/include/zephyr/devicetree.h:326:31: note: in expansion of macro ‘UTIL_CAT’
  326 | #define DT_INST(inst, compat) UTIL_CAT(DT_N_INST, DT_DASH(inst, compat))
      |                               ^~~~~~~~
/home/mackendy/src/zephyr/zmk/app/include/zmk/keymap.h:13:23: note: in expansion of macro ‘DT_INST’
   13 |     (DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0)
      |                       ^~~~~~~
/home/mackendy/src/zephyr/zmk/app/src/keymap.c:67:47: note: in expansion of macro ‘ZMK_KEYMAP_LAYERS_LEN’
   67 | static struct zmk_behavior_binding zmk_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = {
      |                                               ^~~~~~~~~~~~~~~~~~~~~
/home/mackendy/src/zephyr/zmk/app/include/zmk/keymap.h:13:47: error: ‘ZMK_LAYER_CHILD_LEN_PLUS_ONE’ undeclared here (not in a function)
   13 |     (DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0)
      |                                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/mackendy/src/zephyr/zmk/zephyr/include/zephyr/devicetree.h:2296:41: note: in definition of macro ‘DT_FOREACH_CHILD’
 2296 |         DT_CAT(node_id, _FOREACH_CHILD)(fn)
      |                                         ^~
/home/mackendy/src/zephyr/zmk/app/src/keymap.c:67:47: note: in expansion of macro ‘ZMK_KEYMAP_LAYERS_LEN’
   67 | static struct zmk_behavior_binding zmk_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = {
      |                                               ^~~~~~~~~~~~~~~~~~~~~
compilation terminated due to -Wfatal-errors.
[35/79] Building C object zephyr/boards/boards/posix/native_posix_64/CMakeFiles/boards__posix__native_posix.dir/cmdline_common.c.obj
ninja: build stopped: subcommand failed.
FATAL ERROR: command exited with status 1: /usr/bin/cmake --build /home/mackendy/src/zephyr/zmk/app/build/tests/momentary-layer

ecstatic-morse avatar Nov 06 '23 23:11 ecstatic-morse

Thanks @caksoylar. The rebased version seems to be working fine (I've been running it since last night).

I've been using this for a few months now and still find it useful as part of my keymap, mostly for locking the navigation layer. I noticed the old documentation was a bit spartan so I added the example. It would be nice to get it upstreamed, but seeing as I'm the only user that seems a bit premature. Maybe I'll ask around on the Discord to see if anyone else wants to try it out...

ecstatic-morse avatar Feb 13 '24 02:02 ecstatic-morse

Any progress on this? :) Does the layer lock work also with &lt?

Dom324 avatar May 22 '24 15:05 Dom324

I've been using this feature for some time now, and I think this design is simple, and achieves everything one might need to keep a momentary layer toggled.

BTW, this works with &mo and &lt.

Townk avatar Jun 18 '24 11:06 Townk

Great change. I've also been using this for some time and it really works well.

alternateved avatar Jun 18 '24 12:06 alternateved