@ -4,58 +4,238 @@
@@ -4,58 +4,238 @@
* SPDX - License - Identifier : MIT
*/
# include <init.h>
# include <settings/settings.h>
# include <zmk/ble.h>
# include <zmk/endpoints.h>
# include <zmk/hid.h>
# include <zmk/usb.h>
# include <zmk/hog.h>
# include <zmk/event-manager.h>
# include <zmk/events/ble-active-profile-changed.h>
# include <zmk/events/usb-conn-state-changed.h>
# include <logging/log.h>
LOG_MODULE_DECLARE ( zmk , CONFIG_ZMK_LOG_LEVEL ) ;
int zmk_endpoints_send_report ( u8_t usage_page ) {
int err ;
struct zmk_hid_keypad_report * keypad_report ;
struct zmk_hid_consumer_report * consumer_report ;
LOG_DBG ( " usage page 0x%02X " , usage_page ) ;
switch ( usage_page ) {
case USAGE_KEYPAD :
keypad_report = zmk_hid_get_keypad_report ( ) ;
# ifdef CONFIG_ZMK_USB
if ( zmk_usb_hid_send_report ( ( u8_t * ) keypad_report , sizeof ( struct zmk_hid_keypad_report ) ) ! =
0 ) {
LOG_DBG ( " USB Send Failed " ) ;
# define DEFAULT_ENDPOINT \
COND_CODE_1 ( IS_ENABLED ( CONFIG_ZMK_BLE ) , ( ZMK_ENDPOINT_BLE ) , ( ZMK_ENDPOINT_USB ) )
static enum zmk_endpoint current_endpoint = DEFAULT_ENDPOINT ;
static enum zmk_endpoint preferred_endpoint =
ZMK_ENDPOINT_USB ; /* Used if multiple endpoints are ready */
static void update_current_endpoint ( ) ;
int zmk_endpoints_select ( enum zmk_endpoint endpoint ) {
LOG_DBG ( " Selected endpoint %d " , endpoint ) ;
if ( preferred_endpoint = = endpoint ) {
return 0 ;
}
preferred_endpoint = endpoint ;
# if IS_ENABLED(CONFIG_SETTINGS)
settings_save_one ( " endpoints/preferred " , & preferred_endpoint , sizeof ( preferred_endpoint ) ) ;
# endif
update_current_endpoint ( ) ;
return 0 ;
}
int zmk_endpoints_toggle ( ) {
enum zmk_endpoint new_endpoint =
( preferred_endpoint = = ZMK_ENDPOINT_USB ) ? ZMK_ENDPOINT_BLE : ZMK_ENDPOINT_USB ;
return zmk_endpoints_select ( new_endpoint ) ;
}
static int send_keypad_report ( ) {
struct zmk_hid_keypad_report * keypad_report = zmk_hid_get_keypad_report ( ) ;
switch ( current_endpoint ) {
# if IS_ENABLED(CONFIG_ZMK_USB)
case ZMK_ENDPOINT_USB : {
int err = zmk_usb_hid_send_report ( ( u8_t * ) keypad_report , sizeof ( * keypad_report ) ) ;
if ( err ) {
LOG_ERR ( " FAILED TO SEND OVER USB: %d " , err ) ;
}
# endif /* CONFIG_ZMK_USB */
return err ;
}
# endif /* IS_ENABLED(CONFIG_ZMK_USB) */
# ifdef CONFIG_ZMK_BLE
err = zmk_hog_send_keypad_report ( & keypad_report - > body ) ;
# if IS_ENABLED(CONFIG_ZMK_BLE)
case ZMK_ENDPOINT_BLE : {
int err = zmk_hog_send_keypad_report ( & keypad_report - > body ) ;
if ( err ) {
LOG_ERR ( " FAILED TO SEND OVER HOG: %d " , err ) ;
}
# endif /* CONFIG_ZMK_BLE */
return err ;
}
# endif /* IS_ENABLED(CONFIG_ZMK_BLE) */
break ;
case USAGE_CONSUMER :
consumer_report = zmk_hid_get_consumer_report ( ) ;
# ifdef CONFIG_ZMK_USB
if ( zmk_usb_hid_send_report ( ( u8_t * ) consumer_report ,
sizeof ( struct zmk_hid_consumer_report ) ) ! = 0 ) {
LOG_DBG ( " USB Send Failed " ) ;
default :
LOG_ERR ( " Unsupported endpoint %d " , current_endpoint ) ;
return - ENOTSUP ;
}
}
static int send_consumer_report ( ) {
struct zmk_hid_consumer_report * consumer_report = zmk_hid_get_consumer_report ( ) ;
switch ( current_endpoint ) {
# if IS_ENABLED(CONFIG_ZMK_USB)
case ZMK_ENDPOINT_USB : {
int err = zmk_usb_hid_send_report ( ( u8_t * ) consumer_report , sizeof ( * consumer_report ) ) ;
if ( err ) {
LOG_ERR ( " FAILED TO SEND OVER USB: %d " , err ) ;
}
# endif /* CONFIG_ZMK_USB */
return err ;
}
# endif /* IS_ENABLED(CONFIG_ZMK_USB) */
# ifdef CONFIG_ZMK_BLE
err = zmk_hog_send_consumer_report ( & consumer_report - > body ) ;
# if IS_ENABLED(CONFIG_ZMK_BLE)
case ZMK_ENDPOINT_BLE : {
int err = zmk_hog_send_consumer_report ( & consumer_report - > body ) ;
if ( err ) {
LOG_ERR ( " FAILED TO SEND OVER HOG: %d " , err ) ;
}
# endif /* CONFIG_ZMK_BLE */
return err ;
}
# endif /* IS_ENABLED(CONFIG_ZMK_BLE) */
break ;
default :
LOG_ERR ( " Unsupported endpoint %d " , current_endpoint ) ;
return - ENOTSUP ;
}
}
int zmk_endpoints_send_report ( u8_t usage_page ) {
LOG_DBG ( " usage page 0x%02X " , usage_page ) ;
switch ( usage_page ) {
case USAGE_KEYPAD :
return send_keypad_report ( ) ;
case USAGE_CONSUMER :
return send_consumer_report ( ) ;
default :
LOG_ERR ( " Unsupported usage page %d " , usage_page ) ;
return - ENOTSUP ;
}
}
# if IS_ENABLED(CONFIG_SETTINGS)
static int endpoints_handle_set ( const char * name , size_t len , settings_read_cb read_cb ,
void * cb_arg ) {
LOG_DBG ( " Setting endpoint value %s " , log_strdup ( name ) ) ;
if ( settings_name_steq ( name , " preferred " , NULL ) ) {
if ( len ! = sizeof ( enum zmk_endpoint ) ) {
LOG_ERR ( " Invalid endpoint size (got %d expected %d) " , len , sizeof ( enum zmk_endpoint ) ) ;
return - EINVAL ;
}
int err = read_cb ( cb_arg , & preferred_endpoint , sizeof ( enum zmk_endpoint ) ) ;
if ( err < = 0 ) {
LOG_ERR ( " Failed to read preferred endpoint from settings (err %d) " , err ) ;
return err ;
}
update_current_endpoint ( ) ;
}
return 0 ;
}
struct settings_handler endpoints_handler = { . name = " endpoints " , . h_set = endpoints_handle_set } ;
# endif /* IS_ENABLED(CONFIG_SETTINGS) */
static int zmk_endpoints_init ( struct device * _arg ) {
# if IS_ENABLED(CONFIG_SETTINGS)
settings_subsys_init ( ) ;
int err = settings_register ( & endpoints_handler ) ;
if ( err ) {
LOG_ERR ( " Failed to register the endpoints settings handler (err %d) " , err ) ;
return err ;
}
settings_load ( ) ;
# endif
return 0 ;
}
static bool is_usb_ready ( ) {
# if IS_ENABLED(CONFIG_ZMK_USB)
return zmk_usb_is_hid_ready ( ) ;
# else
return false ;
# endif
}
static bool is_ble_ready ( ) {
# if IS_ENABLED(CONFIG_ZMK_BLE)
return zmk_ble_active_profile_is_connected ( ) ;
# else
return false ;
# endif
}
static enum zmk_endpoint get_selected_endpoint ( ) {
if ( is_ble_ready ( ) ) {
if ( is_usb_ready ( ) ) {
LOG_DBG ( " Both endpoints are ready. Using %d " , preferred_endpoint ) ;
return preferred_endpoint ;
}
LOG_DBG ( " Only BLE is ready. " ) ;
return ZMK_ENDPOINT_BLE ;
}
if ( is_usb_ready ( ) ) {
LOG_DBG ( " Only USB is ready. " ) ;
return ZMK_ENDPOINT_USB ;
}
LOG_DBG ( " No endpoints are ready. " ) ;
return DEFAULT_ENDPOINT ;
}
static void disconnect_current_endpoint ( ) {
zmk_hid_keypad_clear ( ) ;
zmk_hid_consumer_clear ( ) ;
zmk_endpoints_send_report ( USAGE_KEYPAD ) ;
zmk_endpoints_send_report ( USAGE_CONSUMER ) ;
}
static void update_current_endpoint ( ) {
enum zmk_endpoint new_endpoint = get_selected_endpoint ( ) ;
if ( new_endpoint ! = current_endpoint ) {
/* Cancel all current keypresses so keys don't stay held on the old endpoint. */
disconnect_current_endpoint ( ) ;
current_endpoint = new_endpoint ;
LOG_INF ( " Endpoint changed: %d " , current_endpoint ) ;
}
}
static int endpoint_listener ( const struct zmk_event_header * eh ) {
update_current_endpoint ( ) ;
return 0 ;
}
ZMK_LISTENER ( endpoint_listener , endpoint_listener ) ;
# if IS_ENABLED(CONFIG_ZMK_USB)
ZMK_SUBSCRIPTION ( endpoint_listener , usb_conn_state_changed ) ;
# endif
# if IS_ENABLED(CONFIG_ZMK_BLE)
ZMK_SUBSCRIPTION ( endpoint_listener , ble_active_profile_changed ) ;
# endif
SYS_INIT ( zmk_endpoints_init , APPLICATION , CONFIG_APPLICATION_INIT_PRIORITY ) ;