From 8625f2c8a4aa2896f15514f1bb2a241f7168db09 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 23 Nov 2024 11:08:51 +0100 Subject: [PATCH] various: define builtin options and key bindings for images This makes mpv a good image viewer out of the box, as it is currently hard to setup. It adds a builtin image conditional profile that users can extend in mpv.conf. It is written to not restore and reapply the options on each image change, because that is slow for certain options (e.g. --d3d11-flip=no restarts the VO), and causes visible flicker when options like gamma are unapplied before changing image and reapplied on the next image. But it still restores the previous options after switching to a video or audio file. etc/image-input.conf defines default key bindings for image, and ~/.config/mpv/image-input.conf can override them. sxiv is the main inspiration for the default key bindings. Files called image-input.conf are added to an input section called image, and builtin.conf enables it for images and disables it for non-images. Because enable-section and disable-section are only called in builtin.conf, they can be replaced with a different mechanism when deprecated input sections are removed without a breaking change. --- DOCS/man/input.rst | 6 +++ DOCS/man/mpv.rst | 110 +++++++++++++++++++++++++++++++++++++++++++ etc/builtin.conf | 12 +++++ etc/image-input.conf | 86 +++++++++++++++++++++++++++++++++ etc/meson.build | 2 +- input/input.c | 21 ++++++++- meson.build | 2 +- 7 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 etc/image-input.conf diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 45f0e4c9fa7dd..5013d436f010e 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -25,6 +25,12 @@ defined here:: https://github.com/mpv-player/mpv/blob/master/etc/input.conf +Additionally, ``image-input.conf`` can be placed in mpv's configuration +directory to enable key bindings exclusively for images. The default image +bindings are defined here:: + + https://github.com/mpv-player/mpv/blob/master/etc/image-input.conf + A list of special keys can be obtained with ``mpv --input-keylist`` diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index 64de51d112c13..68be27686da38 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -371,6 +371,79 @@ To use this feature, you need to fill the ``menu-data`` property with menu definition data, and add a keybinding to run the ``context-menu`` command, which can be done with a user script. +Image Bindings +-------------- + +Several key bindings are changed when viewing images: + +LEFT, RIGHT, UP, DOWN, h, j, k, l + Pan the image when it is larger than the window. + +Ctrl+LEFT, Ctrl+RIGHT, Ctrl+UP, Ctrl+DOWN, Ctrl+h, Ctrl+j, Ctrl+k, Ctrl+l + Align the image to one of the boundaries of the window when it is larger + than the window. + += and - + Change the zoom. + ++ and _ + Change the zoom slowly. + +0 + Reset the zoom. + +u + Toggle between showing the image unscaled in its original dimensions and + fitting it to the window. + +o + Fill the window with the image. + +s + Toggle between showing images for 5 seconds in a slideshow and keeping them + open forever. + +n + Go to the next playlist entry. + +p + Go to the previous playlist entry. + +N + Go to the next sub-playlist (e.g. directory or achive). + +P + Go to the previous sub-playlist. + +g-g + Go to the first playlist entry. + +G + Go to the last playlist entry. + +] + Skip 10 playlist entries forwards. + +[ + Skip 10 playlist entries backwards. + +r and R + Rotate counterclockwise. + +t + Rotate clockwise. + +v + Rotate by 180 degrees. + +Right click + Pan while holding the button keeping the clicked part of the image under the + cursor. + +Wheel up/down + Change the zoom while keeping the part of the image hovered by the cursor + under it. + USAGE ===== @@ -1008,6 +1081,40 @@ example, ``math`` is defined and gives access to the Lua standard math library. This feature is subject to change indefinitely. You might be forced to adjust your profiles on mpv updates. +Image profile +------------------- + +mpv has a builtin conditional profile that is automatically applied to images +and restored when switching to a video or audio file. Its options are: + +.. admonition:: Builtin profile definition + + :: + + [image] + osc=no + prefetch-playlist + input-preprocess-wheel=no + +It can be extended in mpv.conf without overwriting it completely: + +.. admonition:: Example to enable the screensaver with images + + :: + + [image] + stop-screensaver=no + +This profile uses ``--input-commands`` to enable image specific key bindings. +This can be disabled with ``input-commands-clr``. Extra commands should be +specified with ``input-commands-append`` to keep enabling the image key +bindings. + +To reset zoom and rotation between images, it is recommended to place +``reset-on-next-file=video-rotate,video-zoom,panscan,video-unscaled`` in the top +level of mpv.conf, as enabling it a conditional profile makes it take effect +only from the second file. + Legacy auto profiles -------------------- @@ -1653,6 +1760,9 @@ All configuration files should be encoded in UTF-8. ``~/.config/mpv/input.conf`` key bindings (see `INPUT.CONF`_ section) +``~/.config/mpv/image-input.conf`` + key bindings for images (see `INPUT.CONF`_ section) + ``~/.config/mpv/fonts.conf`` Fontconfig fonts.conf that is customized for mpv. You should include system fonts.conf in this file or mpv would not know about fonts that you already diff --git a/etc/builtin.conf b/etc/builtin.conf index 6108cc71d546a..70ad5cd755646 100644 --- a/etc/builtin.conf +++ b/etc/builtin.conf @@ -97,3 +97,15 @@ sub-shadow-offset=4 [box] profile=osd-box profile=sub-box + +[image] +profile-cond=(get('current-tracks/video', {}).image and not get('current-tracks/video', {}).albumart) or (not get('current-tracks/video') and get('user-data/mpv/image')) +profile-restore=copy +input-commands=no-osd set user-data/mpv/image 1; enable-section image allow-hide-cursor+allow-vo-dragging +osc=no +prefetch-playlist +input-preprocess-wheel=no + +[non-image] +profile-cond=get('user-data/mpv/image') and (not get('current-tracks/video', {}).image or get('current-tracks/video', {}).albumart) +input-commands=no-osd del user-data/mpv/image; disable-section image diff --git a/etc/image-input.conf b/etc/image-input.conf new file mode 100644 index 0000000000000..2056a32013266 --- /dev/null +++ b/etc/image-input.conf @@ -0,0 +1,86 @@ +# Image key bindings +# +# Location of user-defined bindings: ~/.config/mpv/image-input.conf +# +# Lines starting with # are comments. Use SHARP to assign the # key. +# Copy this file and uncomment and edit the bindings you want to change. +# +# List of commands and further details: DOCS/man/input.rst +# List of special keys: --input-keylist +# Keybindings testing mode: mpv --input-test --force-window --idle +# +# Use 'ignore' to unbind a key fully (e.g. 'ctrl+a ignore'). +# +# Strings need to be quoted and escaped: +# KEY show-text "This is a single backslash: \\ and a quote: \" !" +# +# You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with +# the modifiers Shift, Ctrl, Alt and Meta (may not work on the terminal). +# +# The default keybindings are hardcoded into the mpv binary. +# You can disable them completely with: --no-input-default-bindings + +#LEFT script-binding/positioning pan-x -0.2 # pan left +#DOWN script-binding/positioning pan-y 0.2 # pan down +#UP script-binding/positioning pan-y -0.2 # pan up +#RIGHT script-binding/positioning pan-x 0.2 # pan right +#h script-binding/positioning pan-x -0.2 # pan left +#j script-binding/positioning pan-y 0.2 # pan down +#k script-binding/positioning pan-y -0.2 # pan up +#l script-binding/positioning pan-x 0.2 # pan right +#Shift+LEFT script-binding/positioning pan-x -0.02 # pan left slowly +#Shift+DOWN script-binding/positioning pan-y 0.02 # pan down slowly +#Shift+UP script-binding/positioning pan-y -0.02 # pan up slowly +#Shift+RIGHT script-binding/positioning pan-x 0.02 # pan right slowly +#H script-binding/positioning pan-x -0.02 # pan left slowly +#J script-binding/positioning pan-y 0.02 # pan down slowly +#K script-binding/positioning pan-y -0.02 # pan up slowly +#L script-binding/positioning pan-x 0.02 # pan right slowly + +# Recommened on a touchpad: +# WHEEL_UP script-binding/positioning pan-y -0.2 # pan up +# WHEEL_DOWN script-binding/positioning pan-y 0.2 # pan down +# WHEEL_LEFT script-binding/positioning pan-x -0.2 # pan left +# WHEEL_RIGHT script-binding/positioning pan-x 0.2 # pan right + +#Ctrl+LEFT no-osd set video-align-x -1 # align to the left +#Ctrl+DOWN no-osd set video-align-y 1 # align to the bottom +#Ctrl+UP no-osd set video-align-y -1 # align to the top +#Ctrl+RIGHT no-osd set video-align-x 1 # align to the right +#Ctrl+h no-osd set video-align-x -1 # align to the left +#Ctrl+j no-osd set video-align-y 1 # align to the bottom +#Ctrl+k no-osd set video-align-y -1 # align to the top +#Ctrl+l no-osd set video-align-x 1 # align to the right + += add video-zoom 0.25 # zoom in +- add video-zoom -0.25 # zoom out ++ add video-zoom 0.05 # zoom in slowly +_ add video-zoom -0.05 # zoom out slowly +0 no-osd set video-zoom 0; no-osd set panscan 0 # reset zoom + +#u no-osd cycle-values video-unscaled yes no; no-osd set video-zoom 0; no-osd set panscan 0 # toggle scaling the image to the window. + +#o no-osd set panscan 1; no-osd set video-unscaled no; no-osd set video-zoom 0 # fill black bars + +#MBTN_RIGHT script-binding positioning/drag-to-pan # pan around the clicked point + +#WHEEL_UP script-message cursor-centric-zoom 0.1 # zoom in towards the cursor +#WHEEL_DOWN script-message cursor-centric-zoom -0.1 # zoom out towards the cursor + +#s cycle-values image-display-duration 5 inf; no-osd set video-zoom 0; no-osd set panscan 0; no-osd set video-unscaled no # toggle slideshow + +#n repeatable playlist-next # go to the next file +#p repeatable playlist-prev # go to the previous file +#N playlist-next-playlist # go to the next sub-playlist +#P playlist-prev-playlist # go to the previous sub-playlist + +#g-g no-osd set playlist-pos 0 # go to the first playlist entry +#G no-osd set playlist-pos-1 ${playlist-count} # go to the last playlist entry + +] no-osd add playlist-pos 10 # go 10 playlist entries forwards +[ no-osd add playlist-pos -10 # go 10 playlist entries backwards + +#r cycle-values video-rotate 270 180 90 0 # rotate counterclockwise +#R cycle-values video-rotate 270 180 90 0 # rotate counterclockwise +#t cycle-values video-rotate 90 180 270 0 # rotate clockwise +#v cycle-values video-rotate 0 180 # rotate by 180 degrees diff --git a/etc/meson.build b/etc/meson.build index ac9eec0e6f831..bfb04b9ebe6ea 100644 --- a/etc/meson.build +++ b/etc/meson.build @@ -9,7 +9,7 @@ foreach size: icons sources += icon endforeach -etc_files = ['input.conf', 'builtin.conf'] +etc_files = ['input.conf', 'builtin.conf', 'image-input.conf'] foreach file: etc_files etc_file = custom_target(file, input: file, diff --git a/input/input.c b/input/input.c index 98ca17b8b6c8b..d190b7cfc8572 100644 --- a/input/input.c +++ b/input/input.c @@ -249,6 +249,10 @@ static const char builtin_input_conf[] = #include "etc/input.conf.inc" ; +static const char builtin_image_input_conf[] = +#include "etc/image-input.conf.inc" +; + static bool test_rect(struct mp_rect *rc, int x, int y) { return x >= rc->x0 && y >= rc->y0 && x < rc->x1 && y < rc->y1; @@ -1477,9 +1481,13 @@ static bool parse_config_file(struct input_ctx *ictx, char *file) bstr data = stream_read_file2(file, tmp, STREAM_ORIGIN_DIRECT | STREAM_READ, ictx->global, 1000000); if (data.start) { + bstr section = (bstr){0}; + if (!strcmp(mp_basename(file), "image-input.conf")) + section = bstr0("image"); + MP_VERBOSE(ictx, "Parsing input config file %s\n", file); bstr_eatstart0(&data, "\xEF\xBB\xBF"); // skip BOM - int num = parse_config(ictx, false, data, file, (bstr){0}); + int num = parse_config(ictx, false, data, file, section); MP_VERBOSE(ictx, "Input config file %s parsed: %d binds\n", file, num); r = true; } else { @@ -1560,6 +1568,14 @@ void mp_input_load_config(struct input_ctx *ictx) parse_config(ictx, true, line, "", (bstr){0}); } + builtin = bstr0(builtin_image_input_conf); + while (ictx->opts->builtin_bindings && builtin.len) { + bstr line = bstr_getline(builtin, &builtin); + bstr_eatstart0(&line, "#"); + if (!bstr_startswith0(line, " ")) + parse_config(ictx, true, line, "", bstr0("image")); + } + bool config_ok = false; if (ictx->opts->config_file && ictx->opts->config_file[0]) config_ok = parse_config_file(ictx, ictx->opts->config_file); @@ -1567,6 +1583,9 @@ void mp_input_load_config(struct input_ctx *ictx) // Try global conf dir void *tmp = talloc_new(NULL); char **files = mp_find_all_config_files(tmp, ictx->global, "input.conf"); + for (int n = 0; files && files[n]; n++) + parse_config_file(ictx, files[n]); + files = mp_find_all_config_files(tmp, ictx->global, "image-input.conf"); for (int n = 0; files && files[n]; n++) parse_config_file(ictx, files[n]); talloc_free(tmp); diff --git a/meson.build b/meson.build index 89806e240b9c4..7845fb41aff6e 100644 --- a/meson.build +++ b/meson.build @@ -1787,7 +1787,7 @@ if get_option('cplayer') datadir = get_option('datadir') confdir = get_option('sysconfdir') - conf_files = ['etc/mpv.conf', 'etc/input.conf', + conf_files = ['etc/mpv.conf', 'etc/input.conf', 'etc/image-input.conf', 'etc/mplayer-input.conf', 'etc/restore-old-bindings.conf', 'etc/restore-osc-bindings.conf'] install_data(conf_files, install_dir: join_paths(datadir, 'doc', 'mpv'))