Ken Van Hoeylandt c729e8340f
Trackball rewrite (#600)
- Implement generic trackball settings
- Refactor T-Deck trackball driver into generic driver at `Drivers/gpio-trackball-module`
- Automatically bind/unbind trackball devices with LVGL
- Automatically load settings for trackball devices on boot
2026-07-30 13:38:19 +02:00

108 lines
4.2 KiB
C

// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <lvgl.h>
#include <tactility/device.h>
#include <tactility/error.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Trackball operating mode.
*/
enum LvglTrackballMode {
/** Navigation via enc_diff (scroll wheel behavior). No cursor is shown. */
LVGL_TRACKBALL_MODE_ENCODER,
/** Mouse cursor via point.x/point.y. A cursor is shown if an image was set via
* lvgl_trackball_set_cursor_image(). */
LVGL_TRACKBALL_MODE_POINTER
};
/**
* @brief Runtime-adjustable trackball behavior. See lvgl_trackball_set_settings()/
* lvgl_trackball_get_settings().
*/
struct LvglTrackballSettings {
enum LvglTrackballMode mode;
/** When false, movement and button presses are drained from the device and discarded:
* the indev reports no movement and stays released. */
bool enabled;
/** Encoder mode: steps per raw trackball tick. Must be >= 1. */
uint8_t encoder_sensitivity;
/** Pointer mode: pixels per raw trackball tick. Must be >= 1. */
uint8_t pointer_sensitivity;
};
/**
* @brief Creates an lv_indev_t bound to the given TRACKBALL_TYPE device and registers a read
* callback that polls the device through its TrackballApi.
*
* The indev starts in LVGL_TRACKBALL_MODE_ENCODER, enabled, with default sensitivities (see
* lvgl_trackball_settings_get_default()). Call lvgl_trackball_set_settings() to change this,
* e.g. to switch to pointer mode - each device added this way can independently run with or
* without pointer support.
*
* @warning Caller must hold the LVGL lock (see lvgl_lock() in lvgl_module.h) — call this from
* LvglModuleConfig.on_start, or after calling lvgl_lock() explicitly.
*
* @param[in] device a device of type TRACKBALL_TYPE
* @param[in] display the display this indev should be associated with, or NULL to leave it unset
* @param[out] out_indev the created indev, valid only when ERROR_NONE is returned
* @retval ERROR_NONE on success
* @retval ERROR_INVALID_ARGUMENT if device or out_indev is NULL, or device is not of type TRACKBALL_TYPE
* @retval ERROR_OUT_OF_MEMORY if allocation failed
*/
error_t lvgl_trackball_add(struct Device* device, lv_display_t* display, lv_indev_t** out_indev);
/**
* @brief Removes an indev previously created with lvgl_trackball_add(), including its cursor
* object (if one was showing).
* @warning Caller must hold the LVGL lock.
*/
void lvgl_trackball_remove(lv_indev_t* indev);
/**
* @return the default (all fields explicitly set) LvglTrackballSettings: encoder mode, enabled,
* encoder_sensitivity 1, pointer_sensitivity 10.
*/
struct LvglTrackballSettings lvgl_trackball_settings_get_default(void);
/**
* @brief Applies settings to an indev previously created with lvgl_trackball_add(). Switching
* `mode` shows/hides the cursor (pointer mode) and re-centers it on the indev's display.
* @warning Caller must hold the LVGL lock.
* @param[in] indev an indev previously created by lvgl_trackball_add()
* @param[in] settings the settings to apply
* @retval ERROR_NONE on success
* @retval ERROR_INVALID_ARGUMENT if indev or settings is NULL, or either sensitivity is 0
*/
error_t lvgl_trackball_set_settings(lv_indev_t* indev, const struct LvglTrackballSettings* settings);
/**
* @brief Retrieves the settings currently active on indev.
* @warning Caller must hold the LVGL lock.
* @return true when indev is a trackball indev (out_settings is filled), false otherwise
*/
bool lvgl_trackball_get_settings(lv_indev_t* indev, struct LvglTrackballSettings* out_settings);
/**
* @brief Sets the image shown as the mouse cursor while indev is in LVGL_TRACKBALL_MODE_POINTER.
* lvgl-module has no bundled cursor asset (it doesn't depend on any particular asset layout), so
* pointer mode has no visible cursor until a caller supplies one here; the indev still moves and
* reports point.x/point.y either way. Pass NULL to remove the cursor.
* @warning Caller must hold the LVGL lock.
* @param[in] indev an indev previously created by lvgl_trackball_add()
* @param[in] image_src an LVGL image source (as accepted by lv_image_set_src()), or NULL
*/
void lvgl_trackball_set_cursor_image(lv_indev_t* indev, const void* image_src);
#ifdef __cplusplus
}
#endif