summaryrefslogtreecommitdiffstats
path: root/mpvcore/input
diff options
context:
space:
mode:
authorStefano Pigozzi <stefano.pigozzi@gmail.com>2013-08-06 22:34:12 +0200
committerStefano Pigozzi <stefano.pigozzi@gmail.com>2013-08-06 22:48:47 +0200
commitbc27f946c27e33933a3a696cade78a04902c8dce (patch)
tree0e4166ba66072d407d0b972842b08cb7fea6f50b /mpvcore/input
parentd40a91e804e19fb32430c5a80a984f5148324f52 (diff)
downloadmpv-bc27f946c27e33933a3a696cade78a04902c8dce.tar.bz2
mpv-bc27f946c27e33933a3a696cade78a04902c8dce.tar.xz
core: move contents to mpvcore (1/2)
core is used in many unix systems for core dumps. For that reason some tools work under the assumption that the file is indeed a core dump (for example autoconf does this). This commit just renames the files. The following one will change all the includes to fix compilation. This is done this way because git has a easier time tracing file changes if there is a pure rename commit.
Diffstat (limited to 'mpvcore/input')
-rw-r--r--mpvcore/input/input.c2284
-rw-r--r--mpvcore/input/input.h273
-rw-r--r--mpvcore/input/joystick.c162
-rw-r--r--mpvcore/input/joystick.h26
-rw-r--r--mpvcore/input/keycodes.h247
-rw-r--r--mpvcore/input/lirc.c123
-rw-r--r--mpvcore/input/lirc.h30
7 files changed, 3145 insertions, 0 deletions
diff --git a/mpvcore/input/input.c b/mpvcore/input/input.c
new file mode 100644
index 0000000000..ae1358a76d
--- /dev/null
+++ b/mpvcore/input/input.c
@@ -0,0 +1,2284 @@
+/*
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <libavutil/avstring.h>
+#include <libavutil/common.h>
+
+#include "osdep/io.h"
+#include "osdep/getch2.h"
+
+#include "input.h"
+#include "keycodes.h"
+#include "osdep/timer.h"
+#include "core/mp_msg.h"
+#include "core/m_config.h"
+#include "core/m_option.h"
+#include "core/path.h"
+#include "talloc.h"
+#include "core/options.h"
+#include "core/bstr.h"
+#include "stream/stream.h"
+#include "core/mp_common.h"
+
+#include "joystick.h"
+
+#ifdef CONFIG_LIRC
+#include "lirc.h"
+#endif
+
+#ifdef CONFIG_LIRCC
+#include <lirc/lircc.h>
+#endif
+
+#ifdef CONFIG_COCOA
+#include "osdep/macosx_events.h"
+#endif
+
+#define MP_MAX_KEY_DOWN 4
+
+struct cmd_bind {
+ int keys[MP_MAX_KEY_DOWN];
+ int num_keys;
+ char *cmd;
+ char *location; // filename/line number of definition
+ bool is_builtin;
+ struct cmd_bind_section *owner;
+};
+
+struct key_name {
+ int key;
+ char *name;
+};
+
+/* This array defines all known commands.
+ * The first field is an id used to recognize the command.
+ * The second is the command name used in slave mode and input.conf.
+ * Then comes the definition of each argument, first mandatory arguments
+ * (ARG_INT, ARG_FLOAT, ARG_STRING) if any, then optional arguments
+ * (OARG_INT(default), etc) if any. The command will be given the default
+ * argument value if the user didn't give enough arguments to specify it.
+ * A command can take a maximum of MP_CMD_MAX_ARGS arguments (10).
+ */
+
+#define ARG_INT { .type = {"", NULL, &m_option_type_int} }
+#define ARG_FLOAT { .type = {"", NULL, &m_option_type_float} }
+#define ARG_DOUBLE { .type = {"", NULL, &m_option_type_double} }
+#define ARG_STRING { .type = {"", NULL, &m_option_type_string} }
+#define ARG_CHOICE(c) { .type = {"", NULL, &m_option_type_choice, \
+ M_CHOICES(c)} }
+#define ARG_TIME { .type = {"", NULL, &m_option_type_time} }
+
+#define OARG_DOUBLE(def) { .type = {"", NULL, &m_option_type_double}, \
+ .optional = true, .v.d = def }
+#define OARG_INT(def) { .type = {"", NULL, &m_option_type_int}, \
+ .optional = true, .v.i = def }
+#define OARG_CHOICE(def, c) { .type = {"", NULL, &m_option_type_choice, \
+ M_CHOICES(c)}, \
+ .optional = true, .v.i = def }
+
+static int parse_cycle_dir(const struct m_option *opt, struct bstr name,
+ struct bstr param, void *dst);
+static const struct m_option_type m_option_type_cycle_dir = {
+ .name = "up|down",
+ .parse = parse_cycle_dir,
+};
+
+static const mp_cmd_t mp_cmds[] = {
+ { MP_CMD_IGNORE, "ignore", },
+
+ { MP_CMD_RADIO_STEP_CHANNEL, "radio_step_channel", { ARG_INT } },
+ { MP_CMD_RADIO_SET_CHANNEL, "radio_set_channel", { ARG_STRING } },
+ { MP_CMD_RADIO_SET_FREQ, "radio_set_freq", { ARG_FLOAT } },
+ { MP_CMD_RADIO_STEP_FREQ, "radio_step_freq", {ARG_FLOAT } },
+
+ { MP_CMD_SEEK, "seek", {
+ ARG_TIME,
+ OARG_CHOICE(0, ({"relative", 0}, {"0", 0},
+ {"absolute-percent", 1}, {"1", 1},
+ {"absolute", 2}, {"2", 2})),
+ OARG_CHOICE(0, ({"default-precise", 0}, {"0", 0},
+ {"exact", 1}, {"1", 1},
+ {"keyframes", -1}, {"-1", -1})),
+ }},
+ { MP_CMD_SPEED_MULT, "speed_mult", { ARG_DOUBLE } },
+ { MP_CMD_QUIT, "quit", { OARG_INT(0) } },
+ { MP_CMD_QUIT_WATCH_LATER, "quit_watch_later", },
+ { MP_CMD_STOP, "stop", },
+ { MP_CMD_FRAME_STEP, "frame_step", },
+ { MP_CMD_FRAME_BACK_STEP, "frame_back_step", },
+ { MP_CMD_PLAYLIST_NEXT, "playlist_next", {
+ OARG_CHOICE(0, ({"weak", 0}, {"0", 0},
+ {"force", 1}, {"1", 1})),
+ }},
+ { MP_CMD_PLAYLIST_PREV, "playlist_prev", {
+ OARG_CHOICE(0, ({"weak", 0}, {"0", 0},
+ {"force", 1}, {"1", 1})),
+ }},
+ { MP_CMD_SUB_STEP, "sub_step", { ARG_INT } },
+ { MP_CMD_OSD, "osd", { OARG_INT(-1) } },
+ { MP_CMD_PRINT_TEXT, "print_text", { ARG_STRING } },
+ { MP_CMD_SHOW_TEXT, "show_text", { ARG_STRING, OARG_INT(-1), OARG_INT(0) } },
+ { MP_CMD_SHOW_PROGRESS, "show_progress", },
+ { MP_CMD_SUB_ADD, "sub_add", { ARG_STRING } },
+ { MP_CMD_SUB_REMOVE, "sub_remove", { OARG_INT(-1) } },
+ { MP_CMD_SUB_RELOAD, "sub_reload", { OARG_INT(-1) } },
+
+ { MP_CMD_TV_START_SCAN, "tv_start_scan", },
+ { MP_CMD_TV_STEP_CHANNEL, "tv_step_channel", { ARG_INT } },
+ { MP_CMD_TV_STEP_NORM, "tv_step_norm", },
+ { MP_CMD_TV_STEP_CHANNEL_LIST, "tv_step_chanlist", },
+ { MP_CMD_TV_SET_CHANNEL, "tv_set_channel", { ARG_STRING } },
+ { MP_CMD_TV_LAST_CHANNEL, "tv_last_channel", },
+ { MP_CMD_TV_SET_FREQ, "tv_set_freq", { ARG_FLOAT } },
+ { MP_CMD_TV_STEP_FREQ, "tv_step_freq", { ARG_FLOAT } },
+ { MP_CMD_TV_SET_NORM, "tv_set_norm", { ARG_STRING } },
+
+ { MP_CMD_DVB_SET_CHANNEL, "dvb_set_channel", { ARG_INT, ARG_INT } },
+
+ { MP_CMD_SCREENSHOT, "screenshot", {
+ OARG_CHOICE(2, ({"video", 0},
+ {"window", 1},
+ {"subtitles", 2})),
+ OARG_CHOICE(0, ({"single", 0},
+ {"each-frame", 1})),
+ }},
+ { MP_CMD_SCREENSHOT_TO_FILE, "screenshot_to_file", {
+ ARG_STRING,
+ OARG_CHOICE(2, ({"video", 0},
+ {"window", 1},
+ {"subtitles", 2})),
+ }},
+ { MP_CMD_LOADFILE, "loadfile", {
+ ARG_STRING,
+ OARG_CHOICE(0, ({"replace", 0}, {"0", 0},
+ {"append", 1}, {"1", 1})),
+ }},
+ { MP_CMD_LOADLIST, "loadlist", {
+ ARG_STRING,
+ OARG_CHOICE(0, ({"replace", 0}, {"0", 0},
+ {"append", 1}, {"1", 1})),
+ }},
+ { MP_CMD_PLAYLIST_CLEAR, "playlist_clear", },
+ { MP_CMD_PLAYLIST_REMOVE, "playlist_remove", { ARG_INT } },
+ { MP_CMD_PLAYLIST_MOVE, "playlist_move", { ARG_INT, ARG_INT } },
+ { MP_CMD_RUN, "run", { ARG_STRING } },
+
+ { MP_CMD_KEYDOWN_EVENTS, "key_down_event", { ARG_INT } },
+ { MP_CMD_SET, "set", { ARG_STRING, ARG_STRING } },
+ { MP_CMD_GET_PROPERTY, "get_property", { ARG_STRING } },
+ { MP_CMD_ADD, "add", { ARG_STRING, OARG_DOUBLE(0) } },
+ { MP_CMD_CYCLE, "cycle", {
+ ARG_STRING,
+ { .type = {"", NULL, &m_option_type_cycle_dir},
+ .optional = true,
+ .v.d = 1 },
+ }},
+
+ { MP_CMD_ENABLE_INPUT_SECTION, "enable_section", {
+ ARG_STRING,
+ OARG_CHOICE(0, ({"default", 0},
+ {"exclusive", 1})),
+ }},
+ { MP_CMD_DISABLE_INPUT_SECTION, "disable_section", { ARG_STRING } },
+
+ { MP_CMD_AF, "af", { ARG_STRING, ARG_STRING } },
+
+ { MP_CMD_VF, "vf", { ARG_STRING, ARG_STRING } },
+
+ { MP_CMD_VO_CMDLINE, "vo_cmdline", { ARG_STRING } },
+
+ {0}
+};
+
+// Map legacy commands to proper commands
+struct legacy_cmd {
+ const char *old, *new;
+};
+static const struct legacy_cmd legacy_cmds[] = {
+ {"loop", "cycle loop"},
+ {"seek_chapter", "add chapter"},
+ {"switch_angle", "cycle angle"},
+ {"pause", "cycle pause"},
+ {"volume", "add volume"},
+ {"mute", "cycle mute"},
+ {"audio_delay", "add audio-delay"},
+ {"switch_audio", "cycle audio"},
+ {"balance", "add balance"},
+ {"vo_fullscreen", "cycle fullscreen"},
+ {"panscan", "add panscan"},
+ {"vo_ontop", "cycle ontop"},
+ {"vo_border", "cycle border"},
+ {"frame_drop", "cycle framedrop"},
+ {"gamma", "add gamma"},
+ {"brightness", "add brightness"},
+ {"contrast", "add contrast"},
+ {"saturation", "add saturation"},
+ {"hue", "add hue"},
+ {"switch_vsync", "cycle vsync"},
+ {"sub_load", "sub_add"},
+ {"sub_select", "cycle sub"},
+ {"sub_pos", "add sub-pos"},
+ {"sub_delay", "add sub-delay"},
+ {"sub_visibility", "cycle sub-visibility"},
+ {"forced_subs_only", "cycle sub-forced-only"},
+ {"sub_scale", "add sub-scale"},
+ {"ass_use_margins", "cycle ass-use-margins"},
+ {"tv_set_brightness", "add tv-brightness"},
+ {"tv_set_hue", "add tv-hue"},
+ {"tv_set_saturation", "add tv-saturation"},
+ {"tv_set_contrast", "add tv-contrast"},
+ {"step_property_osd", "cycle"},
+ {"step_property", "no-osd cycle"},
+ {"set_property", "no-osd set"},
+ {"set_property_osd", "set"},
+ {"speed_set", "set speed"},
+ {"osd_show_text", "show_text"},
+ {"osd_show_property_text", "show_text"},
+ {"osd_show_progression", "show_progress"},
+ {"show_chapters_osd", "show_text ${chapter-list}"},
+ {"!show_chapters", "show_text ${chapter-list}"},
+ {"show_tracks_osd", "show_text ${track-list}"},
+ {"!show_tracks", "show_text ${track-list}"},
+ {"!show_playlist", "show_text ${playlist}"},
+
+ // Approximate (can fail if user added additional whitespace)
+ {"pt_step 1", "playlist_next"},
+ {"pt_step -1", "playlist_prev"},
+ // Switch_ratio without argument resets aspect ratio
+ {"switch_ratio ", "set aspect "},
+ {"switch_ratio", "set aspect 0"},
+ {0}
+};
+
+
+/// The names of the keys as used in input.conf
+/// If you add some new keys, you also need to add them here
+
+static const struct key_name key_names[] = {
+ { ' ', "SPACE" },
+ { '#', "SHARP" },
+ { MP_KEY_ENTER, "ENTER" },
+ { MP_KEY_TAB, "TAB" },
+ { MP_KEY_BACKSPACE, "BS" },
+ { MP_KEY_DELETE, "DEL" },
+ { MP_KEY_INSERT, "INS" },
+ { MP_KEY_HOME, "HOME" },
+ { MP_KEY_END, "END" },
+ { MP_KEY_PAGE_UP, "PGUP" },
+ { MP_KEY_PAGE_DOWN, "PGDWN" },
+ { MP_KEY_ESC, "ESC" },
+ { MP_KEY_PRINT, "PRINT" },
+ { MP_KEY_RIGHT, "RIGHT" },
+ { MP_KEY_LEFT, "LEFT" },
+ { MP_KEY_DOWN, "DOWN" },
+ { MP_KEY_UP, "UP" },
+ { MP_KEY_F+1, "F1" },
+ { MP_KEY_F+2, "F2" },
+ { MP_KEY_F+3, "F3" },
+ { MP_KEY_F+4, "F4" },
+ { MP_KEY_F+5, "F5" },
+ { MP_KEY_F+6, "F6" },
+ { MP_KEY_F+7, "F7" },
+ { MP_KEY_F+8, "F8" },
+ { MP_KEY_F+9, "F9" },
+ { MP_KEY_F+10, "F10" },
+ { MP_KEY_F+11, "F11" },
+ { MP_KEY_F+12, "F12" },
+ { MP_KEY_KP0, "KP0" },
+ { MP_KEY_KP1, "KP1" },
+ { MP_KEY_KP2, "KP2" },
+ { MP_KEY_KP3, "KP3" },
+ { MP_KEY_KP4, "KP4" },
+ { MP_KEY_KP5, "KP5" },
+ { MP_KEY_KP6, "KP6" },
+ { MP_KEY_KP7, "KP7" },
+ { MP_KEY_KP8, "KP8" },
+ { MP_KEY_KP9, "KP9" },
+ { MP_KEY_KPDEL, "KP_DEL" },
+ { MP_KEY_KPDEC, "KP_DEC" },
+ { MP_KEY_KPINS, "KP_INS" },
+ { MP_KEY_KPENTER, "KP_ENTER" },
+ { MP_MOUSE_BTN0, "MOUSE_BTN0" },
+ { MP_MOUSE_BTN1, "MOUSE_BTN1" },
+ { MP_MOUSE_BTN2, "MOUSE_BTN2" },
+ { MP_MOUSE_BTN3, "MOUSE_BTN3" },
+ { MP_MOUSE_BTN4, "MOUSE_BTN4" },
+ { MP_MOUSE_BTN5, "MOUSE_BTN5" },
+ { MP_MOUSE_BTN6, "MOUSE_BTN6" },
+ { MP_MOUSE_BTN7, "MOUSE_BTN7" },
+ { MP_MOUSE_BTN8, "MOUSE_BTN8" },
+ { MP_MOUSE_BTN9, "MOUSE_BTN9" },
+ { MP_MOUSE_BTN10, "MOUSE_BTN10" },
+ { MP_MOUSE_BTN11, "MOUSE_BTN11" },
+ { MP_MOUSE_BTN12, "MOUSE_BTN12" },
+ { MP_MOUSE_BTN13, "MOUSE_BTN13" },
+ { MP_MOUSE_BTN14, "MOUSE_BTN14" },
+ { MP_MOUSE_BTN15, "MOUSE_BTN15" },
+ { MP_MOUSE_BTN16, "MOUSE_BTN16" },
+ { MP_MOUSE_BTN17, "MOUSE_BTN17" },
+ { MP_MOUSE_BTN18, "MOUSE_BTN18" },
+ { MP_MOUSE_BTN19, "MOUSE_BTN19" },
+ { MP_MOUSE_BTN0_DBL, "MOUSE_BTN0_DBL" },
+ { MP_MOUSE_BTN1_DBL, "MOUSE_BTN1_DBL" },
+ { MP_MOUSE_BTN2_DBL, "MOUSE_BTN2_DBL" },
+ { MP_MOUSE_BTN3_DBL, "MOUSE_BTN3_DBL" },
+ { MP_MOUSE_BTN4_DBL, "MOUSE_BTN4_DBL" },
+ { MP_MOUSE_BTN5_DBL, "MOUSE_BTN5_DBL" },
+ { MP_MOUSE_BTN6_DBL, "MOUSE_BTN6_DBL" },
+ { MP_MOUSE_BTN7_DBL, "MOUSE_BTN7_DBL" },
+ { MP_MOUSE_BTN8_DBL, "MOUSE_BTN8_DBL" },
+ { MP_MOUSE_BTN9_DBL, "MOUSE_BTN9_DBL" },
+ { MP_MOUSE_BTN10_DBL, "MOUSE_BTN10_DBL" },
+ { MP_MOUSE_BTN11_DBL, "MOUSE_BTN11_DBL" },
+ { MP_MOUSE_BTN12_DBL, "MOUSE_BTN12_DBL" },
+ { MP_MOUSE_BTN13_DBL, "MOUSE_BTN13_DBL" },
+ { MP_MOUSE_BTN14_DBL, "MOUSE_BTN14_DBL" },
+ { MP_MOUSE_BTN15_DBL, "MOUSE_BTN15_DBL" },
+ { MP_MOUSE_BTN16_DBL, "MOUSE_BTN16_DBL" },
+ { MP_MOUSE_BTN17_DBL, "MOUSE_BTN17_DBL" },
+ { MP_MOUSE_BTN18_DBL, "MOUSE_BTN18_DBL" },
+ { MP_MOUSE_BTN19_DBL, "MOUSE_BTN19_DBL" },
+ { MP_JOY_AXIS1_MINUS, "JOY_UP" },
+ { MP_JOY_AXIS1_PLUS, "JOY_DOWN" },
+ { MP_JOY_AXIS0_MINUS, "JOY_LEFT" },
+ { MP_JOY_AXIS0_PLUS, "JOY_RIGHT" },
+
+ { MP_JOY_AXIS0_PLUS, "JOY_AXIS0_PLUS" },
+ { MP_JOY_AXIS0_MINUS, "JOY_AXIS0_MINUS" },
+ { MP_JOY_AXIS1_PLUS, "JOY_AXIS1_PLUS" },
+ { MP_JOY_AXIS1_MINUS, "JOY_AXIS1_MINUS" },
+ { MP_JOY_AXIS2_PLUS, "JOY_AXIS2_PLUS" },
+ { MP_JOY_AXIS2_MINUS, "JOY_AXIS2_MINUS" },
+ { MP_JOY_AXIS3_PLUS, "JOY_AXIS3_PLUS" },
+ { MP_JOY_AXIS3_MINUS, "JOY_AXIS3_MINUS" },
+ { MP_JOY_AXIS4_PLUS, "JOY_AXIS4_PLUS" },
+ { MP_JOY_AXIS4_MINUS, "JOY_AXIS4_MINUS" },
+ { MP_JOY_AXIS5_PLUS, "JOY_AXIS5_PLUS" },
+ { MP_JOY_AXIS5_MINUS, "JOY_AXIS5_MINUS" },
+ { MP_JOY_AXIS6_PLUS, "JOY_AXIS6_PLUS" },
+ { MP_JOY_AXIS6_MINUS, "JOY_AXIS6_MINUS" },
+ { MP_JOY_AXIS7_PLUS, "JOY_AXIS7_PLUS" },
+ { MP_JOY_AXIS7_MINUS, "JOY_AXIS7_MINUS" },
+ { MP_JOY_AXIS8_PLUS, "JOY_AXIS8_PLUS" },
+ { MP_JOY_AXIS8_MINUS, "JOY_AXIS8_MINUS" },
+ { MP_JOY_AXIS9_PLUS, "JOY_AXIS9_PLUS" },
+ { MP_JOY_AXIS9_MINUS, "JOY_AXIS9_MINUS" },
+
+ { MP_JOY_BTN0, "JOY_BTN0" },
+ { MP_JOY_BTN1, "JOY_BTN1" },
+ { MP_JOY_BTN2, "JOY_BTN2" },
+ { MP_JOY_BTN3, "JOY_BTN3" },
+ { MP_JOY_BTN4, "JOY_BTN4" },
+ { MP_JOY_BTN5, "JOY_BTN5" },
+ { MP_JOY_BTN6, "JOY_BTN6" },
+ { MP_JOY_BTN7, "JOY_BTN7" },
+ { MP_JOY_BTN8, "JOY_BTN8" },
+ { MP_JOY_BTN9, "JOY_BTN9" },
+
+ { MP_AR_PLAY, "AR_PLAY" },
+ { MP_AR_PLAY_HOLD, "AR_PLAY_HOLD" },
+ { MP_AR_CENTER, "AR_CENTER" },
+ { MP_AR_CENTER_HOLD, "AR_CENTER_HOLD" },
+ { MP_AR_NEXT, "AR_NEXT" },
+ { MP_AR_NEXT_HOLD, "AR_NEXT_HOLD" },
+ { MP_AR_PREV, "AR_PREV" },
+ { MP_AR_PREV_HOLD, "AR_PREV_HOLD" },
+ { MP_AR_MENU, "AR_MENU" },
+ { MP_AR_MENU_HOLD, "AR_MENU_HOLD" },
+ { MP_AR_VUP, "AR_VUP" },
+ { MP_AR_VUP_HOLD, "AR_VUP_HOLD" },
+ { MP_AR_VDOWN, "AR_VDOWN" },
+ { MP_AR_VDOWN_HOLD, "AR_VDOWN_HOLD" },
+
+ { MP_MK_PLAY, "MK_PLAY" },
+ { MP_MK_PREV, "MK_PREV" },
+ { MP_MK_NEXT, "MK_NEXT" },
+
+ { MP_KEY_POWER, "POWER" },
+ { MP_KEY_MENU, "MENU" },
+ { MP_KEY_PLAY, "PLAY" },
+ { MP_KEY_PAUSE, "PAUSE" },
+ { MP_KEY_PLAYPAUSE, "PLAYPAUSE" },
+ { MP_KEY_STOP, "STOP" },
+ { MP_KEY_FORWARD, "FORWARD" },
+ { MP_KEY_REWIND, "REWIND" },
+ { MP_KEY_NEXT, "NEXT" },
+ { MP_KEY_PREV, "PREV" },
+ { MP_KEY_VOLUME_UP, "VOLUME_UP" },
+ { MP_KEY_VOLUME_DOWN, "VOLUME_DOWN" },
+ { MP_KEY_MUTE, "MUTE" },
+
+ // These are kept for backward compatibility
+ { MP_KEY_PAUSE, "XF86_PAUSE" },
+ { MP_KEY_STOP, "XF86_STOP" },
+ { MP_KEY_PREV, "XF86_PREV" },
+ { MP_KEY_NEXT, "XF86_NEXT" },
+
+ { MP_KEY_CLOSE_WIN, "CLOSE_WIN" },
+ { MP_KEY_MOUSE_MOVE, "MOUSE_MOVE" },
+ { MP_KEY_MOUSE_LEAVE, "MOUSE_LEAVE" },
+
+ { 0, NULL }
+};
+
+struct key_name modifier_names[] = {
+ { MP_KEY_MODIFIER_SHIFT, "Shift" },
+ { MP_KEY_MODIFIER_CTRL, "Ctrl" },
+ { MP_KEY_MODIFIER_ALT, "Alt" },
+ { MP_KEY_MODIFIER_META, "Meta" },
+ { 0 }
+};
+
+#define MP_MAX_FDS 10
+
+struct input_fd {
+ int fd;
+ int (*read_key)(void *ctx, int fd);
+ int (*read_cmd)(int fd, char *dest, int size);
+ int (*close_func)(int fd);
+ void *ctx;
+ unsigned eof : 1;
+ unsigned drop : 1;
+ unsigned dead : 1;
+ unsigned got_cmd : 1;
+ unsigned select : 1;
+ // These fields are for the cmd fds.
+ char *buffer;
+ int pos, size;
+};
+
+struct cmd_bind_section {
+ struct cmd_bind *binds;
+ int num_binds;
+ char *section;
+ struct mp_rect mouse_area; // set at runtime, if at all
+ bool mouse_area_set; // mouse_area is valid and should be tested
+ struct cmd_bind_section *next;
+};
+
+#define MAX_ACTIVE_SECTIONS 5
+
+struct active_section {
+ char *name;
+ int flags;
+};
+
+struct cmd_queue {
+ struct mp_cmd *first;
+};
+
+struct input_ctx {
+ bool using_ar;
+ bool using_cocoa_media_keys;
+
+ // Autorepeat stuff
+ short ar_state;
+ int64_t last_ar;
+ // Autorepeat config
+ unsigned int ar_delay;
+ unsigned int ar_rate;
+ // Maximum number of queued commands from keypresses (limit to avoid
+ // repeated slow commands piling up)
+ int key_fifo_size;
+
+ // these are the keys currently down
+ int key_down[MP_MAX_KEY_DOWN];
+ unsigned int num_key_down;
+ int64_t last_key_down;
+ struct mp_cmd *current_down_cmd;
+
+ int doubleclick_time;
+ int last_doubleclick_key_down;
+ double last_doubleclick_time;
+
+ // Mouse position on the consumer side (as command.c sees it)
+ int mouse_x, mouse_y;
+ char *mouse_section; // last section to receive mouse event
+
+ // Mouse position on the producer side (as the VO sees it)
+ // Unlike mouse_x/y, this can be used to resolve mouse click bindings.
+ int mouse_vo_x, mouse_vo_y;
+
+ bool test;
+
+ bool default_bindings;
+ // List of command binding sections
+ struct cmd_bind_section *cmd_bind_sections;
+
+ // List currently active command sections
+ struct active_section active_sections[MAX_ACTIVE_SECTIONS];
+ int num_active_sections;
+
+ // Used to track whether we managed to read something while checking
+ // events sources. If yes, the sources may have more queued.
+ bool got_new_events;
+
+ unsigned int mouse_event_counter;
+
+ struct input_fd fds[MP_MAX_FDS];
+ unsigned int num_fds;
+
+ struct cmd_queue key_cmd_queue;
+ struct cmd_queue control_cmd_queue;
+
+ int wakeup_pipe[2];
+};
+
+
+int async_quit_request;
+
+static int print_key_list(m_option_t *cfg, char *optname, char *optparam);
+static int print_cmd_list(m_option_t *cfg, char *optname, char *optparam);
+
+#define OPT_BASE_STRUCT struct MPOpts
+
+// Our command line options
+static const m_option_t input_config[] = {
+ OPT_STRING("conf", input.config_file, CONF_GLOBAL),
+ OPT_INT("ar-delay", input.ar_delay, CONF_GLOBAL),
+ OPT_INT("ar-rate", input.ar_rate, CONF_GLOBAL),
+ { "keylist", print_key_list, CONF_TYPE_PRINT_FUNC, CONF_GLOBAL | CONF_NOCFG },
+ { "cmdlist", print_cmd_list, CONF_TYPE_PRINT_FUNC, CONF_GLOBAL | CONF_NOCFG },
+ OPT_STRING("js-dev", input.js_dev, CONF_GLOBAL),
+ OPT_STRING("file", input.in_file, CONF_GLOBAL),
+ OPT_FLAG("default-bindings", input.default_bindings, CONF_GLOBAL),
+ OPT_FLAG("test", input.test, CONF_GLOBAL),
+ { NULL, NULL, 0, 0, 0, 0, NULL}
+};
+
+const m_option_t mp_input_opts[] = {
+ { "input", (void *)&input_config, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
+ OPT_INTRANGE("doubleclick-time", input.doubleclick_time, 0, 0, 1000),
+ OPT_FLAG("joystick", input.use_joystick, CONF_GLOBAL),
+ OPT_FLAG("lirc", input.use_lirc, CONF_GLOBAL),
+ OPT_FLAG("lircc", input.use_lircc, CONF_GLOBAL),
+#ifdef CONFIG_COCOA
+ OPT_FLAG("ar", input.use_ar, CONF_GLOBAL),
+ OPT_FLAG("media-keys", input.use_media_keys, CONF_GLOBAL),
+#endif
+ { NULL, NULL, 0, 0, 0, 0, NULL}
+};
+
+static int default_cmd_func(int fd, char *buf, int l);
+
+static const char builtin_input_conf[] =
+#include "core/input/input_conf.h"
+;
+
+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;
+}
+
+static char *get_key_name(int key, char *ret)
+{
+ for (int i = 0; modifier_names[i].name; i++) {
+ if (modifier_names[i].key & key) {
+ ret = talloc_asprintf_append_buffer(ret, "%s+",
+ modifier_names[i].name);
+ key -= modifier_names[i].key;
+ }
+ }
+ for (int i = 0; key_names[i].name != NULL; i++) {
+ if (key_names[i].key == key)
+ return talloc_asprintf_append_buffer(ret, "%s", key_names[i].name);
+ }
+
+ // printable, and valid unicode range
+ if (key >= 32 && key <= 0x10FFFF)
+ return mp_append_utf8_buffer(ret, key);
+
+ // Print the hex key code
+ return talloc_asprintf_append_buffer(ret, "%#-8x", key);
+}
+
+static char *get_key_combo_name(int *keys, int max)
+{
+ char *ret = talloc_strdup(NULL, "");
+ while (max > 0) {
+ ret = get_key_name(*keys, ret);
+ if (--max && *++keys)
+ ret = talloc_asprintf_append_buffer(ret, "-");
+ else
+ break;
+ }
+ return ret;
+}
+
+bool mp_input_is_abort_cmd(int cmd_id)
+{
+ switch (cmd_id) {
+ case MP_CMD_QUIT:
+ case MP_CMD_PLAYLIST_NEXT:
+ case MP_CMD_PLAYLIST_PREV:
+ return true;
+ }
+ return false;
+}
+
+static int queue_count_cmds(struct cmd_queue *queue)
+{
+ int res = 0;
+ for (struct mp_cmd *cmd = queue->first; cmd; cmd = cmd->queue_next)
+ res++;
+ return res;
+}
+
+static bool queue_has_abort_cmds(struct cmd_queue *queue)
+{
+ for (struct mp_cmd *cmd = queue->first; cmd; cmd = cmd->queue_next) {
+ if (mp_input_is_abort_cmd(cmd->id))
+ return true;
+ }
+ return false;
+}
+
+static void queue_remove(struct cmd_queue *queue, struct mp_cmd *cmd)
+{
+ struct mp_cmd **p_prev = &queue->first;
+ while (*p_prev != cmd) {
+ p_prev = &(*p_prev)->queue_next;
+ }
+ // if this fails, cmd was not in the queue
+ assert(*p_prev == cmd);
+ *p_prev = cmd->queue_next;
+}
+
+static void queue_add(struct cmd_queue *queue, struct mp_cmd *cmd,
+ bool at_head)
+{
+ if (at_head) {
+ cmd->queue_next = queue->first;
+ queue->first = cmd;
+ } else {
+ struct mp_cmd **p_prev = &queue->first;
+ while (*p_prev)
+ p_prev = &(*p_prev)->queue_next;
+ *p_prev = cmd;
+ cmd->queue_next = NULL;
+ }
+}
+
+static struct input_fd *mp_input_add_fd(struct input_ctx *ictx)
+{
+ if (ictx->num_fds == MP_MAX_FDS) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Too many file descriptors.\n");
+ return NULL;
+ }
+
+ struct input_fd *fd = &ictx->fds[ictx->num_fds];
+ *fd = (struct input_fd){
+ .fd = -1,
+ };
+ ictx->num_fds++;
+
+ return fd;
+}
+
+int mp_input_add_cmd_fd(struct input_ctx *ictx, int unix_fd, int select,
+ int read_func(int fd, char *dest, int size),
+ int close_func(int fd))
+{
+ if (select && unix_fd < 0) {
+ mp_msg(MSGT_INPUT, MSGL_ERR,
+ "Invalid fd %d in mp_input_add_cmd_fd", unix_fd);
+ return 0;
+ }
+
+ struct input_fd *fd = mp_input_add_fd(ictx);
+ if (!fd)
+ return 0;
+ fd->fd = unix_fd;
+ fd->select = select;
+ fd->read_cmd = read_func ? read_func : default_cmd_func;
+ fd->close_func = close_func;
+ return 1;
+}
+
+int mp_input_add_key_fd(struct input_ctx *ictx, int unix_fd, int select,
+ int read_func(void *ctx, int fd),
+ int close_func(int fd), void *ctx)
+{
+ if (select && unix_fd < 0) {
+ mp_msg(MSGT_INPUT, MSGL_ERR,
+ "Invalid fd %d in mp_input_add_key_fd", unix_fd);
+ return 0;
+ }
+ assert(read_func);
+
+ struct input_fd *fd = mp_input_add_fd(ictx);
+ if (!fd)
+ return 0;
+ fd->fd = unix_fd;
+ fd->select = select;
+ fd->read_key = read_func;
+ fd->close_func = close_func;
+ fd->ctx = ctx;
+ return 1;
+}
+
+
+static void mp_input_rm_fd(struct input_ctx *ictx, int fd)
+{
+ struct input_fd *fds = ictx->fds;
+ unsigned int i;
+
+ for (i = 0; i < ictx->num_fds; i++) {
+ if (fds[i].fd == fd)
+ break;
+ }
+ if (i == ictx->num_fds)
+ return;
+ if (fds[i].close_func)
+ fds[i].close_func(fds[i].fd);
+ talloc_free(fds[i].buffer);
+
+ if (i + 1 < ictx->num_fds)
+ memmove(&fds[i], &fds[i + 1],
+ (ictx->num_fds - i - 1) * sizeof(struct input_fd));
+ ictx->num_fds--;
+}
+
+void mp_input_rm_key_fd(struct input_ctx *ictx, int fd)
+{
+ mp_input_rm_fd(ictx, fd);
+}
+
+static int parse_cycle_dir(const struct m_option *opt, struct bstr name,
+ struct bstr param, void *dst)
+{
+ double val;
+ if (bstrcmp0(param, "up") == 0) {
+ val = +1;
+ } else if (bstrcmp0(param, "down") == 0) {
+ val = -1;
+ } else {
+ return m_option_type_double.parse(opt, name, param, dst);
+ }
+ *(double *)dst = val;
+ return 1;
+}
+
+static bool read_token(bstr str, bstr *out_rest, bstr *out_token)
+{
+ bstr t = bstr_lstrip(str);
+ int next = bstrcspn(t, WHITESPACE "#");
+ // Handle comments
+ if (t.len && t.start[next] == '#')
+ t = bstr_splice(t, 0, next);
+ if (!t.len)
+ return false;
+ *out_token = bstr_splice(t, 0, next);
+ *out_rest = bstr_cut(t, next);
+ return true;
+}
+
+static bool eat_token(bstr *str, const char *tok)
+{
+ bstr rest, token;
+ if (read_token(*str, &rest, &token) && bstrcmp0(token, tok) == 0) {
+ *str = rest;
+ return true;
+ }
+ return false;
+}
+
+static bool read_escaped_string(void *talloc_ctx, bstr *str, bstr *literal)
+{
+ bstr t = *str;
+ char *new = talloc_strdup(talloc_ctx, "");
+ while (t.len) {
+ if (t.start[0] == '"')
+ break;
+ if (t.start[0] == '\\') {
+ t = bstr_cut(t, 1);
+ if (!mp_parse_escape(&t, &new))
+ goto error;
+ } else {
+ new = talloc_strndup_append_buffer(new, t.start, 1);
+ t = bstr_cut(t, 1);
+ }
+ }
+ int len = str->len - t.len;
+ *literal = new ? bstr0(new) : bstr_splice(*str, 0, len);
+ *str = bstr_cut(*str, len);
+ return true;
+error:
+ talloc_free(new);
+ return false;
+}
+
+// If dest is non-NULL when calling this function, append the command to the
+// list formed by dest->queue_next, otherwise just set *dest = new_cmd;
+static int parse_cmd(struct mp_cmd **dest, bstr str, const char *loc)
+{
+ int pausing = 0;
+ int on_osd = MP_ON_OSD_AUTO;
+ bool raw_args = false;
+ struct mp_cmd *cmd = NULL;
+ bstr start = str;
+ bstr next = {0};
+ void *tmp = talloc_new(NULL);
+
+ str = bstr_lstrip(str);
+ for (const struct legacy_cmd *entry = legacy_cmds; entry->old; entry++) {
+ bstr old = bstr0(entry->old);
+ bool silent = bstr_eatstart0(&old, "!");
+ if (bstrcasecmp(bstr_splice(str, 0, old.len), old) == 0) {
+ if (!silent) {
+ mp_tmsg(MSGT_INPUT, MSGL_WARN, "Warning: command '%.*s' is "
+ "deprecated, replaced with '%s' at %s.\n",
+ BSTR_P(old), entry->new, loc);
+ }
+ bstr s = bstr_cut(str, old.len);
+ str = bstr0(talloc_asprintf(tmp, "%s%.*s", entry->new, BSTR_P(s)));
+ start = str;
+ break;
+ }
+ }
+
+ while (1) {
+ if (eat_token(&str, "pausing")) {
+ pausing = 1;
+ } else if (eat_token(&str, "pausing_keep")) {
+ pausing = 2;
+ } else if (eat_token(&str, "pausing_toggle")) {
+ pausing = 3;
+ } else if (eat_token(&str, "pausing_keep_force")) {
+ pausing = 4;
+ } else if (eat_token(&str, "no-osd")) {
+ on_osd = MP_ON_OSD_NO;
+ } else if (eat_token(&str, "osd-bar")) {
+ on_osd = MP_ON_OSD_BAR;
+ } else if (eat_token(&str, "osd-msg")) {
+ on_osd = MP_ON_OSD_MSG;
+ } else if (eat_token(&str, "osd-msg-bar")) {
+ on_osd = MP_ON_OSD_MSG | MP_ON_OSD_BAR;
+ } else if (eat_token(&str, "osd-auto")) {
+ // default
+ } else if (eat_token(&str, "raw")) {
+ raw_args = true;
+ } else if (eat_token(&str, "expand-properties")) {
+ // default
+ } else {
+ break;
+ }
+ }
+
+ int cmd_idx = 0;
+ while (mp_cmds[cmd_idx].name != NULL) {
+ if (eat_token(&str, mp_cmds[cmd_idx].name))
+ break;
+ cmd_idx++;
+ }
+
+ if (mp_cmds[cmd_idx].name == NULL) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command '%.*s' not found.\n",
+ BSTR_P(str));
+ goto error;
+ }
+
+ cmd = talloc_ptrtype(NULL, cmd);
+ *cmd = mp_cmds[cmd_idx];
+ cmd->pausing = pausing;
+ cmd->on_osd = on_osd;
+ cmd->raw_args = raw_args;
+
+ for (int i = 0; i < MP_CMD_MAX_ARGS; i++) {
+ struct mp_cmd_arg *cmdarg = &cmd->args[i];
+ if (!cmdarg->type.type)
+ break;
+ str = bstr_lstrip(str);
+ if (eat_token(&str, ";")) {
+ next = str;
+ str.len = 0;
+ break;
+ }
+ cmd->nargs++;
+ bstr arg = {0};
+ if (bstr_eatstart0(&str, "\"")) {
+ if (!read_escaped_string(tmp, &str, &arg)) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d "
+ "has broken string escapes.\n", cmd->name, i + 1);
+ goto error;
+ }
+ if (!bstr_eatstart0(&str, "\"")) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d is "
+ "unterminated.\n", cmd->name, i + 1);
+ goto error;
+ }
+ } else {
+ if (!read_token(str, &str, &arg))
+ break;
+ if (cmdarg->optional && bstrcmp0(arg, "-") == 0)
+ continue;
+ }
+ // Prevent option API from trying to deallocate static strings
+ cmdarg->v = ((struct mp_cmd_arg) {{0}}).v;
+ int r = m_option_parse(&cmdarg->type, bstr0(cmd->name), arg, &cmdarg->v);
+ if (r < 0) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d "
+ "can't be parsed: %s.\n", cmd->name, i + 1,
+ m_option_strerror(r));
+ goto error;
+ }
+ if (cmdarg->type.type == &m_option_type_string)
+ cmdarg->v.s = talloc_steal(cmd, cmdarg->v.s);
+ }
+
+ if (eat_token(&str, ";")) {
+ next = str;
+ str.len = 0;