lvgl / lv_drivers

TFT and touch pad drivers for LVGL embedded GUI library
https://docs.lvgl.io/master/porting/index.html
MIT License
306 stars 314 forks source link

Make it possible to use multiple devices with the libinput and XKB drivers #165

Closed Johennes closed 3 years ago

Johennes commented 3 years ago

This change bundles all of the previously file-global device-specific state in libinput.c and xkb.c into new driver state structs with a default value. All of the existing public functions are retained and operate on the default struct values. To allow the use of multiple devices, a second set of public functions is introduced that also take the specific driver state as an argument. It is left up to the caller where to store the driver state and how to retrieve it when reading input events.

The diff makes this look like a huge change but almost all of it just moves existing code around or renames variables.

Here is an example of how to use the new functions to connect multiple keyboards:

void libinput_read_cb(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) {
    libinput_read_state(indev_drv->user_data, indev_drv, data); // <== Retrieve driver state from user data
}

int main(void)
{
    ...

    // Connect keyboards
    #define MAX_KEYBOARDS 4
    char *keyboard_devices[MAX_KEYBOARDS] = { NULL, NULL, NULL, NULL  };
    lv_indev_t *keyboard_indevs[MAX_KEYBOARDS] = { NULL, NULL, NULL, NULL };

    lv_indev_drv_t keyboard_indev_drvs[MAX_KEYBOARDS];
    memset(keyboard_indev_drvs, 0, MAX_KEYBOARDS * sizeof(lv_indev_drv_t));

    libinput_drv_state keyboard_drv_states[MAX_KEYBOARDS];
    memset(keyboard_drv_states, 0, MAX_KEYBOARDS * sizeof(libinput_drv_state));

    size_t num_keyboards = libinput_find_devs(LIBINPUT_CAPABILITY_KEYBOARD, keyboard_devices, MAX_KEYBOARDS, false);

    for (int i = 0; i < num_keyboards; ++i) {
        printf("found keyboard device %s\n", keyboard_devices[i]);
        libinput_init_state(&keyboard_drv_states[i], keyboard_devices[i]);
        lv_indev_drv_init(&keyboard_indev_drvs[i]);
        keyboard_indev_drvs[i].type = LV_INDEV_TYPE_KEYPAD;
        keyboard_indev_drvs[i].read_cb = libinput_read_cb; // <== Use custom read callback
        keyboard_indev_drvs[i].user_data = &keyboard_drv_states[i]; // <== Store driver state in user data
        keyboard_indevs[i] = lv_indev_drv_register(&keyboard_indev_drvs[i]);
    }

    ...
}

I'm hoping that this is a good compromise. The existing API interface is retained and merely extended with a second set of functions that perform the same operations but on a specific driver state. No assumptions are being made about where the driver state is stored and the overhead on the calling site to store and retrieve the state is minimal.

Closes: #151

kisvegabor commented 3 years ago

We are thinking about designed generic drivers that includes low level embedded drivers (SPI, I2C displays and touch panels) and desktop libs (libinput, SDL, fbdev, etc) too.

Your updates on the current drivers add a very meaningful hint about what the capabilities the new driver architecture should have. So keep it up! :+1:

What I've learned so far:

Johennes commented 3 years ago

We are thinking about designed generic drivers that includes low level embedded drivers (SPI, I2C displays and touch panels) and desktop libs (libinput, SDL, fbdev, etc) too.

Your updates on the current drivers add a very meaningful hint about what the capabilities the new driver architecture should have. So keep it up! +1

Oh nice! Happy to hear I'm helping and not just stealing your time. :slightly_smiling_face:

kisvegabor commented 3 years ago

not just stealing your time.

Definitely not. :slightly_smiling_face:

Merging, thank you!