zmk/app/include/zmk/display.h
Joel Spadin 92e95d44cf feat(ble): Add passkey display/confirm support
Added support for passkey display and passkey confirmation when
pairing. Passkey display is enabled automatically when a display is
enabled. Passkey confirm can be manually enabled if the keyboard has an
Enter key.

Updated the passkey entry code to require all 6 digits have been entered
before confirming and to support backspace to remove a digit.

Added a pairing screen for displays and refactored the display code to
allow for switching between multiple screens. The screens are now
initialized immediately instead of on the display work queue, because
widgets will read state from other files when they are initialized, and
this can only be done safely from the system queue. Blank on idle and
theme initialization are pulled out to separate files to simplify the
main file.

The pairing screen supports all three passkey modes:

- Passkey display just shows the passkey.

- Passkey confirm shows the passkey and an icon indicating that you
  must press Enter to confirm.

- Passkey entry shows the current passkey entry state and shows an icon
  indicating that you must press Enter to confirm once all 6 digits
  have been entered. (If passkey display or confirm are supported, it
  seems that Windows will always choose those over passkey entry, but
  the pairing screen still supports this in case other OSes work
  differently.)

Added configs for normal and large font sizes. The large font is used
for the passkey on the pairing screen on larger displays.
CONFIG_LV_FONT_DEFAULT is no longer used for the normal font size,
because setting a default value for it in display/Kconfig prevented
display shields from picking a more appropriate default.
2023-11-05 18:34:25 -06:00

66 lines
3.9 KiB
C

/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
/** @file display.h
* @brief Display functions and macros.
*/
#pragma once
#include <stdbool.h>
#include <zephyr/kernel.h>
struct k_work_q *zmk_display_work_q(void);
bool zmk_display_is_initialized(void);
int zmk_display_init(void);
void zmk_display_blanking_on(void);
void zmk_display_blanking_off(void);
/**
* @brief Macro to define a ZMK event listener that handles the thread safety of fetching
* the necessary state from the system work queue context, invoking a work callback
* in the display queue context, and properly accessing that state safely when performing
* display/LVGL updates.
*
* @param listener THe ZMK Event manager listener name.
* @param state_type The struct/enum type used to store/transfer state.
* @param cb The callback to invoke in the dispaly queue context to update the UI. Should be `void
* func(state_type)` signature.
* @param state_func The callback function to invoke to fetch the updated state from ZMK core.
* Should be `state type func(const zmk_event_t *eh)` signature.
* @retval listner##_init Generates a function `listener##_init` that should be called by the widget
* once ready to be updated.
**/
#define ZMK_DISPLAY_WIDGET_LISTENER(listener, state_type, cb, state_func) \
K_MUTEX_DEFINE(listener##_mutex); \
static state_type __##listener##_state; \
static state_type listener##_get_local_state() { \
k_mutex_lock(&listener##_mutex, K_FOREVER); \
state_type copy = __##listener##_state; \
k_mutex_unlock(&listener##_mutex); \
return copy; \
}; \
static void listener##_work_cb(struct k_work *work) { cb(listener##_get_local_state()); }; \
K_WORK_DEFINE(listener##_work, listener##_work_cb); \
static void listener##_refresh_state(const zmk_event_t *eh) { \
k_mutex_lock(&listener##_mutex, K_FOREVER); \
__##listener##_state = state_func(eh); \
k_mutex_unlock(&listener##_mutex); \
}; \
static void listener##_init() { \
listener##_refresh_state(NULL); \
listener##_work_cb(NULL); \
} \
static int listener##_cb(const zmk_event_t *eh) { \
if (zmk_display_is_initialized()) { \
listener##_refresh_state(eh); \
k_work_submit_to_queue(zmk_display_work_q(), &listener##_work); \
} \
return ZMK_EV_EVENT_BUBBLE; \
} \
ZMK_LISTENER(listener, listener##_cb);