how to implement mouse click in nrf desktop

Hello,

I am looking at nrf desktop sample in ncs 2.4.2. I am using nrf52840dk and relevant files. My goal is to make composite usb/bt device mouse and keyboard work.

I see in src/hw_interface there is

-buttons_sim.c, which shows how to do keyboard keypresses.

-motion_buttons.c, which simulates mouse movement using buttons

1. Are my interpretations of these files correct?

2. Is there an example implementation where a mouse click is shown?

If not, could you give a small example for how to do this? The example I'm looking for should be end in APP_EVENT_SUBMIT()

An explanatory explanation of how to do it could also suffice.

Eg. for mouse movement, it is very simple

void mouse_movement_send(int8_t x, int8_t y)
{
    struct motion_event *event = new_motion_event();
    event->dx = x;
    event->dy = y;
    APP_EVENT_SUBMIT(event);
}

Thank you!
Parents Reply
  • Hi Kenneth,

    I tried to search new_button_event before making my original post. As far as I can tell button module is only used for Keyboard input. The example you gave is also for keyboard input.

    I'm only interested in mouse click here, keyboard input and mouse movement are already functional.

    Is it possible that it is not implemented? I could not find it, hence my post.

    If it is not implemented, it would be good to add for completeness.

    Thank you.

Children
  • Looks like the buttons are added when the mouse hid report is sent, ref send_report_mouse()/send_report_boot_mouse() in hid_state.c

    send_report_mouse()
        event->dyndata.data[0] = rs->report_id;
        event->dyndata.data[1] = button_bm;
        event->dyndata.data[2] = wheel;
        event->dyndata.data[3] = x_buff[0];
        event->dyndata.data[4] = (y_buff[0] << 4) | (x_buff[1] & 0x0f);
        event->dyndata.data[5] = (y_buff[1] << 4) | (y_buff[0] >> 4);

    send_report_boot_mouse()
        event->dyndata.data[0] = rs->report_id;
        event->dyndata.data[1] = button_bm;
        event->dyndata.data[2] = dx;
        event->dyndata.data[3] = dy;

    Edit: Looks like it, since all events are handled by APP_EVENT_LISTENER(MODULE, app_event_handler);

    Kenneth

  • Cool, I'm following.

    From just earlier in the same file, the creation of the button bitmask:

        /* Traverse pressed keys and build mouse buttons bitmask */
        uint8_t button_bm = 0;
        for (size_t i = 0; i < ARRAY_SIZE(rd->items.item); i++) {
            struct item item = rd->items.item[i];

            if (item.usage_id) {
                __ASSERT_NO_MSG(item.usage_id <= 8);
                __ASSERT_NO_MSG(item.value > 0);

                uint8_t mask = 1 << (item.usage_id - 1);

                button_bm |= mask;
            }
        }
    Which bit is left, right, middle mouse?

    Zooming out one level to the main handlers in app_event_handler: handle_motion_event(), handle_wheel_event(), handle_keyboard_event(). The contents of these functions clearly show what is being updated, and a mouse click action (appending a struct item) never occurs.

    While I agree that the driver handles mouse clicks on a lower level, the application does not have a way to transmit mouse clicks to its own driver. 

    If that's the case, I'm thinkin I'll update or create an event type to include mouse clicks.

    Thank you!

  • Okay, I shall answer my own question. The reason this is hard is because I'm trying to make a mouse and keyboard work at the same time.

    Critical definitions change for different build configurations. I was working in nrf52840dk_nrf52840 configuration, which uses hid_keymap_def_keyboard.h and omits the essential definitions (keymaps) required for mouse clicking. The definitions are found in hid_keymap_def.h from nrf52840mouse_nrf52840 or similar gmouse build.

    These keymaps have the same structure as the keyboard keymap, but very different contents. As far as I can tell, only one can be active at a time.

    To make both keymaps work, I will try editing the button_event to have an enum which tells the button handler which keymap to use. 

  • It's working.

    I ended up adding more items to the hid_keymap in hid_keymap_def_keyboard.h.

    A critical piece is a different first index in KEY_ID to allow it to coexist with the keyboard definitions.

        //Other keyboard definitions above...
        { KEY_ID(0x00, 0x1B), 0x001B, REPORT_ID_KEYBOARD_KEYS }, /* X */
        { KEY_ID(0x00, 0x1C), 0x001C, REPORT_ID_KEYBOARD_KEYS }, /* Y */
        { KEY_ID(0x00, 0x1D), 0x001D, REPORT_ID_KEYBOARD_KEYS }, /* Z */
    
    //New mouse definitions. Note new major index
        { KEY_ID(0x01, 0x00), 0x01, REPORT_ID_MOUSE }, /* Left Mouse Button */
        { KEY_ID(0x01, 0x01), 0x02, REPORT_ID_MOUSE }, /* Right Mouse Button */
        { KEY_ID(0x01, 0x02), 0x03, REPORT_ID_MOUSE }, /* Middle Mouse Button */
    
    You need to redefine the KEY_IDs in a place that's visible or accessible to the sender. There's definitely a cleaner way to do this, I'm just happy it's working for now.
    const static uint16_t mouse_click_keys[] = {
        KEY_ID(0x01, 0x00), /* LMB */
        KEY_ID(0x01, 0x01), /* RMB */
        KEY_ID(0x01, 0x02), /* MMB */
    };
    My send function:
            struct button_event *event = new_button_event();
            event->key_id = mouse_click_keys[MOUSE_BTN_IDX_LEFT];
            event->pressed = down;
            APP_EVENT_SUBMIT(event);
Related