summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin Glidic <sardemff7+git@sardemff7.net>2016-04-07 20:28:40 +0200
committerQuentin Glidic <sardemff7+git@sardemff7.net>2016-05-07 11:31:04 +0200
commit67b0ce036f19fa0caa95461ab213717237b279dd (patch)
tree58070e5a8cc1c07e0bcffa2c42229105445fa087
parent20791d4a71f2cca4f7388d69ea2afdad03737eab (diff)
keybindings: Implement on-release bindings
Signed-off-by: Quentin Glidic <sardemff7+git@sardemff7.net>
-rw-r--r--doc/rofi-manpage.markdown2
-rw-r--r--doc/rofi.13
-rw-r--r--include/keyb.h2
-rw-r--r--include/x11-helper.h4
-rw-r--r--source/keyb.c30
-rw-r--r--source/rofi.c5
-rw-r--r--source/view.c28
-rw-r--r--source/x11-helper.c18
8 files changed, 86 insertions, 6 deletions
diff --git a/doc/rofi-manpage.markdown b/doc/rofi-manpage.markdown
index 78865739..e795659e 100644
--- a/doc/rofi-manpage.markdown
+++ b/doc/rofi-manpage.markdown
@@ -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-`.
Keybindings can be modified using the configuration systems.
+A keybinding starting with `!` will act when all keys have been released.
+
## Available Modi
### Window
diff --git a/doc/rofi.1 b/doc/rofi.1
index 40d30c62..443b6205 100644
--- a/doc/rofi.1
+++ b/doc/rofi.1
@@ -1160,6 +1160,9 @@ The first two fields specify the alpha level\. This determines the amount of tra
.P
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"
.
.SS "Window"
diff --git a/include/keyb.h b/include/keyb.h
index e7128498..5bdea14b 100644
--- a/include/keyb.h
+++ b/include/keyb.h
@@ -100,5 +100,7 @@ void cleanup_abe ( void );
*/
KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key );
+void abe_trigger_release ( void );
+
/*@}*/
#endif // ROFI_KEYB_H
diff --git a/include/x11-helper.h b/include/x11-helper.h
index c6704ff4..ef761bd9 100644
--- a/include/x11-helper.h
+++ b/include/x11-helper.h
@@ -81,6 +81,8 @@ int take_keyboard ( xcb_window_t w );
*/
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 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.
*/
-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.
diff --git a/source/keyb.c b/source/keyb.c
index 1a1e5690..c9fe83dc 100644
--- a/source/keyb.c
+++ b/source/keyb.c
@@ -8,6 +8,7 @@ typedef struct
{
unsigned int modmask;
xkb_keysym_t keysym;
+ gboolean release;
} KeyBinding;
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 ) ) {
abe[iter].kb = g_realloc ( abe[iter].kb, ( abe[iter].num_bindings + 1 ) * sizeof ( KeyBinding ) );
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 );
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 )
{
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++ ) {
const KeyBinding * const kb = &( akb->kb[iter] );
if ( ( kb->keysym == key ) && ( kb->modmask == mask ) ) {
- return TRUE;
+ if ( kb->release ) {
+ _abe_trigger_on_release[action] = TRUE;
+ }
+ else {
+ return TRUE;
+ }
}
}
return FALSE;
}
+
KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key )
{
KeyBindingAction action;
@@ -161,3 +171,19 @@ KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key )
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 );
+}
diff --git a/source/rofi.c b/source/rofi.c
index b1684d21..b293c570 100644
--- a/source/rofi.c
+++ b/source/rofi.c
@@ -439,6 +439,7 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN
case XCB_XKB_STATE_NOTIFY:
{
xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *) ev;
+ guint modmask;
xkb_state_update_mask ( xkb.state,
ksne->baseMods,
ksne->latchedMods,
@@ -446,6 +447,10 @@ static gboolean main_loop_x11_event_handler ( xcb_generic_event_t *ev, G_GNUC_UN
ksne->baseGroup,
ksne->latchedGroup,
ksne->lockedGroup );
+ modmask = x11_get_current_mask ( &xkb );
+ if ( modmask == 0 ) {
+ abe_trigger_release ( );
+ }
break;
}
}
diff --git a/source/view.c b/source/view.c
index a338df4d..885b8051 100644
--- a/source/view.c
+++ b/source/view.c
@@ -550,8 +550,8 @@ void __create_window ( MenuFlags menu_flags )
0,
0,
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_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_1_MOTION,
+ XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEYMAP_STATE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_1_MOTION,
map
};
@@ -1542,9 +1542,33 @@ static void rofi_view_mainloop_iter ( RofiViewState *state, xcb_generic_event_t
case XCB_SELECTION_NOTIFY:
rofi_view_paste ( state, (xcb_selection_notify_event_t *) ev );
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:
rofi_view_handle_keypress ( state, xkb, (xcb_key_press_event_t *) ev );
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.
if ( state->refilter ) {
diff --git a/source/x11-helper.c b/source/x11-helper.c
index b6c0b232..8adb6c54 100644
--- a/source/x11-helper.c
+++ b/source/x11-helper.c
@@ -437,12 +437,28 @@ unsigned int x11_canonalize_mask ( unsigned int 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
-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 ( "" );
unsigned int modmask = 0;
+ if ( g_str_has_prefix(combo, "!") ) {
+ ++combo;
+ *release = TRUE;
+ }
+
if ( strcasestr ( combo, "shift" ) ) {
modmask |= x11_mod_masks[X11MOD_SHIFT];
if ( x11_mod_masks[X11MOD_SHIFT] == 0 ) {