Moved spellcheck and rawhid to kb folder

This commit is contained in:
2022-07-21 17:21:40 -07:00
parent 584b39f4c2
commit 4cb3fe0ee9
8 changed files with 13 additions and 12 deletions

View File

@ -0,0 +1,170 @@
#include "betalupi_ergodox.h"
#include "features/beta_rawhid.h"
#include "extra_mappings.h"
extern uint8_t layer_layouts[];
#include "features/spellcheck.h"
// See features/beta_rawhid.h for prococol documentation
void raw_hid_receive(uint8_t *data, uint8_t length) {
uint8_t cmd = data[0];
switch (cmd) {
case CMD_HELLO:
ergodox_right_led_1_on();
_delay_ms(50);
ergodox_right_led_1_off();
hid_send_state();
break;
#ifdef RGB_MATRIX_FRAMEBUFFER_EFFECTS
case CMD_ANIM_DATA:
cmd_animation(data, length);
break;
#endif
case CMD_SPELLCHECK_WORD:
if (data[1]) {
ergodox_right_led_1_on();
_delay_ms(50);
ergodox_right_led_1_off();
}
break;
default:
break;
}
}
uint8_t nth_byte(size_t n, uint32_t data) {
return (data >> (8 * n)) & 0xFF;
}
// state: layer state.
// If this is 0, we'll use global layer_state instead.
void _hid_send_state(_hid_send_state_args args) {
uint32_t state = args.state ? args.state : layer_state;
uint8_t packet[RAW_EPSIZE] = {
CMD_SEND_STATE,
// Animation state, set later
0x00,
// Layer state
nth_byte(0, state),
nth_byte(1, state),
nth_byte(2, state),
nth_byte(3, state),
// Keymap for active layer
layer_layouts[biton32(state)]
};
// Set second byte
if (rgb_matrix_get_flags() != LED_FLAG_ALL) {
// RGB matrix is disabled
packet[1] = 0x00;
} else {
uint8_t mode = rgb_matrix_get_mode();
switch (mode) {
#ifdef RGB_MATRIX_FRAMEBUFFER_EFFECTS
case RGB_MATRIX_CUSTOM_FFT_ANIM:
// FFT Animation is active
packet[1] = 0x02;
break;
#endif
default:
// Normal animation is active
packet[1] = 0x01;
break;
}
}
// Note that all sent packets MUST be
// RAW_EPSIZE long.
raw_hid_send(packet, RAW_EPSIZE);
}
void hid_send_word() {
uint8_t packet[RAW_EPSIZE] = {
CMD_SPELLCHECK_WORD,
spellcheck_buffer_size
};
for (int i = 0; i < 2 + spellcheck_buffer_size; i++) {
packet[i + 2] = spellcheck_buffer[i];
}
raw_hid_send(packet, RAW_EPSIZE);
}
#ifdef RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define FFT_PER_KEY 50
void cmd_animation(uint8_t *data, uint8_t length) {
switch (data[1]) {
case CMD_ANIM_DATA_fft:
// Only read data if animation is in fft mode
if (rgb_matrix_get_mode() == RGB_MATRIX_CUSTOM_FFT_ANIM) {
// Data should be a pointer to 10 uint8_ts, each representing
// the height of a bar on the display.
for (uint8_t bin = 0; bin < 10; bin++) {
// Scale data values
uint8_t d = data[bin + 2];
for (uint8_t i = 0; i < 5; i++) {
// Ignore negative indices.
// See fft_col_to_array definition.
if (fft_col_to_array[bin][i] < 0) {
if (d >= FFT_PER_KEY) {
d -= FFT_PER_KEY;
} else {
d = 0;
}
continue;
}
uint8_t row = fft_col_to_array[bin][i] % MATRIX_ROWS;
uint8_t col = fft_col_to_array[bin][i] / MATRIX_ROWS;
if (d >= FFT_PER_KEY) {
g_rgb_frame_buffer[row][col] = 0xFF;
d -= FFT_PER_KEY;
} else if (d > 0) {
g_rgb_frame_buffer[row][col] = ((double) d / FFT_PER_KEY) * 0xFF;
d = 0;
} else {
g_rgb_frame_buffer[row][col] = 0;
}
/*
rgb_matrix_set_color(
fft_col_to_array[bin][i],
last_brightness, 0x00, last_brightness
);
*/
}
}
} else {
// If not in fft mode and we receive fft data, send a state packet so host stops sending data.
hid_send_state();
}
break;
}
}
#endif

View File

@ -0,0 +1,108 @@
#pragma once
#include "raw_hid.h"
void raw_hid_receive(uint8_t *data, uint8_t length);
void hid_send_word(void);
// hid_send_state with advanced arguments
typedef struct {
uint32_t state;
} _hid_send_state_args;
void _hid_send_state(_hid_send_state_args args);
#define hid_send_state(...) _hid_send_state( \
(_hid_send_state_args) { \
.state = 0, \
__VA_ARGS__ \
} \
)
void cmd_animation(uint8_t *data, uint8_t length);
#ifdef RGB_MATRIX_FRAMEBUFFER_EFFECTS
extern uint8_t g_rgb_frame_buffer[MATRIX_ROWS][MATRIX_COLS];
#endif
// Sent by host when connection is initiated.
//
// Packet structure:
// Data: | cmd |
// # of Bytes: | 1 |
#define CMD_HELLO 0x00
// Sent periodically by host to test connection.
// Keyboard should ignore this command.
//
// Packet structure:
// Data: | cmd |
// # of Bytes: | 1 |
#define CMD_RUTHERE 0x01
// Send keyboard state to host.
//
// Packet structure:
// Data: | cmd | anim state | layer state | layer layout |
// # of Bytes: | 1 | 1 | 4 | 1 |
//
// anim state:
// 0x00: RGBMatrix disabled
// 0x01: normal animation, no HID data.
// 0x02: FFT Animation
//
// layer state: layer state right now.
// This is a uint32_t, where each bit corresponds to a layer index.
// Lowest-order bit is base layer, highest bit is layer 31.
// Layer indices are defined by the LAYER_* enum in layer.h,
// host interface should have a matching enum.
// Make sure to update it when you change your layers!
//
// layer layout:
// The layout this layer was designed for.
// 0x00: en_us
// 0x01: russian
#define CMD_SEND_STATE 0x02
// Sent by keyboard to host when a complete word is typed.
// Host checks if this is a known word.
// If it is not, host responds with the same CMD (see below).
//
// Packet structure (sent by keyboard):
// Data: | cmd | word length | keycodes |
// # of Bytes: | 1 | 1 | ? |
//
// word length: number of bytes in `keycodes` block
//
//
// Packet structure (sent by host):
// Data: | cmd | typo? |
// # of Bytes: | 1 | 1 |
//
// typo: If this is 0x01, the word we got was a typo.
#define CMD_SPELLCHECK_WORD 0x04
// Animation data. Sent by host.
//
// Packet structure:
// Data: | cmd | data type | data |
// # of Bytes: | 1 | 1 | ? |
//
// data type:
// Which animation this data is for. These are defined below.
//
// data:
// Animation data. Content depends on data type.
#define CMD_ANIM_DATA 0x03
// Data for FFT animation.
// Data segment consists of 10 bits, each representing the height of a column.
// Minimum height is 0, maximum is 250.
#define CMD_ANIM_DATA_fft 0x00

View File

@ -0,0 +1,110 @@
#include "features/spellcheck.h"
#include "features/beta_rawhid.h"
uint8_t spellcheck_buffer[SPELLCHECK_BUFFER_MAX] = {0};
uint8_t spellcheck_buffer_size = 0;
bool process_spellcheck(uint16_t keycode, keyrecord_t* record) {
// Ignore key release; we only process key presses.
if (!record->event.pressed) { return true; }
#ifndef NO_ACTION_ONESHOT
const uint8_t mods = get_mods() | get_oneshot_mods();
#else
const uint8_t mods = get_mods();
#endif
// Disable autocorrection while a mod other than shift is active.
if ((mods & ~MOD_MASK_SHIFT) != 0) {
spellcheck_buffer_size = 0;
return true;
}
// The following switch cases address various kinds of keycodes. This logic is
// split over two switches rather than merged into one. The first switch may
// extract a basic keycode which is then further handled by the second switch,
// e.g. a layer-tap key with Caps Lock `LT(layer, KC_CAPS)`.
switch (keycode) {
#ifndef NO_ACTION_TAPPING
case QK_MOD_TAP ... QK_MOD_TAP_MAX: // Tap-hold keys.
#ifndef NO_ACTION_LAYER
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
#endif
// Ignore when tap-hold keys are held.
if (record->tap.count == 0) { return true; }
// Otherwise when tapped, get the basic keycode.
// Fallthrough intended.
#endif
// Handle shifted keys, e.g. symbols like KC_EXLM = S(KC_1).
case QK_LSFT ... QK_LSFT + 255:
case QK_RSFT ... QK_RSFT + 255:
keycode &= 0xff; // Get the basic keycode.
break;
// NOTE: Space Cadet keys expose no info to check whether they are being
// tapped vs. held. This makes autocorrection ambiguous, e.g. KC_LCPO might
// be '(', which we would treat as a word break, or it might be shift, which
// we would treat as having no effect. To behave cautiously, we allow Space
// Cadet keycodes to fall to the logic below and clear autocorrection state.
}
switch (keycode) {
// Ignore shifts, Caps Lock, one-shot mods, and layer switch keys.
case KC_NO:
case KC_LSFT:
case KC_RSFT:
case KC_CAPS:
case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:
case QK_TO ... QK_TO_MAX:
case QK_MOMENTARY ... QK_MOMENTARY_MAX:
case QK_DEF_LAYER ... QK_DEF_LAYER_MAX:
case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX:
case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:
case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
case QK_LAYER_MOD ... QK_LAYER_MOD_MAX:
return true; // Ignore these keys.
}
if (keycode == KC_QUOT) {
// Treat " (shifted ') as a word boundary.
if ((mods & MOD_MASK_SHIFT) != 0) { keycode = KC_SPC; }
} else if (!(KC_A <= keycode && keycode <= KC_Z)) {
if (keycode == KC_BSPC) {
// Remove last character from the buffer.
if (spellcheck_buffer_size > 0) { --spellcheck_buffer_size; }
return true;
} else if (KC_1 <= keycode && keycode <= KC_SLSH && keycode != KC_ESC) {
// Set a word boundary if space, period, digit, etc. is pressed.
// Behave more conservatively for the enter key. Reset, so that enter
// can't be used on a word ending.
if (keycode == KC_ENT) { spellcheck_buffer_size = 0; }
keycode = KC_SPC;
} else {
// Clear state if some other non-alpha key is pressed.
spellcheck_buffer_size = 0;
return true;
}
}
// If the buffer is full, rotate it to discard the oldest character.
if (spellcheck_buffer_size >= SPELLCHECK_BUFFER_MAX) {
memmove(spellcheck_buffer, spellcheck_buffer + 1, SPELLCHECK_BUFFER_MAX - 1);
spellcheck_buffer_size = SPELLCHECK_BUFFER_MAX - 1;
}
// NOTE: `keycode` must be a basic keycode (0-255) by this point.
// A to Z keycodes
if (keycode >= 0x04 && keycode <= 0x1D) {
spellcheck_buffer[spellcheck_buffer_size++] = (uint8_t) keycode;
} else if (spellcheck_buffer_size > 0) {
hid_send_word();
spellcheck_buffer_size = 0;
}
return true;
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "quantum.h"
// spellcheck_buffer holds keycode history.
// It can only contain values 0x00 - 0xFF, aka standard usb hid codes.
// Host software is responsible for turning this into a usable string.
//
// Note that SOME preprocessing is done,see spellcheck.c
#define SPELLCHECK_BUFFER_MAX 16
uint8_t spellcheck_buffer[SPELLCHECK_BUFFER_MAX];
uint8_t spellcheck_buffer_size;
bool process_spellcheck(uint16_t keycode, keyrecord_t* record);