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

feat: Refine behavior_binding_event, nested trans #2848

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

Nick-Munnich
Copy link
Contributor

@Nick-Munnich Nick-Munnich commented Feb 27, 2025

This PR essentially does multiple things in one commit. These are all quite linked to one another, I wasn't quite able to untangle them from each other.

  • Refactors the existing sensor code, making encoder rotational tracking happen outside of behaviors and inside sensors.c.
  • Revamps zmk_behavior_binding_event so that it is actually a zmk event, i.e. is raised and managed by event_manager.
  • Allow the nesting of &trans inside of other behaviors, getting rid of ZMK_BEHAVIOR_TRANSPARENT in the process.

Taking the explanation from #573:
We currently have the following events

  • position_state_changed
    • keycode_state_changed
    • layer_state_changed

What is missing from this event flow are behavior bindings. This means they can not be observed like other events.

  • position_state_changed
    • behavior_binding_event
      • keycode_state_changed
      • layer_state_changed

This refactor/feat will allow for much more advanced and elegant handling in the future. My goal is to use this to rework combos a bit further. Nesting &trans is also a benefit that should not be underestimated, it will make things like home-row mods much easier to set up. The sensor refactor should allow further work on that part to be simpler as well.

Needs documentation and lots of testing, particularly around the encoder bits as the tests we have are very rudimentary. There are likely some stylistic bits that could use tidying up as well.

Closes: #573, #532, #2368

PR check-list

  • Branch has a clean commit history
  • Additional tests are included, if changing behaviors/core code that is testable.
  • Proper Copyright + License headers added to applicable files (Generally, we stick to "The ZMK Contributors" for copyrights to help avoid churn when files get edited)
  • Pre-commit used to check formatting of files, commit messages, etc.
  • Includes any necessary documentation changes.

Adds some encoder tests for rotating, and basic layers.
Mock Kscans don't seem to interact nicely, slightly on the hacky side.
However, better to have hacky tests than no tests.
@Nick-Munnich Nick-Munnich requested a review from a team as a code owner February 27, 2025 22:33
@Nick-Munnich Nick-Munnich added core Core functionality/behavior of ZMK behaviors encoders refactor labels Feb 27, 2025
@caksoylar
Copy link
Contributor

What documentation changes do you have in mind, besides updating the new behavior guide?

Copy link
Contributor

@caksoylar caksoylar left a comment

Choose a reason for hiding this comment

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

I haven't really reviewed the sensor parts since I am not familiar with those bits, but otherwise the broad strokes LGTM.

}

// TODO: Pass the event in as pointers, rather than copying in the struct
// Make this change as part of a breaking release
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this passing it as a pointer already?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here I'm referring to the behavior_keymap_binding_pressed etc functions. We're dereferencing the event struct before passing it in for backwards compatibility reasons. That way this isn't a breaking change for external behavior modules. I think that passing the struct in as a pointer would be slightly more efficient though, so doing it as part of a breaking change would be a good idea imo.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it, so the comment applies to the function calls inside. Though I don't know enough to say whether passing a pointer rather than a struct gives a non-trivial performance gain. I'd be interested to learn if e.g. @joelspadin has thoughts on it.

@@ -73,8 +74,9 @@ int zmk_keymap_save_changes(void);
int zmk_keymap_discard_changes(void);
int zmk_keymap_reset_settings(void);

int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
int64_t timestamp);
int zmk_keymap_raise_binding_event_at_layer_idx(zmk_keymap_layer_id_t layer_id, uint8_t source,
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably should be ..._layer_id, to disambiguate between layer_id and layer_index?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Considering the other conversationy bits I think renaming this to ..._layer_index might be better?

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess that function interface will be changed to use indices anyway, so it makes sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should be fixed now. Turns out I had half the solution in the code already. I think I may have fixed a bug that currently might exist in the process: We currently loop until LAYER_ID_TO_INDEX(default_layer). I think if someone reordered their layers to put the original default layer at the top of their layers and then tried to use &trans, they would have a bad time. Might be wrong, haven't tested this.

Copy link
Contributor Author

@Nick-Munnich Nick-Munnich 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 review! Regarding documentation changes, it is pretty much just the new behavior guide that I was thinking of, at least for now. Some further changes in the future might result in a nested trans making for a nice example in e.g. hold-taps, but that shouldn't be a part of this PR imo.

}

// TODO: Pass the event in as pointers, rather than copying in the struct
// Make this change as part of a breaking release
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here I'm referring to the behavior_keymap_binding_pressed etc functions. We're dereferencing the event struct before passing it in for backwards compatibility reasons. That way this isn't a breaking change for external behavior modules. I think that passing the struct in as a pointer would be slightly more efficient though, so doing it as part of a breaking change would be a good idea imo.

* RGB behaviors) does not modify it, e.g. if the behavior is stored in a combo_cfg
*/
struct zmk_behavior_binding binding = *(event->binding);
int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, *event);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe that L111 is making the copy, and then L112 is passing in a pointer to the copy so that the copy can be modified appropriately. We're then passing the adjusted behavior in as the first argument to the other functions, with the event having the behavior prior to any sort of adjustment.

@Nick-Munnich Nick-Munnich force-pushed the behavior-event branch 2 times, most recently from d812522 to 4079dca Compare March 6, 2025 08:32
@Nick-Munnich Nick-Munnich requested a review from a team as a code owner March 8, 2025 09:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
behaviors core Core functionality/behavior of ZMK encoders refactor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants