Both palm keys together to trigger a separate layer?

Could someone open a ticket for this bug?

1 Like

Thereā€™s another thread where I suggested an idea that would make use of a variable that records and makes the number of layers accessible.

I mapped the palm keys on my numpad layer (only) to ShiftToLayer(FUNCTION) and everything seems to be OK. Thanks!

1 Like

Iā€™ll take responsibility for writing this up and submitting an issue for it, unless someone else gets to it before me (later tonight). Itā€™s in layers.cpp: Layer.next()ā€¦

2 Likes

So, I went ahead and opened a pull request (two, actually: both Model01-Firmware #35 & Kaleidoscope #244), but the only way I can think of to fix this is to introduce a new constant that stores the number of layers defined in keymaps[] in the sketch file. Unfortunately, the compiler/linker has defeated my attempts to get Kaleidoscope to build. When I build it from Model01-Firmware, everything looks fine, but if I try to build Kaleidoscope independently, it quits with an ā€œundefined referenceā€ error. Iā€™ve tried lots of variations, but nothing works. The real mystery to me is that keymaps[], which is defined in the same place as the new variable LayerCount in my PR doesnā€™t cause the same error. Iā€™m totally baffled by the fact that one works, but the other causes an error.

Iā€™m hoping that someone more familiar with the build system in particular, or the C++ compiler & linker in general can help me make sense of this.

2 Likes

After some trial and error, I figured out the build problem. I hadnā€™t updated the example sketches. So in order to make the change Iā€™m proposing, all of the example sketches in every plugin would need to add that one line tooā€¦

2 Likes

Update for everyone in this discussion:

There are a couple of changes that have recently been merged into the master branch of Kaleidoscope that address issues that were discussed here.

  1. @algernon mentioned that it was necessary to have Key_KeymapNext_Momentary on both the layer that was being switched from and the one above it in order to keep the upper layer from getting stuck on. This should no longer be the case, as of Kaleidoscope #247.

  2. @andrewg pointed out that use of Key_KeymapNext_Momentary could result in reading past the end of the keymaps[] array into uninitialized memory. There is now a fix for that, as well, in #244, but it only works if the sketch file is updated to use the new KEYMAPS() macro to define the keymap, instead of initializing keymaps[] directly.

To use the new macro to define a keymap, all you need to do is replace this line in your sketch file:

const Key keymaps[][ROWS][COLS] PROGMEM = {

ā€¦with this:

KEYMAPS(

ā€¦and replace the closing brace line:

};

ā€¦with this:

)

That makes a variable storing the number of defined layers available to Kaleidoscope, so it can stop trying to read past the end of the array.

2 Likes

I also wanted to implement that (separate layer for both palm key).
I didnā€™t want to use the magiccombo plugin as the function are trigger only it the combo is the only thing that itā€™s pressed.
For example, I want the ā€œboth palm keyā€ layer to be triggered even if ā€œa+left fn+right fnā€ is pressed.
Also magiccombo are triggered by a loop.

My (simplified) layer stack is: NORMAL, LEFT_FN, RIGHT_FN, LEFT_AND_RIGHT_FN

At first I was just using ShiftToLayer(LEFT_FN) and ShiftToLayer(RIGHT_FN) in the NORMAL layer. And ShiftToLayer(LEFT_AND_RIGHT_FN) in the LEFT_FN and RIGHT_FN layers.

It works but have a huge drawback.
When pressed left fn+right fn then release left fn the LEFT_AND_RIGHT_FN layer stay active, instead of switching to the RIGHT_FN as the right fn is still held.

What I do now: I use Key_KeymapNext_Momentary and Key_KeymapNextNext_Momentary (a dirty hack).
The left fn is configure to increment the layer by one, the right fn increment the layer by two.

so:
NORMAL+left fn ā†’ 0+1 ā†’ LEFT_FN
NORMAL+right fn ā†’ 0+2 ā†’ RIGHT_FN
NORMAL+left fn+right fn ā†’ 0+1+2 ā†’ LEFT_AND_RIGHT_FN

Here is the Key_KeymapNextNext_Momentary dirty hack:

diff --git a/src/key_defs_keymaps.h b/src/key_defs_keymaps.h
index c0dda0f..87997dd 100644
--- a/src/key_defs_keymaps.h
+++ b/src/key_defs_keymaps.h
@@ -15,6 +15,7 @@ static const uint8_t LAYER_SHIFT_OFFSET = 42;

 #define KEYMAP_PREVIOUS  33
 #define KEYMAP_NEXT      34
+#define KEYMAP_NEXT_NEXT 35


 #define Key_Keymap0 (Key) { KEYMAP_0,  KEY_FLAGS | SYNTHETIC | SWITCH_TO_KEYMAP  }
@@ -31,9 +32,9 @@ static const uint8_t LAYER_SHIFT_OFFSET = 42;
 #define Key_Keymap5_Momentary (Key){ KEYMAP_5 + LAYER_SHIFT_OFFSET, KEY_FLAGS | SYNTHETIC | SWITCH_TO_KEYMAP }

 #define Key_KeymapNext_Momentary (Key) { KEYMAP_NEXT + LAYER_SHIFT_OFFSET, KEY_FLAGS | SYNTHETIC | SWITCH_TO_KEYMAP }
+#define Key_KeymapNextNext_Momentary (Key) { KEYMAP_NEXT_NEXT + LAYER_SHIFT_OFFSET, KEY_FLAGS | SYNTHETIC | SWITCH_TO_KEYMAP }
 #define Key_KeymapPrevious_Momentary (Key) { KEYMAP_PREVIOUS + LAYER_SHIFT_OFFSET, KEY_FLAGS | SYNTHETIC | SWITCH_TO_KEYMAP }

-
 /** Lock/Unlock layer `n`.
  *
  * When locking a layer, it will remain active until unlocked explicitly. `n`
diff --git a/src/layers.cpp b/src/layers.cpp
index 389d8e9..9b646bc 100644
--- a/src/layers.cpp
+++ b/src/layers.cpp
@@ -23,6 +23,16 @@ static void handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState) {
     uint8_t target = keymapEntry.keyCode - LAYER_SHIFT_OFFSET;

     switch (target) {
+    case KEYMAP_NEXT_NEXT:
+      if (keyToggledOn(keyState)) {
+        Layer.next();
+        Layer.next();
+      } else if (keyToggledOff(keyState)) {
+        Layer.previous();
+        Layer.previous();
+      }
+      break;
+
     case KEYMAP_NEXT:
       if (keyToggledOn(keyState))
         Layer.next();

(How to decrement the layer by two without calling Layer.previous() two times ?)

And now it works as expected.
left fn+right fn - left fn ā†’ RIGHT_FN

Iā€™m now trying to do the same thing on my Model 100, via firmware (Iā€™m not using Chrysalis).

I have my main layer, then function, then doublefunction, then numpad, as before. On my main layer I have both function keys set to Key_KeymapNext_Momentary. On the other layers theyā€™re set to transparent.

But whether Iā€™m holding one or both function keys, Iā€™m getting the function layer behaviour, not the doublefunction layer behaviour.

Any ideas as to what might be wrong? Does anyone else have this method working on Model 100?

I am now using another approach ; I use macro.

basically:

enum {
	MACRO_KEY_LF,
	MACRO_KEY_RF,
};
 
const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
	enum {
		LAYER_NORM,
		LAYER_LF,
		LAYER_RF,
		LAYER_LF_PLUS_RF,
	};

	switch (macro_id) {

		case MACRO_KEY_LF:
			if (keyToggledOn(event.state)) {
				if (Layer.isActive(LAYER_RF)) {
					Layer.deactivate(LAYER_RF);
					Layer.activate(LAYER_LF_PLUS_RF);
				} else {
					Layer.activate(LAYER_LF);
				}
			} else if (keyToggledOff(event.state)) {
				if (Layer.isActive(LAYER_LF_PLUS_RF)) {
					Layer.deactivate(LAYER_LF_PLUS_RF);
					Layer.activate(LAYER_RF);
				} else {
					Layer.deactivate(LAYER_LF);
				}
			}
			break;

		case MACRO_KEY_RF:
			if (keyToggledOn(event.state)) {
				if (Layer.isActive(LAYER_LF)) {
					Layer.deactivate(LAYER_LF);
					Layer.activate(LAYER_LF_PLUS_RF);
				} else {
					Layer.activate(LAYER_RF);
				}
			} else if (keyToggledOff(event.state)) {
				if (Layer.isActive(LAYER_LF_PLUS_RF)) {
					Layer.deactivate(LAYER_LF_PLUS_RF);
					Layer.activate(LAYER_LF);
				} else {
					Layer.deactivate(LAYER_RF);
				}
			}
			break;
	}

	return MACRO_NONE;
}

(this code need to be adapt to your ino fileā€¦ but you get the idea).

Ah so you have separate layers for leftfn and rightfn, and then separate again for both.

I imagine I could do something very similar to what you suggested with a shared function layer for just one palm key being held down. Thank you for sharing your code.

I think Iā€™ll hold back on trying that just for now though, since Key_KeymapNext_Momentary seems like it ought to work; it feels like a bug, whether in my code or in Kaleidoscope. Having said that, maybe Iā€™ll ask on the Kaleidoscope trackerā€¦

Yes, looking at the code, this does appear to be a bug in the treatment of Key_KeymapNext_Momentary. Would you mind submitting a Kaleidoscope issue for this?

1 Like

Itā€™s working again; thanks @merlin!

1 Like