Skip to content

Conversation

@BafS
Copy link

@BafS BafS commented Apr 10, 2025

Show "Layer-Tap" information on the keys, before it was empty, we now see which layer will be enabled on hold and which key will be send on tap.

Instead of the layer logo I was hesitant to add "Hold" to show that this behavior is triggered when it's hold, but it could be done as a future improvement.

Before:

image

After:

image

@netlify
Copy link

netlify bot commented Apr 10, 2025

Deploy Preview for zmk-studio ready!

Name Link
🔨 Latest commit a177a63
🔍 Latest deploy log https://app.netlify.com/projects/zmk-studio/deploys/69409bdaab5d5300088b0833
😎 Deploy Preview https://deploy-preview-135.preview.zmk.studio
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@nmunnich
Copy link

This looks very similar to https://discordapp.com/channels/719497620560543766/722441520741089317/1293320175482966037, which I quite like the look of. If you're able to adjust it to match more closely, that would be great.

Does this work with all hold-taps? If not, it should be extended as such.

@BafS
Copy link
Author

BafS commented Apr 11, 2025

Updated the design and made it work with mode-tap too

image

@BafS BafS changed the title Show Layer-Tap information on keys Show Layer-Tap/Mod-Tap information on keys Apr 11, 2025
@BafS
Copy link
Author

BafS commented Apr 11, 2025

Added indicators and some fine tuning

image

behavior: string,
binding: KeyBinding,
): JSX.Element | JSX.Element[] => {
if (behavior === "Layer-Tap") {
Copy link
Author

@BafS BafS May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those if should probably be improved, not sure if we should add the "behavior type" and/or binding-cells. Could maybe be a followup?

@BafS BafS force-pushed the feat/layer-tap-key-1 branch 2 times, most recently from 86d2c86 to e214945 Compare May 16, 2025 19:02
@danielsvane
Copy link
Contributor

I agree that it would be nice to see the layer and mod tap info on the keys, but I think we should start out with a simpler visualisation like

image
image

This is personal preference though. I feel its simpler to review, and improve over time, when making as few changes as possible.

Also the linting changes you (or your editor) has done, makes it more difficult to review, and should be done in a seperate PR. The actual important changes are confined to 1 or 2 files.

Copy link
Collaborator

@petejohanson petejohanson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! The main concern for me is the trigger/logic used to determine when to render these differently.

];
}

if (behavior === "Mod-Tap") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We really can't do this. We need to be inspecting the metadata information to determine what to do here. Because:

  • Users might have multiple mod taps with different names,
  • Users might translate the display names to their language in the devicetree.
  • General flexibility for custom behavior support in studio.

So... this is great to work on... and it must be metadata driven. For instance, we might choose this rendering style if both param1 and param2 are of parameter metadata type "HID usage".

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about the latest changes? Like that we don't depend on the name. It's not perfect but it's more generic.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const param1IsHidUsage = isHidUsageParameter(binding.param1, behavior.metadata, layerIds);
const param2IsHidUsage = isHidUsageParameter(binding.param2, behavior.metadata, layerIds);
const param1IsLayerId = isLayerIdParameter(binding.param1, behavior.metadata, layerIds);
const param2IsLayerId = isLayerIdParameter(binding.param2, behavior.metadata, layerIds);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chiming in because I think this is a cool change and I hope it hits studio main soon:

This variable here param2IsLayerId is never used, so CI is failing.

@alvinometric
Copy link

Any updates on this?

@BafS
Copy link
Author

BafS commented Aug 18, 2025

I wish sorry, I pinged the devs a few times on Discord, I don't know what to do to get it reviewed again/merged. I lost motivation.

@nmunnich
Copy link

Last I checked, Pete is planning on doing more with Studio after we bump Zephyr to 4.1.

@BafS
Copy link
Author

BafS commented Nov 17, 2025

Is there still hope to help me review/merge this MR?

@nmunnich
Copy link

I believe this PR as-is is seen as too specific for the current state of Studio. See https://discord.com/channels/719497620560543766/719909884769992755/1435008086329917521 for a recent discussion we had - I believe that a generic "display both params of behaviour with two params" needs to come first, then figure out how to make that look good, then do edge cases for things like layer-tap.

I do think this PR could be modified to cover the more general case, but I would understand (yet feel saddened if you feel too demotivated to do said work.

@awkannan
Copy link
Contributor

I believe this PR as-is is seen as too specific for the current state of Studio. See https://discord.com/channels/719497620560543766/719909884769992755/1435008086329917521 for a recent discussion we had - I believe that a generic "display both params of behaviour with two params" needs to come first, then figure out how to make that look good, then do edge cases for things like layer-tap.

I do think this PR could be modified to cover the more general case, but I would understand (yet feel saddened if you feel too demotivated to do said work.

So this is basically what @danielsvane suggested above.

If this change would be green lit, I'd be happy to take a stab at it

@petejohanson
Copy link
Collaborator

I'd love to see improvements here, yes, that align with the metadata approach so we can have a sane display for any possible parameter combination, with enhanced/imporved display for specific pairs of parameter types.

Important note: The calculation of the second parameter type can depend on the given first parameter value, so the calculation for what that second type is can be non-trivial. We do that right now for the behavior parameter picker here, if you need to see that in action: https://github.com/zmkfirmware/zmk-studio/blob/main/src/behaviors/BehaviorParametersPicker.tsx

@BafS
Copy link
Author

BafS commented Nov 17, 2025

Ok, thank you guys for the quick answers, I'll try to update this PR one of those days and make it more simple.

@BafS
Copy link
Author

BafS commented Nov 17, 2025

Still a WIP but it's now closer to the behavior param picker

image

What would be good, I think, is to send the behavior name in the protocol.
Currently, we don't have this information, we only have the "display_name" but not the "behavior_name" (see behavior_subsystem.c in the firmware).
With this info we could have a design closer to https://nickcoutsos.github.io/keymap-editor/ for instance.

@awkannan
Copy link
Contributor

Since we pretty much have to deal with the protocol we have now, I think using display_name would be a good solution for now.
We can consider using the shorter behavior name later.

Maybe something like this:
image

Copy link
Contributor

@awkannan awkannan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a great start!

const matchingSet = findMatchingParameterSet(binding.param1, behavior.metadata, layerIds);

// If both parameters are zero
if (binding.param1 === 0 && binding.param2 === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be a valid configuration for some behaviors - so I don't think we can return an empty div here


// Both parameters present and should be displayed
if (param1Display && param2Display) {
return [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ordering here is tricky and I think could be up for discussion, but imo is fine for now

param1?: number,
param2?: number
): boolean {
if (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a few comments about what each check does.

For example - I'm personally a bit lost as to why we are doing a param1 === 0 check here.

For some behaviors, like bluetooth, param1 could be 0 to indicate clear current profile

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you, but I didn't touch the logic, this function was moved. I reverted it to simplify the diff.

}

// Get displays for both parameters
const param1Display = binding.param1 !== 0 ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 is a valid value for a param, i don't think this should be gated behind that

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

getParameterDisplay(binding.param1, behavior.metadata.flatMap(m => m.param1), layers) :
null;

const param2Display = binding.param2 !== 0 && matchingSet ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@BafS
Copy link
Author

BafS commented Nov 17, 2025

If we go that route @awkannan I think it would be better to open a separate PR that only change the design. Right now we show this info when we have the cursor "on hover".

I would gladly take care of the implementation, but to avoid back-and-forth it would help to have a specific design/idea/goal in mind before I start.

And thanks for your review! I'll check this soon

@awkannan
Copy link
Contributor

Agreed - I think that should be a separate PR!

@peterjc
Copy link
Contributor

peterjc commented Nov 18, 2025

This would close #147 which would be great 😍

@awkannan
Copy link
Contributor

Since #141 was merged, there are some merge conflicts now.
But hopefully it's not too bad to fix up!

@BafS BafS force-pushed the feat/layer-tap-key-1 branch from c0f3ce6 to 7b9bf07 Compare December 3, 2025 00:27
@BafS
Copy link
Author

BafS commented Dec 3, 2025

I still need to work on it, but that's how it currently looks like with the rebase from main

image

@BafS BafS force-pushed the feat/layer-tap-key-1 branch from 69e4140 to 8926887 Compare December 15, 2025 23:26
@BafS
Copy link
Author

BafS commented Dec 15, 2025

I tried to revert everything that was not required for this change, to simplify the diff.

With the latest change:

image

Let me know what you think, there are some issues with key display in "main", especially when it's long, but I didn't want to change this in this PR, I can do a followup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants