diff options
Diffstat (limited to 'keyboards/bastardkb/charybdis/charybdis.c')
-rw-r--r-- | keyboards/bastardkb/charybdis/charybdis.c | 343 |
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 | |||
56 | typedef 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 | |||
66 | static 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 | */ | ||
76 | static 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 | */ | ||
90 | static 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. */ | ||
93 | static 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. */ | ||
96 | static 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. */ | ||
99 | static 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 | */ | ||
115 | static 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 | */ | ||
126 | static 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 | |||
131 | uint16_t charybdis_get_pointer_default_dpi(void) { return get_pointer_default_dpi(&g_charybdis_config); } | ||
132 | |||
133 | uint16_t charybdis_get_pointer_sniping_dpi(void) { return get_pointer_sniping_dpi(&g_charybdis_config); } | ||
134 | |||
135 | void charybdis_cycle_pointer_default_dpi_noeeprom(bool forward) { step_pointer_default_dpi(&g_charybdis_config, forward); } | ||
136 | |||
137 | void 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 | |||
142 | void charybdis_cycle_pointer_sniping_dpi_noeeprom(bool forward) { step_pointer_sniping_dpi(&g_charybdis_config, forward); } | ||
143 | |||
144 | void 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 | |||
149 | bool charybdis_get_pointer_sniping_enabled(void) { return g_charybdis_config.is_sniping_enabled; } | ||
150 | |||
151 | void 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 | |||
156 | bool charybdis_get_pointer_dragscroll_enabled(void) { return g_charybdis_config.is_dragscroll_enabled; } | ||
157 | |||
158 | void 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 | |||
163 | void 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 | */ | ||
192 | static 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 | |||
222 | report_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. */ | ||
232 | static 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 | */ | ||
252 | static 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 | |||
267 | bool 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 | |||
332 | void 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 | |||
339 | void matrix_init_kb(void) { | ||
340 | read_charybdis_config_from_eeprom(&g_charybdis_config); | ||
341 | matrix_init_user(); | ||
342 | } | ||
343 | #endif // POINTING_DEVICE_ENABLE | ||