Merge 442179d7ea
into d7d9eed317
This commit is contained in:
commit
59e9e430dc
26 changed files with 1198 additions and 301 deletions
|
@ -70,6 +70,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||||
target_sources(app PRIVATE src/events/keycode_state_changed.c)
|
target_sources(app PRIVATE src/events/keycode_state_changed.c)
|
||||||
|
|
||||||
if (CONFIG_ZMK_BLE)
|
if (CONFIG_ZMK_BLE)
|
||||||
|
target_sources(app PRIVATE src/events/ble_auth_state_changed.c)
|
||||||
target_sources(app PRIVATE src/events/ble_active_profile_changed.c)
|
target_sources(app PRIVATE src/events/ble_active_profile_changed.c)
|
||||||
target_sources(app PRIVATE src/behaviors/behavior_bt.c)
|
target_sources(app PRIVATE src/behaviors/behavior_bt.c)
|
||||||
target_sources(app PRIVATE src/ble.c)
|
target_sources(app PRIVATE src/ble.c)
|
||||||
|
@ -93,6 +94,6 @@ target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/backlight.c)
|
||||||
target_sources(app PRIVATE src/workqueue.c)
|
target_sources(app PRIVATE src/workqueue.c)
|
||||||
target_sources(app PRIVATE src/main.c)
|
target_sources(app PRIVATE src/main.c)
|
||||||
|
|
||||||
add_subdirectory(src/display/)
|
add_subdirectory_ifdef(CONFIG_ZMK_DISPLAY src/display/)
|
||||||
|
|
||||||
zephyr_cc_option(-Wfatal-errors)
|
zephyr_cc_option(-Wfatal-errors)
|
||||||
|
|
22
app/Kconfig
22
app/Kconfig
|
@ -174,10 +174,30 @@ config BT_GATT_AUTO_SEC_REQ
|
||||||
config BT_DEVICE_APPEARANCE
|
config BT_DEVICE_APPEARANCE
|
||||||
default 961
|
default 961
|
||||||
|
|
||||||
|
config ZMK_BLE_PASSKEY_DISPLAY
|
||||||
|
bool "BLE passkey display"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable keyboard to display a passkey used to complete pairing. The keyboard
|
||||||
|
will display a 6-digit passkey, and the user must enter it on the host.
|
||||||
|
|
||||||
|
config ZMK_BLE_PASSKEY_CONFIRM
|
||||||
|
bool "BLE passkey confirmation"
|
||||||
|
default n
|
||||||
|
select ZMK_BLE_PASSKEY_DISPLAY
|
||||||
|
help
|
||||||
|
Enables a simpler pairing method, where the keyboard and host each display
|
||||||
|
a passkey, and the user must confirm that they match by pressing enter or
|
||||||
|
keypad enter.
|
||||||
|
|
||||||
config ZMK_BLE_PASSKEY_ENTRY
|
config ZMK_BLE_PASSKEY_ENTRY
|
||||||
bool "Require passkey entry on the keyboard to complete pairing"
|
bool "BLE passkey entry"
|
||||||
default n
|
default n
|
||||||
select RING_BUFFER
|
select RING_BUFFER
|
||||||
|
help
|
||||||
|
Require passkey entry on the keyboard to complete pairing. The host will
|
||||||
|
display a 6-digit passkey, and the user must type it using the number or
|
||||||
|
keypad number keys, then press enter or keypad enter.
|
||||||
|
|
||||||
config BT_PERIPHERAL_PREF_MIN_INT
|
config BT_PERIPHERAL_PREF_MIN_INT
|
||||||
default 6
|
default 6
|
||||||
|
|
|
@ -24,6 +24,18 @@ choice ZMK_DISPLAY_STATUS_SCREEN
|
||||||
default ZMK_DISPLAY_STATUS_SCREEN_CUSTOM
|
default ZMK_DISPLAY_STATUS_SCREEN_CUSTOM
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
choice ZMK_LV_FONT_DEFAULT_SMALL
|
||||||
|
default ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_16
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice ZMK_LV_FONT_DEFAULT_NORMAL
|
||||||
|
default ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_22
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice ZMK_LV_FONT_DEFAULT_LARGE
|
||||||
|
default ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_28
|
||||||
|
endchoice
|
||||||
|
|
||||||
config ZMK_DISPLAY_STATUS_SCREEN_CUSTOM
|
config ZMK_DISPLAY_STATUS_SCREEN_CUSTOM
|
||||||
imply NICE_VIEW_WIDGET_STATUS
|
imply NICE_VIEW_WIDGET_STATUS
|
||||||
|
|
||||||
|
@ -46,7 +58,4 @@ config NICE_VIEW_WIDGET_STATUS
|
||||||
|
|
||||||
endif # !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL
|
endif # !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL
|
||||||
|
|
||||||
config ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN
|
|
||||||
select LV_FONT_MONTSERRAT_26
|
|
||||||
|
|
||||||
endif # SHIELD_NICE_VIEW
|
endif # SHIELD_NICE_VIEW
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <zmk/keys.h>
|
#include <zmk/keys.h>
|
||||||
|
#include <zmk/ble/auth.h>
|
||||||
#include <zmk/ble/profile.h>
|
#include <zmk/ble/profile.h>
|
||||||
|
|
||||||
#define ZMK_BLE_IS_CENTRAL \
|
#define ZMK_BLE_IS_CENTRAL \
|
||||||
|
@ -20,18 +21,18 @@
|
||||||
#define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED
|
#define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int zmk_ble_clear_bonds();
|
int zmk_ble_clear_bonds(void);
|
||||||
int zmk_ble_prof_next();
|
int zmk_ble_prof_next(void);
|
||||||
int zmk_ble_prof_prev();
|
int zmk_ble_prof_prev(void);
|
||||||
int zmk_ble_prof_select(uint8_t index);
|
int zmk_ble_prof_select(uint8_t index);
|
||||||
|
|
||||||
int zmk_ble_active_profile_index();
|
int zmk_ble_active_profile_index(void);
|
||||||
bt_addr_le_t *zmk_ble_active_profile_addr();
|
bt_addr_le_t *zmk_ble_active_profile_addr(void);
|
||||||
bool zmk_ble_active_profile_is_open();
|
bool zmk_ble_active_profile_is_open(void);
|
||||||
bool zmk_ble_active_profile_is_connected();
|
bool zmk_ble_active_profile_is_connected(void);
|
||||||
char *zmk_ble_active_profile_name();
|
char *zmk_ble_active_profile_name(void);
|
||||||
|
|
||||||
int zmk_ble_unpair_all();
|
struct zmk_ble_auth_state zmk_ble_get_auth_state(void);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||||
int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr);
|
int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr);
|
||||||
|
|
32
app/include/zmk/ble/auth.h
Normal file
32
app/include/zmk/ble/auth.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum zmk_ble_auth_mode {
|
||||||
|
// Not authenticating
|
||||||
|
ZMK_BLE_AUTH_MODE_NONE,
|
||||||
|
// User must confirm keyboard and host are displaying the same passkey.
|
||||||
|
ZMK_BLE_AUTH_MODE_PASSKEY_CONFIRM,
|
||||||
|
// Keyboard is dispaying a passkey, and user must enter it on the host.
|
||||||
|
ZMK_BLE_AUTH_MODE_PASSKEY_DISPLAY,
|
||||||
|
// Host is displaying a passkey, and user must enter it on the keyboard.
|
||||||
|
ZMK_BLE_AUTH_MODE_PASSKEY_ENTRY,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct zmk_ble_auth_state {
|
||||||
|
enum zmk_ble_auth_mode mode;
|
||||||
|
// Index of the profile being authenticated.
|
||||||
|
uint8_t profile_index;
|
||||||
|
// In passkey entry mode, the index of the next digit to enter.
|
||||||
|
uint8_t cursor_index;
|
||||||
|
// The current passkey. The value will be in the range 0 - 999999 and should
|
||||||
|
// be padded with zeros so that six digits are always shown. E.g. the value
|
||||||
|
// 37 should be shown as 000037.
|
||||||
|
unsigned int passkey;
|
||||||
|
};
|
|
@ -10,10 +10,16 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
struct k_work_q *zmk_display_work_q();
|
#include <stdbool.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
bool zmk_display_is_initialized();
|
struct k_work_q *zmk_display_work_q(void);
|
||||||
int zmk_display_init();
|
|
||||||
|
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
|
* @brief Macro to define a ZMK event listener that handles the thread safety of fetching
|
||||||
|
|
11
app/include/zmk/display/pairing_screen.h
Normal file
11
app/include/zmk/display/pairing_screen.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <lvgl.h>
|
||||||
|
|
||||||
|
lv_obj_t *zmk_display_pairing_screen(void);
|
|
@ -8,4 +8,4 @@
|
||||||
|
|
||||||
#include <lvgl.h>
|
#include <lvgl.h>
|
||||||
|
|
||||||
lv_obj_t *zmk_display_status_screen();
|
lv_obj_t *zmk_display_status_screen(void);
|
21
app/include/zmk/display/widgets/ble_passkey.h
Normal file
21
app/include/zmk/display/widgets/ble_passkey.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <lvgl.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
|
struct zmk_widget_ble_passkey {
|
||||||
|
sys_snode_t node;
|
||||||
|
lv_obj_t *obj;
|
||||||
|
lv_obj_t *profile;
|
||||||
|
lv_obj_t *title;
|
||||||
|
lv_obj_t *passkey;
|
||||||
|
};
|
||||||
|
|
||||||
|
int zmk_widget_ble_passkey_init(struct zmk_widget_ble_passkey *widget, lv_obj_t *parent);
|
||||||
|
lv_obj_t *zmk_widget_ble_passkey_obj(struct zmk_widget_ble_passkey *widget);
|
16
app/include/zmk/events/ble_auth_state_changed.h
Normal file
16
app/include/zmk/events/ble_auth_state_changed.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <zmk/event_manager.h>
|
||||||
|
#include <zmk/ble/auth.h>
|
||||||
|
|
||||||
|
struct zmk_ble_auth_state_changed {
|
||||||
|
struct zmk_ble_auth_state state;
|
||||||
|
};
|
||||||
|
|
||||||
|
ZMK_EVENT_DECLARE(zmk_ble_auth_state_changed);
|
438
app/src/ble.c
438
app/src/ble.c
|
@ -36,17 +36,27 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
#include <zmk/split/bluetooth/uuid.h>
|
#include <zmk/split/bluetooth/uuid.h>
|
||||||
#include <zmk/event_manager.h>
|
#include <zmk/event_manager.h>
|
||||||
#include <zmk/events/ble_active_profile_changed.h>
|
#include <zmk/events/ble_active_profile_changed.h>
|
||||||
|
#include <zmk/events/ble_auth_state_changed.h>
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) || IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
#include <zmk/events/keycode_state_changed.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||||
#include <zmk/events/keycode_state_changed.h>
|
|
||||||
|
|
||||||
#define PASSKEY_DIGITS 6
|
#define PASSKEY_DIGITS 6
|
||||||
|
|
||||||
static struct bt_conn *auth_passkey_entry_conn;
|
static struct bt_conn *auth_passkey_entry_conn;
|
||||||
RING_BUF_DECLARE(passkey_entries, PASSKEY_DIGITS);
|
RING_BUF_DECLARE(passkey_entries, PASSKEY_DIGITS);
|
||||||
|
|
||||||
#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */
|
#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_DISPLAY)
|
||||||
|
static bool is_displaying_passkey = false;
|
||||||
|
static unsigned int current_passkey = 0;
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
static struct bt_conn *auth_passkey_confirm_conn;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
enum advertising_type {
|
enum advertising_type {
|
||||||
ZMK_ADV_NONE,
|
ZMK_ADV_NONE,
|
||||||
ZMK_ADV_DIR,
|
ZMK_ADV_DIR,
|
||||||
|
@ -82,7 +92,19 @@ static bt_addr_le_t peripheral_addrs[ZMK_SPLIT_BLE_PERIPHERAL_COUNT];
|
||||||
|
|
||||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
||||||
|
|
||||||
static void raise_profile_changed_event() {
|
static void raise_auth_state_changed_event(void) {
|
||||||
|
ZMK_EVENT_RAISE(new_zmk_ble_auth_state_changed((struct zmk_ble_auth_state_changed){
|
||||||
|
.state = zmk_ble_get_auth_state(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void raise_auth_state_changed_event_callback(struct k_work *work) {
|
||||||
|
raise_auth_state_changed_event();
|
||||||
|
}
|
||||||
|
|
||||||
|
K_WORK_DEFINE(raise_auth_state_changed_event_work, raise_auth_state_changed_event_callback);
|
||||||
|
|
||||||
|
static void raise_profile_changed_event(void) {
|
||||||
ZMK_EVENT_RAISE(new_zmk_ble_active_profile_changed((struct zmk_ble_active_profile_changed){
|
ZMK_EVENT_RAISE(new_zmk_ble_active_profile_changed((struct zmk_ble_active_profile_changed){
|
||||||
.index = active_profile, .profile = &profiles[active_profile]}));
|
.index = active_profile, .profile = &profiles[active_profile]}));
|
||||||
}
|
}
|
||||||
|
@ -93,7 +115,7 @@ static void raise_profile_changed_event_callback(struct k_work *work) {
|
||||||
|
|
||||||
K_WORK_DEFINE(raise_profile_changed_event_work, raise_profile_changed_event_callback);
|
K_WORK_DEFINE(raise_profile_changed_event_work, raise_profile_changed_event_callback);
|
||||||
|
|
||||||
bool zmk_ble_active_profile_is_open() {
|
bool zmk_ble_active_profile_is_open(void) {
|
||||||
return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY);
|
return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +132,7 @@ void set_profile_address(uint8_t index, const bt_addr_le_t *addr) {
|
||||||
k_work_submit(&raise_profile_changed_event_work);
|
k_work_submit(&raise_profile_changed_event_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool zmk_ble_active_profile_is_connected() {
|
bool zmk_ble_active_profile_is_connected(void) {
|
||||||
struct bt_conn *conn;
|
struct bt_conn *conn;
|
||||||
struct bt_conn_info info;
|
struct bt_conn_info info;
|
||||||
bt_addr_le_t *addr = zmk_ble_active_profile_addr();
|
bt_addr_le_t *addr = zmk_ble_active_profile_addr();
|
||||||
|
@ -127,42 +149,46 @@ bool zmk_ble_active_profile_is_connected() {
|
||||||
return info.state == BT_CONN_STATE_CONNECTED;
|
return info.state == BT_CONN_STATE_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECKED_ADV_STOP() \
|
static int checked_adv_stop(void) {
|
||||||
err = bt_le_adv_stop(); \
|
int err = bt_le_adv_stop();
|
||||||
advertising_status = ZMK_ADV_NONE; \
|
if (err) {
|
||||||
if (err) { \
|
LOG_ERR("Failed to stop advertising (err %d)", err);
|
||||||
LOG_ERR("Failed to stop advertising (err %d)", err); \
|
} else {
|
||||||
return err; \
|
advertising_status = ZMK_ADV_NONE;
|
||||||
}
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECKED_DIR_ADV() \
|
static int checked_dir_adv(void) {
|
||||||
addr = zmk_ble_active_profile_addr(); \
|
bt_addr_le_t *addr = zmk_ble_active_profile_addr();
|
||||||
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); \
|
struct bt_conn *conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr);
|
||||||
if (conn != NULL) { /* TODO: Check status of connection */ \
|
if (conn != NULL) { /* TODO: Check status of connection */
|
||||||
LOG_DBG("Skipping advertising, profile host is already connected"); \
|
LOG_DBG("Skipping advertising, profile host is already connected");
|
||||||
bt_conn_unref(conn); \
|
bt_conn_unref(conn);
|
||||||
return 0; \
|
return 0;
|
||||||
} \
|
}
|
||||||
err = bt_le_adv_start(BT_LE_ADV_CONN_DIR_LOW_DUTY(addr), zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), \
|
int err = bt_le_adv_start(BT_LE_ADV_CONN_DIR_LOW_DUTY(addr), zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad),
|
||||||
NULL, 0); \
|
NULL, 0);
|
||||||
if (err) { \
|
if (err) {
|
||||||
LOG_ERR("Advertising failed to start (err %d)", err); \
|
LOG_ERR("Advertising failed to start (err %d)", err);
|
||||||
return err; \
|
} else {
|
||||||
} \
|
advertising_status = ZMK_ADV_DIR;
|
||||||
advertising_status = ZMK_ADV_DIR;
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECKED_OPEN_ADV() \
|
static int checked_open_adv(void) {
|
||||||
err = bt_le_adv_start(ZMK_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); \
|
int err = bt_le_adv_start(ZMK_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0);
|
||||||
if (err) { \
|
if (err) {
|
||||||
LOG_ERR("Advertising failed to start (err %d)", err); \
|
LOG_ERR("Advertising failed to start (err %d)", err);
|
||||||
return err; \
|
} else {
|
||||||
} \
|
advertising_status = ZMK_ADV_CONN;
|
||||||
advertising_status = ZMK_ADV_CONN;
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
int update_advertising() {
|
int update_advertising(void) {
|
||||||
int err = 0;
|
int err = 0;
|
||||||
bt_addr_le_t *addr;
|
|
||||||
struct bt_conn *conn;
|
|
||||||
enum advertising_type desired_adv = ZMK_ADV_NONE;
|
enum advertising_type desired_adv = ZMK_ADV_NONE;
|
||||||
|
|
||||||
if (zmk_ble_active_profile_is_open()) {
|
if (zmk_ble_active_profile_is_open()) {
|
||||||
|
@ -182,33 +208,37 @@ int update_advertising() {
|
||||||
switch (desired_adv + CURR_ADV(advertising_status)) {
|
switch (desired_adv + CURR_ADV(advertising_status)) {
|
||||||
case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_DIR):
|
case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_DIR):
|
||||||
case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_CONN):
|
case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_CONN):
|
||||||
CHECKED_ADV_STOP();
|
err = checked_adv_stop();
|
||||||
break;
|
break;
|
||||||
case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_DIR):
|
case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_DIR):
|
||||||
case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_CONN):
|
case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_CONN):
|
||||||
CHECKED_ADV_STOP();
|
err = checked_adv_stop();
|
||||||
CHECKED_DIR_ADV();
|
if (!err) {
|
||||||
|
err = checked_dir_adv();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_NONE):
|
case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_NONE):
|
||||||
CHECKED_DIR_ADV();
|
err = checked_dir_adv();
|
||||||
break;
|
break;
|
||||||
case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_DIR):
|
case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_DIR):
|
||||||
CHECKED_ADV_STOP();
|
err = checked_adv_stop();
|
||||||
CHECKED_OPEN_ADV();
|
if (!err) {
|
||||||
|
err = checked_open_adv();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_NONE):
|
case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_NONE):
|
||||||
CHECKED_OPEN_ADV();
|
err = checked_open_adv();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void update_advertising_callback(struct k_work *work) { update_advertising(); }
|
static void update_advertising_callback(struct k_work *work) { update_advertising(); }
|
||||||
|
|
||||||
K_WORK_DEFINE(update_advertising_work, update_advertising_callback);
|
K_WORK_DEFINE(update_advertising_work, update_advertising_callback);
|
||||||
|
|
||||||
int zmk_ble_clear_bonds() {
|
int zmk_ble_clear_bonds(void) {
|
||||||
LOG_DBG("");
|
LOG_DBG("");
|
||||||
|
|
||||||
if (bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY)) {
|
if (bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY)) {
|
||||||
|
@ -222,7 +252,7 @@ int zmk_ble_clear_bonds() {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
int zmk_ble_active_profile_index() { return active_profile; }
|
int zmk_ble_active_profile_index(void) { return active_profile; }
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||||
static void ble_save_profile_work(struct k_work *work) {
|
static void ble_save_profile_work(struct k_work *work) {
|
||||||
|
@ -232,7 +262,7 @@ static void ble_save_profile_work(struct k_work *work) {
|
||||||
static struct k_work_delayable ble_save_work;
|
static struct k_work_delayable ble_save_work;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int ble_save_profile() {
|
static int ble_save_profile(void) {
|
||||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||||
return k_work_reschedule(&ble_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
|
return k_work_reschedule(&ble_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
|
||||||
#else
|
#else
|
||||||
|
@ -260,20 +290,74 @@ int zmk_ble_prof_select(uint8_t index) {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
int zmk_ble_prof_next() {
|
int zmk_ble_prof_next(void) {
|
||||||
LOG_DBG("");
|
LOG_DBG("");
|
||||||
return zmk_ble_prof_select((active_profile + 1) % ZMK_BLE_PROFILE_COUNT);
|
return zmk_ble_prof_select((active_profile + 1) % ZMK_BLE_PROFILE_COUNT);
|
||||||
};
|
};
|
||||||
|
|
||||||
int zmk_ble_prof_prev() {
|
int zmk_ble_prof_prev(void) {
|
||||||
LOG_DBG("");
|
LOG_DBG("");
|
||||||
return zmk_ble_prof_select((active_profile + ZMK_BLE_PROFILE_COUNT - 1) %
|
return zmk_ble_prof_select((active_profile + ZMK_BLE_PROFILE_COUNT - 1) %
|
||||||
ZMK_BLE_PROFILE_COUNT);
|
ZMK_BLE_PROFILE_COUNT);
|
||||||
};
|
};
|
||||||
|
|
||||||
bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].peer; }
|
bt_addr_le_t *zmk_ble_active_profile_addr(void) { return &profiles[active_profile].peer; }
|
||||||
|
|
||||||
char *zmk_ble_active_profile_name() { return profiles[active_profile].name; }
|
char *zmk_ble_active_profile_name(void) { return profiles[active_profile].name; }
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||||
|
static unsigned int get_passkey_entry_passkey(void) {
|
||||||
|
uint8_t digits[PASSKEY_DIGITS];
|
||||||
|
uint32_t count = ring_buf_peek(&passkey_entries, digits, PASSKEY_DIGITS);
|
||||||
|
|
||||||
|
unsigned int passkey = 0;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
passkey = (passkey * 10) + digits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return passkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t get_passkey_entry_cursor_index(void) {
|
||||||
|
const uint32_t size = ring_buf_size_get(&passkey_entries);
|
||||||
|
__ASSERT(size <= 255, "Invalid passkey size %u", size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct zmk_ble_auth_state zmk_ble_get_auth_state(void) {
|
||||||
|
struct zmk_ble_auth_state state = {
|
||||||
|
.mode = ZMK_BLE_AUTH_MODE_NONE,
|
||||||
|
.profile_index = active_profile,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
if (auth_passkey_confirm_conn) {
|
||||||
|
state.mode = ZMK_BLE_AUTH_MODE_PASSKEY_CONFIRM;
|
||||||
|
state.passkey = current_passkey;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_DISPLAY)
|
||||||
|
if (is_displaying_passkey) {
|
||||||
|
state.mode = ZMK_BLE_AUTH_MODE_PASSKEY_DISPLAY;
|
||||||
|
state.passkey = current_passkey;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||||
|
if (auth_passkey_entry_conn) {
|
||||||
|
state.mode = ZMK_BLE_AUTH_MODE_PASSKEY_ENTRY;
|
||||||
|
state.passkey = get_passkey_entry_passkey();
|
||||||
|
state.cursor_index = get_passkey_entry_cursor_index();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||||
|
|
||||||
|
@ -427,6 +511,8 @@ static void connected(struct bt_conn *conn, uint8_t err) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void passkey_cancel(void);
|
||||||
|
|
||||||
static void disconnected(struct bt_conn *conn, uint8_t reason) {
|
static void disconnected(struct bt_conn *conn, uint8_t reason) {
|
||||||
char addr[BT_ADDR_LE_STR_LEN];
|
char addr[BT_ADDR_LE_STR_LEN];
|
||||||
struct bt_conn_info info;
|
struct bt_conn_info info;
|
||||||
|
@ -442,6 +528,8 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
passkey_cancel();
|
||||||
|
|
||||||
// We need to do this in a work callback, otherwise the advertising update will still see the
|
// We need to do this in a work callback, otherwise the advertising update will still see the
|
||||||
// connection for a profile as active, and not start advertising yet.
|
// connection for a profile as active, and not start advertising yet.
|
||||||
k_work_submit(&update_advertising_work);
|
k_work_submit(&update_advertising_work);
|
||||||
|
@ -480,15 +568,49 @@ static struct bt_conn_cb conn_callbacks = {
|
||||||
.le_param_updated = le_param_updated,
|
.le_param_updated = le_param_updated,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_DISPLAY)
|
||||||
|
|
||||||
static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) {
|
static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) {
|
||||||
char addr[BT_ADDR_LE_STR_LEN];
|
char addr[BT_ADDR_LE_STR_LEN];
|
||||||
|
|
||||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||||
|
|
||||||
LOG_DBG("Passkey for %s: %06u", addr, passkey);
|
LOG_DBG("Passkey for %s: %06u", addr, passkey);
|
||||||
|
|
||||||
|
is_displaying_passkey = true;
|
||||||
|
current_passkey = passkey;
|
||||||
|
|
||||||
|
k_work_submit(&raise_auth_state_changed_event_work);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
static void auth_passkey_display_stop(void) {
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
if (auth_passkey_confirm_conn) {
|
||||||
|
LOG_DBG("Passkey confirmation stopped");
|
||||||
|
bt_conn_unref(auth_passkey_confirm_conn);
|
||||||
|
auth_passkey_confirm_conn = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (is_displaying_passkey) {
|
||||||
|
LOG_DBG("Passkey display stopped");
|
||||||
|
|
||||||
|
is_displaying_passkey = false;
|
||||||
|
current_passkey = 0;
|
||||||
|
k_work_submit(&raise_auth_state_changed_event_work);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_DISPLAY)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
|
||||||
|
static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey) {
|
||||||
|
LOG_DBG("Waiting for passkey confirmation");
|
||||||
|
|
||||||
|
auth_passkey_confirm_conn = bt_conn_ref(conn);
|
||||||
|
auth_passkey_display(conn, passkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||||
|
|
||||||
|
@ -500,25 +622,38 @@ static void auth_passkey_entry(struct bt_conn *conn) {
|
||||||
LOG_DBG("Passkey entry requested for %s", addr);
|
LOG_DBG("Passkey entry requested for %s", addr);
|
||||||
ring_buf_reset(&passkey_entries);
|
ring_buf_reset(&passkey_entries);
|
||||||
auth_passkey_entry_conn = bt_conn_ref(conn);
|
auth_passkey_entry_conn = bt_conn_ref(conn);
|
||||||
|
|
||||||
|
k_work_submit(&raise_auth_state_changed_event_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void auth_passkey_entry_stop(void) {
|
||||||
|
if (auth_passkey_entry_conn) {
|
||||||
|
LOG_DBG("Passkey entry stopped");
|
||||||
|
|
||||||
|
bt_conn_unref(auth_passkey_entry_conn);
|
||||||
|
auth_passkey_entry_conn = NULL;
|
||||||
|
k_work_submit(&raise_auth_state_changed_event_work);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||||
|
|
||||||
|
static void passkey_cancel(void) {
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_DISPLAY)
|
||||||
|
auth_passkey_display_stop();
|
||||||
#endif
|
#endif
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||||
|
auth_passkey_entry_stop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void auth_cancel(struct bt_conn *conn) {
|
static void auth_cancel(struct bt_conn *conn) {
|
||||||
char addr[BT_ADDR_LE_STR_LEN];
|
char addr[BT_ADDR_LE_STR_LEN];
|
||||||
|
|
||||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
|
||||||
if (auth_passkey_entry_conn) {
|
|
||||||
bt_conn_unref(auth_passkey_entry_conn);
|
|
||||||
auth_passkey_entry_conn = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_buf_reset(&passkey_entries);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
LOG_DBG("Pairing cancelled: %s", addr);
|
LOG_DBG("Pairing cancelled: %s", addr);
|
||||||
|
|
||||||
|
passkey_cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum bt_security_err auth_pairing_accept(struct bt_conn *conn,
|
static enum bt_security_err auth_pairing_accept(struct bt_conn *conn,
|
||||||
|
@ -540,6 +675,10 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) {
|
||||||
char addr[BT_ADDR_LE_STR_LEN];
|
char addr[BT_ADDR_LE_STR_LEN];
|
||||||
const bt_addr_le_t *dst = bt_conn_get_dst(conn);
|
const bt_addr_le_t *dst = bt_conn_get_dst(conn);
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_DISPLAY)
|
||||||
|
auth_passkey_display_stop();
|
||||||
|
#endif
|
||||||
|
|
||||||
bt_addr_le_to_str(dst, addr, sizeof(addr));
|
bt_addr_le_to_str(dst, addr, sizeof(addr));
|
||||||
bt_conn_get_info(conn, &info);
|
bt_conn_get_info(conn, &info);
|
||||||
|
|
||||||
|
@ -554,14 +693,20 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Pairing complete: %s", addr);
|
||||||
|
|
||||||
set_profile_address(active_profile, dst);
|
set_profile_address(active_profile, dst);
|
||||||
update_advertising();
|
update_advertising();
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct bt_conn_auth_cb zmk_ble_auth_cb_display = {
|
static struct bt_conn_auth_cb zmk_ble_auth_cb_display = {
|
||||||
.pairing_accept = auth_pairing_accept,
|
.pairing_accept = auth_pairing_accept,
|
||||||
// .passkey_display = auth_passkey_display,
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
.passkey_confirm = auth_passkey_confirm,
|
||||||
|
#endif
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_DISPLAY)
|
||||||
|
.passkey_display = auth_passkey_display,
|
||||||
|
#endif
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||||
.passkey_entry = auth_passkey_entry,
|
.passkey_entry = auth_passkey_entry,
|
||||||
#endif
|
#endif
|
||||||
|
@ -656,60 +801,123 @@ static bool zmk_ble_numeric_usage_to_value(const zmk_key_t key, const zmk_key_t
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zmk_ble_handle_key_user(struct zmk_keycode_state_changed *event) {
|
static bool get_numeric_usage_value(const zmk_key_t key, uint8_t *value) {
|
||||||
zmk_key_t key = event->keycode;
|
return zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYBOARD_1_AND_EXCLAMATION,
|
||||||
|
HID_USAGE_KEY_KEYBOARD_0_AND_RIGHT_PARENTHESIS, value) ||
|
||||||
LOG_DBG("key %d", key);
|
zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYPAD_1_AND_END,
|
||||||
|
HID_USAGE_KEY_KEYPAD_0_AND_INSERT, value);
|
||||||
if (!auth_passkey_entry_conn) {
|
}
|
||||||
LOG_DBG("No connection for passkey entry");
|
|
||||||
return ZMK_EV_EVENT_BUBBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!event->state) {
|
|
||||||
LOG_DBG("Key released, ignoring");
|
|
||||||
return ZMK_EV_EVENT_BUBBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == HID_USAGE_KEY_KEYBOARD_ESCAPE) {
|
|
||||||
bt_conn_auth_cancel(auth_passkey_entry_conn);
|
|
||||||
return ZMK_EV_EVENT_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == HID_USAGE_KEY_KEYBOARD_RETURN || key == HID_USAGE_KEY_KEYBOARD_RETURN_ENTER) {
|
|
||||||
uint8_t digits[PASSKEY_DIGITS];
|
|
||||||
uint32_t count = ring_buf_get(&passkey_entries, digits, PASSKEY_DIGITS);
|
|
||||||
|
|
||||||
uint32_t passkey = 0;
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
passkey = (passkey * 10) + digits[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DBG("Final passkey: %d", passkey);
|
|
||||||
bt_conn_auth_passkey_entry(auth_passkey_entry_conn, passkey);
|
|
||||||
bt_conn_unref(auth_passkey_entry_conn);
|
|
||||||
auth_passkey_entry_conn = NULL;
|
|
||||||
return ZMK_EV_EVENT_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t val;
|
|
||||||
if (!(zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYBOARD_1_AND_EXCLAMATION,
|
|
||||||
HID_USAGE_KEY_KEYBOARD_0_AND_RIGHT_PARENTHESIS, &val) ||
|
|
||||||
zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYPAD_1_AND_END,
|
|
||||||
HID_USAGE_KEY_KEYPAD_0_AND_INSERT, &val))) {
|
|
||||||
LOG_DBG("Key not a number, ignoring");
|
|
||||||
return ZMK_EV_EVENT_BUBBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
static void add_passkey_digit(uint8_t value) {
|
||||||
if (ring_buf_space_get(&passkey_entries) <= 0) {
|
if (ring_buf_space_get(&passkey_entries) <= 0) {
|
||||||
uint8_t discard_val;
|
uint8_t discard_val;
|
||||||
ring_buf_get(&passkey_entries, &discard_val, 1);
|
ring_buf_get(&passkey_entries, &discard_val, 1);
|
||||||
}
|
}
|
||||||
ring_buf_put(&passkey_entries, &val, 1);
|
|
||||||
LOG_DBG("value entered: %d, digits collected so far: %d", val,
|
ring_buf_put(&passkey_entries, &value, 1);
|
||||||
|
LOG_DBG("value entered: %d, digits collected so far: %d", value,
|
||||||
ring_buf_size_get(&passkey_entries));
|
ring_buf_size_get(&passkey_entries));
|
||||||
|
|
||||||
return ZMK_EV_EVENT_HANDLED;
|
k_work_submit(&raise_auth_state_changed_event_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_passkey_digit(void) {
|
||||||
|
uint8_t digits[PASSKEY_DIGITS];
|
||||||
|
uint32_t count = ring_buf_get(&passkey_entries, digits, PASSKEY_DIGITS);
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ring_buf_put(&passkey_entries, digits, count - 1);
|
||||||
|
|
||||||
|
k_work_submit(&raise_auth_state_changed_event_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_key_passkey_entry(const zmk_key_t key) {
|
||||||
|
LOG_DBG("Passkey entry: key %d", key);
|
||||||
|
|
||||||
|
if (key == HID_USAGE_KEY_KEYBOARD_ESCAPE) {
|
||||||
|
LOG_DBG("User canceled passkey entry");
|
||||||
|
bt_conn_auth_cancel(auth_passkey_entry_conn);
|
||||||
|
return ZMK_EV_EVENT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == HID_USAGE_KEY_KEYBOARD_DELETE_BACKSPACE || key == HID_USAGE_KEY_KEYPAD_BACKSPACE) {
|
||||||
|
remove_passkey_digit();
|
||||||
|
return ZMK_EV_EVENT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == HID_USAGE_KEY_KEYBOARD_RETURN || key == HID_USAGE_KEY_KEYBOARD_RETURN_ENTER) {
|
||||||
|
if (get_passkey_entry_cursor_index() < PASSKEY_DIGITS) {
|
||||||
|
LOG_DBG("Ignoring incomplete passkey");
|
||||||
|
return ZMK_EV_EVENT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned int passkey = get_passkey_entry_passkey();
|
||||||
|
LOG_DBG("Final passkey: %d", passkey);
|
||||||
|
bt_conn_auth_passkey_entry(auth_passkey_entry_conn, passkey);
|
||||||
|
|
||||||
|
auth_passkey_entry_stop();
|
||||||
|
|
||||||
|
return ZMK_EV_EVENT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t val;
|
||||||
|
if (get_numeric_usage_value(key, &val)) {
|
||||||
|
add_passkey_digit(val);
|
||||||
|
return ZMK_EV_EVENT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Key not used for passkey entry, ignoring");
|
||||||
|
return ZMK_EV_EVENT_BUBBLE;
|
||||||
|
}
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
static int handle_key_passkey_confirm(const zmk_key_t key) {
|
||||||
|
LOG_DBG("Passkey confirm: key %d", key);
|
||||||
|
|
||||||
|
if (key == HID_USAGE_KEY_KEYBOARD_ESCAPE) {
|
||||||
|
LOG_DBG("User canceled passkey confirmation");
|
||||||
|
bt_conn_auth_cancel(auth_passkey_confirm_conn);
|
||||||
|
return ZMK_EV_EVENT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == HID_USAGE_KEY_KEYBOARD_RETURN || key == HID_USAGE_KEY_KEYBOARD_RETURN_ENTER) {
|
||||||
|
LOG_DBG("Passkey confirmed");
|
||||||
|
bt_conn_auth_passkey_confirm(auth_passkey_confirm_conn);
|
||||||
|
auth_passkey_display_stop();
|
||||||
|
|
||||||
|
return ZMK_EV_EVENT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Key not used for passkey confirmation, ignoring");
|
||||||
|
return ZMK_EV_EVENT_BUBBLE;
|
||||||
|
}
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) || IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
|
||||||
|
static int zmk_ble_handle_key_user(struct zmk_keycode_state_changed *event) {
|
||||||
|
if (!event->state) {
|
||||||
|
// Key released. Ignore.
|
||||||
|
return ZMK_EV_EVENT_BUBBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
if (auth_passkey_confirm_conn) {
|
||||||
|
return handle_key_passkey_confirm(event->keycode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||||
|
if (auth_passkey_entry_conn) {
|
||||||
|
return handle_key_passkey_entry(event->keycode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Passkey entry/confirm not active. Ignore.
|
||||||
|
return ZMK_EV_EVENT_BUBBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zmk_ble_listener(const zmk_event_t *eh) {
|
static int zmk_ble_listener(const zmk_event_t *eh) {
|
||||||
|
@ -726,6 +934,6 @@ static int zmk_ble_listener(const zmk_event_t *eh) {
|
||||||
|
|
||||||
ZMK_LISTENER(zmk_ble, zmk_ble_listener);
|
ZMK_LISTENER(zmk_ble, zmk_ble_listener);
|
||||||
ZMK_SUBSCRIPTION(zmk_ble, zmk_keycode_state_changed);
|
ZMK_SUBSCRIPTION(zmk_ble, zmk_keycode_state_changed);
|
||||||
#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */
|
#endif // IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) || IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_CONFIRM)
|
||||||
|
|
||||||
SYS_INIT(zmk_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY);
|
SYS_INIT(zmk_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY);
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
# Copyright (c) 2020 The ZMK Contributors
|
# Copyright (c) 2020 The ZMK Contributors
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE main.c)
|
target_sources(app PRIVATE main.c)
|
||||||
|
target_sources(app PRIVATE theme.c)
|
||||||
|
target_sources_ifdef(CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE app PRIVATE idle.c)
|
||||||
|
target_sources_ifdef(CONFIG_ZMK_DISPLAY_PAIRING_SCREEN_BUILT_IN app PRIVATE pairing_screen.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN app PRIVATE status_screen.c)
|
target_sources_ifdef(CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN app PRIVATE status_screen.c)
|
||||||
|
|
||||||
add_subdirectory_ifdef(CONFIG_ZMK_DISPLAY widgets/)
|
add_subdirectory(widgets/)
|
||||||
|
|
|
@ -7,6 +7,7 @@ menuconfig ZMK_DISPLAY
|
||||||
select DISPLAY
|
select DISPLAY
|
||||||
select LVGL
|
select LVGL
|
||||||
select LV_CONF_MINIMAL
|
select LV_CONF_MINIMAL
|
||||||
|
imply ZMK_BLE_PASSKEY_DISPLAY
|
||||||
|
|
||||||
if ZMK_DISPLAY
|
if ZMK_DISPLAY
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ if LV_USE_THEME_MONO
|
||||||
config ZMK_DISPLAY_INVERT
|
config ZMK_DISPLAY_INVERT
|
||||||
bool "Invert display colors"
|
bool "Invert display colors"
|
||||||
|
|
||||||
endif
|
endif # LV_USE_THEME_MONO
|
||||||
|
|
||||||
choice LV_TXT_ENC
|
choice LV_TXT_ENC
|
||||||
default LV_TXT_ENC_UTF8
|
default LV_TXT_ENC_UTF8
|
||||||
|
@ -36,7 +37,7 @@ config LV_Z_MEM_POOL_MAX_SIZE
|
||||||
default 8192
|
default 8192
|
||||||
|
|
||||||
choice ZMK_DISPLAY_STATUS_SCREEN
|
choice ZMK_DISPLAY_STATUS_SCREEN
|
||||||
prompt "Default status screen for displays"
|
prompt "Status screen for displays"
|
||||||
|
|
||||||
config ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN
|
config ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN
|
||||||
bool "Built in status screen"
|
bool "Built in status screen"
|
||||||
|
@ -52,6 +53,20 @@ config ZMK_DISPLAY_STATUS_SCREEN_CUSTOM
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
if ZMK_BLE && (!ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL)
|
||||||
|
choice ZMK_DISPLAY_PAIRING_SCREEN
|
||||||
|
prompt "Bluetooth pairing screen for displays"
|
||||||
|
|
||||||
|
config ZMK_DISPLAY_PAIRING_SCREEN_BUILT_IN
|
||||||
|
bool "Built in bluetooth pairing screen"
|
||||||
|
select ZMK_WIDGET_BLE_PASSKEY
|
||||||
|
|
||||||
|
config ZMK_DISPLAY_PAIRING_SCREEN_CUSTOM
|
||||||
|
bool "Custom bluetooth pairing screen"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
endif # ZMK_BLE
|
||||||
|
|
||||||
choice ZMK_DISPLAY_WORK_QUEUE
|
choice ZMK_DISPLAY_WORK_QUEUE
|
||||||
prompt "Work queue selection for UI updates"
|
prompt "Work queue selection for UI updates"
|
||||||
|
|
||||||
|
@ -75,33 +90,16 @@ config ZMK_DISPLAY_DEDICATED_THREAD_PRIORITY
|
||||||
|
|
||||||
endif # ZMK_DISPLAY_WORK_QUEUE_DEDICATED
|
endif # ZMK_DISPLAY_WORK_QUEUE_DEDICATED
|
||||||
|
|
||||||
if ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN
|
|
||||||
|
|
||||||
config LV_FONT_MONTSERRAT_16
|
|
||||||
default y
|
|
||||||
|
|
||||||
choice LV_FONT_DEFAULT
|
|
||||||
default LV_FONT_DEFAULT_MONTSERRAT_16
|
|
||||||
|
|
||||||
endchoice
|
|
||||||
|
|
||||||
config LV_FONT_MONTSERRAT_12
|
|
||||||
default y
|
|
||||||
|
|
||||||
endif # ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN
|
|
||||||
|
|
||||||
choice ZMK_LV_FONT_DEFAULT_SMALL
|
choice ZMK_LV_FONT_DEFAULT_SMALL
|
||||||
prompt "Select theme default small font"
|
prompt "Select theme default small font"
|
||||||
default ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12
|
|
||||||
help
|
config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12
|
||||||
Select theme default small font
|
bool "Montserrat 12"
|
||||||
|
select LV_FONT_MONTSERRAT_12
|
||||||
|
|
||||||
config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_8
|
config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_8
|
||||||
bool "Montserrat 8"
|
bool "Montserrat 8"
|
||||||
select LV_FONT_MONTSERRAT_8
|
select LV_FONT_MONTSERRAT_8
|
||||||
config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12
|
|
||||||
bool "Montserrat 12"
|
|
||||||
select LV_FONT_MONTSERRAT_12
|
|
||||||
config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_14
|
config ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_14
|
||||||
bool "Montserrat 14"
|
bool "Montserrat 14"
|
||||||
select LV_FONT_MONTSERRAT_14
|
select LV_FONT_MONTSERRAT_14
|
||||||
|
@ -176,6 +174,174 @@ choice ZMK_LV_FONT_DEFAULT_SMALL
|
||||||
select LV_FONT_UNSCII_16
|
select LV_FONT_UNSCII_16
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
choice ZMK_LV_FONT_DEFAULT_NORMAL
|
||||||
|
prompt "Select theme default normal font"
|
||||||
|
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_16
|
||||||
|
bool "Montserrat 16"
|
||||||
|
select LV_FONT_MONTSERRAT_16
|
||||||
|
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_8
|
||||||
|
bool "Montserrat 8"
|
||||||
|
select LV_FONT_MONTSERRAT_8
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_12
|
||||||
|
bool "Montserrat 12"
|
||||||
|
select LV_FONT_MONTSERRAT_12
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_14
|
||||||
|
bool "Montserrat 14"
|
||||||
|
select LV_FONT_MONTSERRAT_14
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_18
|
||||||
|
bool "Montserrat 18"
|
||||||
|
select LV_FONT_MONTSERRAT_18
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_20
|
||||||
|
bool "Montserrat 20"
|
||||||
|
select LV_FONT_MONTSERRAT_20
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_22
|
||||||
|
bool "Montserrat 22"
|
||||||
|
select LV_FONT_MONTSERRAT_22
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_24
|
||||||
|
bool "Montserrat 24"
|
||||||
|
select LV_FONT_MONTSERRAT_24
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_26
|
||||||
|
bool "Montserrat 26"
|
||||||
|
select LV_FONT_MONTSERRAT_26
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_28
|
||||||
|
bool "Montserrat 28"
|
||||||
|
select LV_FONT_MONTSERRAT_28
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_30
|
||||||
|
bool "Montserrat 30"
|
||||||
|
select LV_FONT_MONTSERRAT_30
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_32
|
||||||
|
bool "Montserrat 32"
|
||||||
|
select LV_FONT_MONTSERRAT_32
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_34
|
||||||
|
bool "Montserrat 34"
|
||||||
|
select LV_FONT_MONTSERRAT_34
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_36
|
||||||
|
bool "Montserrat 36"
|
||||||
|
select LV_FONT_MONTSERRAT_36
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_38
|
||||||
|
bool "Montserrat 38"
|
||||||
|
select LV_FONT_MONTSERRAT_38
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_40
|
||||||
|
bool "Montserrat 40"
|
||||||
|
select LV_FONT_MONTSERRAT_40
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_42
|
||||||
|
bool "Montserrat 42"
|
||||||
|
select LV_FONT_MONTSERRAT_42
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_44
|
||||||
|
bool "Montserrat 44"
|
||||||
|
select LV_FONT_MONTSERRAT_44
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_46
|
||||||
|
bool "Montserrat 46"
|
||||||
|
select LV_FONT_MONTSERRAT_46
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_48
|
||||||
|
bool "Montserrat 48"
|
||||||
|
select LV_FONT_MONTSERRAT_48
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_12_SUBPX
|
||||||
|
bool "Montserrat 12 sub-pixel"
|
||||||
|
select LV_FONT_MONTSERRAT_12_SUBPX
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_28_COMPRESSED
|
||||||
|
bool "Montserrat 28 compressed"
|
||||||
|
select LV_FONT_MONTSERRAT_28_COMPRESSED
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_DEJAVU_16_PERSIAN_HEBREW
|
||||||
|
bool "Dejavu 16 Persian, Hebrew, Arabic letters"
|
||||||
|
select LV_FONT_DEJAVU_16_PERSIAN_HEBREW
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_SIMSUN_16_CJK
|
||||||
|
bool "Simsun 16 CJK"
|
||||||
|
select LV_FONT_SIMSUN_16_CJK
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_UNSCII_8
|
||||||
|
bool "UNSCII 8 (Perfect monospace font)"
|
||||||
|
select LV_FONT_UNSCII_8
|
||||||
|
config ZMK_LV_FONT_DEFAULT_NORMAL_UNSCII_16
|
||||||
|
bool "UNSCII 16 (Perfect monospace font)"
|
||||||
|
select LV_FONT_UNSCII_16
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice ZMK_LV_FONT_DEFAULT_LARGE
|
||||||
|
prompt "Select theme default large font"
|
||||||
|
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_20
|
||||||
|
bool "Montserrat 20"
|
||||||
|
select LV_FONT_MONTSERRAT_20
|
||||||
|
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_8
|
||||||
|
bool "Montserrat 8"
|
||||||
|
select LV_FONT_MONTSERRAT_8
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_12
|
||||||
|
bool "Montserrat 12"
|
||||||
|
select LV_FONT_MONTSERRAT_12
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_14
|
||||||
|
bool "Montserrat 14"
|
||||||
|
select LV_FONT_MONTSERRAT_14
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_16
|
||||||
|
bool "Montserrat 16"
|
||||||
|
select LV_FONT_MONTSERRAT_16
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_18
|
||||||
|
bool "Montserrat 18"
|
||||||
|
select LV_FONT_MONTSERRAT_18
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_22
|
||||||
|
bool "Montserrat 22"
|
||||||
|
select LV_FONT_MONTSERRAT_22
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_24
|
||||||
|
bool "Montserrat 24"
|
||||||
|
select LV_FONT_MONTSERRAT_24
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_26
|
||||||
|
bool "Montserrat 26"
|
||||||
|
select LV_FONT_MONTSERRAT_26
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_28
|
||||||
|
bool "Montserrat 28"
|
||||||
|
select LV_FONT_MONTSERRAT_28
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_30
|
||||||
|
bool "Montserrat 30"
|
||||||
|
select LV_FONT_MONTSERRAT_30
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_32
|
||||||
|
bool "Montserrat 32"
|
||||||
|
select LV_FONT_MONTSERRAT_32
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_34
|
||||||
|
bool "Montserrat 34"
|
||||||
|
select LV_FONT_MONTSERRAT_34
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_36
|
||||||
|
bool "Montserrat 36"
|
||||||
|
select LV_FONT_MONTSERRAT_36
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_38
|
||||||
|
bool "Montserrat 38"
|
||||||
|
select LV_FONT_MONTSERRAT_38
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_40
|
||||||
|
bool "Montserrat 40"
|
||||||
|
select LV_FONT_MONTSERRAT_40
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_42
|
||||||
|
bool "Montserrat 42"
|
||||||
|
select LV_FONT_MONTSERRAT_42
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_44
|
||||||
|
bool "Montserrat 44"
|
||||||
|
select LV_FONT_MONTSERRAT_44
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_46
|
||||||
|
bool "Montserrat 46"
|
||||||
|
select LV_FONT_MONTSERRAT_46
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_48
|
||||||
|
bool "Montserrat 48"
|
||||||
|
select LV_FONT_MONTSERRAT_48
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_12_SUBPX
|
||||||
|
bool "Montserrat 12 sub-pixel"
|
||||||
|
select LV_FONT_MONTSERRAT_12_SUBPX
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_28_COMPRESSED
|
||||||
|
bool "Montserrat 28 compressed"
|
||||||
|
select LV_FONT_MONTSERRAT_28_COMPRESSED
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_DEJAVU_16_PERSIAN_HEBREW
|
||||||
|
bool "Dejavu 16 Persian, Hebrew, Arabic letters"
|
||||||
|
select LV_FONT_DEJAVU_16_PERSIAN_HEBREW
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_SIMSUN_16_CJK
|
||||||
|
bool "Simsun 16 CJK"
|
||||||
|
select LV_FONT_SIMSUN_16_CJK
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_UNSCII_8
|
||||||
|
bool "UNSCII 8 (Perfect monospace font)"
|
||||||
|
select LV_FONT_UNSCII_8
|
||||||
|
config ZMK_LV_FONT_DEFAULT_LARGE_UNSCII_16
|
||||||
|
bool "UNSCII 16 (Perfect monospace font)"
|
||||||
|
select LV_FONT_UNSCII_16
|
||||||
|
endchoice
|
||||||
|
|
||||||
rsource "widgets/Kconfig"
|
rsource "widgets/Kconfig"
|
||||||
|
|
||||||
endif
|
endif # ZMK_DISPLAY
|
||||||
|
|
38
app/src/display/idle.c
Normal file
38
app/src/display/idle.c
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zmk/display.h>
|
||||||
|
#include <zmk/event_manager.h>
|
||||||
|
#include <zmk/events/activity_state_changed.h>
|
||||||
|
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
|
static int display_event_handler(const zmk_event_t *eh) {
|
||||||
|
struct zmk_activity_state_changed *ev = as_zmk_activity_state_changed(eh);
|
||||||
|
if (!ev) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ev->state) {
|
||||||
|
case ZMK_ACTIVITY_ACTIVE:
|
||||||
|
zmk_display_blanking_off();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case ZMK_ACTIVITY_IDLE:
|
||||||
|
case ZMK_ACTIVITY_SLEEP:
|
||||||
|
zmk_display_blanking_on();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_WRN("Unhandled activity state: %d", ev->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZMK_LISTENER(display_idle, display_event_handler);
|
||||||
|
ZMK_SUBSCRIPTION(display_idle, zmk_activity_state_changed);
|
|
@ -17,21 +17,44 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
|
|
||||||
#include <zmk/event_manager.h>
|
|
||||||
#include <zmk/events/activity_state_changed.h>
|
|
||||||
#include <zmk/display/status_screen.h>
|
#include <zmk/display/status_screen.h>
|
||||||
|
#include <zmk/event_manager.h>
|
||||||
|
|
||||||
static const struct device *display = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
|
#define HAS_PAIRING_SCREEN \
|
||||||
static bool initialized = false;
|
(IS_ENABLED(CONFIG_ZMK_DISPLAY_PAIRING_SCREEN_BUILT_IN) || \
|
||||||
|
IS_ENABLED(CONFIG_ZMK_DISPLAY_PAIRING_SCREEN_CUSTOM))
|
||||||
|
|
||||||
static lv_obj_t *screen;
|
#if HAS_PAIRING_SCREEN
|
||||||
|
#include <zmk/ble.h>
|
||||||
__attribute__((weak)) lv_obj_t *zmk_display_status_screen() { return NULL; }
|
#include <zmk/display/pairing_screen.h>
|
||||||
|
#include <zmk/events/ble_auth_state_changed.h>
|
||||||
void display_tick_cb(struct k_work *work) { lv_task_handler(); }
|
#endif
|
||||||
|
|
||||||
#define TICK_MS 10
|
#define TICK_MS 10
|
||||||
|
|
||||||
|
enum screen_type {
|
||||||
|
SCREEN_TYPE_STATUS,
|
||||||
|
#if HAS_PAIRING_SCREEN
|
||||||
|
SCREEN_TYPE_PAIRING,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct device *display = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
|
||||||
|
static lv_obj_t *current_screen = NULL;
|
||||||
|
static bool initialized = false;
|
||||||
|
|
||||||
|
static lv_obj_t *status_screen = NULL;
|
||||||
|
#if HAS_PAIRING_SCREEN
|
||||||
|
static lv_obj_t *pairing_screen = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__attribute__((weak)) lv_obj_t *zmk_display_status_screen(void) { return NULL; }
|
||||||
|
#if HAS_PAIRING_SCREEN
|
||||||
|
__attribute__((weak)) lv_obj_t *zmk_display_pairing_screen(void) { return NULL; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void display_tick_cb(struct k_work *work) { lv_task_handler(); }
|
||||||
|
|
||||||
K_WORK_DEFINE(display_tick_work, display_tick_cb);
|
K_WORK_DEFINE(display_tick_work, display_tick_cb);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED)
|
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED)
|
||||||
|
@ -42,7 +65,7 @@ static struct k_work_q display_work_q;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct k_work_q *zmk_display_work_q() {
|
struct k_work_q *zmk_display_work_q(void) {
|
||||||
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED)
|
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED)
|
||||||
return &display_work_q;
|
return &display_work_q;
|
||||||
#else
|
#else
|
||||||
|
@ -50,25 +73,25 @@ struct k_work_q *zmk_display_work_q() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_timer_cb() { k_work_submit_to_queue(zmk_display_work_q(), &display_tick_work); }
|
static void display_timer_cb(struct k_timer *timer) {
|
||||||
|
k_work_submit_to_queue(zmk_display_work_q(), &display_tick_work);
|
||||||
|
}
|
||||||
|
|
||||||
K_TIMER_DEFINE(display_timer, display_timer_cb, NULL);
|
K_TIMER_DEFINE(display_timer, display_timer_cb, NULL);
|
||||||
|
|
||||||
void unblank_display_cb(struct k_work *work) {
|
static void unblank_display_cb(struct k_work *work) {
|
||||||
display_blanking_off(display);
|
display_blanking_off(display);
|
||||||
k_timer_start(&display_timer, K_MSEC(TICK_MS), K_MSEC(TICK_MS));
|
k_timer_start(&display_timer, K_MSEC(TICK_MS), K_MSEC(TICK_MS));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE)
|
static void blank_display_cb(struct k_work *work) {
|
||||||
|
|
||||||
void blank_display_cb(struct k_work *work) {
|
|
||||||
k_timer_stop(&display_timer);
|
k_timer_stop(&display_timer);
|
||||||
display_blanking_on(display);
|
display_blanking_on(display);
|
||||||
}
|
}
|
||||||
K_WORK_DEFINE(blank_display_work, blank_display_cb);
|
K_WORK_DEFINE(blank_display_work, blank_display_cb);
|
||||||
K_WORK_DEFINE(unblank_display_work, unblank_display_cb);
|
K_WORK_DEFINE(unblank_display_work, unblank_display_cb);
|
||||||
|
|
||||||
static void start_display_updates() {
|
void zmk_display_blanking_off(void) {
|
||||||
if (display == NULL) {
|
if (display == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +99,7 @@ static void start_display_updates() {
|
||||||
k_work_submit_to_queue(zmk_display_work_q(), &unblank_display_work);
|
k_work_submit_to_queue(zmk_display_work_q(), &unblank_display_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop_display_updates() {
|
void zmk_display_blanking_on(void) {
|
||||||
if (display == NULL) {
|
if (display == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -84,48 +107,82 @@ static void stop_display_updates() {
|
||||||
k_work_submit_to_queue(zmk_display_work_q(), &blank_display_work);
|
k_work_submit_to_queue(zmk_display_work_q(), &blank_display_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int zmk_display_is_initialized(void) { return initialized; }
|
||||||
|
|
||||||
|
K_MUTEX_DEFINE(screen_state_mutex);
|
||||||
|
#if HAS_PAIRING_SCREEN
|
||||||
|
static struct zmk_ble_auth_state ble_auth_state;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int zmk_display_is_initialized() { return initialized; }
|
static enum screen_type get_screen_type(void) {
|
||||||
|
enum screen_type screen_type = SCREEN_TYPE_STATUS;
|
||||||
|
|
||||||
static void initialize_theme() {
|
#if HAS_PAIRING_SCREEN
|
||||||
#if IS_ENABLED(CONFIG_LV_USE_THEME_MONO)
|
k_mutex_lock(&screen_state_mutex, K_FOREVER);
|
||||||
lv_disp_t *disp = lv_disp_get_default();
|
|
||||||
lv_theme_t *theme =
|
|
||||||
lv_theme_mono_init(disp, IS_ENABLED(CONFIG_ZMK_DISPLAY_INVERT), CONFIG_LV_FONT_DEFAULT);
|
|
||||||
theme->font_small = CONFIG_ZMK_LV_FONT_DEFAULT_SMALL;
|
|
||||||
|
|
||||||
disp->theme = theme;
|
if (ble_auth_state.mode != ZMK_BLE_AUTH_MODE_NONE) {
|
||||||
#endif // CONFIG_LV_USE_THEME_MONO
|
screen_type = SCREEN_TYPE_PAIRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_mutex_unlock(&screen_state_mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return screen_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize_display(struct k_work *work) {
|
static void update_screen(struct k_work *work) {
|
||||||
LOG_DBG("");
|
enum screen_type new_screen_type = get_screen_type();
|
||||||
|
lv_obj_t *new_screen = NULL;
|
||||||
|
|
||||||
if (!device_is_ready(display)) {
|
switch (new_screen_type) {
|
||||||
LOG_ERR("Failed to find display device");
|
case SCREEN_TYPE_STATUS:
|
||||||
return;
|
new_screen = status_screen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if HAS_PAIRING_SCREEN
|
||||||
|
case SCREEN_TYPE_PAIRING:
|
||||||
|
new_screen = pairing_screen;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_ERR("Unhandled screen type: %d", new_screen_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_screen != current_screen) {
|
||||||
|
current_screen = new_screen;
|
||||||
|
lv_scr_load(current_screen);
|
||||||
|
unblank_display_cb(work);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
K_WORK_DEFINE(update_screen_work, update_screen);
|
||||||
|
|
||||||
|
static void initialize_display(struct k_work *work) {
|
||||||
|
update_screen(work);
|
||||||
|
|
||||||
|
if (!current_screen) {
|
||||||
|
LOG_ERR("No status screen provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
initialize_theme();
|
|
||||||
|
|
||||||
screen = zmk_display_status_screen();
|
|
||||||
|
|
||||||
if (screen == NULL) {
|
|
||||||
LOG_ERR("No status screen provided");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lv_scr_load(screen);
|
|
||||||
|
|
||||||
unblank_display_cb(work);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
K_WORK_DEFINE(init_work, initialize_display);
|
K_WORK_DEFINE(init_work, initialize_display);
|
||||||
|
|
||||||
int zmk_display_init() {
|
int zmk_display_init(void) {
|
||||||
|
if (!device_is_ready(display)) {
|
||||||
|
LOG_ERR("Failed to find display device");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
zmk_display_initialize_theme();
|
||||||
|
|
||||||
|
status_screen = zmk_display_status_screen();
|
||||||
|
#if HAS_PAIRING_SCREEN
|
||||||
|
pairing_screen = zmk_display_pairing_screen();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED)
|
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED)
|
||||||
k_work_queue_start(&display_work_q, display_work_stack_area,
|
k_work_queue_start(&display_work_q, display_work_stack_area,
|
||||||
K_THREAD_STACK_SIZEOF(display_work_stack_area),
|
K_THREAD_STACK_SIZEOF(display_work_stack_area),
|
||||||
|
@ -134,33 +191,28 @@ int zmk_display_init() {
|
||||||
|
|
||||||
k_work_submit_to_queue(zmk_display_work_q(), &init_work);
|
k_work_submit_to_queue(zmk_display_work_q(), &init_work);
|
||||||
|
|
||||||
LOG_DBG("");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE)
|
#if HAS_PAIRING_SCREEN
|
||||||
int display_event_handler(const zmk_event_t *eh) {
|
static int handle_ble_auth_state_changed(const struct zmk_ble_auth_state_changed *ev) {
|
||||||
struct zmk_activity_state_changed *ev = as_zmk_activity_state_changed(eh);
|
k_mutex_lock(&screen_state_mutex, K_FOREVER);
|
||||||
if (ev == NULL) {
|
ble_auth_state = ev->state;
|
||||||
return -ENOTSUP;
|
k_mutex_unlock(&screen_state_mutex);
|
||||||
|
|
||||||
|
k_work_submit_to_queue(zmk_display_work_q(), &update_screen_work);
|
||||||
|
return ZMK_EV_EVENT_BUBBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int display_event_handler(const zmk_event_t *eh) {
|
||||||
|
const struct zmk_ble_auth_state_changed *auth_ev = as_zmk_ble_auth_state_changed(eh);
|
||||||
|
if (auth_ev) {
|
||||||
|
return handle_ble_auth_state_changed(auth_ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ev->state) {
|
return -ENOTSUP;
|
||||||
case ZMK_ACTIVITY_ACTIVE:
|
|
||||||
start_display_updates();
|
|
||||||
break;
|
|
||||||
case ZMK_ACTIVITY_IDLE:
|
|
||||||
case ZMK_ACTIVITY_SLEEP:
|
|
||||||
stop_display_updates();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_WRN("Unhandled activity state: %d", ev->state);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMK_LISTENER(display, display_event_handler);
|
ZMK_LISTENER(display, display_event_handler);
|
||||||
ZMK_SUBSCRIPTION(display, zmk_activity_state_changed);
|
ZMK_SUBSCRIPTION(display, zmk_ble_auth_state_changed);
|
||||||
|
#endif // HAS_PAIRING_SCREEN
|
||||||
#endif /* IS_ENABLED(CONFIG_ZMK_DISPLAY_BLANK_ON_IDLE) */
|
|
||||||
|
|
24
app/src/display/pairing_screen.c
Normal file
24
app/src/display/pairing_screen.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <lvgl.h>
|
||||||
|
|
||||||
|
#include <zmk/display/widgets/ble_passkey.h>
|
||||||
|
|
||||||
|
static struct zmk_widget_ble_passkey passkey_widget;
|
||||||
|
|
||||||
|
lv_obj_t *zmk_display_pairing_screen(void) {
|
||||||
|
lv_obj_t *screen;
|
||||||
|
screen = lv_obj_create(NULL);
|
||||||
|
|
||||||
|
zmk_widget_ble_passkey_init(&passkey_widget, screen);
|
||||||
|
|
||||||
|
lv_obj_t *widget = zmk_widget_ble_passkey_obj(&passkey_widget);
|
||||||
|
lv_obj_set_width(widget, LV_PCT(100));
|
||||||
|
lv_obj_set_height(widget, LV_PCT(100));
|
||||||
|
|
||||||
|
return screen;
|
||||||
|
}
|
|
@ -34,7 +34,9 @@ static struct zmk_widget_layer_status layer_status_widget;
|
||||||
static struct zmk_widget_wpm_status wpm_status_widget;
|
static struct zmk_widget_wpm_status wpm_status_widget;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lv_obj_t *zmk_display_status_screen() {
|
static bool is_small_display(void) { return lv_disp_get_ver_res(lv_disp_get_default()) < 40; }
|
||||||
|
|
||||||
|
lv_obj_t *zmk_display_status_screen(void) {
|
||||||
lv_obj_t *screen;
|
lv_obj_t *screen;
|
||||||
screen = lv_obj_create(NULL);
|
screen = lv_obj_create(NULL);
|
||||||
|
|
||||||
|
@ -56,9 +58,11 @@ lv_obj_t *zmk_display_status_screen() {
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_WIDGET_LAYER_STATUS)
|
#if IS_ENABLED(CONFIG_ZMK_WIDGET_LAYER_STATUS)
|
||||||
zmk_widget_layer_status_init(&layer_status_widget, screen);
|
zmk_widget_layer_status_init(&layer_status_widget, screen);
|
||||||
lv_obj_set_style_text_font(zmk_widget_layer_status_obj(&layer_status_widget),
|
|
||||||
lv_theme_get_font_small(screen), LV_PART_MAIN);
|
|
||||||
lv_obj_align(zmk_widget_layer_status_obj(&layer_status_widget), LV_ALIGN_BOTTOM_LEFT, 0, 0);
|
lv_obj_align(zmk_widget_layer_status_obj(&layer_status_widget), LV_ALIGN_BOTTOM_LEFT, 0, 0);
|
||||||
|
if (is_small_display()) {
|
||||||
|
lv_obj_set_style_text_font(zmk_widget_layer_status_obj(&layer_status_widget),
|
||||||
|
lv_theme_get_font_small(screen), LV_PART_MAIN);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_WIDGET_WPM_STATUS)
|
#if IS_ENABLED(CONFIG_ZMK_WIDGET_WPM_STATUS)
|
||||||
|
|
|
@ -1,73 +1,51 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 The ZMK Contributors
|
* Copyright (c) 2023 The ZMK Contributors
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "theme.h"
|
||||||
|
|
||||||
#include <lvgl.h>
|
#include <lvgl.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
|
||||||
#if defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_8)
|
#if IS_ENABLED(CONFIG_LV_USE_THEME_MONO)
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_8
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_10)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_10
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_12
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_14)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_14
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_16)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_16
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_18)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_18
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_20)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_20
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_22)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_22
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_24)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_24
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_26)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_26
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_28)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_28
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_30)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_30
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_32)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_32
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_34)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_34
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_36)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_36
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_38)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_38
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_40)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_40
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_42)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_42
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_44)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_44
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_46)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_46
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_48)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_48
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12_SUBPX)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_12_subpx
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_28_COMPRESSED)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_montserrat_28_compressed
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_DEJAVU_16_PERSIAN_HEBREW)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_dejavu_16_persian_hebrew
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_SIMSUN_16_CJK)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_simsun_16_cjk
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_8)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_unscii_8
|
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_16)
|
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_unscii_16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void zmk_display_theme_init(lv_obj_t *obj) {
|
static lv_theme_t *initialize_theme(lv_disp_t *disp) {
|
||||||
lv_theme_t *theme = lv_theme_get_from_obj(obj);
|
lv_theme_t *theme = lv_theme_mono_init(disp, IS_ENABLED(CONFIG_ZMK_DISPLAY_INVERT),
|
||||||
|
CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL);
|
||||||
if (theme == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
theme->font_small = CONFIG_ZMK_LV_FONT_DEFAULT_SMALL;
|
theme->font_small = CONFIG_ZMK_LV_FONT_DEFAULT_SMALL;
|
||||||
|
theme->font_normal = CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL;
|
||||||
|
theme->font_large = CONFIG_ZMK_LV_FONT_DEFAULT_LARGE;
|
||||||
|
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Create a basic theme which only sets font sizes.
|
||||||
|
static lv_theme_t theme;
|
||||||
|
|
||||||
|
static void theme_apply(lv_theme_t *th, lv_obj_t *obj) {
|
||||||
|
LV_UNUSED(th);
|
||||||
|
LV_UNUSED(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static lv_theme_t *initialize_theme(lv_disp_t *disp) {
|
||||||
|
theme.disp = disp;
|
||||||
|
theme.font_small = CONFIG_ZMK_LV_FONT_DEFAULT_SMALL;
|
||||||
|
theme.font_normal = CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL;
|
||||||
|
theme.font_large = CONFIG_ZMK_LV_FONT_DEFAULT_LARGE;
|
||||||
|
theme.apply_cb = theme_apply;
|
||||||
|
|
||||||
|
return &theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_LV_USE_THEME_MONO)
|
||||||
|
|
||||||
|
void zmk_display_initialize_theme(void) {
|
||||||
|
lv_disp_t *disp = lv_disp_get_default();
|
||||||
|
lv_theme_t *theme = initialize_theme(disp);
|
||||||
|
lv_disp_set_theme(disp, theme);
|
||||||
}
|
}
|
|
@ -63,3 +63,117 @@
|
||||||
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_16)
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_UNSCII_16)
|
||||||
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_unscii_16
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_SMALL &lv_font_unscii_16
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_8)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_8
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_10)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_10
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_12)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_12
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_14)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_14
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_16)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_16
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_18)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_18
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_20)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_20
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_22)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_22
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_24)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_24
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_26)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_26
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_28)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_28
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_30)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_30
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_32)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_32
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_34)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_34
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_36)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_36
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_38)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_38
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_40)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_40
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_42)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_42
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_44)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_44
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_46)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_46
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_48)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_48
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_12_SUBPX)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_12_subpx
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_28_COMPRESSED)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_montserrat_28_compressed
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_DEJAVU_16_PERSIAN_HEBREW)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_dejavu_16_persian_hebrew
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_SIMSUN_16_CJK)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_simsun_16_cjk
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_UNSCII_8)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_unscii_8
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_UNSCII_16)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL &lv_font_unscii_16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_8)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_8
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_10)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_10
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_12)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_12
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_14)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_14
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_16)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_16
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_18)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_18
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_20)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_20
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_22)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_22
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_24)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_24
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_26)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_26
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_28)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_28
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_30)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_30
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_32)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_32
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_34)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_34
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_36)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_36
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_38)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_38
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_40)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_40
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_42)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_42
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_44)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_44
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_46)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_46
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_48)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_48
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_12_SUBPX)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_12_subpx
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_28_COMPRESSED)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_montserrat_28_compressed
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_DEJAVU_16_PERSIAN_HEBREW)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_dejavu_16_persian_hebrew
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_SIMSUN_16_CJK)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_simsun_16_cjk
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_UNSCII_8)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_unscii_8
|
||||||
|
#elif defined(CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_UNSCII_16)
|
||||||
|
#define CONFIG_ZMK_LV_FONT_DEFAULT_LARGE &lv_font_unscii_16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void zmk_display_initialize_theme(void);
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
# Copyright (c) 2020 The ZMK Contributors
|
# Copyright (c) 2020 The ZMK Contributors
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
# Status widgets
|
||||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_BATTERY_STATUS app PRIVATE battery_status.c)
|
target_sources_ifdef(CONFIG_ZMK_WIDGET_BATTERY_STATUS app PRIVATE battery_status.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_OUTPUT_STATUS app PRIVATE output_status.c)
|
target_sources_ifdef(CONFIG_ZMK_WIDGET_OUTPUT_STATUS app PRIVATE output_status.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS app PRIVATE peripheral_status.c)
|
target_sources_ifdef(CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS app PRIVATE peripheral_status.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_LAYER_STATUS app PRIVATE layer_status.c)
|
target_sources_ifdef(CONFIG_ZMK_WIDGET_LAYER_STATUS app PRIVATE layer_status.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_WPM_STATUS app PRIVATE wpm_status.c)
|
target_sources_ifdef(CONFIG_ZMK_WIDGET_WPM_STATUS app PRIVATE wpm_status.c)
|
||||||
|
|
||||||
|
# BLE authentication widgets
|
||||||
|
target_sources_ifdef(CONFIG_ZMK_WIDGET_BLE_PASSKEY app PRIVATE ble_passkey.c)
|
||||||
|
|
|
@ -36,4 +36,10 @@ config ZMK_WIDGET_WPM_STATUS
|
||||||
select LV_USE_LABEL
|
select LV_USE_LABEL
|
||||||
select ZMK_WPM
|
select ZMK_WPM
|
||||||
|
|
||||||
|
config ZMK_WIDGET_BLE_PASSKEY
|
||||||
|
bool "Widget for displaying BLE pairing passkey"
|
||||||
|
depends on ZMK_BLE
|
||||||
|
select LV_USE_LABEL
|
||||||
|
select LV_USE_GRID
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
111
app/src/display/widgets/ble_passkey.c
Normal file
111
app/src/display/widgets/ble_passkey.c
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <lvgl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
|
#include <zmk/ble.h>
|
||||||
|
#include <zmk/ble/auth.h>
|
||||||
|
#include <zmk/display.h>
|
||||||
|
#include <zmk/display/widgets/ble_passkey.h>
|
||||||
|
#include <zmk/event_manager.h>
|
||||||
|
#include <zmk/events/ble_auth_state_changed.h>
|
||||||
|
|
||||||
|
static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets);
|
||||||
|
|
||||||
|
static void get_passkey_entry_text(char *str, size_t size, const struct zmk_ble_auth_state *state) {
|
||||||
|
if (state->cursor_index == 0) {
|
||||||
|
snprintf(str, size, "_");
|
||||||
|
} else if (state->cursor_index == 6) {
|
||||||
|
snprintf(str, size, "%06u " LV_SYMBOL_NEW_LINE, state->passkey);
|
||||||
|
} else {
|
||||||
|
snprintf(str, size, "%0*u_", state->cursor_index, state->passkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_passkey_widget(struct zmk_widget_ble_passkey *widget,
|
||||||
|
const struct zmk_ble_auth_state *state) {
|
||||||
|
const int profile_index = state->profile_index + 1;
|
||||||
|
lv_label_set_text_fmt(widget->profile, LV_SYMBOL_WIFI " %i", profile_index);
|
||||||
|
|
||||||
|
switch (state->mode) {
|
||||||
|
case ZMK_BLE_AUTH_MODE_PASSKEY_CONFIRM:
|
||||||
|
lv_label_set_text_static(widget->title, "Confirm PIN");
|
||||||
|
lv_label_set_text_fmt(widget->passkey, "%06u " LV_SYMBOL_NEW_LINE, state->passkey);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ZMK_BLE_AUTH_MODE_PASSKEY_ENTRY: {
|
||||||
|
char passkey[16];
|
||||||
|
lv_label_set_text_static(widget->title, "Enter PIN");
|
||||||
|
get_passkey_entry_text(passkey, sizeof(passkey), state);
|
||||||
|
lv_label_set_text(widget->passkey, passkey);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ZMK_BLE_AUTH_MODE_PASSKEY_DISPLAY:
|
||||||
|
default:
|
||||||
|
lv_label_set_text_static(widget->title, "Pairing PIN");
|
||||||
|
lv_label_set_text_fmt(widget->passkey, "%06u", state->passkey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ble_passkey_update_cb(struct zmk_ble_auth_state state) {
|
||||||
|
struct zmk_widget_ble_passkey *widget;
|
||||||
|
SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { update_passkey_widget(widget, &state); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct zmk_ble_auth_state ble_passkey_get_state(const zmk_event_t *eh) {
|
||||||
|
return zmk_ble_get_auth_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
ZMK_DISPLAY_WIDGET_LISTENER(widget_ble_passkey, struct zmk_ble_auth_state, ble_passkey_update_cb,
|
||||||
|
ble_passkey_get_state);
|
||||||
|
ZMK_SUBSCRIPTION(widget_ble_passkey, zmk_ble_auth_state_changed);
|
||||||
|
|
||||||
|
static bool is_small_display(void) { return lv_disp_get_ver_res(lv_disp_get_default()) < 40; }
|
||||||
|
|
||||||
|
int zmk_widget_ble_passkey_init(struct zmk_widget_ble_passkey *widget, lv_obj_t *parent) {
|
||||||
|
static const lv_coord_t col_dsc[] = {LV_GRID_CONTENT, LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
|
||||||
|
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
|
||||||
|
|
||||||
|
sys_slist_append(&widgets, &widget->node);
|
||||||
|
|
||||||
|
const bool is_small = is_small_display();
|
||||||
|
const lv_font_t *passkey_font =
|
||||||
|
is_small ? lv_theme_get_font_normal(parent) : lv_theme_get_font_large(parent);
|
||||||
|
|
||||||
|
widget->obj = lv_obj_create(parent);
|
||||||
|
lv_obj_set_scrollbar_mode(widget->obj, LV_SCROLLBAR_MODE_OFF);
|
||||||
|
lv_obj_set_style_border_width(widget->obj, 0, 0);
|
||||||
|
lv_obj_set_grid_dsc_array(widget->obj, col_dsc, row_dsc);
|
||||||
|
lv_obj_set_layout(widget->obj, LV_LAYOUT_GRID);
|
||||||
|
|
||||||
|
if (is_small) {
|
||||||
|
lv_obj_set_style_pad_all(widget->obj, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
widget->profile = lv_label_create(widget->obj);
|
||||||
|
lv_obj_set_style_text_font(widget->profile, lv_theme_get_font_small(parent), LV_PART_MAIN);
|
||||||
|
lv_obj_set_grid_cell(widget->profile, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 0, 1);
|
||||||
|
|
||||||
|
widget->title = lv_label_create(widget->obj);
|
||||||
|
lv_obj_set_style_text_font(widget->title, lv_theme_get_font_small(parent), LV_PART_MAIN);
|
||||||
|
lv_obj_set_grid_cell(widget->title, LV_GRID_ALIGN_CENTER, 1, 1, LV_GRID_ALIGN_START, 0, 1);
|
||||||
|
|
||||||
|
widget->passkey = lv_label_create(widget->obj);
|
||||||
|
lv_obj_set_style_text_font(widget->passkey, passkey_font, LV_PART_MAIN);
|
||||||
|
lv_obj_set_grid_cell(widget->passkey, LV_GRID_ALIGN_CENTER, 0, 2, LV_GRID_ALIGN_CENTER, 1, 1);
|
||||||
|
|
||||||
|
widget_ble_passkey_init();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_obj_t *zmk_widget_ble_passkey_obj(struct zmk_widget_ble_passkey *widget) { return widget->obj; }
|
9
app/src/events/ble_auth_state_changed.c
Normal file
9
app/src/events/ble_auth_state_changed.c
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zmk/events/ble_auth_state_changed.h>
|
||||||
|
|
||||||
|
ZMK_EVENT_IMPL(zmk_ble_auth_state_changed);
|
|
@ -9,7 +9,24 @@ See [Configuration Overview](index.md) for instructions on how to change these s
|
||||||
|
|
||||||
## Kconfig
|
## Kconfig
|
||||||
|
|
||||||
| Option | Type | Description | Default |
|
| Option | Type | Description | Default |
|
||||||
| ------------------------------------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
| ------------------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------- | ------- |
|
||||||
| `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Enable passkey entry during pairing for enhanced security. (Note: After enabling this, you will need to re-pair all previously paired hosts) | n |
|
| `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications. | y |
|
||||||
| `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications. | y |
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
The following options can be used to mitigate man-in-the-middle (MITM) attacks during initial pairing. These require features which are not necessarily present on all keyboards, so they are not enabled by default.
|
||||||
|
|
||||||
|
| Option | Type | Description | Default |
|
||||||
|
| -------------------------------- | ---- | --------------------------------------- | -------------------- |
|
||||||
|
| `CONFIG_ZMK_BLE_PASSKEY_CONFIRM` | bool | Enable pairing with numeric comparison. | n |
|
||||||
|
| `CONFIG_ZMK_BLE_PASSKEY_DISPLAY` | bool | Enable passkey display during pairing. | `CONFIG_ZMK_DISPLAY` |
|
||||||
|
| `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Enable passkey entry during pairing. | n |
|
||||||
|
|
||||||
|
`CONFIG_ZMK_BLE_PASSKEY_ENTRY` enables pairing with passkey entry on the keyboard. The host will display a 6-digit passkey which you must type on the keyboard, then press `ENTER` to complete pairing. Pressing `BACKSPACE` will delete the last digit, and pressing `ESCAPE` will cancel pairing. This requires that you have the digits `N0`-`N9` or `KP_N0`-`KP_N9` and `ENTER` or `KP_ENTER` bound to your keymap.
|
||||||
|
|
||||||
|
`CONFIG_ZMK_BLE_PASSKEY_DISPLAY` enables pairing with passkey entry on the host. The keyboard will display a 6-digit passkey which you must enter on the host to complete pairing. This requires only that your keyboard has a display, so it is automatically enabled with `CONFIG_ZMK_DISPLAY`.
|
||||||
|
|
||||||
|
`CONFIG_ZMK_BLE_PASSKEY_CONFIRM` enables pairing with numeric comparison. Both the host and keyboard will display a 6-digit passkey. You must check that they match, then press `ENTER` on they keyboard and confirm on the host as well to complete pairing. Pressing `ESCAPE` will cancel pairing. This requires that your keyboard has a display and you have `ENTER` or `KP_ENTER` bound to your keymap.
|
||||||
|
|
||||||
|
If multiple of the above options are enabled, the host will typically try to use numeric comparison first, then fallback to one of the passkey entry options.
|
||||||
|
|
|
@ -26,6 +26,8 @@ Definition files:
|
||||||
|
|
||||||
Note that `CONFIG_ZMK_DISPLAY_INVERT` setting might not work as expected with custom status screens that utilize images.
|
Note that `CONFIG_ZMK_DISPLAY_INVERT` setting might not work as expected with custom status screens that utilize images.
|
||||||
|
|
||||||
|
### Status Screen
|
||||||
|
|
||||||
If `CONFIG_ZMK_DISPLAY` is enabled, exactly zero or one of the following options must be set to `y`. The first option is used if none are set.
|
If `CONFIG_ZMK_DISPLAY` is enabled, exactly zero or one of the following options must be set to `y`. The first option is used if none are set.
|
||||||
|
|
||||||
| Config | Description |
|
| Config | Description |
|
||||||
|
@ -33,6 +35,29 @@ If `CONFIG_ZMK_DISPLAY` is enabled, exactly zero or one of the following options
|
||||||
| `CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN` | Use the built-in status screen |
|
| `CONFIG_ZMK_DISPLAY_STATUS_SCREEN_BUILT_IN` | Use the built-in status screen |
|
||||||
| `CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM` | Use a custom status screen |
|
| `CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM` | Use a custom status screen |
|
||||||
|
|
||||||
|
If `CONFIG_ZMK_DISPLAY_STATUS_SCREEN_CUSTOM` is enabled, you must add a C file to the build which implements the following function.
|
||||||
|
|
||||||
|
```c
|
||||||
|
lv_obj_t *zmk_display_status_screen(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pairing Screen
|
||||||
|
|
||||||
|
If `CONFIG_ZMK_DISPLAY` and `CONFIG_ZMK_BLE` are enabled, exactly zero or one of the following options must be set to `y`. The first option is used if none are set.
|
||||||
|
|
||||||
|
| Config | Description |
|
||||||
|
| -------------------------------------------- | -------------------------------------------- |
|
||||||
|
| `CONFIG_ZMK_DISPLAY_PAIRING_SCREEN_BUILT_IN` | Use the built-in bluetooth pairing screen |
|
||||||
|
| `CONFIG_ZMK_DISPLAY_PAIRING_SCREEN_CUSTOM` | Use a custom bluetooth pairing screen screen |
|
||||||
|
|
||||||
|
If `CONFIG_ZMK_DISPLAY_PAIRING_SCREEN_CUSTOM` is enabled, you must add a C file to the build which implements the following function.
|
||||||
|
|
||||||
|
```c
|
||||||
|
lv_obj_t *zmk_display_pairing_screen(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Work Queue
|
||||||
|
|
||||||
If `CONFIG_ZMK_DISPLAY` is enabled, exactly zero or one of the following options must be set to `y`. The first option is used if none are set.
|
If `CONFIG_ZMK_DISPLAY` is enabled, exactly zero or one of the following options must be set to `y`. The first option is used if none are set.
|
||||||
|
|
||||||
| Config | Description |
|
| Config | Description |
|
||||||
|
@ -47,9 +72,29 @@ Using a dedicated thread requires more memory but prevents displays with slow up
|
||||||
| `CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE` | int | Stack size for the UI thread | 2048 |
|
| `CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE` | int | Stack size for the UI thread | 2048 |
|
||||||
| `CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_PRIORITY` | int | Priority for the UI thread | 5 |
|
| `CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_PRIORITY` | int | Priority for the UI thread | 5 |
|
||||||
|
|
||||||
You must also configure the driver for your display. ZMK provides the following display drivers:
|
### Default Fonts
|
||||||
|
|
||||||
- [IL0323](https://github.com/zmkfirmware/zmk/blob/main/app/module/drivers/display/Kconfig.il0323)
|
ZMK's built-in screens use three sizes of fonts:
|
||||||
|
|
||||||
|
| Config | Default |
|
||||||
|
| ----------------------------------- | ------------------------------------------------- |
|
||||||
|
| `CONFIG_ZMK_LV_FONT_DEFAULT_SMALL` | `CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_12` |
|
||||||
|
| `CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL` | `CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_16` |
|
||||||
|
| `CONFIG_ZMK_LV_FONT_DEFAULT_LARGE` | `CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_20` |
|
||||||
|
|
||||||
|
See [zmk/app/src/display/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/display/Kconfig) for a full list of the possible fonts. To change the font, set the option for the specific font to `y`. For example, to increase all font sizes to be slightly larger than the defaults, you could set
|
||||||
|
|
||||||
|
```kconfig
|
||||||
|
CONFIG_ZMK_LV_FONT_DEFAULT_SMALL_MONTSERRAT_14=y
|
||||||
|
CONFIG_ZMK_LV_FONT_DEFAULT_NORMAL_MONTSERRAT_18=y
|
||||||
|
CONFIG_ZMK_LV_FONT_DEFAULT_LARGE_MONTSERRAT_22=y
|
||||||
|
```
|
||||||
|
|
||||||
|
### Display Driver
|
||||||
|
|
||||||
|
You may also need to configure the driver for your display. ZMK provides the following display drivers:
|
||||||
|
|
||||||
|
- [IL0323 E-Paper Display](https://github.com/zmkfirmware/zmk/blob/main/app/module/drivers/display/Kconfig.il0323)
|
||||||
|
|
||||||
Zephyr provides several display drivers as well. Search for the name of your display in [Zephyr's Kconfig options](https://docs.zephyrproject.org/latest/kconfig.html) documentation.
|
Zephyr provides several display drivers as well. Search for the name of your display in [Zephyr's Kconfig options](https://docs.zephyrproject.org/latest/kconfig.html) documentation.
|
||||||
|
|
||||||
|
@ -57,8 +102,9 @@ Zephyr provides several display drivers as well. Search for the name of your dis
|
||||||
|
|
||||||
See the Devicetree bindings for your display. Here are the bindings for common displays:
|
See the Devicetree bindings for your display. Here are the bindings for common displays:
|
||||||
|
|
||||||
- [IL0323](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/display/gooddisplay%2Cil0323.yaml)
|
- [IL0323 E-Paper Display](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/display/gooddisplay%2Cil0323.yaml)
|
||||||
- [SSD1306 (i2c)](https://docs.zephyrproject.org/latest/build/dts/api/bindings/display/solomon,ssd1306fb-i2c.html)
|
- [LS0xx Memory LCD](https://docs.zephyrproject.org/latest/build/dts/api/bindings/display/sharp%2Cls0xx.html)
|
||||||
- [SSD1306 (spi)](https://docs.zephyrproject.org/latest/build/dts/api/bindings/display/solomon,ssd1306fb-spi.html)
|
- [SSD1306 OLED (i2c)](https://docs.zephyrproject.org/latest/build/dts/api/bindings/display/solomon,ssd1306fb-i2c.html)
|
||||||
|
- [SSD1306 OLED (spi)](https://docs.zephyrproject.org/latest/build/dts/api/bindings/display/solomon,ssd1306fb-spi.html)
|
||||||
|
|
||||||
A full list of drivers provided by Zephyr can be found in [Zephyr's Devicetree bindings index](https://docs.zephyrproject.org/latest/build/dts/api/bindings.html).
|
A full list of drivers provided by Zephyr can be found in [Zephyr's Devicetree bindings index](https://docs.zephyrproject.org/latest/build/dts/api/bindings.html).
|
||||||
|
|
|
@ -15,7 +15,7 @@ Bluetooth 4.2 or newer is required in order to connect to a ZMK keyboard. ZMK im
|
||||||
|
|
||||||
BLE connections between keyboards and hosts are secured by an initial pairing/bonding process that establishes long term keys (LTK) shared between the two sides, using Elliptic Curve Diffie Hellman (ECDH) for key generation. The same security is used to secure the communication between the two sides of split keyboards running ZMK.
|
BLE connections between keyboards and hosts are secured by an initial pairing/bonding process that establishes long term keys (LTK) shared between the two sides, using Elliptic Curve Diffie Hellman (ECDH) for key generation. The same security is used to secure the communication between the two sides of split keyboards running ZMK.
|
||||||
|
|
||||||
The only known vulnerability in the protocol is a risk of an active man-in-the-middle (MITM) attack exactly during the initial pairing, which can be mitigated in the future using the Numeric Comparison association model. Support for that in ZMK is still experimental, so if you have serious concerns about an active attacker with physical proximity to your device, consider only pairing/bonding your keyboards in a controlled environment.
|
The only known vulnerability in the protocol is a risk of an active man-in-the-middle (MITM) attack exactly during the initial pairing, which can be mitigated using the Numeric Comparison or Passkey Entry association models. These may be enabled with the [`CONFIG_ZMK_BLE_PASSKEY_*` options](../config/bluetooth.md#security). Support for that in ZMK is still experimental, so if you have serious concerns about an active attacker with physical proximity to your device, consider only pairing/bonding your keyboards in a controlled environment.
|
||||||
|
|
||||||
## Profiles
|
## Profiles
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue