mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-25 13:55:34 -05:00
keybindings: Rework the matching
Now we check all bindings in one place, allowing for future naughty matching. Signed-off-by: Quentin Glidic <sardemff7+git@sardemff7.net>
This commit is contained in:
parent
65447b496a
commit
54f85fabaa
6 changed files with 167 additions and 135 deletions
|
@ -95,10 +95,10 @@ void setup_abe ( void );
|
|||
void cleanup_abe ( void );
|
||||
|
||||
/**
|
||||
* Check if this key has been triggered.
|
||||
* @returns TRUE if key combo matches, FALSE otherwise.
|
||||
* Find if a binding has been triggered.
|
||||
* @returns NUM_ABE if no key combo matches, a valid action otherwise.
|
||||
*/
|
||||
int abe_test_action ( KeyBindingAction action, unsigned int mask, xkb_keysym_t key );
|
||||
KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key );
|
||||
|
||||
/*@}*/
|
||||
#endif // ROFI_KEYB_H
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <cairo.h>
|
||||
#include "widget.h"
|
||||
#include "x11-helper.h"
|
||||
#include "keyb.h"
|
||||
|
||||
/**
|
||||
* @defgroup Textbox Textbox
|
||||
|
@ -101,15 +102,7 @@ void textbox_text ( textbox *tb, const char *text );
|
|||
*/
|
||||
void textbox_draw ( textbox *tb, cairo_t *draw );
|
||||
|
||||
/**
|
||||
* @param tb Handle to the textbox
|
||||
* @param ev XEvent key inputs to textbox
|
||||
*
|
||||
* Let the textbox handle the input event.
|
||||
*
|
||||
* @returns if the key was handled (1), unhandled(0) or handled and return was pressed (-1)
|
||||
*/
|
||||
int textbox_keybinding ( textbox *tb, unsigned int modstate, xkb_keysym_t key );
|
||||
int textbox_keybinding ( textbox *tb, KeyBindingAction action );
|
||||
gboolean textbox_append ( textbox *tb, char *pad, int pad_len );
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "widget.h"
|
||||
#include "textbox.h"
|
||||
#include "scrollbar.h"
|
||||
#include "keyb.h"
|
||||
#include "x11-helper.h"
|
||||
|
||||
/**
|
||||
|
@ -47,7 +48,7 @@ struct RofiViewState
|
|||
// Last offset in paginating.
|
||||
unsigned int last_offset;
|
||||
|
||||
xkb_keysym_t prev_key;
|
||||
KeyBindingAction prev_action;
|
||||
xcb_timestamp_t last_button_press;
|
||||
|
||||
int quit;
|
||||
|
|
|
@ -135,7 +135,7 @@ void cleanup_abe ( void )
|
|||
}
|
||||
}
|
||||
|
||||
int 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] );
|
||||
|
||||
|
@ -148,3 +148,16 @@ int abe_test_action ( KeyBindingAction action, unsigned int mask, xkb_keysym_t k
|
|||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
KeyBindingAction abe_find_action ( unsigned int mask, xkb_keysym_t key )
|
||||
{
|
||||
KeyBindingAction action;
|
||||
|
||||
for ( action = 0 ; action < NUM_ABE ; ++action ) {
|
||||
if ( abe_test_action ( action, mask, key ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
|
|
@ -525,78 +525,67 @@ static void textbox_cursor_del_word ( textbox *tb )
|
|||
// 0 = unhandled
|
||||
// 1 = handled
|
||||
// -1 = handled and return pressed (finished)
|
||||
int textbox_keybinding ( textbox *tb, unsigned int modstate, xkb_keysym_t key )
|
||||
int textbox_keybinding ( textbox *tb, KeyBindingAction action )
|
||||
{
|
||||
if ( !( tb->flags & TB_EDITABLE ) ) {
|
||||
g_return_val_if_reached(0);
|
||||
}
|
||||
int old_blink = tb->blink;
|
||||
tb->blink = 2;
|
||||
|
||||
switch ( action )
|
||||
{
|
||||
// Left or Ctrl-b
|
||||
if ( abe_test_action ( MOVE_CHAR_BACK, modstate, key ) ) {
|
||||
case MOVE_CHAR_BACK:
|
||||
textbox_cursor_dec ( tb );
|
||||
return 2;
|
||||
}
|
||||
// Right or Ctrl-F
|
||||
if ( abe_test_action ( MOVE_CHAR_FORWARD, modstate, key ) ) {
|
||||
case MOVE_CHAR_FORWARD:
|
||||
textbox_cursor_inc ( tb );
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Ctrl-U: Kill from the beginning to the end of the line.
|
||||
if ( abe_test_action ( CLEAR_LINE, modstate, key ) ) {
|
||||
case CLEAR_LINE:
|
||||
textbox_text ( tb, "" );
|
||||
return 1;
|
||||
}
|
||||
// Ctrl-A
|
||||
if ( abe_test_action ( MOVE_FRONT, modstate, key ) ) {
|
||||
case MOVE_FRONT:
|
||||
textbox_cursor ( tb, 0 );
|
||||
return 2;
|
||||
}
|
||||
// Ctrl-E
|
||||
if ( abe_test_action ( MOVE_END, modstate, key ) ) {
|
||||
case MOVE_END:
|
||||
textbox_cursor_end ( tb );
|
||||
return 2;
|
||||
}
|
||||
// Ctrl-Alt-h
|
||||
if ( abe_test_action ( REMOVE_WORD_BACK, modstate, key ) ) {
|
||||
case REMOVE_WORD_BACK:
|
||||
textbox_cursor_bkspc_word ( tb );
|
||||
return 1;
|
||||
}
|
||||
// Ctrl-Alt-d
|
||||
if ( abe_test_action ( REMOVE_WORD_FORWARD, modstate, key ) ) {
|
||||
case REMOVE_WORD_FORWARD:
|
||||
textbox_cursor_del_word ( tb );
|
||||
return 1;
|
||||
} // Delete or Ctrl-D
|
||||
if ( abe_test_action ( REMOVE_CHAR_FORWARD, modstate, key ) ) {
|
||||
// Delete or Ctrl-D
|
||||
case REMOVE_CHAR_FORWARD:
|
||||
textbox_cursor_del ( tb );
|
||||
return 1;
|
||||
}
|
||||
// Alt-B
|
||||
if ( abe_test_action ( MOVE_WORD_BACK, modstate, key ) ) {
|
||||
case MOVE_WORD_BACK:
|
||||
textbox_cursor_dec_word ( tb );
|
||||
return 2;
|
||||
}
|
||||
// Alt-F
|
||||
if ( abe_test_action ( MOVE_WORD_FORWARD, modstate, key ) ) {
|
||||
case MOVE_WORD_FORWARD:
|
||||
textbox_cursor_inc_word ( tb );
|
||||
return 2;
|
||||
}
|
||||
// BackSpace, Ctrl-h
|
||||
if ( abe_test_action ( REMOVE_CHAR_BACK, modstate, key ) ) {
|
||||
case REMOVE_CHAR_BACK:
|
||||
textbox_cursor_bkspc ( tb );
|
||||
return 1;
|
||||
}
|
||||
if ( abe_test_action ( ACCEPT_CUSTOM, modstate, key ) ) {
|
||||
case ACCEPT_CUSTOM:
|
||||
return -2;
|
||||
}
|
||||
if ( abe_test_action ( ACCEPT_ENTRY, modstate, key ) ) {
|
||||
case ACCEPT_ENTRY:
|
||||
return -1;
|
||||
default:
|
||||
g_return_val_if_reached(0);
|
||||
}
|
||||
|
||||
tb->blink = old_blink;
|
||||
return 0;
|
||||
g_return_val_if_reached(0);
|
||||
}
|
||||
|
||||
gboolean textbox_append ( textbox *tb, char *pad, int pad_len )
|
||||
|
|
160
source/view.c
160
source/view.c
|
@ -1087,30 +1087,30 @@ static void rofi_view_paste ( RofiViewState *state, xcb_selection_notify_event_t
|
|||
*
|
||||
* Keyboard navigation through the elements.
|
||||
*/
|
||||
static int rofi_view_keyboard_navigation ( RofiViewState *state, xkb_keysym_t key, unsigned int modstate )
|
||||
static void rofi_view_keyboard_navigation ( RofiViewState *state, KeyBindingAction action )
|
||||
{
|
||||
switch ( action )
|
||||
{
|
||||
// pressing one of the global key bindings closes the switcher. This allows fast closing of the
|
||||
// menu if an item is not selected
|
||||
if ( abe_test_action ( CANCEL, modstate, key ) ) {
|
||||
case CANCEL:
|
||||
state->retv = MENU_CANCEL;
|
||||
state->quit = TRUE;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
// Up, Ctrl-p or Shift-Tab
|
||||
if ( abe_test_action ( ROW_UP, modstate, key ) ) {
|
||||
case ROW_UP:
|
||||
rofi_view_nav_up ( state );
|
||||
return 1;
|
||||
}
|
||||
if ( abe_test_action ( ROW_TAB, modstate, key ) ) {
|
||||
break;
|
||||
case ROW_TAB:
|
||||
if ( state->filtered_lines == 1 ) {
|
||||
state->retv = MENU_OK;
|
||||
( state->selected_line ) = state->line_map[state->selected];
|
||||
state->quit = 1;
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Double tab!
|
||||
if ( state->filtered_lines == 0 && key == state->prev_key ) {
|
||||
if ( state->filtered_lines == 0 && action == state->prev_action ) {
|
||||
state->retv = MENU_NEXT;
|
||||
( state->selected_line ) = 0;
|
||||
state->quit = TRUE;
|
||||
|
@ -1118,39 +1118,31 @@ static int rofi_view_keyboard_navigation ( RofiViewState *state, xkb_keysym_t ke
|
|||
else {
|
||||
rofi_view_nav_down ( state );
|
||||
}
|
||||
state->prev_key = key;
|
||||
return 1;
|
||||
}
|
||||
state->prev_action = action;
|
||||
break;
|
||||
// Down, Ctrl-n
|
||||
if ( abe_test_action ( ROW_DOWN, modstate, key ) ) {
|
||||
case ROW_DOWN:
|
||||
rofi_view_nav_down ( state );
|
||||
return 1;
|
||||
}
|
||||
if ( abe_test_action ( ROW_LEFT, modstate, key ) ) {
|
||||
break;
|
||||
case ROW_LEFT:
|
||||
rofi_view_nav_left ( state );
|
||||
return 1;
|
||||
}
|
||||
if ( abe_test_action ( ROW_RIGHT, modstate, key ) ) {
|
||||
break;
|
||||
case ROW_RIGHT:
|
||||
rofi_view_nav_right ( state );
|
||||
return 1;
|
||||
}
|
||||
if ( abe_test_action ( PAGE_PREV, modstate, key ) ) {
|
||||
break;
|
||||
case PAGE_PREV:
|
||||
rofi_view_nav_page_prev ( state );
|
||||
return 1;
|
||||
}
|
||||
if ( abe_test_action ( PAGE_NEXT, modstate, key ) ) {
|
||||
break;
|
||||
case PAGE_NEXT:
|
||||
rofi_view_nav_page_next ( state );
|
||||
return 1;
|
||||
}
|
||||
if ( abe_test_action ( ROW_FIRST, modstate, key ) ) {
|
||||
break;
|
||||
case ROW_FIRST:
|
||||
rofi_view_nav_first ( state );
|
||||
return 1;
|
||||
}
|
||||
if ( abe_test_action ( ROW_LAST, modstate, key ) ) {
|
||||
break;
|
||||
case ROW_LAST:
|
||||
rofi_view_nav_last ( state );
|
||||
return 1;
|
||||
}
|
||||
if ( abe_test_action ( ROW_SELECT, modstate, key ) ) {
|
||||
break;
|
||||
case ROW_SELECT:
|
||||
// If a valid item is selected, return that..
|
||||
if ( state->selected < state->filtered_lines ) {
|
||||
char *str = mode_get_completion ( state->sw, state->line_map[state->selected] );
|
||||
|
@ -1160,9 +1152,10 @@ static int rofi_view_keyboard_navigation ( RofiViewState *state, xkb_keysym_t ke
|
|||
state->update = TRUE;
|
||||
state->refilter = TRUE;
|
||||
}
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
g_return_if_reached();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rofi_view_mouse_navigation ( RofiViewState *state, xcb_button_press_event_t *xbe )
|
||||
|
@ -1356,77 +1349,115 @@ static void rofi_view_handle_keypress ( RofiViewState *state, xkb_stuff *xkb, xc
|
|||
unsigned int modstate = x11_canonalize_mask ( xkpe->state );
|
||||
|
||||
if ( key != XKB_KEY_NoSymbol ) {
|
||||
KeyBindingAction action;
|
||||
|
||||
action = abe_find_action ( modstate, key );
|
||||
switch ( action )
|
||||
{
|
||||
// Handling of paste
|
||||
if ( abe_test_action ( PASTE_PRIMARY, modstate, key ) ) {
|
||||
case PASTE_PRIMARY:
|
||||
xcb_convert_selection ( xcb->connection, CacheState.main_window, XCB_ATOM_PRIMARY,
|
||||
xcb->ewmh.UTF8_STRING, xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME );
|
||||
xcb_flush ( xcb->connection );
|
||||
return;
|
||||
}
|
||||
if ( abe_test_action ( PASTE_SECONDARY, modstate, key ) ) {
|
||||
case PASTE_SECONDARY:
|
||||
xcb_convert_selection ( xcb->connection, CacheState.main_window, XCB_ATOM_SECONDARY,
|
||||
xcb->ewmh.UTF8_STRING, xcb->ewmh.UTF8_STRING, XCB_CURRENT_TIME );
|
||||
xcb_flush ( xcb->connection );
|
||||
return;
|
||||
}
|
||||
if ( abe_test_action ( SCREENSHOT, modstate, key ) ) {
|
||||
case SCREENSHOT:
|
||||
menu_capture_screenshot ( );
|
||||
return;
|
||||
}
|
||||
if ( abe_test_action ( TOGGLE_SORT, modstate, key ) ) {
|
||||
case TOGGLE_SORT:
|
||||
config.levenshtein_sort = !config.levenshtein_sort;
|
||||
state->refilter = TRUE;
|
||||
state->update = TRUE;
|
||||
textbox_text ( state->case_indicator, get_matching_state () );
|
||||
return;
|
||||
}
|
||||
if ( abe_test_action ( MODE_PREVIOUS, modstate, key ) ) {
|
||||
case MODE_PREVIOUS:
|
||||
state->retv = MENU_PREVIOUS;
|
||||
( state->selected_line ) = 0;
|
||||
state->quit = TRUE;
|
||||
return;
|
||||
}
|
||||
// Menu navigation.
|
||||
if ( abe_test_action ( MODE_NEXT, modstate, key ) ) {
|
||||
case MODE_NEXT:
|
||||
state->retv = MENU_NEXT;
|
||||
( state->selected_line ) = 0;
|
||||
state->quit = TRUE;
|
||||
return;
|
||||
}
|
||||
// Toggle case sensitivity.
|
||||
if ( abe_test_action ( TOGGLE_CASE_SENSITIVITY, modstate, key ) ) {
|
||||
case TOGGLE_CASE_SENSITIVITY:
|
||||
config.case_sensitive = !config.case_sensitive;
|
||||
( state->selected_line ) = 0;
|
||||
state->refilter = TRUE;
|
||||
state->update = TRUE;
|
||||
textbox_text ( state->case_indicator, get_matching_state () );
|
||||
return;
|
||||
}
|
||||
// Special delete entry command.
|
||||
if ( abe_test_action ( DELETE_ENTRY, modstate, key ) ) {
|
||||
case DELETE_ENTRY:
|
||||
if ( state->selected < state->filtered_lines ) {
|
||||
( state->selected_line ) = state->line_map[state->selected];
|
||||
state->retv = MENU_ENTRY_DELETE;
|
||||
state->quit = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
for ( unsigned int a = CUSTOM_1; a <= CUSTOM_19; a++ ) {
|
||||
if ( abe_test_action ( a, modstate, key ) ) {
|
||||
break;
|
||||
case CUSTOM_1:
|
||||
case CUSTOM_2:
|
||||
case CUSTOM_3:
|
||||
case CUSTOM_4:
|
||||
case CUSTOM_5:
|
||||
case CUSTOM_6:
|
||||
case CUSTOM_7:
|
||||
case CUSTOM_8:
|
||||
case CUSTOM_9:
|
||||
case CUSTOM_10:
|
||||
case CUSTOM_11:
|
||||
case CUSTOM_12:
|
||||
case CUSTOM_13:
|
||||
case CUSTOM_14:
|
||||
case CUSTOM_15:
|
||||
case CUSTOM_16:
|
||||
case CUSTOM_17:
|
||||
case CUSTOM_18:
|
||||
case CUSTOM_19:
|
||||
state->selected_line = UINT32_MAX;
|
||||
if ( state->selected < state->filtered_lines ) {
|
||||
( state->selected_line ) = state->line_map[state->selected];
|
||||
}
|
||||
state->retv = MENU_QUICK_SWITCH | ( ( a - CUSTOM_1 ) & MENU_LOWER_MASK );
|
||||
state->retv = MENU_QUICK_SWITCH | ( ( action - CUSTOM_1 ) & MENU_LOWER_MASK );
|
||||
state->quit = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( rofi_view_keyboard_navigation ( state, key, modstate ) ) {
|
||||
// If you add a binding here, make sure to add it to rofi_view_keyboard_navigation too
|
||||
case CANCEL:
|
||||
case ROW_UP:
|
||||
case ROW_TAB:
|
||||
case ROW_DOWN:
|
||||
case ROW_LEFT:
|
||||
case ROW_RIGHT:
|
||||
case PAGE_PREV:
|
||||
case PAGE_NEXT:
|
||||
case ROW_FIRST:
|
||||
case ROW_LAST:
|
||||
case ROW_SELECT:
|
||||
rofi_view_keyboard_navigation ( state, action );
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = textbox_keybinding ( state->text, modstate, key );
|
||||
// If you add a binding here, make sure to add it to textbox_keybinding too
|
||||
case MOVE_CHAR_BACK:
|
||||
case MOVE_CHAR_FORWARD:
|
||||
case CLEAR_LINE:
|
||||
case MOVE_FRONT:
|
||||
case MOVE_END:
|
||||
case REMOVE_WORD_BACK:
|
||||
case REMOVE_WORD_FORWARD:
|
||||
case REMOVE_CHAR_FORWARD:
|
||||
case MOVE_WORD_BACK:
|
||||
case MOVE_WORD_FORWARD:
|
||||
case REMOVE_CHAR_BACK:
|
||||
case ACCEPT_CUSTOM:
|
||||
case ACCEPT_ENTRY:
|
||||
{
|
||||
int rc = textbox_keybinding ( state->text, action );
|
||||
// Row is accepted.
|
||||
if ( rc < 0 ) {
|
||||
// If a valid item is selected, return that..
|
||||
|
@ -1457,6 +1488,11 @@ static void rofi_view_handle_keypress ( RofiViewState *state, xkb_stuff *xkb, xc
|
|||
state->update = TRUE;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NUM_ABE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( len > 0 ) && ( textbox_append ( state->text, pad, len ) ) ) {
|
||||
|
|
Loading…
Reference in a new issue