~andrew/qmk

1d4e8cb52af67afffa8eef768079948aeebed0d5 — Andrew Reisner 17 minutes ago 2924169 main
Add raw hid for waybar state
M keyboards/keyball/keyball39/keymaps/init/keymap.c => keyboards/keyball/keyball39/keymaps/init/keymap.c +56 -1
@@ 20,6 20,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "quantum.h"
#include "os_detection.h"
#include "raw_hid.h"

// Home row mods
#define HR_A KC_A


@@ 139,26 140,80 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    ),

    // Nav/Settings layer
    // F13/F14/F15 (below left/down/right arrows) are otherwise-unused
    // keysyms bound in dwl to office shade open/stop/close -- picked so
    // they don't need a modifier chord, since there's no home row mod
    // available while this layer is held.
    [5] = LAYOUT_universal(
        RGB_TOG  , AML_TO   , AML_I50  , AML_D50  , TG(1)   ,                            _______ , SSNP_VRT , KC_UP    , SSNP_FRE ,  QK_BOOT  ,
        WAYHALF  , WAYFULL  , KC_CAD   , KC_AENTER, SCRL_DVI,                            CPI_I100, KC_LEFT  , KC_DOWN  , KC_RGHT  , _______ ,
        RGB_MOD  , RGB_RMOD  , RGB_VAI  , RGB_VAD , SCRL_DVD,                            CPI_D100, _______  , _______  , _______  , _______ ,
        RGB_MOD  , RGB_RMOD  , RGB_VAI  , RGB_VAD , SCRL_DVD,                            CPI_D100, KC_F13   , KC_F14   , KC_F15   , _______ ,
        QK_BOOT  , KBC_RST  , _______ , _______ , _______ , _______ ,          _______ , SSNP_VRT, SSNP_HOR , SSNP_FRE , KC_PGDN , KBC_SAVE
    ),
};
// clang-format on

// waybar qmk/qmk-layers/qmk-trackball modules: raw HID protocol. Fixed-size
// unnumbered reports (QMK_RAW_REPORT_SIZE bytes); byte 0 is a command. 0x01
// (host->keyboard) asks for the current state; 0x02 (keyboard->host) carries
// it: bytes 1-4 are layer_state as a little-endian uint32_t, bytes 5-6 are
// the trackball's CPI as a little-endian uint16_t, byte 7 is the scroll
// divisor, byte 8 is the scroll-mode flag (0/1). See man/waybar-qmk.5.scd
// and man/waybar-qmk-trackball.5.scd in the waybar repo for the host-side
// half of this.
enum {
    QMK_RAW_CMD_GET_LAYER   = 0x01,
    QMK_RAW_CMD_LAYER_STATE = 0x02,
};

// Fixed at 32 (QMK's RAW_EPSIZE for USB LUFA/ChibiOS targets) rather than
// referencing RAW_EPSIZE directly: that macro lives in usb_descriptor.h,
// which isn't visible from this translation unit (e.g. when this file is
// pulled into quantum/keymap_introspection.c for keymap introspection).
#define QMK_RAW_REPORT_SIZE 32

static void send_layer_state(void) {
    uint8_t response[QMK_RAW_REPORT_SIZE] = {0};
    response[0] = QMK_RAW_CMD_LAYER_STATE;
    uint32_t state = layer_state;
    memcpy(&response[1], &state, sizeof(state));
    uint16_t cpi = keyball_get_cpi();
    memcpy(&response[5], &cpi, sizeof(cpi));
    response[7] = keyball_get_scroll_div();
    response[8] = keyball_get_scroll_mode() ? 1 : 0;
    raw_hid_send(response, sizeof(response));
}

void raw_hid_receive(uint8_t *data, uint8_t length) {
    if (length > 0 && data[0] == QMK_RAW_CMD_GET_LAYER) {
        send_layer_state();
    }
}

layer_state_t layer_state_set_user(layer_state_t state) {
    // Auto enable scroll mode on layer 5 (nav layer)
    // Only force scroll ON for layer 5; let SCRL_TO handle toggling otherwise
    if (get_highest_layer(state) == 5) {
        keyball_set_scroll_mode(true);
    }
    send_layer_state();
    return state;
}

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    switch (keycode) {
        case TD(TD_NAV):
            // Backstop: QMK's tap-dance reset() isn't reliably tied to physical
            // key release (it can be deferred past the next tap-dance timeout
            // if other keys are pressed/released while this key is still held,
            // leaving layer 5 stuck on with nothing visibly held). Force it off
            // the instant this key physically releases, regardless of what the
            // tap-dance state machine thinks it's doing.
            if (!record->event.pressed && nav_tap_state == TD_NAV_SINGLE_HOLD) {
                layer_off(5);
                nav_tap_state = TD_NAV_NONE;
            }
            break;
        case HR_L:
            if (record->event.pressed && record->tap.count && layer_state_is(1)) {
                uint8_t mods    = get_mods();

M keyboards/keyball/keyball39/keymaps/init/rules.mk => keyboards/keyball/keyball39/keymaps/init/rules.mk +1 -0
@@ 5,4 5,5 @@ TAP_DANCE_ENABLE = yes
COMBO_ENABLE = yes
POINTING_DEVICE_ENABLE = yes
OS_DETECTION_ENABLE = yes
RAW_ENABLE = yes            # waybar qmk module: push layer state over raw HID