qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

pointing_device.c (20571B)


      1 /* Copyright 2017 Joshua Broekhuijsen <snipeye+qmk@gmail.com>
      2  * Copyright 2020 Christopher Courtney, aka Drashna Jael're  (@drashna) <drashna@live.com>
      3  * Copyright 2021 Dasky (@daskygit)
      4  *
      5  * This program is free software: you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation, either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include "pointing_device.h"
     20 #include <string.h>
     21 #include "timer.h"
     22 #include "gpio.h"
     23 
     24 #ifdef MOUSEKEY_ENABLE
     25 #    include "mousekey.h"
     26 #endif
     27 
     28 #ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
     29 #    include "usb_descriptor_common.h"
     30 #endif
     31 
     32 #if (defined(POINTING_DEVICE_ROTATION_90) + defined(POINTING_DEVICE_ROTATION_180) + defined(POINTING_DEVICE_ROTATION_270)) > 1
     33 #    error More than one rotation selected.  This is not supported.
     34 #endif
     35 
     36 #if defined(POINTING_DEVICE_LEFT) || defined(POINTING_DEVICE_RIGHT) || defined(POINTING_DEVICE_COMBINED)
     37 #    ifndef SPLIT_POINTING_ENABLE
     38 #        error "Using POINTING_DEVICE_LEFT or POINTING_DEVICE_RIGHT or POINTING_DEVICE_COMBINED, then SPLIT_POINTING_ENABLE is required but has not been defined"
     39 #    endif
     40 #endif
     41 
     42 #if defined(SPLIT_POINTING_ENABLE)
     43 #    include "transactions.h"
     44 #    include "keyboard.h"
     45 
     46 report_mouse_t shared_mouse_report = {};
     47 uint16_t       shared_cpi          = 0;
     48 
     49 /**
     50  * @brief Sets the shared mouse report used be pointing device task
     51  *
     52  * NOTE : Only available when using SPLIT_POINTING_ENABLE
     53  *
     54  * @param[in] new_mouse_report report_mouse_t
     55  */
     56 void pointing_device_set_shared_report(report_mouse_t new_mouse_report) {
     57     shared_mouse_report = new_mouse_report;
     58 }
     59 
     60 /**
     61  * @brief Gets current pointing device CPI if supported
     62  *
     63  * Gets current cpi of the shared report and returns it as uint16_t
     64  *
     65  * NOTE : Only available when using SPLIT_POINTING_ENABLE
     66  *
     67  * @return cpi value as uint16_t
     68  */
     69 uint16_t pointing_device_get_shared_cpi(void) {
     70     return shared_cpi;
     71 }
     72 
     73 #    if defined(POINTING_DEVICE_LEFT)
     74 #        define POINTING_DEVICE_THIS_SIDE is_keyboard_left()
     75 #    elif defined(POINTING_DEVICE_RIGHT)
     76 #        define POINTING_DEVICE_THIS_SIDE !is_keyboard_left()
     77 #    elif defined(POINTING_DEVICE_COMBINED)
     78 #        define POINTING_DEVICE_THIS_SIDE true
     79 #    endif
     80 
     81 #endif // defined(SPLIT_POINTING_ENABLE)
     82 
     83 static report_mouse_t           local_mouse_report         = {};
     84 static bool                     pointing_device_force_send = false;
     85 static pointing_device_status_t pointing_device_status     = POINTING_DEVICE_STATUS_UNKNOWN;
     86 
     87 #ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
     88 static uint16_t hires_scroll_resolution;
     89 #endif
     90 
     91 #define POINTING_DEVICE_DRIVER_CONCAT(name) name##_pointing_device_driver
     92 #define POINTING_DEVICE_DRIVER(name) POINTING_DEVICE_DRIVER_CONCAT(name)
     93 
     94 #ifdef POINTING_DEVICE_DRIVER_custom
     95 __attribute__((weak)) bool pointing_device_driver_init(void) {
     96     return false;
     97 }
     98 __attribute__((weak)) report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) {
     99     return mouse_report;
    100 }
    101 __attribute__((weak)) uint16_t pointing_device_driver_get_cpi(void) {
    102     return 0;
    103 }
    104 __attribute__((weak)) void pointing_device_driver_set_cpi(uint16_t cpi) {}
    105 
    106 const pointing_device_driver_t custom_pointing_device_driver = {
    107     .init       = pointing_device_driver_init,
    108     .get_report = pointing_device_driver_get_report,
    109     .get_cpi    = pointing_device_driver_get_cpi,
    110     .set_cpi    = pointing_device_driver_set_cpi,
    111 };
    112 #endif
    113 
    114 const pointing_device_driver_t *pointing_device_driver = &POINTING_DEVICE_DRIVER(POINTING_DEVICE_DRIVER_NAME);
    115 
    116 __attribute__((weak)) void           pointing_device_init_modules(void) {}
    117 __attribute__((weak)) report_mouse_t pointing_device_task_modules(report_mouse_t mouse_report) {
    118     return mouse_report;
    119 }
    120 
    121 /**
    122  * @brief Keyboard level code pointing device initialisation
    123  *
    124  */
    125 __attribute__((weak)) void pointing_device_init_kb(void) {}
    126 
    127 /**
    128  * @brief User level code pointing device initialisation
    129  *
    130  */
    131 __attribute__((weak)) void pointing_device_init_user(void) {}
    132 
    133 /**
    134  * @brief Weak function allowing for keyboard level mouse report modification
    135  *
    136  * Takes report_mouse_t struct allowing modification at keyboard level then returns report_mouse_t.
    137  *
    138  * @param[in] mouse_report report_mouse_t
    139  * @return report_mouse_t
    140  */
    141 __attribute__((weak)) report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
    142     return pointing_device_task_user(mouse_report);
    143 }
    144 
    145 /**
    146  * @brief Weak function allowing for user level mouse report modification
    147  *
    148  * Takes report_mouse_t struct allowing modification at user level then returns report_mouse_t.
    149  *
    150  * @param[in] mouse_report report_mouse_t
    151  * @return report_mouse_t
    152  */
    153 __attribute__((weak)) report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
    154     return mouse_report;
    155 }
    156 
    157 /**
    158  * @brief Handles pointing device buttons
    159  *
    160  * Returns modified button bitmask using bool pressed and selected pointing_device_buttons_t button in uint8_t buttons bitmask.
    161  *
    162  * @param buttons[in] uint8_t bitmask
    163  * @param pressed[in] bool
    164  * @param button[in] pointing_device_buttons_t value
    165  * @return Modified uint8_t bitmask buttons
    166  */
    167 __attribute__((weak)) uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) {
    168     if (pressed) {
    169         buttons |= 1 << (button);
    170     } else {
    171         buttons &= ~(1 << (button));
    172     }
    173     return buttons;
    174 }
    175 
    176 /**
    177  * @brief Initialises pointing device
    178  *
    179  * Initialises pointing device, perform driver init and optional keyboard/user level code.
    180  */
    181 __attribute__((weak)) void pointing_device_init(void) {
    182 #if defined(SPLIT_POINTING_ENABLE)
    183     if ((POINTING_DEVICE_THIS_SIDE))
    184 #endif
    185     {
    186         if (pointing_device_driver->init()) {
    187             pointing_device_status = POINTING_DEVICE_STATUS_SUCCESS;
    188         } else {
    189             pointing_device_status = POINTING_DEVICE_STATUS_INIT_FAILED;
    190         }
    191 #ifdef POINTING_DEVICE_MOTION_PIN
    192 #    ifdef POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW
    193         gpio_set_pin_input_high(POINTING_DEVICE_MOTION_PIN);
    194 #    else
    195         gpio_set_pin_input(POINTING_DEVICE_MOTION_PIN);
    196 #    endif
    197 #endif
    198     }
    199 #ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
    200     hires_scroll_resolution = POINTING_DEVICE_HIRES_SCROLL_MULTIPLIER;
    201     for (int i = 0; i < POINTING_DEVICE_HIRES_SCROLL_EXPONENT; i++) {
    202         hires_scroll_resolution *= 10;
    203     }
    204 #endif
    205 
    206     pointing_device_init_modules();
    207     pointing_device_init_kb();
    208     pointing_device_init_user();
    209 }
    210 
    211 /**
    212  * @brief Gets status of pointing device
    213  *
    214  * Returns current pointing device status
    215  * @return pointing_device_status_t
    216  */
    217 __attribute__((weak)) pointing_device_status_t pointing_device_get_status(void) {
    218 #ifdef SPLIT_POINTING_ENABLE
    219     // Assume target side is always good, split transaction checksum should stop additional reports being generated.
    220     return POINTING_DEVICE_THIS_SIDE ? pointing_device_status : POINTING_DEVICE_STATUS_SUCCESS;
    221 #else
    222     return pointing_device_status;
    223 #endif
    224 }
    225 
    226 /**
    227  * @brief Sets status of pointing device
    228  */
    229 void pointing_device_set_status(pointing_device_status_t status) {
    230     pointing_device_status = status;
    231 }
    232 
    233 /**
    234  * @brief Sends processed mouse report to host
    235  *
    236  * This sends the mouse report generated by pointing_device_task if changed since the last report. Once send zeros mouse report except buttons.
    237  *
    238  */
    239 __attribute__((weak)) bool pointing_device_send(void) {
    240     static report_mouse_t old_report         = {};
    241     bool                  should_send_report = has_mouse_report_changed(&local_mouse_report, &old_report);
    242 
    243     if (should_send_report) {
    244         host_mouse_send(&local_mouse_report);
    245     }
    246     // send it and 0 it out except for buttons, so those stay until they are explicity over-ridden using update_pointing_device
    247     uint8_t buttons = local_mouse_report.buttons;
    248     memset(&local_mouse_report, 0, sizeof(local_mouse_report));
    249     local_mouse_report.buttons = buttons;
    250     memcpy(&old_report, &local_mouse_report, sizeof(local_mouse_report));
    251 
    252     return should_send_report || buttons;
    253 }
    254 
    255 /**
    256  * @brief Adjust mouse report by any optional common pointing configuration defines
    257  *
    258  * This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines.
    259  *
    260  * @param mouse_report[in] takes a report_mouse_t to be adjusted
    261  * @return report_mouse_t with adjusted values
    262  */
    263 report_mouse_t pointing_device_adjust_by_defines(report_mouse_t mouse_report) {
    264     // Support rotation of the sensor data
    265 #if defined(POINTING_DEVICE_ROTATION_90) || defined(POINTING_DEVICE_ROTATION_180) || defined(POINTING_DEVICE_ROTATION_270)
    266     mouse_xy_report_t x = mouse_report.x;
    267     mouse_xy_report_t y = mouse_report.y;
    268 #    if defined(POINTING_DEVICE_ROTATION_90)
    269     mouse_report.x = y;
    270     mouse_report.y = -x;
    271 #    elif defined(POINTING_DEVICE_ROTATION_180)
    272     mouse_report.x = -x;
    273     mouse_report.y = -y;
    274 #    elif defined(POINTING_DEVICE_ROTATION_270)
    275     mouse_report.x = -y;
    276     mouse_report.y = x;
    277 #    else
    278 #        error "How the heck did you get here?!"
    279 #    endif
    280 #endif
    281     // Support Inverting the X and Y Axises
    282 #if defined(POINTING_DEVICE_INVERT_X)
    283     mouse_report.x = -mouse_report.x;
    284 #endif
    285 #if defined(POINTING_DEVICE_INVERT_Y)
    286     mouse_report.y = -mouse_report.y;
    287 #endif
    288     return mouse_report;
    289 }
    290 
    291 /**
    292  * @brief Retrieves and processes pointing device data.
    293  *
    294  * This function is part of the keyboard loop and retrieves the mouse report from the pointing device driver.
    295  * It applies any optional configuration e.g. rotation or axis inversion and then initiates a send.
    296  *
    297  */
    298 __attribute__((weak)) bool pointing_device_task(void) {
    299 #if defined(SPLIT_POINTING_ENABLE)
    300     // Don't poll the target side pointing device.
    301     if (!is_keyboard_master()) {
    302         return false;
    303     };
    304 #endif
    305 
    306 #if (POINTING_DEVICE_TASK_THROTTLE_MS > 0)
    307     static uint32_t last_exec = 0;
    308     if (timer_elapsed32(last_exec) < POINTING_DEVICE_TASK_THROTTLE_MS) {
    309         return false;
    310     }
    311     last_exec = timer_read32();
    312 #endif
    313 
    314     if (pointing_device_get_status() != POINTING_DEVICE_STATUS_SUCCESS) {
    315         return false;
    316     }
    317 
    318     // Gather report info
    319 #ifdef POINTING_DEVICE_MOTION_PIN
    320 #    if defined(SPLIT_POINTING_ENABLE)
    321 #        error POINTING_DEVICE_MOTION_PIN not supported when sharing the pointing device report between sides.
    322 #    endif
    323 #    ifdef POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW
    324     if (!gpio_read_pin(POINTING_DEVICE_MOTION_PIN))
    325 #    else
    326     if (gpio_read_pin(POINTING_DEVICE_MOTION_PIN))
    327 #    endif
    328     {
    329 #endif
    330 
    331 #if defined(SPLIT_POINTING_ENABLE)
    332 #    if defined(POINTING_DEVICE_COMBINED)
    333         static uint8_t old_buttons = 0;
    334         local_mouse_report.buttons = old_buttons;
    335         local_mouse_report         = pointing_device_driver->get_report(local_mouse_report);
    336         old_buttons                = local_mouse_report.buttons;
    337 #    elif defined(POINTING_DEVICE_LEFT) || defined(POINTING_DEVICE_RIGHT)
    338         local_mouse_report = POINTING_DEVICE_THIS_SIDE ? pointing_device_driver->get_report(local_mouse_report) : shared_mouse_report;
    339 #    else
    340 #        error "You need to define the side(s) the pointing device is on. POINTING_DEVICE_COMBINED / POINTING_DEVICE_LEFT / POINTING_DEVICE_RIGHT"
    341 #    endif
    342 #else
    343     local_mouse_report = pointing_device_driver->get_report(local_mouse_report);
    344 #endif // defined(SPLIT_POINTING_ENABLE)
    345 
    346 #ifdef POINTING_DEVICE_MOTION_PIN
    347     }
    348 #endif
    349 
    350     // allow kb to intercept and modify report
    351 #if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED)
    352     if (is_keyboard_left()) {
    353         local_mouse_report  = pointing_device_adjust_by_defines(local_mouse_report);
    354         shared_mouse_report = pointing_device_adjust_by_defines_right(shared_mouse_report);
    355     } else {
    356         local_mouse_report  = pointing_device_adjust_by_defines_right(local_mouse_report);
    357         shared_mouse_report = pointing_device_adjust_by_defines(shared_mouse_report);
    358     }
    359     local_mouse_report = is_keyboard_left() ? pointing_device_task_combined_kb(local_mouse_report, shared_mouse_report) : pointing_device_task_combined_kb(shared_mouse_report, local_mouse_report);
    360 #else
    361     local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report);
    362 #endif
    363     local_mouse_report = pointing_device_task_modules(local_mouse_report);
    364     local_mouse_report = pointing_device_task_kb(local_mouse_report);
    365     // automatic mouse layer function
    366 #ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE
    367     pointing_device_task_auto_mouse(local_mouse_report);
    368 #endif
    369     // combine with mouse report to ensure that the combined is sent correctly
    370 #ifdef MOUSEKEY_ENABLE
    371     report_mouse_t mousekey_report = mousekey_get_report();
    372     local_mouse_report.buttons     = local_mouse_report.buttons | mousekey_report.buttons;
    373 #endif
    374 
    375     const bool send_report     = pointing_device_send() || pointing_device_force_send;
    376     pointing_device_force_send = false;
    377 
    378     return send_report;
    379 }
    380 
    381 /**
    382  * @brief Gets current mouse report used by pointing device task
    383  *
    384  * @return report_mouse_t
    385  */
    386 report_mouse_t pointing_device_get_report(void) {
    387     return local_mouse_report;
    388 }
    389 
    390 /**
    391  * @brief Sets mouse report used be pointing device task
    392  *
    393  * @param[in] mouse_report
    394  */
    395 void pointing_device_set_report(report_mouse_t mouse_report) {
    396     pointing_device_force_send = has_mouse_report_changed(&local_mouse_report, &mouse_report);
    397     memcpy(&local_mouse_report, &mouse_report, sizeof(local_mouse_report));
    398 }
    399 
    400 /**
    401  * @brief Gets current pointing device CPI if supported
    402  *
    403  * Gets current cpi from pointing device driver if supported and returns it as uint16_t
    404  *
    405  * @return cpi value as uint16_t
    406  */
    407 uint16_t pointing_device_get_cpi(void) {
    408 #if defined(SPLIT_POINTING_ENABLE)
    409     return POINTING_DEVICE_THIS_SIDE ? pointing_device_driver->get_cpi() : shared_cpi;
    410 #else
    411     return pointing_device_driver->get_cpi();
    412 #endif
    413 }
    414 
    415 /**
    416  * @brief Set pointing device CPI if supported
    417  *
    418  * Takes a uint16_t value to set pointing device cpi if supported by driver.
    419  *
    420  * @param[in] cpi uint16_t value.
    421  */
    422 void pointing_device_set_cpi(uint16_t cpi) {
    423 #if defined(SPLIT_POINTING_ENABLE)
    424     if (POINTING_DEVICE_THIS_SIDE) {
    425         pointing_device_driver->set_cpi(cpi);
    426     } else {
    427         shared_cpi = cpi;
    428     }
    429 #else
    430     pointing_device_driver->set_cpi(cpi);
    431 #endif
    432 }
    433 
    434 #if defined(SPLIT_POINTING_ENABLE) && defined(POINTING_DEVICE_COMBINED)
    435 /**
    436  * @brief Set pointing device CPI if supported
    437  *
    438  * Takes a bool and uint16_t and allows setting cpi for a single side when using 2 pointing devices with a split keyboard.
    439  *
    440  * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
    441  *
    442  * @param[in] left true = left, false = right.
    443  * @param[in] cpi uint16_t value.
    444  */
    445 void pointing_device_set_cpi_on_side(bool left, uint16_t cpi) {
    446     bool local = (is_keyboard_left() == left);
    447     if (local) {
    448         pointing_device_driver->set_cpi(cpi);
    449     } else {
    450         shared_cpi = cpi;
    451     }
    452 }
    453 
    454 /**
    455  * @brief clamps int16_t to int8_t, or int32_t to int16_t
    456  *
    457  * @param[in] hv_clamp_range_t value
    458  * @return mouse_hv_report_t clamped value
    459  */
    460 static inline mouse_hv_report_t pointing_device_hv_clamp(hv_clamp_range_t value) {
    461     if (value < MOUSE_REPORT_HV_MIN) {
    462         return MOUSE_REPORT_HV_MIN;
    463     } else if (value > MOUSE_REPORT_HV_MAX) {
    464         return MOUSE_REPORT_HV_MAX;
    465     } else {
    466         return value;
    467     }
    468 }
    469 
    470 /**
    471  * @brief clamps int16_t to int8_t, or int32_t to int16_t
    472  *
    473  * @param[in] xy_clamp_range_t value
    474  * @return mouse_xy_report_t clamped value
    475  */
    476 static inline mouse_xy_report_t pointing_device_xy_clamp(xy_clamp_range_t value) {
    477     if (value < MOUSE_REPORT_XY_MIN) {
    478         return MOUSE_REPORT_XY_MIN;
    479     } else if (value > MOUSE_REPORT_XY_MAX) {
    480         return MOUSE_REPORT_XY_MAX;
    481     } else {
    482         return value;
    483     }
    484 }
    485 /**
    486  * @brief combines 2 mouse reports and returns 2
    487  *
    488  * Combines 2 report_mouse_t structs, clamping movement values to int8_t and ignores report_id then returns the resulting report_mouse_t struct.
    489  *
    490  * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
    491  *
    492  * @param[in] left_report left report_mouse_t
    493  * @param[in] right_report right report_mouse_t
    494  * @return combined report_mouse_t of left_report and right_report
    495  */
    496 report_mouse_t pointing_device_combine_reports(report_mouse_t left_report, report_mouse_t right_report) {
    497     left_report.x = pointing_device_xy_clamp((xy_clamp_range_t)left_report.x + right_report.x);
    498     left_report.y = pointing_device_xy_clamp((xy_clamp_range_t)left_report.y + right_report.y);
    499     left_report.h = pointing_device_hv_clamp((hv_clamp_range_t)left_report.h + right_report.h);
    500     left_report.v = pointing_device_hv_clamp((hv_clamp_range_t)left_report.v + right_report.v);
    501     left_report.buttons |= right_report.buttons;
    502     return left_report;
    503 }
    504 
    505 /**
    506  * @brief Adjust mouse report by any optional right pointing configuration defines
    507  *
    508  * This applies rotation or inversion to the mouse report as selected by the pointing device common configuration defines.
    509  *
    510  * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
    511  *
    512  * @param[in] mouse_report report_mouse_t to be adjusted
    513  * @return report_mouse_t with adjusted values
    514  */
    515 report_mouse_t pointing_device_adjust_by_defines_right(report_mouse_t mouse_report) {
    516     // Support rotation of the sensor data
    517 #    if defined(POINTING_DEVICE_ROTATION_90_RIGHT) || defined(POINTING_DEVICE_ROTATION_180_RIGHT) || defined(POINTING_DEVICE_ROTATION_270_RIGHT)
    518     mouse_xy_report_t x = mouse_report.x;
    519     mouse_xy_report_t y = mouse_report.y;
    520 #        if defined(POINTING_DEVICE_ROTATION_90_RIGHT)
    521     mouse_report.x = y;
    522     mouse_report.y = -x;
    523 #        elif defined(POINTING_DEVICE_ROTATION_180_RIGHT)
    524     mouse_report.x = -x;
    525     mouse_report.y = -y;
    526 #        elif defined(POINTING_DEVICE_ROTATION_270_RIGHT)
    527     mouse_report.x = -y;
    528     mouse_report.y = x;
    529 #        else
    530 #            error "How the heck did you get here?!"
    531 #        endif
    532 #    endif
    533     // Support Inverting the X and Y Axises
    534 #    if defined(POINTING_DEVICE_INVERT_X_RIGHT)
    535     mouse_report.x = -mouse_report.x;
    536 #    endif
    537 #    if defined(POINTING_DEVICE_INVERT_Y_RIGHT)
    538     mouse_report.y = -mouse_report.y;
    539 #    endif
    540     return mouse_report;
    541 }
    542 
    543 /**
    544  * @brief Weak function allowing for keyboard level mouse report modification
    545  *
    546  * Takes 2 report_mouse_t structs allowing individual modification of sides at keyboard level then returns pointing_device_task_combined_user.
    547  *
    548  * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
    549  *
    550  * @param[in] left_report report_mouse_t
    551  * @param[in] right_report report_mouse_t
    552  * @return pointing_device_task_combined_user(left_report, right_report) by default
    553  */
    554 __attribute__((weak)) report_mouse_t pointing_device_task_combined_kb(report_mouse_t left_report, report_mouse_t right_report) {
    555     return pointing_device_task_combined_user(left_report, right_report);
    556 }
    557 
    558 /**
    559  * @brief Weak function allowing for user level mouse report modification
    560  *
    561  * Takes 2 report_mouse_t structs allowing individual modification of sides at user level then returns pointing_device_combine_reports.
    562  *
    563  * NOTE: Only available when using SPLIT_POINTING_ENABLE and POINTING_DEVICE_COMBINED
    564  *
    565  * @param[in] left_report report_mouse_t
    566  * @param[in] right_report report_mouse_t
    567  * @return pointing_device_combine_reports(left_report, right_report) by default
    568  */
    569 __attribute__((weak)) report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) {
    570     return pointing_device_combine_reports(left_report, right_report);
    571 }
    572 #endif
    573 
    574 __attribute__((weak)) void pointing_device_keycode_handler(uint16_t keycode, bool pressed) {
    575     if IS_MOUSEKEY_BUTTON (keycode) {
    576         local_mouse_report.buttons = pointing_device_handle_buttons(local_mouse_report.buttons, pressed, keycode - QK_MOUSE_BUTTON_1);
    577         pointing_device_send();
    578     }
    579 }
    580 
    581 #ifdef POINTING_DEVICE_HIRES_SCROLL_ENABLE
    582 uint16_t pointing_device_get_hires_scroll_resolution(void) {
    583     return hires_scroll_resolution;
    584 }
    585 #endif