mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-18 13:54:36 -05:00
keybindings: Implement on-release bindings
Signed-off-by: Quentin Glidic <sardemff7+git@sardemff7.net>
This commit is contained in:
parent
20791d4a71
commit
67b0ce036f
8 changed files with 86 additions and 6 deletions
|
@ -704,6 +704,8 @@ The first two fields specify the alpha level. This determines the amount of tran
|
||||||
To get a full list of keybindings, see `rofi -dump-xresources | grep kb-`.
|
To get a full list of keybindings, see `rofi -dump-xresources | grep kb-`.
|
||||||
Keybindings can be modified using the configuration systems.
|
Keybindings can be modified using the configuration systems.
|
||||||
|
|
||||||
|
A keybinding starting with `!` will act when all keys have been released.
|
||||||
|
|
||||||
## Available Modi
|
## Available Modi
|
||||||
|
|
||||||
### Window
|
### Window
|
||||||
|
|
|
@ -1160,6 +1160,9 @@ The first two fields specify the alpha level\. This determines the amount of tra
|
||||||
.P
|
.P
|
||||||
To get a full list of keybindings, see \fBrofi \-dump\-xresources | grep kb\-\fR\. Keybindings can be modified using the configuration systems\.
|
To get a full list of keybindings, see \fBrofi \-dump\-xresources | grep kb\-\fR\. Keybindings can be modified using the configuration systems\.
|
||||||
.
|
.
|
||||||
|
.P
|
||||||
|
A keybinding starting with \fB!\fR will act when all keys have been released\.
|
||||||
|
.
|
||||||
.SH "Available Modi"
|
.SH "Available Modi"
|
||||||
.
|
.
|
||||||
.SS "Window"
|
.SS "Window"
|
||||||
|
|
|
@ -100,5 +100,7 @@ void cleanup_abe ( void );
|
||||||
*/
|
*/
|
||||||
KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key );
|
KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key );
|
||||||
|
|
||||||
|
void abe_trigger_release ( void );
|
||||||
|
|
||||||
/*@}*/
|
/*@}*/
|
||||||
#endif // ROFI_KEYB_H
|
#endif // ROFI_KEYB_H
|
||||||
|
|
|
@ -81,6 +81,8 @@ int take_keyboard ( xcb_window_t w );
|
||||||
*/
|
*/
|
||||||
unsigned int x11_canonalize_mask ( unsigned int mask );
|
unsigned int x11_canonalize_mask ( unsigned int mask );
|
||||||
|
|
||||||
|
unsigned int x11_get_current_mask ( xkb_stuff *xkb );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param combo String representing the key combo
|
* @param combo String representing the key combo
|
||||||
* @param mod [out] The modifier specified (or AnyModifier if not specified)
|
* @param mod [out] The modifier specified (or AnyModifier if not specified)
|
||||||
|
@ -88,7 +90,7 @@ unsigned int x11_canonalize_mask ( unsigned int mask );
|
||||||
*
|
*
|
||||||
* Parse key from user input string.
|
* Parse key from user input string.
|
||||||
*/
|
*/
|
||||||
gboolean x11_parse_key ( char *combo, unsigned int *mod, xkb_keysym_t *key );
|
gboolean x11_parse_key ( char *combo, unsigned int *mod, xkb_keysym_t *key, gboolean *release );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param display The connection to the X server.
|
* @param display The connection to the X server.
|
||||||
|
|
|
@ -8,6 +8,7 @@ typedef struct
|
||||||
{
|
{
|
||||||
unsigned int modmask;
|
unsigned int modmask;
|
||||||
xkb_keysym_t keysym;
|
xkb_keysym_t keysym;
|
||||||
|
gboolean release;
|
||||||
} KeyBinding;
|
} KeyBinding;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -114,7 +115,8 @@ gboolean parse_keys_abe ( void )
|
||||||
for ( char *entry = strtok_r ( keystr, sep, &sp ); entry != NULL; entry = strtok_r ( NULL, sep, &sp ) ) {
|
for ( char *entry = strtok_r ( keystr, sep, &sp ); entry != NULL; entry = strtok_r ( NULL, sep, &sp ) ) {
|
||||||
abe[iter].kb = g_realloc ( abe[iter].kb, ( abe[iter].num_bindings + 1 ) * sizeof ( KeyBinding ) );
|
abe[iter].kb = g_realloc ( abe[iter].kb, ( abe[iter].num_bindings + 1 ) * sizeof ( KeyBinding ) );
|
||||||
KeyBinding *kb = &( abe[iter].kb[abe[iter].num_bindings] );
|
KeyBinding *kb = &( abe[iter].kb[abe[iter].num_bindings] );
|
||||||
if ( !x11_parse_key ( entry, &( kb->modmask ), &( kb->keysym ) ) ) {
|
memset(kb, 0, sizeof(KeyBinding));
|
||||||
|
if ( !x11_parse_key ( entry, &( kb->modmask ), &( kb->keysym ), &( kb->release ) ) ) {
|
||||||
g_free ( keystr );
|
g_free ( keystr );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +137,8 @@ void cleanup_abe ( void )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean _abe_trigger_on_release[NUM_ABE] = { 0 };
|
||||||
|
|
||||||
static gboolean abe_test_action ( KeyBindingAction action, unsigned int mask, xkb_keysym_t key )
|
static gboolean abe_test_action ( KeyBindingAction action, unsigned int mask, xkb_keysym_t key )
|
||||||
{
|
{
|
||||||
ActionBindingEntry *akb = &( abe[action] );
|
ActionBindingEntry *akb = &( abe[action] );
|
||||||
|
@ -142,13 +146,19 @@ static gboolean abe_test_action ( KeyBindingAction action, unsigned int mask, xk
|
||||||
for ( int iter = 0; iter < akb->num_bindings; iter++ ) {
|
for ( int iter = 0; iter < akb->num_bindings; iter++ ) {
|
||||||
const KeyBinding * const kb = &( akb->kb[iter] );
|
const KeyBinding * const kb = &( akb->kb[iter] );
|
||||||
if ( ( kb->keysym == key ) && ( kb->modmask == mask ) ) {
|
if ( ( kb->keysym == key ) && ( kb->modmask == mask ) ) {
|
||||||
return TRUE;
|
if ( kb->release ) {
|
||||||
|
_abe_trigger_on_release[action] = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key )
|
KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key )
|
||||||
{
|
{
|
||||||
KeyBindingAction action;
|
KeyBindingAction action;
|
||||||
|
@ -161,3 +171,19 @@ KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key )
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void abe_trigger_release ( void )
|
||||||
|
{
|
||||||
|
RofiViewState *state;
|
||||||
|
KeyBindingAction action;
|
||||||
|
|
||||||
|
state = rofi_view_get_active ( );
|
||||||
|
for ( action = 0 ; action < NUM_ABE ; ++action ) {
|
||||||
|
if ( _abe_trigger_on_release[action] ) {
|
||||||
|
rofi_view_trigger_action ( state, action );
|
||||||
|
_abe_trigger_on_release[action] = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rofi_view_update ( state );
|
||||||
|
}
|
||||||
|
|
|
@ -439,6 +439,7 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN
|
||||||
case XCB_XKB_STATE_NOTIFY:
|
case XCB_XKB_STATE_NOTIFY:
|
||||||
{
|
{
|
||||||
xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev;
|
xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev;
|
||||||
|
guint modmask;
|
||||||
xkb_state_update_mask ( xkb.state,
|
xkb_state_update_mask ( xkb.state,
|
||||||
ksne->baseMods,
|
ksne->baseMods,
|
||||||
ksne->latchedMods,
|
ksne->latchedMods,
|
||||||
|
@ -446,6 +447,10 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN
|
||||||
ksne->baseGroup,
|
ksne->baseGroup,
|
||||||
ksne->latchedGroup,
|
ksne->latchedGroup,
|
||||||
ksne->lockedGroup );
|
ksne->lockedGroup );
|
||||||
|
modmask = x11_get_current_mask ( &xkb );
|
||||||
|
if ( modmask == 0 ) {
|
||||||
|
abe_trigger_release ( );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -550,8 +550,8 @@ void __create_window ( MenuFlags menu_flags )
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
|
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
|
||||||
XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE |
|
||||||
XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_1_MOTION,
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_1_MOTION,
|
||||||
map
|
map
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1542,9 +1542,33 @@ static void rofi_view_mainloop_iter ( RofiViewState *state, xcb_generic_event_t
|
||||||
case XCB_SELECTION_NOTIFY:
|
case XCB_SELECTION_NOTIFY:
|
||||||
rofi_view_paste ( state, (xcb_selection_notify_event_t *) ev );
|
rofi_view_paste ( state, (xcb_selection_notify_event_t *) ev );
|
||||||
break;
|
break;
|
||||||
|
case XCB_KEYMAP_NOTIFY:
|
||||||
|
{
|
||||||
|
xcb_keymap_notify_event_t *kne = (xcb_keymap_notify_event_t *) ev;
|
||||||
|
guint modstate = x11_get_current_mask ( xkb );
|
||||||
|
for ( gint32 by = 0 ; by < 32 ; ++by ) {
|
||||||
|
for ( gint8 bi = 0 ; bi < 7 ; ++bi ) {
|
||||||
|
if ( kne->keys[by] & (1 << bi) ) {
|
||||||
|
// X11 keycodes starts at 8
|
||||||
|
xkb_keysym_t key = xkb_state_key_get_one_sym ( xkb->state, ( 8 * by + bi ) + 8 );
|
||||||
|
abe_find_action ( modstate, key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case XCB_KEY_PRESS:
|
case XCB_KEY_PRESS:
|
||||||
rofi_view_handle_keypress ( state, xkb, (xcb_key_press_event_t *) ev );
|
rofi_view_handle_keypress ( state, xkb, (xcb_key_press_event_t *) ev );
|
||||||
break;
|
break;
|
||||||
|
case XCB_KEY_RELEASE:
|
||||||
|
{
|
||||||
|
xcb_key_release_event_t *xkre = (xcb_key_release_event_t *) ev;
|
||||||
|
unsigned int modstate = x11_canonalize_mask ( xkre->state );
|
||||||
|
if ( modstate == 0 ) {
|
||||||
|
abe_trigger_release ( );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Update if requested.
|
// Update if requested.
|
||||||
if ( state->refilter ) {
|
if ( state->refilter ) {
|
||||||
|
|
|
@ -437,12 +437,28 @@ unsigned int x11_canonalize_mask ( unsigned int mask )
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int x11_get_current_mask ( xkb_stuff *xkb )
|
||||||
|
{
|
||||||
|
unsigned int mask = 0;
|
||||||
|
for ( gsize i = 0 ; i < xkb_keymap_num_mods(xkb->keymap) ; ++i ) {
|
||||||
|
if ( xkb_state_mod_index_is_active ( xkb->state, i, XKB_STATE_MODS_EFFECTIVE ) ) {
|
||||||
|
mask |= ( 1 << i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x11_canonalize_mask ( mask );
|
||||||
|
}
|
||||||
|
|
||||||
// convert a Mod+key arg to mod mask and keysym
|
// convert a Mod+key arg to mod mask and keysym
|
||||||
gboolean x11_parse_key ( char *combo, unsigned int *mod, xkb_keysym_t *key )
|
gboolean x11_parse_key ( char *combo, unsigned int *mod, xkb_keysym_t *key, gboolean *release )
|
||||||
{
|
{
|
||||||
GString *str = g_string_new ( "" );
|
GString *str = g_string_new ( "" );
|
||||||
unsigned int modmask = 0;
|
unsigned int modmask = 0;
|
||||||
|
|
||||||
|
if ( g_str_has_prefix(combo, "!") ) {
|
||||||
|
++combo;
|
||||||
|
*release = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if ( strcasestr ( combo, "shift" ) ) {
|
if ( strcasestr ( combo, "shift" ) ) {
|
||||||
modmask |= x11_mod_masks[X11MOD_SHIFT];
|
modmask |= x11_mod_masks[X11MOD_SHIFT];
|
||||||
if ( x11_mod_masks[X11MOD_SHIFT] == 0 ) {
|
if ( x11_mod_masks[X11MOD_SHIFT] == 0 ) {
|
||||||
|
|
Loading…
Reference in a new issue