|
| 1 | +/* |
| 2 | + * Copyright (c) 2024 The ZMK Contributors |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: MIT |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/logging/log.h> |
| 8 | + |
| 9 | +LOG_MODULE_DECLARE(zmk_studio, CONFIG_ZMK_STUDIO_LOG_LEVEL); |
| 10 | + |
| 11 | +#include <drivers/behavior.h> |
| 12 | + |
| 13 | +#include <zmk/behavior.h> |
| 14 | +#include <zmk/matrix.h> |
| 15 | +#include <zmk/keymap.h> |
| 16 | +#include <zmk/studio/rpc.h> |
| 17 | + |
| 18 | +#include <pb_encode.h> |
| 19 | + |
| 20 | +ZMK_RPC_SUBSYSTEM(keymap) |
| 21 | + |
| 22 | +#define KEYMAP_RESPONSE(type, ...) ZMK_RPC_RESPONSE(keymap, type, __VA_ARGS__) |
| 23 | + |
| 24 | +static bool encode_layer_bindings(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { |
| 25 | + const uint8_t layer_idx = *(uint8_t *)*arg; |
| 26 | + |
| 27 | + for (int b = 0; b < ZMK_KEYMAP_LEN; b++) { |
| 28 | + const struct zmk_behavior_binding *binding = |
| 29 | + zmk_keymap_get_layer_binding_at_idx(layer_idx, b); |
| 30 | + |
| 31 | + zmk_keymap_BehaviorBinding bb = zmk_keymap_BehaviorBinding_init_zero; |
| 32 | + |
| 33 | + bb.behavior_id = zmk_behavior_get_local_id(binding->behavior_dev); |
| 34 | + bb.param1 = binding->param1; |
| 35 | + bb.param2 = binding->param2; |
| 36 | + |
| 37 | + if (!pb_encode_tag_for_field(stream, field)) { |
| 38 | + return false; |
| 39 | + } |
| 40 | + |
| 41 | + if (!pb_encode_submessage(stream, &zmk_keymap_BehaviorBinding_msg, &bb)) { |
| 42 | + return false; |
| 43 | + } |
| 44 | + } |
| 45 | + |
| 46 | + return true; |
| 47 | +} |
| 48 | + |
| 49 | +static bool encode_layer_name(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { |
| 50 | + const uint8_t layer_idx = *(uint8_t *)*arg; |
| 51 | + |
| 52 | + const char *name = zmk_keymap_layer_name(layer_idx); |
| 53 | + |
| 54 | + if (!name) { |
| 55 | + return true; |
| 56 | + } |
| 57 | + |
| 58 | + if (!pb_encode_tag_for_field(stream, field)) { |
| 59 | + return false; |
| 60 | + } |
| 61 | + |
| 62 | + return pb_encode_string(stream, name, strlen(name)); |
| 63 | +} |
| 64 | + |
| 65 | +static bool encode_keymap_layers(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { |
| 66 | + for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) { |
| 67 | + |
| 68 | + if (!pb_encode_tag_for_field(stream, field)) { |
| 69 | + LOG_DBG("Failed to encode tag"); |
| 70 | + return false; |
| 71 | + } |
| 72 | + |
| 73 | + zmk_keymap_Layer layer = zmk_keymap_Layer_init_zero; |
| 74 | + |
| 75 | + layer.name.funcs.encode = encode_layer_name; |
| 76 | + layer.name.arg = &l; |
| 77 | + |
| 78 | + layer.bindings.funcs.encode = encode_layer_bindings; |
| 79 | + layer.bindings.arg = &l; |
| 80 | + |
| 81 | + if (!pb_encode_submessage(stream, &zmk_keymap_Layer_msg, &layer)) { |
| 82 | + LOG_DBG("Failed to encode layer submessage"); |
| 83 | + return false; |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + return true; |
| 88 | +} |
| 89 | + |
| 90 | +zmk_Response get_keymap(const zmk_Request *req) { |
| 91 | + zmk_keymap_Keymap resp = zmk_keymap_Keymap_init_zero; |
| 92 | + |
| 93 | + resp.layers.funcs.encode = encode_keymap_layers; |
| 94 | + |
| 95 | + return KEYMAP_RESPONSE(get_keymap, resp); |
| 96 | +} |
| 97 | + |
| 98 | +zmk_Response set_layer_binding(const zmk_Request *req) { |
| 99 | + const zmk_keymap_SetLayerBindingRequest *set_req = |
| 100 | + &req->subsystem.keymap.request_type.set_layer_binding; |
| 101 | + |
| 102 | + zmk_behavior_local_id_t bid = set_req->binding.behavior_id; |
| 103 | + |
| 104 | + const char *behavior_name = zmk_behavior_find_behavior_name_from_local_id(bid); |
| 105 | + |
| 106 | + if (!behavior_name) { |
| 107 | + return KEYMAP_RESPONSE(set_layer_binding, |
| 108 | + zmk_keymap_SetLayerBindingResponse_INVALID_BEHAVIOR); |
| 109 | + } |
| 110 | + |
| 111 | + struct zmk_behavior_binding binding = (struct zmk_behavior_binding){ |
| 112 | + .behavior_dev = behavior_name, |
| 113 | + .param1 = set_req->binding.param1, |
| 114 | + .param2 = set_req->binding.param2, |
| 115 | + }; |
| 116 | + |
| 117 | + int ret = zmk_behavior_validate_binding(&binding); |
| 118 | + if (ret < 0) { |
| 119 | + return KEYMAP_RESPONSE(set_layer_binding, |
| 120 | + zmk_keymap_SetLayerBindingResponse_INVALID_PARAMETERS); |
| 121 | + } |
| 122 | + |
| 123 | + ret = zmk_keymap_set_layer_binding_at_idx(set_req->layer, set_req->key_position, binding); |
| 124 | + |
| 125 | + if (ret < 0) { |
| 126 | + LOG_DBG("Setting the binding failed with %d", ret); |
| 127 | + switch (ret) { |
| 128 | + case -EINVAL: |
| 129 | + return KEYMAP_RESPONSE(set_layer_binding, |
| 130 | + zmk_keymap_SetLayerBindingResponse_INVALID_LOCATION); |
| 131 | + default: |
| 132 | + return ZMK_RPC_SIMPLE_ERR(GENERIC); |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + return KEYMAP_RESPONSE(set_layer_binding, zmk_keymap_SetLayerBindingResponse_SUCCESS); |
| 137 | +} |
| 138 | + |
| 139 | +zmk_Response save_changes(const zmk_Request *req) { |
| 140 | + int ret = zmk_keymap_save_changes(); |
| 141 | + if (ret < 0) { |
| 142 | + return ZMK_RPC_SIMPLE_ERR(GENERIC); |
| 143 | + } |
| 144 | + |
| 145 | + return KEYMAP_RESPONSE(save_changes, true); |
| 146 | +} |
| 147 | + |
| 148 | +zmk_Response discard_changes(const zmk_Request *req) { |
| 149 | + int ret = zmk_keymap_discard_changes(); |
| 150 | + if (ret < 0) { |
| 151 | + return ZMK_RPC_SIMPLE_ERR(GENERIC); |
| 152 | + } |
| 153 | + |
| 154 | + return KEYMAP_RESPONSE(discard_changes, true); |
| 155 | +} |
| 156 | + |
| 157 | +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, get_keymap, true); |
| 158 | +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, set_layer_binding, true); |
| 159 | +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, save_changes, true); |
| 160 | +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, discard_changes, true); |
| 161 | + |
| 162 | +static int event_mapper(const zmk_event_t *eh, zmk_Notification *n) { return 0; } |
| 163 | + |
| 164 | +ZMK_RPC_EVENT_MAPPER(keymap, event_mapper); |
0 commit comments