aboutsummaryrefslogtreecommitdiff
path: root/keyboards/bastardkb/charybdis/charybdis.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/bastardkb/charybdis/charybdis.c')
-rw-r--r--keyboards/bastardkb/charybdis/charybdis.c343
1 files changed, 343 insertions, 0 deletions
diff --git a/keyboards/bastardkb/charybdis/charybdis.c b/keyboards/bastardkb/charybdis/charybdis.c
new file mode 100644
index 000000000..f94682ba4
--- /dev/null
+++ b/keyboards/bastardkb/charybdis/charybdis.c
@@ -0,0 +1,343 @@
1/*
2 * Copyright 2020 Christopher Courtney <drashna@live.com> (@drashna)
3 * Copyright 2021 Quentin LEBASTARD <qlebastard@gmail.com>
4 * Copyright 2021 Charly Delay <charly@codesink.dev> (@0xcharly)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Publicw License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "charybdis.h"
21
22#ifdef CONSOLE_ENABLE
23# include "print.h"
24#endif // CONSOLE_ENABLE
25
26#ifdef POINTING_DEVICE_ENABLE
27# ifndef CHARYBDIS_MINIMUM_DEFAULT_DPI
28# define CHARYBDIS_MINIMUM_DEFAULT_DPI 400
29# endif // CHARYBDIS_MINIMUM_DEFAULT_DPI
30
31# ifndef CHARYBDIS_DEFAULT_DPI_CONFIG_STEP
32# define CHARYBDIS_DEFAULT_DPI_CONFIG_STEP 200
33# endif // CHARYBDIS_DEFAULT_DPI_CONFIG_STEP
34
35# ifndef CHARYBDIS_MINIMUM_SNIPING_DPI
36# define CHARYBDIS_MINIMUM_SNIPING_DPI 200
37# endif // CHARYBDIS_MINIMUM_SNIPER_MODE_DPI
38
39# ifndef CHARYBDIS_SNIPING_DPI_CONFIG_STEP
40# define CHARYBDIS_SNIPING_DPI_CONFIG_STEP 100
41# endif // CHARYBDIS_SNIPING_DPI_CONFIG_STEP
42
43// Fixed DPI for drag-scroll.
44# ifndef CHARYBDIS_DRAGSCROLL_DPI
45# define CHARYBDIS_DRAGSCROLL_DPI 100
46# endif // CHARYBDIS_DRAGSCROLL_DPI
47
48# ifndef CHARYBDIS_DRAGSCROLL_BUFFER_SIZE
49# define CHARYBDIS_DRAGSCROLL_BUFFER_SIZE 6
50# endif // !CHARYBDIS_DRAGSCROLL_BUFFER_SIZE
51
52# ifndef CHARYBDIS_POINTER_ACCELERATION_FACTOR
53# define CHARYBDIS_POINTER_ACCELERATION_FACTOR 24
54# endif // !CHARYBDIS_POINTER_ACCELERATION_FACTOR
55
56typedef union {
57 uint8_t raw;
58 struct {
59 uint8_t pointer_default_dpi : 4; // 16 steps available.
60 uint8_t pointer_sniping_dpi : 2; // 4 steps available.
61 bool is_dragscroll_enabled : 1;
62 bool is_sniping_enabled : 1;
63 } __attribute__((packed));
64} charybdis_config_t;
65
66static charybdis_config_t g_charybdis_config = {0};
67
68/**
69 * \brief Set the value of `config` from EEPROM.
70 *
71 * Note that `is_dragscroll_enabled` and `is_sniping_enabled` are purposefully
72 * ignored since we do not want to persist this state to memory. In practice,
73 * this state is always written to maximize write-performances. Therefore, we
74 * explicitly set them to `false` in this function.
75 */
76static void read_charybdis_config_from_eeprom(charybdis_config_t* config) {
77 config->raw = eeconfig_read_kb() & 0xff;
78 config->is_dragscroll_enabled = false;
79 config->is_sniping_enabled = false;
80}
81
82/**
83 * \brief Save the value of `config` to eeprom.
84 *
85 * Note that all values are written verbatim, including whether drag-scroll
86 * and/or sniper mode are enabled. `read_charybdis_config_from_eeprom(…)`
87 * resets these 2 values to `false` since it does not make sense to persist
88 * these across reboots of the board.
89 */
90static void write_charybdis_config_to_eeprom(charybdis_config_t* config) { eeconfig_update_kb(config->raw); }
91
92/** \brief Return the current value of the pointer's default DPI. */
93static uint16_t get_pointer_default_dpi(charybdis_config_t* config) { return (uint16_t)config->pointer_default_dpi * CHARYBDIS_DEFAULT_DPI_CONFIG_STEP + CHARYBDIS_MINIMUM_DEFAULT_DPI; }
94
95/** \brief Return the current value of the pointer's sniper-mode DPI. */
96static uint16_t get_pointer_sniping_dpi(charybdis_config_t* config) { return (uint16_t)config->pointer_sniping_dpi * CHARYBDIS_SNIPING_DPI_CONFIG_STEP + CHARYBDIS_MINIMUM_SNIPING_DPI; }
97
98/** \brief Set the appropriate DPI for the input config. */
99static void maybe_update_pointing_device_cpi(charybdis_config_t* config) {
100 if (config->is_dragscroll_enabled) {
101 pointing_device_set_cpi(CHARYBDIS_DRAGSCROLL_DPI);
102 } else if (config->is_sniping_enabled) {
103 pointing_device_set_cpi(get_pointer_sniping_dpi(config));
104 } else {
105 pointing_device_set_cpi(get_pointer_default_dpi(config));
106 }
107}
108
109/**
110 * \brief Update the pointer's default DPI to the next or previous step.
111 *
112 * Increases the DPI value if `forward` is `true`, decreases it otherwise.
113 * The increment/decrement steps are equal to CHARYBDIS_DEFAULT_DPI_CONFIG_STEP.
114 */
115static void step_pointer_default_dpi(charybdis_config_t* config, bool forward) {
116 config->pointer_default_dpi += forward ? 1 : -1;
117 maybe_update_pointing_device_cpi(config);
118}
119
120/**
121 * \brief Update the pointer's sniper-mode DPI to the next or previous step.
122 *
123 * Increases the DPI value if `forward` is `true`, decreases it otherwise.
124 * The increment/decrement steps are equal to CHARYBDIS_SNIPING_DPI_CONFIG_STEP.
125 */
126static void step_pointer_sniping_dpi(charybdis_config_t* config, bool forward) {
127 config->pointer_sniping_dpi += forward ? 1 : -1;
128 maybe_update_pointing_device_cpi(config);
129}
130
131uint16_t charybdis_get_pointer_default_dpi(void) { return get_pointer_default_dpi(&g_charybdis_config); }
132
133uint16_t charybdis_get_pointer_sniping_dpi(void) { return get_pointer_sniping_dpi(&g_charybdis_config); }
134
135void charybdis_cycle_pointer_default_dpi_noeeprom(bool forward) { step_pointer_default_dpi(&g_charybdis_config, forward); }
136
137void charybdis_cycle_pointer_default_dpi(bool forward) {
138 step_pointer_default_dpi(&g_charybdis_config, forward);
139 write_charybdis_config_to_eeprom(&g_charybdis_config);
140}
141
142void charybdis_cycle_pointer_sniping_dpi_noeeprom(bool forward) { step_pointer_sniping_dpi(&g_charybdis_config, forward); }
143
144void charybdis_cycle_pointer_sniping_dpi(bool forward) {
145 step_pointer_sniping_dpi(&g_charybdis_config, forward);
146 write_charybdis_config_to_eeprom(&g_charybdis_config);
147}
148
149bool charybdis_get_pointer_sniping_enabled(void) { return g_charybdis_config.is_sniping_enabled; }
150
151void charybdis_set_pointer_sniping_enabled(bool enable) {
152 g_charybdis_config.is_sniping_enabled = enable;
153 maybe_update_pointing_device_cpi(&g_charybdis_config);
154}
155
156bool charybdis_get_pointer_dragscroll_enabled(void) { return g_charybdis_config.is_dragscroll_enabled; }
157
158void charybdis_set_pointer_dragscroll_enabled(bool enable) {
159 g_charybdis_config.is_dragscroll_enabled = enable;
160 maybe_update_pointing_device_cpi(&g_charybdis_config);
161}
162
163void pointing_device_init_kb(void) { maybe_update_pointing_device_cpi(&g_charybdis_config); }
164
165# ifndef CONSTRAIN_HID
166# define CONSTRAIN_HID(value) ((value) < -127 ? -127 : ((value) > 127 ? 127 : (value)))
167# endif // !CONSTRAIN_HID
168
169/**
170 * \brief Add optional acceleration effect.
171 *
172 * If `CHARYBDIS_ENABLE_POINTER_ACCELERATION` is defined, add a simple and naive
173 * acceleration effect to the provided value. Return the value unchanged
174 * otherwise.
175 */
176# ifndef DISPLACEMENT_WITH_ACCELERATION
177# ifdef CHARYBDIS_POINTER_ACCELERATION_ENABLE
178# define DISPLACEMENT_WITH_ACCELERATION(d) (CONSTRAIN_HID(d > 0 ? d * d / CHARYBDIS_POINTER_ACCELERATION_FACTOR + d : -d * d / CHARYBDIS_POINTER_ACCELERATION_FACTOR + d))
179# else // !CHARYBDIS_POINTER_ACCELERATION_ENABLE
180# define DISPLACEMENT_WITH_ACCELERATION(d) (d)
181# endif // CHARYBDIS_POINTER_ACCELERATION_ENABLE
182# endif // !DISPLACEMENT_WITH_ACCELERATION
183
184/**
185 * \brief Augment the pointing device behavior.
186 *
187 * Implement the Charybdis-specific features for pointing devices:
188 * - Drag-scroll
189 * - Sniping
190 * - Acceleration
191 */
192static void pointing_device_task_charybdis(report_mouse_t* mouse_report) {
193 static int16_t scroll_buffer_x = 0;
194 static int16_t scroll_buffer_y = 0;
195 if (g_charybdis_config.is_dragscroll_enabled) {
196# ifdef CHARYBDIS_DRAGSCROLL_REVERSE_X
197 scroll_buffer_x -= mouse_report->x;
198# else
199 scroll_buffer_x += mouse_report->x;
200# endif // CHARYBDIS_DRAGSCROLL_REVERSE_X
201# ifdef CHARYBDIS_DRAGSCROLL_REVERSE_Y
202 scroll_buffer_y -= mouse_report->y;
203# else
204 scroll_buffer_y += mouse_report->y;
205# endif // CHARYBDIS_DRAGSCROLL_REVERSE_Y
206 mouse_report->x = 0;
207 mouse_report->y = 0;
208 if (abs(scroll_buffer_x) > CHARYBDIS_DRAGSCROLL_BUFFER_SIZE) {
209 mouse_report->h = scroll_buffer_x > 0 ? 1 : -1;
210 scroll_buffer_x = 0;
211 }
212 if (abs(scroll_buffer_y) > CHARYBDIS_DRAGSCROLL_BUFFER_SIZE) {
213 mouse_report->v = scroll_buffer_y > 0 ? 1 : -1;
214 scroll_buffer_y = 0;
215 }
216 } else if (!g_charybdis_config.is_sniping_enabled) {
217 mouse_report->x = DISPLACEMENT_WITH_ACCELERATION(mouse_report->x);
218 mouse_report->y = DISPLACEMENT_WITH_ACCELERATION(mouse_report->y);
219 }
220}
221
222report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
223 if (is_keyboard_master()) {
224 pointing_device_task_charybdis(&mouse_report);
225 mouse_report = pointing_device_task_user(mouse_report);
226 }
227 return mouse_report;
228}
229
230# if defined(POINTING_DEVICE_ENABLE) && !defined(NO_CHARYBDIS_KEYCODES)
231/** \brief Whether SHIFT mod is enabled. */
232static bool has_shift_mod(void) {
233# ifdef NO_ACTION_ONESHOT
234 return mod_config(get_mods()) & MOD_MASK_SHIFT;
235# else
236 return mod_config(get_mods() | get_oneshot_mods()) & MOD_MASK_SHIFT;
237# endif // NO_ACTION_ONESHOT
238}
239# endif // POINTING_DEVICE_ENABLE && !NO_CHARYBDIS_KEYCODES
240
241/**
242 * \brief Outputs the Charybdis configuration to console.
243 *
244 * Prints the in-memory configuration structure to console, for debugging.
245 * Includes:
246 * - raw value
247 * - drag-scroll: on/off
248 * - sniping: on/off
249 * - default DPI: internal table index/actual DPI
250 * - sniping DPI: internal table index/actual DPI
251 */
252static void debug_charybdis_config_to_console(charybdis_config_t* config) {
253# ifdef CONSOLE_ENABLE
254 dprintf("(charybdis) process_record_kb: config = {\n"
255 "\traw = 0x%04X,\n"
256 "\t{\n"
257 "\t\tis_dragscroll_enabled=%b\n"
258 "\t\tis_sniping_enabled=%b\n"
259 "\t\tdefault_dpi=0x%02X (%ld)\n"
260 "\t\tsniping_dpi=0x%01X (%ld)\n"
261 "\t}\n"
262 "}\n",
263 config->raw, config->is_dragscroll_enabled, config->is_sniping_enabled, config->pointer_default_dpi, get_pointer_default_dpi(config), config->pointer_sniping_dpi, get_pointer_sniping_dpi(config));
264# endif // CONSOLE_ENABLE
265}
266
267bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
268 if (!process_record_user(keycode, record)) {
269 debug_charybdis_config_to_console(&g_charybdis_config);
270 return false;
271 }
272# ifdef POINTING_DEVICE_ENABLE
273# ifndef NO_CHARYBDIS_KEYCODES
274 switch (keycode) {
275 case POINTER_DEFAULT_DPI_FORWARD:
276 if (record->event.pressed) {
277 // Step backward if shifted, forward otherwise.
278 charybdis_cycle_pointer_default_dpi(/* forward= */ !has_shift_mod());
279 }
280 break;
281 case POINTER_DEFAULT_DPI_REVERSE:
282 if (record->event.pressed) {
283 // Step forward if shifted, backward otherwise.
284 charybdis_cycle_pointer_default_dpi(/* forward= */ has_shift_mod());
285 }
286 break;
287 case POINTER_SNIPING_DPI_FORWARD:
288 if (record->event.pressed) {
289 // Step backward if shifted, forward otherwise.
290 charybdis_cycle_pointer_sniping_dpi(/* forward= */ !has_shift_mod());
291 }
292 break;
293 case POINTER_SNIPING_DPI_REVERSE:
294 if (record->event.pressed) {
295 // Step forward if shifted, backward otherwise.
296 charybdis_cycle_pointer_sniping_dpi(/* forward= */ has_shift_mod());
297 }
298 break;
299 case SNIPING_MODE:
300 charybdis_set_pointer_sniping_enabled(record->event.pressed);
301 break;
302 case SNIPING_MODE_TOGGLE:
303 if (record->event.pressed) {
304 charybdis_set_pointer_sniping_enabled(!charybdis_get_pointer_sniping_enabled());
305 }
306 break;
307 case DRAGSCROLL_MODE:
308 charybdis_set_pointer_dragscroll_enabled(record->event.pressed);
309 break;
310 case DRAGSCROLL_MODE_TOGGLE:
311 if (record->event.pressed) {
312 charybdis_set_pointer_dragscroll_enabled(!charybdis_get_pointer_dragscroll_enabled());
313 }
314 break;
315 }
316# endif // !NO_CHARYBDIS_KEYCODES
317# ifndef MOUSEKEY_ENABLE
318 // Simulate mouse keys if full support is not enabled (reduces firmware size
319 // while maintaining support for mouse keys).
320 if (IS_MOUSEKEY_BUTTON(keycode)) {
321 report_mouse_t mouse_report = pointing_device_get_report();
322 mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, record->event.pressed, keycode - KC_MS_BTN1);
323 pointing_device_set_report(mouse_report);
324 pointing_device_send();
325 }
326# endif // !MOUSEKEY_ENABLE
327# endif // POINTING_DEVICE_ENABLE
328 debug_charybdis_config_to_console(&g_charybdis_config);
329 return true;
330}
331
332void eeconfig_init_kb(void) {
333 g_charybdis_config.raw = 0;
334 write_charybdis_config_to_eeprom(&g_charybdis_config);
335 maybe_update_pointing_device_cpi(&g_charybdis_config);
336 eeconfig_init_user();
337}
338
339void matrix_init_kb(void) {
340 read_charybdis_config_from_eeprom(&g_charybdis_config);
341 matrix_init_user();
342}
343#endif // POINTING_DEVICE_ENABLE