Last active
October 31, 2021 05:45
-
-
Save akagisho/0dbbb498aeddf2e1a73a64fcd1ac682f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright 2020 sekigon-gonnoc | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation, either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
#include "keymap_jp.h" | |
#include "quantum.h" | |
#include QMK_KEYBOARD_H | |
#include "pointing_device.h" | |
#include "debug.h" | |
#include "report_parser.h" | |
#define GESTURE_MOVE_THRESHOLD 50 | |
enum custom_keycodes { | |
SPD_1 = SAFE_RANGE, | |
SPD_2, | |
SPD_3, | |
}; | |
typedef enum { | |
GESTURE_NONE = 0, | |
GESTURE_DOWN_RIGHT, | |
GESTURE_DOWN_LEFT, | |
GESTURE_UP_LEFT, | |
GESTURE_UP_RIGHT, | |
} gesture_id_t; | |
// clang-format off | |
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {{{KC_NO}}}; | |
// clang-format on | |
extern bool mouse_send_flag; | |
static uint8_t spd_rate_num = 1; | |
static uint8_t spd_rate_den = 1; | |
static int16_t gesture_move_x = 0; | |
static int16_t gesture_move_y = 0; | |
static bool gesture_wait = false; | |
static uint8_t kc_no_to_kc_offset = 0; | |
static uint8_t btn_release_flag = 0; | |
static int16_t wheel_move_v = 0; | |
static int16_t wheel_move_h = 0; | |
gesture_id_t recognize_gesture(int16_t x, int16_t y) { | |
gesture_id_t gesture_id = 0; | |
if (abs(x) + abs(y) < GESTURE_MOVE_THRESHOLD) { | |
gesture_id = GESTURE_NONE; | |
} else if (x >= 0 && y >= 0) { | |
gesture_id = GESTURE_DOWN_RIGHT; | |
} else if (x < 0 && y >= 0) { | |
gesture_id = GESTURE_DOWN_LEFT; | |
} else if (x < 0 && y < 0) { | |
gesture_id = GESTURE_UP_LEFT; | |
} else if (x >= 0 && y < 0) { | |
gesture_id = GESTURE_UP_RIGHT; | |
} | |
return gesture_id; | |
} | |
void process_gesture(uint8_t layer, gesture_id_t gesture_id) { | |
switch (gesture_id) { | |
case GESTURE_DOWN_RIGHT ... GESTURE_UP_RIGHT: { | |
keypos_t keypos = {.row = MATRIX_MSGES_ROW, .col = gesture_id - 1}; | |
uint16_t keycode = keymap_key_to_keycode(layer, keypos); | |
tap_code16(keycode); | |
} break; | |
default: | |
break; | |
} | |
} | |
bool remap_shifted(uint16_t keycode, keyrecord_t* record) { | |
if (!record->event.pressed) | |
return true; | |
uint8_t shift = keyboard_report->mods & (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)); | |
if (!shift) | |
return true; | |
unregister_mods(shift); | |
tap_code16(keycode); | |
register_mods(shift); | |
return false; | |
} | |
bool remap_both(uint16_t keycode1, uint16_t keycode2, keyrecord_t* record) { | |
if (!record->event.pressed) | |
return true; | |
uint8_t shift = keyboard_report->mods & (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)); | |
if (!shift) | |
tap_code16(keycode1); | |
else | |
tap_code16(keycode2); | |
return false; | |
} | |
bool process_record_user(uint16_t keycode, keyrecord_t* record) { | |
switch (keycode) { | |
case JP_2: | |
return remap_shifted(JP_AT, record); | |
case JP_6: | |
return remap_shifted(JP_CIRC, record); | |
case JP_7: | |
return remap_shifted(JP_AMPR, record); | |
case JP_8: | |
return remap_shifted(JP_ASTR, record); | |
case JP_9: | |
return remap_shifted(JP_LPRN, record); | |
case JP_0: | |
return remap_shifted(JP_RPRN, record); | |
case JP_GRV: | |
return remap_shifted(JP_TILD, record); | |
case JP_EQL: | |
return remap_shifted(JP_PLUS, record); | |
case JP_MINS: | |
return remap_shifted(JP_UNDS, record); | |
case JP_QUOT: | |
return remap_shifted(JP_DQUO, record); | |
case JP_SCLN: | |
return remap_shifted(JP_COLN, record); | |
case JP_CIRC: // = | |
return remap_both(JP_EQL, JP_PLUS, record); | |
case KC_BSLASH: | |
return remap_both(JP_BSLS, JP_PIPE, record); | |
case JP_ZKHK: // ` | |
return remap_both(JP_GRV, JP_TILD, record); | |
case JP_AT: // [ | |
return remap_both(JP_LBRC, JP_LCBR, record); | |
case JP_LBRC: // ] | |
return remap_both(JP_RBRC, JP_RCBR, record); | |
case JP_COLN: // ' | |
return remap_both(JP_QUOT, JP_DQUO, record); | |
case KC_BTN1 ... KC_BTN5: { | |
mouse_send_flag = true; | |
return true; | |
} break; | |
case KC_MS_WH_UP ... KC_MS_WH_DOWN: { | |
if (wheel_move_v != 0) { | |
report_mouse_t report = pointing_device_get_report(); | |
report.v = keycode == KC_MS_WH_UP ? abs(wheel_move_v) | |
: -abs(wheel_move_v); | |
pointing_device_set_report(report); | |
mouse_send_flag = true; | |
return false; | |
} else { | |
return true; | |
} | |
} break; | |
case KC_MS_WH_LEFT ... KC_MS_WH_RIGHT: { | |
if (wheel_move_h != 0) { | |
report_mouse_t report = pointing_device_get_report(); | |
report.h = keycode == KC_MS_WH_LEFT ? abs(wheel_move_h) | |
: -abs(wheel_move_h); | |
pointing_device_set_report(report); | |
mouse_send_flag = true; | |
return false; | |
} else { | |
return true; | |
} | |
} break; | |
case SPD_1: | |
spd_rate_num = 1; | |
spd_rate_den = 1; | |
return false; | |
case SPD_2: | |
spd_rate_num = 1; | |
spd_rate_den = 2; | |
return false; | |
case SPD_3: | |
spd_rate_num = 2; | |
spd_rate_den = 1; | |
return false; | |
default: | |
break; | |
} | |
// Enable layer tap with KC_BTNx | |
if (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX) { | |
uint8_t kc = keycode & 0xFF; | |
if (kc == KC_NO) { | |
kc = kc_no_to_kc_offset; | |
// dprintf("KC:%d, tap:%d\n", kc, record->tap.count); | |
if (record->tap.count > 0 && !record->tap.interrupted) { | |
// set mouse button bit | |
report_mouse_t mouse = pointing_device_get_report(); | |
mouse.buttons |= (1 << (kc - KC_BTN1)); | |
pointing_device_set_report(mouse); | |
mouse_send_flag = true; | |
btn_release_flag |= (1 << (kc - KC_BTN1)); | |
} | |
} | |
} | |
return true; | |
} | |
// override keymap_key_to_keycode | |
uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) { | |
uint16_t keycode = KC_NO; | |
// uint16_t keycode = pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]); | |
if (layer < DYNAMIC_KEYMAP_LAYER_COUNT && key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { | |
keycode = dynamic_keymap_get_keycode(layer, key.row, key.col); | |
} | |
// To use LT with mouse button, replace keycode and save offset | |
if (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX) { | |
uint8_t kc = keycode & 0xFF; | |
if (kc >= KC_BTN1 && kc <= KC_BTN5) { | |
kc_no_to_kc_offset = kc; | |
return keycode & 0xFF00; | |
} else { | |
kc_no_to_kc_offset = 0; | |
} | |
} | |
return keycode; | |
} | |
void matrix_scan_user(void) { | |
if (btn_release_flag) { | |
report_mouse_t mouse = pointing_device_get_report(); | |
mouse.buttons &= ~btn_release_flag; | |
btn_release_flag = 0; | |
pointing_device_set_report(mouse); | |
mouse_send_flag = true; | |
} | |
} | |
// Start gesture recognition | |
static void gesture_start(void) { | |
dprint("Gesture start\n"); | |
gesture_wait = true; | |
gesture_move_x = 0; | |
gesture_move_y = 0; | |
} | |
uint16_t get_tapping_term(uint16_t keycode, keyrecord_t* record) { | |
// Gesture recognition trick | |
// Start gesture when LT key is pressed | |
if (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX) { | |
if (record->event.pressed && gesture_wait == false) { | |
gesture_start(); | |
} | |
} | |
return TAPPING_TERM; | |
} | |
void post_process_record_user(uint16_t keycode, keyrecord_t* record) { | |
if (keycode >= QK_MOMENTARY && keycode <= QK_MOMENTARY_MAX) { | |
if (record->event.pressed && gesture_wait == false) { | |
gesture_start(); | |
} | |
} | |
if ((keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX) || (keycode >= QK_MOMENTARY && keycode <= QK_MOMENTARY_MAX)) { | |
if ((!record->event.pressed) && gesture_wait == true) { | |
gesture_wait = false; | |
gesture_id_t gesture_id = recognize_gesture(gesture_move_x, gesture_move_y); | |
uint8_t layer = 0; | |
if ((keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) { | |
layer = (keycode >> 8) & 0x0F; | |
} else { | |
layer = keycode & 0xFF; | |
} | |
process_gesture(layer, gesture_id); | |
// dprintf("id:%d x:%d,y:%d\n", gesture_id, gesture_move_x, gesture_move_y); | |
} | |
} | |
} | |
extern bool matrix_has_changed; | |
extern matrix_row_t* matrix_mouse_dest; | |
void mouse_report_hook(mouse_parse_result_t const* report) { | |
if (debug_enable) { | |
xprintf("Mouse report\n"); | |
xprintf("b:%d ", report->button); | |
xprintf("x:%d ", report->x); | |
xprintf("y:%d ", report->y); | |
xprintf("v:%d ", report->v); | |
xprintf("h:%d ", report->h); | |
xprintf("undef:%u\n", report->undefined); | |
} | |
// | |
// Assign buttons to matrix | |
// 8 button mouse is assumed | |
// | |
uint8_t button_prev = matrix_mouse_dest[0]; | |
uint8_t button_current = report->button; | |
if (button_current != button_prev) { | |
matrix_has_changed = true; | |
} | |
matrix_mouse_dest[0] = button_current; | |
// | |
// Assign wheel to key action | |
// | |
if (report->v != 0) { | |
keypos_t key; | |
wheel_move_v = report->v; | |
key.row = MATRIX_MSWHEEL_ROW; | |
key.col = report->v > 0 ? MATRIX_MSWHEEL_COL : MATRIX_MSWHEEL_COL + 1; | |
action_exec((keyevent_t){ | |
.key = key, .pressed = true, .time = (timer_read() | 1)}); | |
action_exec((keyevent_t){ | |
.key = key, .pressed = false, .time = (timer_read() | 1)}); | |
} | |
if (report->h != 0) { | |
keypos_t key; | |
wheel_move_h = report->h; | |
key.row = MATRIX_MSWHEEL_ROW; | |
key.col = | |
report->h > 0 ? MATRIX_MSWHEEL_COL + 2 : MATRIX_MSWHEEL_COL + 3; | |
action_exec((keyevent_t){ | |
.key = key, .pressed = true, .time = (timer_read() | 1)}); | |
action_exec((keyevent_t){ | |
.key = key, .pressed = false, .time = (timer_read() | 1)}); | |
} | |
// | |
// Assign mouse movement | |
// | |
mouse_send_flag = true; | |
report_mouse_t mouse = pointing_device_get_report(); | |
static int16_t x_rem; | |
static int16_t y_rem; | |
int16_t x = (x_rem + report->x) * spd_rate_num / spd_rate_den; | |
int16_t y = (y_rem + report->y) * spd_rate_num / spd_rate_den; | |
if (spd_rate_den - spd_rate_num > 0) { | |
x_rem = (x_rem + report->x) - (x * spd_rate_den); | |
y_rem = (y_rem + report->y) - (y * spd_rate_den); | |
} else { | |
x_rem = 0; | |
y_rem = 0; | |
} | |
mouse.x += x; | |
mouse.y += y; | |
pointing_device_set_report(mouse); | |
// | |
// Save movement to recognize gesture | |
// | |
if (gesture_wait) { | |
gesture_move_x += report->x; | |
gesture_move_y += report->y; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment