@ -24,6 +24,7 @@ void free_sway_binding(struct sway_binding *binding) {
}
list_free_items_and_destroy ( binding - > keys ) ;
list_free_items_and_destroy ( binding - > syms ) ;
free ( binding - > input ) ;
free ( binding - > command ) ;
free ( binding ) ;
@ -249,14 +250,30 @@ static struct cmd_results *switch_binding_remove(
switchcombo ) ;
}
static struct cmd_results * binding_add ( struct sway_binding * binding ,
list_t * mode_bindings , const char * bindtype ,
const char * keycombo , bool warn ) {
// overwrite the binding if it already exists
bool overwritten = false ;
/**
* Insert or update the binding .
* Return the binding which has been replaced or NULL .
*/
static struct sway_binding * binding_upsert ( struct sway_binding * binding ,
list_t * mode_bindings ) {
for ( int i = 0 ; i < mode_bindings - > length ; + + i ) {
struct sway_binding * config_binding = mode_bindings - > items [ i ] ;
if ( binding_key_compare ( binding , config_binding ) ) {
mode_bindings - > items [ i ] = binding ;
return config_binding ;
}
}
list_add ( mode_bindings , binding ) ;
return NULL ;
}
static struct cmd_results * binding_add ( struct sway_binding * binding ,
list_t * mode_bindings , const char * bindtype ,
const char * keycombo , bool warn ) {
struct sway_binding * config_binding = binding_upsert ( binding , mode_bindings ) ;
if ( config_binding ) {
sway_log ( SWAY_INFO , " Overwriting binding '%s' for device '%s' "
" to `%s` from `%s` " , keycombo , binding - > input ,
binding - > command , config_binding - > command ) ;
@ -267,13 +284,7 @@ static struct cmd_results *binding_add(struct sway_binding *binding,
config_binding - > command ) ;
}
free_sway_binding ( config_binding ) ;
mode_bindings - > items [ i ] = binding ;
overwritten = true ;
}
}
if ( ! overwritten ) {
list_add ( mode_bindings , binding ) ;
} else {
sway_log ( SWAY_DEBUG , " %s - Bound %s to command `%s` for device '%s' " ,
bindtype , keycombo , binding - > command , binding - > input ) ;
}
@ -329,7 +340,6 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
bool exclude_titlebar = false ;
bool warn = true ;
// Handle --release and --locked
while ( argc > 0 ) {
if ( strcmp ( " --release " , argv [ 0 ] ) = = 0 ) {
binding - > flags | = BINDING_RELEASE ;
@ -339,6 +349,10 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
binding - > flags | = BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR ;
} else if ( strcmp ( " --border " , argv [ 0 ] ) = = 0 ) {
binding - > flags | = BINDING_BORDER ;
} else if ( strcmp ( " --to-code " , argv [ 0 ] ) = = 0 ) {
if ( ! bindcode ) {
binding - > flags | = BINDING_CODE ;
}
} else if ( strcmp ( " --exclude-titlebar " , argv [ 0 ] ) = = 0 ) {
exclude_titlebar = true ;
} else if ( strncmp ( " --input-device= " , argv [ 0 ] ,
@ -410,6 +424,12 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
// sort ascending
list_qsort ( binding - > keys , key_qsort_cmp ) ;
// translate keysyms into keycodes
if ( ! translate_binding ( binding ) ) {
sway_log ( SWAY_INFO ,
" Unable to translate bindsym into bindcode: %s " , argv [ 0 ] ) ;
}
list_t * mode_bindings ;
if ( binding - > type = = BINDING_KEYCODE ) {
mode_bindings = config - > current_mode - > keycode_bindings ;
@ -566,3 +586,114 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding)
ipc_event_binding ( binding ) ;
}
}
/**
* The last found keycode associated with the keysym
* and the total count of matches .
*/
struct keycode_matches {
xkb_keysym_t keysym ;
xkb_keycode_t keycode ;
int count ;
} ;
/**
* Iterate through keycodes in the keymap to find ones matching
* the specified keysym .
*/
static void find_keycode ( struct xkb_keymap * keymap ,
xkb_keycode_t keycode , void * data ) {
xkb_keysym_t keysym = xkb_state_key_get_one_sym (
config - > keysym_translation . xkb_state , keycode ) ;
if ( keysym = = XKB_KEY_NoSymbol ) {
return ;
}
struct keycode_matches * matches = data ;
if ( matches - > keysym = = keysym ) {
matches - > keycode = keycode ;
matches - > count + + ;
}
}
/**
* Return the keycode for the specified keysym .
*/
static struct keycode_matches get_keycode_for_keysym ( xkb_keysym_t keysym ) {
struct keycode_matches matches = {
. keysym = keysym ,
. keycode = XKB_KEYCODE_INVALID ,
. count = 0 ,
} ;
xkb_keymap_key_for_each ( config - > keysym_translation . xkb_keymap ,
find_keycode , & matches ) ;
return matches ;
}
bool translate_binding ( struct sway_binding * binding ) {
if ( ( binding - > flags & BINDING_CODE ) = = 0 ) {
return true ;
}
switch ( binding - > type ) {
// a bindsym to translate
case BINDING_KEYSYM :
binding - > syms = binding - > keys ;
binding - > keys = create_list ( ) ;
break ;
// a bindsym to re-translate
case BINDING_KEYCODE :
list_free_items_and_destroy ( binding - > keys ) ;
binding - > keys = create_list ( ) ;
break ;
default :
return true ;
}
for ( int i = 0 ; i < binding - > syms - > length ; + + i ) {
xkb_keysym_t * keysym = binding - > syms - > items [ i ] ;
struct keycode_matches matches = get_keycode_for_keysym ( * keysym ) ;
if ( matches . count ! = 1 ) {
sway_log ( SWAY_INFO , " Unable to convert keysym %d into "
" a single keycode (found %d matches) " ,
* keysym , matches . count ) ;
goto error ;
}
xkb_keycode_t * keycode = malloc ( sizeof ( xkb_keycode_t ) ) ;
if ( ! keycode ) {
sway_log ( SWAY_ERROR , " Unable to allocate memory for a keycode " ) ;
goto error ;
}
* keycode = matches . keycode ;
list_add ( binding - > keys , keycode ) ;
}
list_qsort ( binding - > keys , key_qsort_cmp ) ;
binding - > type = BINDING_KEYCODE ;
return true ;
error :
list_free_items_and_destroy ( binding - > keys ) ;
binding - > type = BINDING_KEYSYM ;
binding - > keys = binding - > syms ;
binding - > syms = NULL ;
return false ;
}
void binding_add_translated ( struct sway_binding * binding ,
list_t * mode_bindings ) {
struct sway_binding * config_binding =
binding_upsert ( binding , mode_bindings ) ;
if ( config_binding ) {
sway_log ( SWAY_INFO , " Overwriting binding for device '%s' "
" to `%s` from `%s` " , binding - > input ,
binding - > command , config_binding - > command ) ;
free_sway_binding ( config_binding ) ;
}
}