Skip to content

Commit

Permalink
Keyboard binding rework
Browse files Browse the repository at this point in the history
Allows to set additional parameters for keyboard actions.
Relates to #81, #92.

Signed-off-by: Artem Senichev <artemsen@gmail.com>
  • Loading branch information
artemsen committed Dec 23, 2023
1 parent 63d625b commit 4564487
Show file tree
Hide file tree
Showing 8 changed files with 375 additions and 234 deletions.
40 changes: 34 additions & 6 deletions extra/swayimgrc.5
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Empty lines and comments are ignored.
.nf
\fIoptimal\fR: 100% or less to fit to window (default);
\fIfit\fR: fit to window;
\fIfill\fR: crop to window size;
\fIreal\fR: real size (100%);
.IP "\fBfullscreen\fR: start in full screen mode, \fIyes\fR or [\fIno\fR];"
.IP "\fBbackground\fR: background for transparent images:"
Expand Down Expand Up @@ -66,16 +67,43 @@ Empty lines and comments are ignored.
.SS Key bindins
.PP
The key bindings are described in the "keys" section.
Each line associates a key with some action.
Each line associates a key with some action and optional parameters.
The key name can be obtained with the \fIxkbcli\fR tool:
`xkbcli interactive-wayland`.
.PP
Valid action are:
none, first_file, last_file, prev_dir, next_dir, prev_file, next_file, prev_frame,
next_frame, animation, slideshow, fullscreen, step_left, step_right, step_up,
step_down, zoom_in, zoom_out, zoom_optimal, zoom_fit, zoom_real, zoom_reset,
rotate_left, rotate_right, flip_vertical, flip_horizontal,
antialiasing, reload, info, exec, quit.
.IP "\fBnone\fR: used for removig default action;"
.IP "\fBfirst_file\fR: jump to the first file;"
.IP "\fBlast_file\fR: jump to the last file;"
.IP "\fBprev_dir\fR: jump to previous directory;"
.IP "\fBnext_dir\fR: jump to next directory;"
.IP "\fBprev_file\fR: jump to previous file;"
.IP "\fBnext_file\fR: jump to next file;"
.IP "\fBprev_frame\fR: show previous frame;"
.IP "\fBnext_frame\fR: show next frame;"
.IP "\fBanimation\fR: start/stop animation;"
.IP "\fBslideshow\fR: start/stop slideshow;"
.IP "\fBfullscreen\fR: switch fullscreen mode;"
.IP "\fBstep_left\fR: move viewport left;"
.IP "\fBstep_right\fR: move viewport right;"
.IP "\fBstep_up\fR: move viewport up;"
.IP "\fBstep_down\fR: move viewport down;"
.IP "\fBzoom_in\fR: zoom in;"
.IP "\fBzoom_out\fR: zoom out;"
.IP "\fBzoom_optimal\fR: set to optimal zoom (100% or less to fit to window);"
.IP "\fBzoom_fit\fR: set scale to fit the window;"
.IP "\fBzoom_fill\fR: set scale to fill the window;"
.IP "\fBzoom_real\fR: set 100% scale;"
.IP "\fBzoom_reset\fR: reset zoom to default settings;"
.IP "\fBrotate_left\fR: rotate image anticlockwise;"
.IP "\fBrotate_right\fR: rotate image clockwise;"
.IP "\fBflip_vertical\fR: flip image vertically;"
.IP "\fBflip_horizontal\fR: flip image horizontally;"
.IP "\fBreload\fR: reset cache and reload current image;"
.IP "\fBantialiasing\fR: switch antialiasing (bicubic interpolation);"
.IP "\fBinfo\fR: show/hide image info;"
.IP "\fBexec\fR: execute external command;"
.IP "\fBquit\fR: quit the application."
.\" example file
.SH EXAMPLES
.EX
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ sources = [
'src/font.c',
'src/image.c',
'src/imagelist.c',
'src/keybind.c',
'src/main.c',
'src/sway.c',
'src/ui.c',
Expand Down
166 changes: 30 additions & 136 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "config.h"

#include "keybind.h"

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
Expand All @@ -21,101 +23,6 @@
#define SECTION_GENERAL "general"
#define SECTION_KEYBIND "keys"

// Default key bindings
static struct config_keybind default_bindings[] = {
{ XKB_KEY_Home, cfgact_first_file },
{ XKB_KEY_g, cfgact_first_file },
{ XKB_KEY_End, cfgact_last_file },
{ XKB_KEY_G, cfgact_last_file },
{ XKB_KEY_P, cfgact_prev_dir },
{ XKB_KEY_N, cfgact_next_dir },
{ XKB_KEY_SunPageUp, cfgact_prev_file },
{ XKB_KEY_p, cfgact_prev_file },
{ XKB_KEY_SunPageDown, cfgact_next_file },
{ XKB_KEY_n, cfgact_next_file },
{ XKB_KEY_space, cfgact_next_file },
{ XKB_KEY_F2, cfgact_prev_frame },
{ XKB_KEY_O, cfgact_prev_frame },
{ XKB_KEY_F3, cfgact_next_frame },
{ XKB_KEY_o, cfgact_next_frame },
{ XKB_KEY_F4, cfgact_animation },
{ XKB_KEY_s, cfgact_animation },
{ XKB_KEY_F9, cfgact_slideshow },
{ XKB_KEY_F11, cfgact_fullscreen },
{ XKB_KEY_f, cfgact_fullscreen },
{ XKB_KEY_Left, cfgact_step_left },
{ XKB_KEY_h, cfgact_step_left },
{ XKB_KEY_Right, cfgact_step_right },
{ XKB_KEY_l, cfgact_step_right },
{ XKB_KEY_Up, cfgact_step_up },
{ XKB_KEY_k, cfgact_step_up },
{ XKB_KEY_Down, cfgact_step_down },
{ XKB_KEY_j, cfgact_step_down },
{ XKB_KEY_equal, cfgact_zoom_in },
{ XKB_KEY_plus, cfgact_zoom_in },
{ XKB_KEY_minus, cfgact_zoom_out },
{ XKB_KEY_x, cfgact_zoom_optimal },
{ XKB_KEY_z, cfgact_zoom_fit },
{ XKB_KEY_Z, cfgact_zoom_fill },
{ XKB_KEY_0, cfgact_zoom_real },
{ XKB_KEY_BackSpace, cfgact_zoom_reset },
{ XKB_KEY_F5, cfgact_rotate_left },
{ XKB_KEY_bracketleft, cfgact_rotate_left },
{ XKB_KEY_F6, cfgact_rotate_right },
{ XKB_KEY_bracketright, cfgact_rotate_right },
{ XKB_KEY_F7, cfgact_flip_vertical },
{ XKB_KEY_F8, cfgact_flip_horizontal },
{ XKB_KEY_a, cfgact_antialiasing },
{ XKB_KEY_r, cfgact_reload },
{ XKB_KEY_i, cfgact_info },
{ XKB_KEY_e, cfgact_exec },
{ XKB_KEY_Escape, cfgact_quit },
{ XKB_KEY_Return, cfgact_quit },
{ XKB_KEY_F10, cfgact_quit },
{ XKB_KEY_q, cfgact_quit },
};

/* Link between action id and its name in config file */
struct action_name {
const char* name;
enum config_action action;
};

static const struct action_name action_names[] = {
{ "none", cfgact_none },
{ "first_file", cfgact_first_file },
{ "last_file", cfgact_last_file },
{ "prev_dir", cfgact_prev_dir },
{ "next_dir", cfgact_next_dir },
{ "prev_file", cfgact_prev_file },
{ "next_file", cfgact_next_file },
{ "prev_frame", cfgact_prev_frame },
{ "next_frame", cfgact_next_frame },
{ "animation", cfgact_animation },
{ "slideshow", cfgact_slideshow },
{ "fullscreen", cfgact_fullscreen },
{ "step_left", cfgact_step_left },
{ "step_right", cfgact_step_right },
{ "step_up", cfgact_step_up },
{ "step_down", cfgact_step_down },
{ "zoom_in", cfgact_zoom_in },
{ "zoom_out", cfgact_zoom_out },
{ "zoom_optimal", cfgact_zoom_optimal },
{ "zoom_fit", cfgact_zoom_fit },
{ "zoom_fill", cfgact_zoom_fill },
{ "zoom_real", cfgact_zoom_real },
{ "zoom_reset", cfgact_zoom_reset },
{ "rotate_left", cfgact_rotate_left },
{ "rotate_right", cfgact_rotate_right },
{ "flip_vertical", cfgact_flip_vertical },
{ "flip_horizontal", cfgact_flip_horizontal },
{ "antialiasing", cfgact_antialiasing },
{ "reload", cfgact_reload },
{ "info", cfgact_info },
{ "exec", cfgact_exec },
{ "quit", cfgact_quit },
};

/** Config file location. */
struct location {
const char* prefix; ///< Environment variable name
Expand Down Expand Up @@ -319,15 +226,22 @@ static bool apply_conf(const char* key, const char* value)

/**
* Apply key binding to configuration.
* @param key property key
* @param value property value
* @return operation complete status, false if key was not handled
* @param key name of the key
* @param action action name
* @param params action specific parameters
* @return operation complete status, false on error
*/
static bool apply_key(const char* key, const char* value)
static bool apply_key(const char* key, const char* action, const char* params)
{
xkb_keysym_t keysym;
enum config_action action;
size_t index;
enum kb_action action_id;

// convert action name to code
action_id = keybind_action(action);
if (action_id == kb_none && strcmp(action, "none")) {
fprintf(stderr, "Invalid binding action: %s\n", action);
return false;
}

// convert key name to code
keysym = xkb_keysym_from_name(key, XKB_KEYSYM_NO_FLAGS);
Expand All @@ -336,38 +250,7 @@ static bool apply_key(const char* key, const char* value)
return false;
}

// convert action name to code
for (index = 0; index < sizeof(action_names) / sizeof(action_names[0]);
++index) {
if (strcmp(value, action_names[index].name) == 0) {
action = action_names[index].action;
break;
}
}
if (index == sizeof(action_names) / sizeof(action_names[0])) {
fprintf(stderr, "Invalid binding action: %s\n", value);
return false;
}

// replace previous binding
for (index = 0; index < MAX_KEYBINDINGS; ++index) {
struct config_keybind* bind = &config.keybind[index];
if (bind->key == XKB_KEY_NoSymbol) {
break;
}
if (bind->key == keysym) {
bind->action = action;
return true;
}
}

// add new binding
if (index == MAX_KEYBINDINGS) {
fprintf(stderr, "Too many key bindins\n");
return false;
}
config.keybind[index].key = keysym;
config.keybind[index].action = action;
keybind_set(keysym, action_id, params);

return true;
}
Expand All @@ -393,7 +276,7 @@ static bool load_config(const char* path)

while ((nread = getline(&buff, &buff_sz, fd)) != -1) {
char* delim;
const char* value;
char* value;
char* line = buff;
bool status = false;

Expand Down Expand Up @@ -451,7 +334,19 @@ static bool load_config(const char* path)
if (!section || strcmp(section, SECTION_GENERAL) == 0) {
status = apply_conf(line, value);
} else if (strcmp(section, SECTION_KEYBIND) == 0) {
status = apply_key(line, value);
// split value to action name and parameters
char* params = value;
while (*params && !isspace(*params)) {
++params;
}
if (isspace(*params)) {
*params = 0;
++params;
while (*params && isspace(*params)) {
++params;
}
}
status = apply_key(line, value, params);
} else {
fprintf(stderr, "Invalid section name: '%s'\n", section);
}
Expand Down Expand Up @@ -492,7 +387,6 @@ void config_init(void)
config.all_files = false;
config.antialiasing = false;
config_set_exec_cmd("echo '%'");
memcpy(config.keybind, default_bindings, sizeof(default_bindings));

// create unique application id
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
Expand Down
46 changes: 0 additions & 46 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
// Copy size from image
#define SAME_AS_IMAGE 0

// Max number of key bindings
#define MAX_KEYBINDINGS 128

/** Order of file list. */
enum config_order {
cfgord_none, ///< Unsorted (system depended)
Expand All @@ -35,48 +32,6 @@ enum config_scale {
cfgsc_real ///< Real image size (100%)
};

/** Action associated with a key. */
enum config_action {
cfgact_none,
cfgact_first_file,
cfgact_last_file,
cfgact_prev_dir,
cfgact_next_dir,
cfgact_prev_file,
cfgact_next_file,
cfgact_prev_frame,
cfgact_next_frame,
cfgact_animation,
cfgact_slideshow,
cfgact_fullscreen,
cfgact_step_left,
cfgact_step_right,
cfgact_step_up,
cfgact_step_down,
cfgact_zoom_in,
cfgact_zoom_out,
cfgact_zoom_optimal,
cfgact_zoom_fit,
cfgact_zoom_fill,
cfgact_zoom_real,
cfgact_zoom_reset,
cfgact_rotate_left,
cfgact_rotate_right,
cfgact_flip_vertical,
cfgact_flip_horizontal,
cfgact_reload,
cfgact_antialiasing,
cfgact_info,
cfgact_exec,
cfgact_quit,
};

/** Key bindings. */
struct config_keybind {
xkb_keysym_t key;
enum config_action action;
};

/** App configuration. */
struct config {
const char* app_id; ///< Window class/app_id name
Expand All @@ -98,7 +53,6 @@ struct config {
bool recursive; ///< Read directories recursively
bool all_files; ///< Open all files from the same directory
const char* exec_cmd; ///< Command to execute
struct config_keybind keybind[MAX_KEYBINDINGS]; ///< Key bindings table
};
extern struct config config;

Expand Down
Loading

0 comments on commit 4564487

Please sign in to comment.