mpv/core/input/input.c

1928 lines
60 KiB
C
Raw Normal View History

/*
* 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>
2009-03-14 22:52:45 +01:00
#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>
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
#include <assert.h>
#include <libavutil/avstring.h>
#include <libavutil/common.h>
#include "osdep/io.h"
#include "osdep/getch2.h"
#include "input.h"
#include "core/mp_fifo.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 {
2011-04-25 10:38:46 +02:00
int input[MP_MAX_KEY_DOWN + 1];
char *cmd;
char *location; // filename/line number of definition
struct cmd_bind_section *owner;
};
struct key_name {
2011-04-25 10:38:46 +02:00
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_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_FLOAT(def) { .type = {"", NULL, &m_option_type_float}, \
.optional = true, .v.f = 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_FLOAT } },
{ 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", },
core: add backstep support Allows stepping back one frame via the frame_back_step inout command, bound to "," by default. This uses the precise seeking facility, and a perfect frame index built on the fly. The index is built during playback and precise seeking, and contains (as of this commit) the last 100 displayed or skipped frames. This index is used to find the PTS of the previous frame, which is then used as target for a precise seek. If no PTS is found, the core attempts to do a seek before the current frame, and skip decoded frames until the current frame is reached; this will create a sufficient index and the normal backstep algorithm can be applied. This can be rather slow. The worst case for backstepping is about the same as the worst case for precise seeking if the previous frame can be deduced from the index. If not, the worst case will be twice as slow. There's also some minor danger that the index is incorrect in case framedropping is involved. For framedropping due to --framedrop, this problem is ignored (use of --framedrop is discouraged anyway). For framedropping during precise seeking (done to make it faster), we try to not add frames to the index that are produced when this can happen. I'm not sure how well that works (or if the logic is sane), and it's sure to break with some video filters. In the worst case, backstepping might silently skip frames if you backstep after a user-initiated precise seek. (Precise seeks to do indexing are not affected.) Likewise, video filters that somehow change timing of frames and do not do this in a deterministic way (i.e. if you seek to a position, frames with different timings are produced than when the position is reached during normal playback) will make backstepping silently jump to the wrong frame. Enabling/disabling filters during playback (like for example deinterlacing) will have similar bad effects.
2013-04-24 19:31:48 +02:00
{ 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_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})),
}},
mplayer: turn playtree into a list, and change per-file option handling Summary: - There is no playtree anymore. It's reduced to a simple list. - Options are now always global. You can still have per-file options, but these are optional and require special syntax. - The slave command pt_step has been removed, and playlist_next and playlist_prev added. (See etc/input.conf changes.) This is a user visible incompatible change, and will break slave-mode applications. - The pt_clear slave command is renamed to playlist_clear. - Playtree entries could have multiple files. This is not the case anymore, and playlist entries have always exactly one entry. Whenever something adds more than one file (like ASX playlists or dvd:// or dvdnav:// on the command line), all files are added as separate playlist entries. Note that some of the changes are quite deep and violent. Expect regressions. The playlist parsing code in particular is of low quality. I didn't try to improve it, and merely spent to least effort necessary to keep it somehow working. (Especially ASX playlist handling.) The playtree code was complicated and bloated. It was also barely used. Most users don't even know that mplayer manages the playlist as tree, or how to use it. The most obscure features was probably specifying a tree on command line (with '{' and '}' to create/close tree nodes). It filled the player code with complexity and confused users with weird slave commands like pt_up. Replace the playtree with a simple flat playlist. Playlist parsers that actually return trees are changed to append all files to the playlist pre-order. It used to be the responsibility of the playtree code to change per-file config options. Now this is done by the player core, and the playlist code is free of such details. Options are not per-file by default anymore. This was a very obscure and complicated feature that confused even experienced users. Consider the following command line: mplayer file1.mkv file2.mkv --no-audio file3.mkv This will disable the audio for file2.mkv only, because options are per-file by default. To make the option affect all files, you're supposed to put it before the first file. This is bad, because normally you don't need per-file options. They are very rarely needed, and the only reasonable use cases I can imagine are use of the encode backend (mplayer encode branch), or for debugging. The normal use case is made harder, and the feature is perceived as bug. Even worse, correct usage is hard to explain for users. Make all options global by default. The position of an option isn't significant anymore (except for options that compensate each other, consider --shuffle --no-shuffle). One other important change is that no options are reset anymore if a new file is started. If you change settings with slave mode commands, they will not be changed by playing a new file. (Exceptions include settings that are too file specific, like audio/subtitle stream selection.) There is still some need for per-file options. Debugging and encoding are use cases that profit from per-file options. Per-file profiles (as well as per-protocol and per-VO/AO options) need the implementation related mechanisms to backup and restore options when the playback file changes. Simplify the save-slot stuff, which is possible because there is no hierarchical play tree anymore. Now there's a simple backup field. Add a way to specify per-file options on command line. Example: mplayer f1.mkv -o0 --{ -o1 f2.mkv -o2 f3.mkv --} f4.mkv -o3 will have the following options per file set: f1.mkv, f4.mkv: -o0 -o3 f2.mkv, f3.mkv: -o0 -o3 -o1 -o2 The options --{ and --} start and end per-file options. All files inside the { } will be affected by the options equally (similar to how global options and multiple files are handled). When playback of a file starts, the per-file options are set according to the command line. When playback ends, the per-file options are restored to the values when playback started.
2012-07-31 21:33:26 +02:00
{ MP_CMD_PLAYLIST_CLEAR, "playlist_clear", },
{ 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_FLOAT(0) } },
{ MP_CMD_CYCLE, "cycle", {
ARG_STRING,
{ .type = {"", NULL, &m_option_type_cycle_dir},
.optional = true,
.v.f = 1 },
}},
{ MP_CMD_SET_MOUSE_POS, "set_mouse_pos", { ARG_INT, ARG_INT } },
{ MP_CMD_AF_SWITCH, "af_switch", { ARG_STRING } },
{ MP_CMD_AF_ADD, "af_add", { ARG_STRING } },
{ MP_CMD_AF_DEL, "af_del", { ARG_STRING } },
{ MP_CMD_AF_CLR, "af_clr", },
{ MP_CMD_AF_CMDLINE, "af_cmdline", { ARG_STRING, ARG_STRING } },
{ MP_CMD_VF, "vf", { ARG_STRING, ARG_STRING } },
{ MP_CMD_SHOW_CHAPTERS, "show_chapters", },
{ MP_CMD_SHOW_TRACKS, "show_tracks", },
{ MP_CMD_SHOW_PLAYLIST, "show_playlist", },
{ 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_chapters"},
{"show_tracks_osd", "show_tracks"},
// 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_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" },
{ 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 }
};
#ifndef MP_MAX_KEY_FD
#define MP_MAX_KEY_FD 10
#endif
#ifndef MP_MAX_CMD_FD
#define MP_MAX_CMD_FD 10
#endif
struct input_fd {
2011-04-25 10:38:46 +02:00
int fd;
union {
int (*key)(void *ctx, int fd);
int (*cmd)(int fd, char *dest, int size);
2011-04-25 10:38:46 +02:00
} read_func;
int (*close_func)(int fd);
2011-04-25 10:38:46 +02:00
void *ctx;
unsigned eof : 1;
unsigned drop : 1;
unsigned dead : 1;
unsigned got_cmd : 1;
unsigned no_select : 1;
// These fields are for the cmd fds.
char *buffer;
int pos, size;
};
struct cmd_bind_section {
struct cmd_bind *cmd_binds;
bool is_builtin;
2011-04-25 10:38:46 +02:00
char *section;
struct cmd_bind_section *next;
};
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
struct cmd_queue {
struct mp_cmd *first;
};
struct input_ctx {
// Autorepeat stuff
short ar_state;
mp_cmd_t *ar_cmd;
int64_t last_ar;
2008-04-30 17:57:02 +02:00
// Autorepeat config
unsigned int ar_delay;
unsigned int ar_rate;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
// 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;
bool test;
2009-04-01 01:26:34 +02:00
bool default_bindings;
// List of command binding sections
struct cmd_bind_section *cmd_bind_sections;
// Name of currently used command section
char *section;
// Bitfield of mp_input_section_flags
int section_flags;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
// 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 key_fds[MP_MAX_KEY_FD];
unsigned int num_key_fd;
struct input_fd cmd_fds[MP_MAX_CMD_FD];
unsigned int num_cmd_fd;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
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
2008-04-26 15:35:40 +02:00
static const m_option_t input_conf[] = {
OPT_STRING("conf", input.config_file, CONF_GLOBAL),
2011-04-25 10:38:46 +02:00
OPT_INT("ar-delay", input.ar_delay, CONF_GLOBAL),
2008-04-30 17:57:02 +02:00
OPT_INT("ar-rate", input.ar_rate, CONF_GLOBAL),
options: get rid of ambiguous option parsing Options parsing used to be ambiguous, as in the splitting into option and values pairs was ambiguous. Example: -option -something It wasn't clear whether -option actually takes an argument or not. The string "-something" could either be a separate option, or an argument to "-option". The code had to call the option specific parser function to resolve this. This made everything complicated and didn't even have a real use. There was only one case where this was actually used: string lists (m_option_type_string_list) and options based on it. That is because this option type actually turns a single option into a proxy for several real arguments, e.g. "vf*" can handle "-vf-add" and "-vf-clr". Options suffixed with "-clr" are the only options of this group which take no arguments. This is ambiguous only with the "old syntax" (as shown above). The "new" option syntax always puts option name and value into same argument. (E.g. "--option=--something" or "--option" "--something".) Simplify the code by making it statically known whether an option takes a parameter or not with the flag M_OPT_TYPE_OLD_SYNTAX_NO_PARAM. If it's set, the option parser assumes the option takes no argument. The only real ambiguity left, string list options that end on "-clr", are special cased in the parser. Remove some duplication of the logic in the command line parser by moving all argument splitting logic into split_opt(). (It's arguable whether that can be considered code duplication, but now the code is a bit simpler anyway. This might be subjective.) Remove the "ambiguous" parameter from all option parsing related code. Make m_config unaware of the pre-parsing concept. Make most CONF_NOCFG options also CONF_GLOBAL (except those explicitly usable as per-file options.)
2012-08-05 23:34:28 +02:00
{ "keylist", print_key_list, CONF_TYPE_PRINT_FUNC, CONF_GLOBAL | CONF_NOCFG },
{ "cmdlist", print_cmd_list, CONF_TYPE_PRINT_FUNC, CONF_GLOBAL | CONF_NOCFG },
2008-04-30 17:57:02 +02:00
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),
2011-04-25 10:38:46 +02:00
{ NULL, NULL, 0, 0, 0, 0, NULL}
};
2008-04-26 15:35:40 +02:00
static const m_option_t mp_input_opts[] = {
{ "input", (void *)&input_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
OPT_FLAG("joystick", input.use_joystick, CONF_GLOBAL),
OPT_FLAG("lirc", input.use_lirc, CONF_GLOBAL),
OPT_FLAG("lircc", input.use_lircc, CONF_GLOBAL),
2011-04-25 10:38:46 +02:00
{ NULL, NULL, 0, 0, 0, 0, NULL}
};
2011-04-25 10:38:46 +02:00
static int default_cmd_func(int fd, char *buf, int l);
static const char builtin_input_conf[] =
#include "core/input/input_conf.h"
;
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 (1) {
ret = get_key_name(*keys, ret);
if (--max && *++keys)
ret = talloc_asprintf_append_buffer(ret, "-");
else
break;
}
return ret;
}
mplayer: turn playtree into a list, and change per-file option handling Summary: - There is no playtree anymore. It's reduced to a simple list. - Options are now always global. You can still have per-file options, but these are optional and require special syntax. - The slave command pt_step has been removed, and playlist_next and playlist_prev added. (See etc/input.conf changes.) This is a user visible incompatible change, and will break slave-mode applications. - The pt_clear slave command is renamed to playlist_clear. - Playtree entries could have multiple files. This is not the case anymore, and playlist entries have always exactly one entry. Whenever something adds more than one file (like ASX playlists or dvd:// or dvdnav:// on the command line), all files are added as separate playlist entries. Note that some of the changes are quite deep and violent. Expect regressions. The playlist parsing code in particular is of low quality. I didn't try to improve it, and merely spent to least effort necessary to keep it somehow working. (Especially ASX playlist handling.) The playtree code was complicated and bloated. It was also barely used. Most users don't even know that mplayer manages the playlist as tree, or how to use it. The most obscure features was probably specifying a tree on command line (with '{' and '}' to create/close tree nodes). It filled the player code with complexity and confused users with weird slave commands like pt_up. Replace the playtree with a simple flat playlist. Playlist parsers that actually return trees are changed to append all files to the playlist pre-order. It used to be the responsibility of the playtree code to change per-file config options. Now this is done by the player core, and the playlist code is free of such details. Options are not per-file by default anymore. This was a very obscure and complicated feature that confused even experienced users. Consider the following command line: mplayer file1.mkv file2.mkv --no-audio file3.mkv This will disable the audio for file2.mkv only, because options are per-file by default. To make the option affect all files, you're supposed to put it before the first file. This is bad, because normally you don't need per-file options. They are very rarely needed, and the only reasonable use cases I can imagine are use of the encode backend (mplayer encode branch), or for debugging. The normal use case is made harder, and the feature is perceived as bug. Even worse, correct usage is hard to explain for users. Make all options global by default. The position of an option isn't significant anymore (except for options that compensate each other, consider --shuffle --no-shuffle). One other important change is that no options are reset anymore if a new file is started. If you change settings with slave mode commands, they will not be changed by playing a new file. (Exceptions include settings that are too file specific, like audio/subtitle stream selection.) There is still some need for per-file options. Debugging and encoding are use cases that profit from per-file options. Per-file profiles (as well as per-protocol and per-VO/AO options) need the implementation related mechanisms to backup and restore options when the playback file changes. Simplify the save-slot stuff, which is possible because there is no hierarchical play tree anymore. Now there's a simple backup field. Add a way to specify per-file options on command line. Example: mplayer f1.mkv -o0 --{ -o1 f2.mkv -o2 f3.mkv --} f4.mkv -o3 will have the following options per file set: f1.mkv, f4.mkv: -o0 -o3 f2.mkv, f3.mkv: -o0 -o3 -o1 -o2 The options --{ and --} start and end per-file options. All files inside the { } will be affected by the options equally (similar to how global options and multiple files are handled). When playback of a file starts, the per-file options are set according to the command line. When playback ends, the per-file options are restored to the values when playback started.
2012-07-31 21:33:26 +02:00
bool mp_input_is_abort_cmd(int cmd_id)
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
{
switch (cmd_id) {
case MP_CMD_QUIT:
mplayer: turn playtree into a list, and change per-file option handling Summary: - There is no playtree anymore. It's reduced to a simple list. - Options are now always global. You can still have per-file options, but these are optional and require special syntax. - The slave command pt_step has been removed, and playlist_next and playlist_prev added. (See etc/input.conf changes.) This is a user visible incompatible change, and will break slave-mode applications. - The pt_clear slave command is renamed to playlist_clear. - Playtree entries could have multiple files. This is not the case anymore, and playlist entries have always exactly one entry. Whenever something adds more than one file (like ASX playlists or dvd:// or dvdnav:// on the command line), all files are added as separate playlist entries. Note that some of the changes are quite deep and violent. Expect regressions. The playlist parsing code in particular is of low quality. I didn't try to improve it, and merely spent to least effort necessary to keep it somehow working. (Especially ASX playlist handling.) The playtree code was complicated and bloated. It was also barely used. Most users don't even know that mplayer manages the playlist as tree, or how to use it. The most obscure features was probably specifying a tree on command line (with '{' and '}' to create/close tree nodes). It filled the player code with complexity and confused users with weird slave commands like pt_up. Replace the playtree with a simple flat playlist. Playlist parsers that actually return trees are changed to append all files to the playlist pre-order. It used to be the responsibility of the playtree code to change per-file config options. Now this is done by the player core, and the playlist code is free of such details. Options are not per-file by default anymore. This was a very obscure and complicated feature that confused even experienced users. Consider the following command line: mplayer file1.mkv file2.mkv --no-audio file3.mkv This will disable the audio for file2.mkv only, because options are per-file by default. To make the option affect all files, you're supposed to put it before the first file. This is bad, because normally you don't need per-file options. They are very rarely needed, and the only reasonable use cases I can imagine are use of the encode backend (mplayer encode branch), or for debugging. The normal use case is made harder, and the feature is perceived as bug. Even worse, correct usage is hard to explain for users. Make all options global by default. The position of an option isn't significant anymore (except for options that compensate each other, consider --shuffle --no-shuffle). One other important change is that no options are reset anymore if a new file is started. If you change settings with slave mode commands, they will not be changed by playing a new file. (Exceptions include settings that are too file specific, like audio/subtitle stream selection.) There is still some need for per-file options. Debugging and encoding are use cases that profit from per-file options. Per-file profiles (as well as per-protocol and per-VO/AO options) need the implementation related mechanisms to backup and restore options when the playback file changes. Simplify the save-slot stuff, which is possible because there is no hierarchical play tree anymore. Now there's a simple backup field. Add a way to specify per-file options on command line. Example: mplayer f1.mkv -o0 --{ -o1 f2.mkv -o2 f3.mkv --} f4.mkv -o3 will have the following options per file set: f1.mkv, f4.mkv: -o0 -o3 f2.mkv, f3.mkv: -o0 -o3 -o1 -o2 The options --{ and --} start and end per-file options. All files inside the { } will be affected by the options equally (similar to how global options and multiple files are handled). When playback of a file starts, the per-file options are set according to the command line. When playback ends, the per-file options are restored to the values when playback started.
2012-07-31 21:33:26 +02:00
case MP_CMD_PLAYLIST_NEXT:
case MP_CMD_PLAYLIST_PREV:
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
return true;
}
return false;
}
static int queue_count_cmds(struct cmd_queue *queue)
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
{
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) {
mplayer: turn playtree into a list, and change per-file option handling Summary: - There is no playtree anymore. It's reduced to a simple list. - Options are now always global. You can still have per-file options, but these are optional and require special syntax. - The slave command pt_step has been removed, and playlist_next and playlist_prev added. (See etc/input.conf changes.) This is a user visible incompatible change, and will break slave-mode applications. - The pt_clear slave command is renamed to playlist_clear. - Playtree entries could have multiple files. This is not the case anymore, and playlist entries have always exactly one entry. Whenever something adds more than one file (like ASX playlists or dvd:// or dvdnav:// on the command line), all files are added as separate playlist entries. Note that some of the changes are quite deep and violent. Expect regressions. The playlist parsing code in particular is of low quality. I didn't try to improve it, and merely spent to least effort necessary to keep it somehow working. (Especially ASX playlist handling.) The playtree code was complicated and bloated. It was also barely used. Most users don't even know that mplayer manages the playlist as tree, or how to use it. The most obscure features was probably specifying a tree on command line (with '{' and '}' to create/close tree nodes). It filled the player code with complexity and confused users with weird slave commands like pt_up. Replace the playtree with a simple flat playlist. Playlist parsers that actually return trees are changed to append all files to the playlist pre-order. It used to be the responsibility of the playtree code to change per-file config options. Now this is done by the player core, and the playlist code is free of such details. Options are not per-file by default anymore. This was a very obscure and complicated feature that confused even experienced users. Consider the following command line: mplayer file1.mkv file2.mkv --no-audio file3.mkv This will disable the audio for file2.mkv only, because options are per-file by default. To make the option affect all files, you're supposed to put it before the first file. This is bad, because normally you don't need per-file options. They are very rarely needed, and the only reasonable use cases I can imagine are use of the encode backend (mplayer encode branch), or for debugging. The normal use case is made harder, and the feature is perceived as bug. Even worse, correct usage is hard to explain for users. Make all options global by default. The position of an option isn't significant anymore (except for options that compensate each other, consider --shuffle --no-shuffle). One other important change is that no options are reset anymore if a new file is started. If you change settings with slave mode commands, they will not be changed by playing a new file. (Exceptions include settings that are too file specific, like audio/subtitle stream selection.) There is still some need for per-file options. Debugging and encoding are use cases that profit from per-file options. Per-file profiles (as well as per-protocol and per-VO/AO options) need the implementation related mechanisms to backup and restore options when the playback file changes. Simplify the save-slot stuff, which is possible because there is no hierarchical play tree anymore. Now there's a simple backup field. Add a way to specify per-file options on command line. Example: mplayer f1.mkv -o0 --{ -o1 f2.mkv -o2 f3.mkv --} f4.mkv -o3 will have the following options per file set: f1.mkv, f4.mkv: -o0 -o3 f2.mkv, f3.mkv: -o0 -o3 -o1 -o2 The options --{ and --} start and end per-file options. All files inside the { } will be affected by the options equally (similar to how global options and multiple files are handled). When playback of a file starts, the per-file options are set according to the command line. When playback ends, the per-file options are restored to the values when playback started.
2012-07-31 21:33:26 +02:00
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;
}
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
static void queue_add(struct cmd_queue *queue, struct mp_cmd *cmd,
bool at_head)
{
if (at_head) {
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
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;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
}
}
int mp_input_add_cmd_fd(struct input_ctx *ictx, int fd, int select,
int read_func(int fd, char *dest, int size),
int close_func(int fd))
{
2011-04-25 10:38:46 +02:00
if (ictx->num_cmd_fd == MP_MAX_CMD_FD) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Too many command file descriptors, "
"cannot register file descriptor %d.\n", fd);
return 0;
}
if (select && fd < 0) {
mp_msg(MSGT_INPUT, MSGL_ERR,
"Invalid fd %d in mp_input_add_cmd_fd", fd);
return 0;
}
ictx->cmd_fds[ictx->num_cmd_fd] = (struct input_fd){
2011-04-25 10:38:46 +02:00
.fd = fd,
.read_func.cmd = read_func ? read_func : default_cmd_func,
.close_func = close_func,
.no_select = !select
};
ictx->num_cmd_fd++;
2011-04-25 10:38:46 +02:00
return 1;
}
void mp_input_rm_cmd_fd(struct input_ctx *ictx, int fd)
{
struct input_fd *cmd_fds = ictx->cmd_fds;
2011-04-25 10:38:46 +02:00
unsigned int i;
for (i = 0; i < ictx->num_cmd_fd; i++) {
if (cmd_fds[i].fd == fd)
break;
}
if (i == ictx->num_cmd_fd)
return;
if (cmd_fds[i].close_func)
cmd_fds[i].close_func(cmd_fds[i].fd);
talloc_free(cmd_fds[i].buffer);
if (i + 1 < ictx->num_cmd_fd)
memmove(&cmd_fds[i], &cmd_fds[i + 1],
(ictx->num_cmd_fd - i - 1) * sizeof(struct input_fd));
2011-04-25 10:38:46 +02:00
ictx->num_cmd_fd--;
}
void mp_input_rm_key_fd(struct input_ctx *ictx, int fd)
{
struct input_fd *key_fds = ictx->key_fds;
2011-04-25 10:38:46 +02:00
unsigned int i;
for (i = 0; i < ictx->num_key_fd; i++) {
if (key_fds[i].fd == fd)
break;
}
if (i == ictx->num_key_fd)
return;
if (key_fds[i].close_func)
key_fds[i].close_func(key_fds[i].fd);
if (i + 1 < ictx->num_key_fd)
memmove(&key_fds[i], &key_fds[i + 1],
(ictx->num_key_fd - i - 1) * sizeof(struct input_fd));
2011-04-25 10:38:46 +02:00
ictx->num_key_fd--;
}
int mp_input_add_key_fd(struct input_ctx *ictx, int fd, int select,
int read_func(void *ctx, int fd),
int close_func(int fd), void *ctx)
{
2011-04-25 10:38:46 +02:00
if (ictx->num_key_fd == MP_MAX_KEY_FD) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Too many key file descriptors, "
"cannot register file descriptor %d.\n", fd);
return 0;
}
if (select && fd < 0) {
mp_msg(MSGT_INPUT, MSGL_ERR,
"Invalid fd %d in mp_input_add_key_fd", fd);
return 0;
}
ictx->key_fds[ictx->num_key_fd] = (struct input_fd){
2011-04-25 10:38:46 +02:00
.fd = fd,
.read_func.key = read_func,
.close_func = close_func,
.no_select = !select,
.ctx = ctx,
};
ictx->num_key_fd++;
return 1;
}
static int parse_cycle_dir(const struct m_option *opt, struct bstr name,
struct bstr param, void *dst)
2011-04-25 10:38:46 +02:00
{
float val;
if (bstrcmp0(param, "up") == 0) {
val = +1;
} else if (bstrcmp0(param, "down") == 0) {
val = -1;
} else {
return m_option_type_float.parse(opt, name, param, dst);
}
*(float *)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.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;
}
mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc)
2011-04-25 10:38:46 +02:00
{
int pausing = 0;
int on_osd = MP_ON_OSD_AUTO;
bool raw_args = false;
struct mp_cmd *cmd = NULL;
bstr start = str;
void *tmp = talloc_new(NULL);
str = bstr_lstrip(str);
for (const struct legacy_cmd *entry = legacy_cmds; entry->old; entry++) {
size_t old_len = strlen(entry->old);
if (bstrcasecmp(bstr_splice(str, 0, old_len),
(bstr) {(char *)entry->old, old_len}) == 0)
{
mp_tmsg(MSGT_INPUT, MSGL_WARN, "Warning: command '%s' is "
"deprecated, replaced with '%s' at %s.\n",
entry->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;
2011-04-25 10:38:46 +02:00
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))
2011-04-25 10:38:46 +02:00
break;
cmd_idx++;
}
2011-04-25 10:38:46 +02:00
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;
2011-04-25 10:38:46 +02:00
for (int i = 0; i < MP_CMD_MAX_ARGS; i++) {
struct mp_cmd_arg *cmdarg = &cmd->args[i];
if (!cmdarg->type.type)
2011-04-25 10:38:46 +02:00
break;
cmd->nargs++;
str = bstr_lstrip(str);
bstr arg = {0};
if (bstr_eatstart0(&str, "\"")) {
if (!read_escaped_string(tmp, &str, &arg)) {
2011-04-25 10:38:46 +02:00
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d "
"has broken string escapes.\n", cmd->name, i + 1);
goto error;
2011-04-25 10:38:46 +02:00
}
if (!bstr_eatstart0(&str, "\"")) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s: argument %d is "
"unterminated.\n", cmd->name, i + 1);
goto error;
2011-04-25 10:38:46 +02:00
}
} else {
if (!read_token(str, &str, &arg))
break;
if (cmdarg->optional && bstrcmp0(arg, "-") == 0)
continue;
2011-04-25 10:38:46 +02:00
}
// 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;
2011-04-25 10:38:46 +02:00
}
if (cmdarg->type.type == &m_option_type_string)
cmdarg->v.s = talloc_steal(cmd, cmdarg->v.s);
2011-04-25 10:38:46 +02:00
}
bstr dummy;
if (read_token(str, &dummy, &dummy)) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s has trailing unused "
"arguments: '%.*s'.\n", cmd->name, BSTR_P(str));
// Better make it fatal to make it clear something is wrong.
goto error;
2011-04-25 10:38:46 +02:00
}
int min_args = 0;
while (min_args < MP_CMD_MAX_ARGS && cmd->args[min_args].type.type
&& !cmd->args[min_args].optional)
{
min_args++;
}
if (cmd->nargs < min_args) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s requires at least %d "
"arguments, we found only %d so far.\n", cmd->name, min_args,
cmd->nargs);
goto error;
2011-04-25 10:38:46 +02:00
}
bstr orig = (bstr) {start.start, str.start - start.start};
cmd->original = bstrdup(cmd, bstr_strip(orig));
talloc_free(tmp);
2011-04-25 10:38:46 +02:00
return cmd;
error:
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command was defined at %s.\n", loc);
talloc_free(cmd);
talloc_free(tmp);
return NULL;
}
#define MP_CMD_MAX_SIZE 4096
static int read_cmd(struct input_fd *mp_fd, char **ret)
{
2011-04-25 10:38:46 +02:00
char *end;
*ret = NULL;
// Allocate the buffer if it doesn't exist
if (!mp_fd->buffer) {
mp_fd->buffer = talloc_size(NULL, MP_CMD_MAX_SIZE);
mp_fd->pos = 0;
mp_fd->size = MP_CMD_MAX_SIZE;
}
2011-04-25 10:38:46 +02:00
// Get some data if needed/possible
while (!mp_fd->got_cmd && !mp_fd->eof && (mp_fd->size - mp_fd->pos > 1)) {
int r = mp_fd->read_func.cmd(mp_fd->fd, mp_fd->buffer + mp_fd->pos,
mp_fd->size - 1 - mp_fd->pos);
// Error ?
if (r < 0) {
switch (r) {
case MP_INPUT_ERROR:
case MP_INPUT_DEAD:
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Error while reading "
"command file descriptor %d: %s\n",
mp_fd->fd, strerror(errno));
case MP_INPUT_NOTHING:
return r;
case MP_INPUT_RETRY:
continue;
}
// EOF ?
} else if (r == 0) {
mp_fd->eof = 1;
break;
}
mp_fd->pos += r;
break;
}
2011-04-25 10:38:46 +02:00
mp_fd->got_cmd = 0;
while (1) {
int l = 0;
// Find the cmd end
mp_fd->buffer[mp_fd->pos] = '\0';
end = strchr(mp_fd->buffer, '\r');
if (end)
*end = '\n';
end = strchr(mp_fd->buffer, '\n');
// No cmd end ?
if (!end) {
// If buffer is full we must drop all until the next \n
if (mp_fd->size - mp_fd->pos <= 1) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command buffer of file "
"descriptor %d is full: dropping content.\n",
mp_fd->fd);
mp_fd->pos = 0;
mp_fd->drop = 1;
}
break;
}
// We already have a cmd : set the got_cmd flag
else if ((*ret)) {
mp_fd->got_cmd = 1;
break;
}
2011-04-25 10:38:46 +02:00
l = end - mp_fd->buffer;
2011-04-25 10:38:46 +02:00
// Not dropping : put the cmd in ret
if (!mp_fd->drop)
*ret = talloc_strndup(NULL, mp_fd->buffer, l);
else
mp_fd->drop = 0;
mp_fd->pos -= l + 1;
memmove(mp_fd->buffer, end + 1, mp_fd->pos);
}
if (*ret)
return 1;
else
return MP_INPUT_NOTHING;
}
2011-04-25 10:38:46 +02:00
static int default_cmd_func(int fd, char *buf, int l)
{
2011-04-25 10:38:46 +02:00
while (1) {
int r = read(fd, buf, l);
// Error ?
if (r < 0) {
if (errno == EINTR)
continue;
else if (errno == EAGAIN)
return MP_INPUT_NOTHING;
return MP_INPUT_ERROR;
// EOF ?
}
return r;
}
}
static int read_wakeup(void *ctx, int fd)
{
char buf[100];
read(fd, buf, sizeof(buf));
return MP_INPUT_NOTHING;
}
static bool bind_matches_key(struct cmd_bind *bind, int n, int *keys);
static void append_bind_info(char **pmsg, struct cmd_bind *bind)
{
char *msg = *pmsg;
struct mp_cmd *cmd = mp_input_parse_cmd(bstr0(bind->cmd), bind->location);
bstr stripped = cmd ? cmd->original : bstr0(bind->cmd);
msg = talloc_asprintf_append(msg, " '%.*s'", BSTR_P(stripped));
if (!cmd)
msg = talloc_asprintf_append(msg, " (invalid)");
if (strcmp(bind->owner->section, "default") != 0)
msg = talloc_asprintf_append(msg, " in section {%s}",
bind->owner->section);
if (bind->owner->is_builtin) {
msg = talloc_asprintf_append(msg, " (default binding)");
} else {
msg = talloc_asprintf_append(msg, " in %s", bind->location);
}
*pmsg = msg;
}
static mp_cmd_t *handle_test(struct input_ctx *ictx, int n, int *keys)
{
char *key_buf = get_key_combo_name(keys, n);
// "$>" to disable property substitution when invoking "show_text"
char *msg = talloc_asprintf(NULL, "$>Key %s is bound to:\n", key_buf);
talloc_free(key_buf);
int count = 0;
for (struct cmd_bind_section *bs = ictx->cmd_bind_sections;
bs; bs = bs->next)
{
for (struct cmd_bind *bind = bs->cmd_binds; bind->cmd; bind++) {
if (bind_matches_key(bind, n, keys)) {
count++;
msg = talloc_asprintf_append(msg, "%d. ", count);
append_bind_info(&msg, bind);
msg = talloc_asprintf_append(msg, "\n");
}
}
}
if (!count)
msg = talloc_asprintf_append(msg, "(nothing)");
mp_cmd_t *res = mp_input_parse_cmd(bstr0("show_text \"\""), "");
res->args[0].v.s = talloc_steal(res, msg);
return res;
}
static bool bind_matches_key(struct cmd_bind *bind, int n, int *keys)
{
int found = 1, s;
for (s = 0; s < n && bind->input[s] != 0; s++) {
if (bind->input[s] != keys[s]) {
found = 0;
break;
}
}
return found && bind->input[s] == 0 && s == n;
}
static struct cmd_bind *find_bind_for_key(struct cmd_bind *binds, int n,
int *keys)
{
2011-04-25 10:38:46 +02:00
int j;
if (n <= 0)
return NULL;
for (j = 0; binds[j].cmd != NULL; j++) {
if (bind_matches_key(&binds[j], n, keys))
2011-04-25 10:38:46 +02:00
break;
}
return binds[j].cmd ? &binds[j] : NULL;
}
static struct cmd_bind_section *get_bind_section(struct input_ctx *ictx,
bool builtin, bstr section)
{
struct cmd_bind_section *bind_section = ictx->cmd_bind_sections;
2011-04-25 10:38:46 +02:00
if (section.len == 0)
section = bstr0("default");
2011-04-25 10:38:46 +02:00
while (bind_section) {
if (bstrcmp0(section, bind_section->section) == 0
&& builtin == bind_section->is_builtin)
2011-04-25 10:38:46 +02:00
return bind_section;
if (bind_section->next == NULL)
break;
bind_section = bind_section->next;
}
if (bind_section) {
bind_section->next = talloc_ptrtype(ictx, bind_section->next);
bind_section = bind_section->next;
} else {
ictx->cmd_bind_sections = talloc_ptrtype(ictx, ictx->cmd_bind_sections);
bind_section = ictx->cmd_bind_sections;
}
bind_section->cmd_binds = NULL;
bind_section->section = bstrdup0(bind_section, section);
bind_section->is_builtin = builtin;
2011-04-25 10:38:46 +02:00
bind_section->next = NULL;
return bind_section;
}
static struct cmd_bind *section_find_bind_for_key(struct input_ctx *ictx,
bool builtin, char *section,
int n, int *keys)
{
struct cmd_bind_section *bs = get_bind_section(ictx, builtin,
bstr0(section));
return bs->cmd_binds ? find_bind_for_key(bs->cmd_binds, n, keys) : NULL;
}
static struct cmd_bind *find_any_bind_for_key(struct input_ctx *ictx,
int n, int *keys)
{
struct cmd_bind *cmd
= section_find_bind_for_key(ictx, false, ictx->section, n, keys);
if (ictx->default_bindings && cmd == NULL)
cmd = section_find_bind_for_key(ictx, true, ictx->section, n, keys);
if (!(ictx->section_flags & MP_INPUT_NO_DEFAULT_SECTION)) {
if (cmd == NULL)
cmd = section_find_bind_for_key(ictx, false, "default", n, keys);
if (ictx->default_bindings && cmd == NULL)
cmd = section_find_bind_for_key(ictx, true, "default", n, keys);
}
return cmd;
}
static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys)
{
if (ictx->test)
return handle_test(ictx, n, keys);
struct cmd_bind *cmd = find_any_bind_for_key(ictx, n, keys);
if (cmd == NULL && n > 1) {
// Hitting two keys at once, and if there's no binding for this
// combination, the key hit last should be checked.
cmd = find_any_bind_for_key(ictx, 1, (int[]){keys[n - 1]});
}
2011-04-25 10:38:46 +02:00
if (cmd == NULL) {
char *key_buf = get_key_combo_name(keys, n);
mp_tmsg(MSGT_INPUT, MSGL_WARN,
"No bind found for key '%s'.\n", key_buf);
2011-04-25 10:38:46 +02:00
talloc_free(key_buf);
return NULL;
}
mp_cmd_t *ret = mp_input_parse_cmd(bstr0(cmd->cmd), cmd->location);
2011-04-25 10:38:46 +02:00
if (!ret) {
char *key_buf = get_key_combo_name(keys, n);
mp_tmsg(MSGT_INPUT, MSGL_ERR,
"Invalid command for bound key '%s': '%s'\n", key_buf, cmd->cmd);
2011-04-25 10:38:46 +02:00
talloc_free(key_buf);
}
2011-04-25 10:38:46 +02:00
return ret;
}
2011-04-25 10:38:46 +02:00
static mp_cmd_t *interpret_key(struct input_ctx *ictx, int code)
{
2011-04-25 10:38:46 +02:00
unsigned int j;
mp_cmd_t *ret;
/* On normal keyboards shift changes the character code of non-special
* keys, so don't count the modifier separately for those. In other words
* we want to have "a" and "A" instead of "a" and "Shift+A"; but a separate
* shift modifier is still kept for special keys like arrow keys.
*/
int unmod = code & ~(MP_KEY_MODIFIER_MASK | MP_KEY_STATE_DOWN);
if (unmod >= 32 && unmod < MP_KEY_BASE)
code &= ~MP_KEY_MODIFIER_SHIFT;
if (code & MP_KEY_STATE_DOWN) {
if (ictx->num_key_down >= MP_MAX_KEY_DOWN) {
2011-04-25 10:38:46 +02:00
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Too many key down events "
"at the same time\n");
return NULL;
}
code &= ~MP_KEY_STATE_DOWN;
2011-04-25 10:38:46 +02:00
// Check if we don't already have this key as pushed
for (j = 0; j < ictx->num_key_down; j++) {
if (ictx->key_down[j] == code)
break;
}
if (j != ictx->num_key_down)
return NULL;
ictx->key_down[ictx->num_key_down] = code;
ictx->num_key_down++;
ictx->last_key_down = mp_time_us();
2011-04-25 10:38:46 +02:00
ictx->ar_state = 0;
ret = NULL;
if (!(code & MP_NO_REPEAT_KEY))
ret = get_cmd_from_keys(ictx, ictx->num_key_down, ictx->key_down);
return ret;
2011-04-25 10:38:46 +02:00
}
// button released or press of key with no separate down/up events
for (j = 0; j < ictx->num_key_down; j++) {
2011-04-25 10:38:46 +02:00
if (ictx->key_down[j] == code)
break;
}
bool doubleclick = code >= MP_MOUSE_BTN0_DBL && code < MP_MOUSE_BTN_DBL_END;
if (doubleclick) {
int btn = code - MP_MOUSE_BTN0_DBL + MP_MOUSE_BTN0;
if (!ictx->num_key_down
|| ictx->key_down[ictx->num_key_down - 1] != btn)
return NULL;
j = ictx->num_key_down - 1;
ictx->key_down[j] = code;
}
bool emit_key = ictx->last_key_down && (code & MP_NO_REPEAT_KEY);
2011-04-25 10:38:46 +02:00
if (j == ictx->num_key_down) { // was not already down; add temporarily
if (ictx->num_key_down > MP_MAX_KEY_DOWN) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Too many key down events "
"at the same time\n");
return NULL;
}
ictx->key_down[ictx->num_key_down] = code;
ictx->num_key_down++;
emit_key = true;
}
2011-04-25 10:38:46 +02:00
// Interpret only maximal point of multibutton event
ret = NULL;
if (emit_key)
ret = get_cmd_from_keys(ictx, ictx->num_key_down, ictx->key_down);
if (doubleclick) {
ictx->key_down[j] = code - MP_MOUSE_BTN0_DBL + MP_MOUSE_BTN0;
return ret;
}
// Remove the key
2011-04-25 10:38:46 +02:00
if (j + 1 < ictx->num_key_down)
memmove(&ictx->key_down[j], &ictx->key_down[j + 1],
(ictx->num_key_down - (j + 1)) * sizeof(int));
ictx->num_key_down--;
ictx->last_key_down = 0;
ictx->ar_state = -1;
mp_cmd_free(ictx->ar_cmd);
ictx->ar_cmd = NULL;
return ret;
}
static mp_cmd_t *check_autorepeat(struct input_ctx *ictx)
{
2011-04-25 10:38:46 +02:00
// No input : autorepeat ?
if (ictx->ar_rate > 0 && ictx->ar_state >= 0 && ictx->num_key_down > 0
&& !(ictx->key_down[ictx->num_key_down - 1] & MP_NO_REPEAT_KEY)) {
int64_t t = mp_time_us();
if (ictx->last_ar + 2000000 < t)
ictx->last_ar = t;
2011-04-25 10:38:46 +02:00
// First time : wait delay
if (ictx->ar_state == 0
&& (t - ictx->last_key_down) >= ictx->ar_delay * 1000)
{
talloc_free(ictx->ar_cmd);
2011-04-25 10:38:46 +02:00
ictx->ar_cmd = get_cmd_from_keys(ictx, ictx->num_key_down,
ictx->key_down);
if (!ictx->ar_cmd) {
ictx->ar_state = -1;
return NULL;
}
ictx->ar_state = 1;
ictx->last_ar = ictx->last_key_down + ictx->ar_delay * 1000;
2011-04-25 10:38:46 +02:00
return mp_cmd_clone(ictx->ar_cmd);
// Then send rate / sec event
} else if (ictx->ar_state == 1
&& (t - ictx->last_ar) >= 1000000 / ictx->ar_rate) {
ictx->last_ar += 1000000 / ictx->ar_rate;
2011-04-25 10:38:46 +02:00
return mp_cmd_clone(ictx->ar_cmd);
}
}
2011-04-25 10:38:46 +02:00
return NULL;
}
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
void mp_input_feed_key(struct input_ctx *ictx, int code)
{
ictx->got_new_events = true;
int unmod = code & ~(MP_KEY_MODIFIER_MASK | MP_KEY_STATE_DOWN);
if (unmod >= MP_MOUSE_BASE && unmod <= MP_MOUSE_BTN_END)
ictx->mouse_event_counter++;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
if (code == MP_INPUT_RELEASE_ALL) {
mp_msg(MSGT_INPUT, MSGL_V, "input: release all\n");
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
memset(ictx->key_down, 0, sizeof(ictx->key_down));
ictx->num_key_down = 0;
ictx->last_key_down = 0;
return;
}
mp_msg(MSGT_INPUT, MSGL_V, "input: key code=%#x\n", code);
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
struct mp_cmd *cmd = interpret_key(ictx, code);
if (!cmd)
return;
struct cmd_queue *queue = &ictx->key_cmd_queue;
if (queue_count_cmds(queue) >= ictx->key_fifo_size &&
mplayer: turn playtree into a list, and change per-file option handling Summary: - There is no playtree anymore. It's reduced to a simple list. - Options are now always global. You can still have per-file options, but these are optional and require special syntax. - The slave command pt_step has been removed, and playlist_next and playlist_prev added. (See etc/input.conf changes.) This is a user visible incompatible change, and will break slave-mode applications. - The pt_clear slave command is renamed to playlist_clear. - Playtree entries could have multiple files. This is not the case anymore, and playlist entries have always exactly one entry. Whenever something adds more than one file (like ASX playlists or dvd:// or dvdnav:// on the command line), all files are added as separate playlist entries. Note that some of the changes are quite deep and violent. Expect regressions. The playlist parsing code in particular is of low quality. I didn't try to improve it, and merely spent to least effort necessary to keep it somehow working. (Especially ASX playlist handling.) The playtree code was complicated and bloated. It was also barely used. Most users don't even know that mplayer manages the playlist as tree, or how to use it. The most obscure features was probably specifying a tree on command line (with '{' and '}' to create/close tree nodes). It filled the player code with complexity and confused users with weird slave commands like pt_up. Replace the playtree with a simple flat playlist. Playlist parsers that actually return trees are changed to append all files to the playlist pre-order. It used to be the responsibility of the playtree code to change per-file config options. Now this is done by the player core, and the playlist code is free of such details. Options are not per-file by default anymore. This was a very obscure and complicated feature that confused even experienced users. Consider the following command line: mplayer file1.mkv file2.mkv --no-audio file3.mkv This will disable the audio for file2.mkv only, because options are per-file by default. To make the option affect all files, you're supposed to put it before the first file. This is bad, because normally you don't need per-file options. They are very rarely needed, and the only reasonable use cases I can imagine are use of the encode backend (mplayer encode branch), or for debugging. The normal use case is made harder, and the feature is perceived as bug. Even worse, correct usage is hard to explain for users. Make all options global by default. The position of an option isn't significant anymore (except for options that compensate each other, consider --shuffle --no-shuffle). One other important change is that no options are reset anymore if a new file is started. If you change settings with slave mode commands, they will not be changed by playing a new file. (Exceptions include settings that are too file specific, like audio/subtitle stream selection.) There is still some need for per-file options. Debugging and encoding are use cases that profit from per-file options. Per-file profiles (as well as per-protocol and per-VO/AO options) need the implementation related mechanisms to backup and restore options when the playback file changes. Simplify the save-slot stuff, which is possible because there is no hierarchical play tree anymore. Now there's a simple backup field. Add a way to specify per-file options on command line. Example: mplayer f1.mkv -o0 --{ -o1 f2.mkv -o2 f3.mkv --} f4.mkv -o3 will have the following options per file set: f1.mkv, f4.mkv: -o0 -o3 f2.mkv, f3.mkv: -o0 -o3 -o1 -o2 The options --{ and --} start and end per-file options. All files inside the { } will be affected by the options equally (similar to how global options and multiple files are handled). When playback of a file starts, the per-file options are set according to the command line. When playback ends, the per-file options are restored to the values when playback started.
2012-07-31 21:33:26 +02:00
(!mp_input_is_abort_cmd(cmd->id) || queue_has_abort_cmds(queue)))
{
talloc_free(cmd);
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
return;
}
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
queue_add(queue, cmd, false);
}
static void read_cmd_fd(struct input_ctx *ictx, struct input_fd *cmd_fd)
{
int r;
char *text;
while ((r = read_cmd(cmd_fd, &text)) >= 0) {
ictx->got_new_events = true;
struct mp_cmd *cmd = mp_input_parse_cmd(bstr0(text), "<pipe>");
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
talloc_free(text);
if (cmd)
queue_add(&ictx->control_cmd_queue, cmd, false);
if (!cmd_fd->got_cmd)
return;
}
if (r == MP_INPUT_ERROR)
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Error on command file descriptor %d\n",
cmd_fd->fd);
else if (r == MP_INPUT_DEAD)
cmd_fd->dead = true;
}
static void read_key_fd(struct input_ctx *ictx, struct input_fd *key_fd)
{
int code = key_fd->read_func.key(key_fd->ctx, key_fd->fd);
if (code >= 0 || code == MP_INPUT_RELEASE_ALL) {
mp_input_feed_key(ictx, code);
return;
}
if (code == MP_INPUT_ERROR)
mp_tmsg(MSGT_INPUT, MSGL_ERR,
"Error on key input file descriptor %d\n", key_fd->fd);
else if (code == MP_INPUT_DEAD) {
mp_tmsg(MSGT_INPUT, MSGL_ERR,
"Dead key input on file descriptor %d\n", key_fd->fd);
key_fd->dead = true;
}
}
/**
* \param time time to wait at most for an event in milliseconds
*/
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
static void read_events(struct input_ctx *ictx, int time)
{
if (ictx->num_key_down) {
time = FFMIN(time, 1000 / ictx->ar_rate);
time = FFMIN(time, ictx->ar_delay);
}
time = FFMAX(time, 0);
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
ictx->got_new_events = false;
struct input_fd *key_fds = ictx->key_fds;
struct input_fd *cmd_fds = ictx->cmd_fds;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
for (int i = 0; i < ictx->num_key_fd; i++)
2011-04-25 10:38:46 +02:00
if (key_fds[i].dead) {
mp_input_rm_key_fd(ictx, key_fds[i].fd);
i--;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
} else if (time && key_fds[i].no_select)
read_key_fd(ictx, &key_fds[i]);
for (int i = 0; i < ictx->num_cmd_fd; i++)
2011-04-25 10:38:46 +02:00
if (cmd_fds[i].dead || cmd_fds[i].eof) {
mp_input_rm_cmd_fd(ictx, cmd_fds[i].fd);
i--;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
} else if (time && cmd_fds[i].no_select)
read_cmd_fd(ictx, &cmd_fds[i]);
if (ictx->got_new_events)
time = 0;
#ifdef HAVE_POSIX_SELECT
fd_set fds;
FD_ZERO(&fds);
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
int max_fd = 0;
for (int i = 0; i < ictx->num_key_fd; i++) {
if (key_fds[i].no_select)
continue;
if (key_fds[i].fd > max_fd)
max_fd = key_fds[i].fd;
FD_SET(key_fds[i].fd, &fds);
}
for (int i = 0; i < ictx->num_cmd_fd; i++) {
if (cmd_fds[i].no_select)
continue;
if (cmd_fds[i].fd > max_fd)
max_fd = cmd_fds[i].fd;
FD_SET(cmd_fds[i].fd, &fds);
}
struct timeval tv, *time_val;
tv.tv_sec = time / 1000;
tv.tv_usec = (time % 1000) * 1000;
time_val = &tv;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
if (select(max_fd + 1, &fds, NULL, NULL, time_val) < 0) {
if (errno != EINTR)
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Select error: %s\n",
strerror(errno));
FD_ZERO(&fds);
}
#else
if (time > 0)
mp_sleep_us(time * 1000);
#endif
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
for (int i = 0; i < ictx->num_key_fd; i++) {
#ifdef HAVE_POSIX_SELECT
2011-04-25 10:38:46 +02:00
if (!key_fds[i].no_select && !FD_ISSET(key_fds[i].fd, &fds))
continue;
#endif
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
read_key_fd(ictx, &key_fds[i]);
}
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
for (int i = 0; i < ictx->num_cmd_fd; i++) {
#ifdef HAVE_POSIX_SELECT
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
if (!cmd_fds[i].no_select && !FD_ISSET(cmd_fds[i].fd, &fds))
2011-04-25 10:38:46 +02:00
continue;
#endif
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
read_cmd_fd(ictx, &cmd_fds[i]);
}
}
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
/* To support blocking file descriptors we don't loop the read over
* every source until it's known to be empty. Instead we use this wrapper
* to run select() again.
*/
static void read_all_fd_events(struct input_ctx *ictx, int time)
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
{
while (1) {
read_events(ictx, time);
if (!ictx->got_new_events)
return;
time = 0;
}
}
static void read_all_events(struct input_ctx *ictx, int time)
{
getch2_poll();
#ifdef CONFIG_COCOA
cocoa_check_events();
#endif
read_all_fd_events(ictx, time);
}
2011-04-25 10:38:46 +02:00
int mp_input_queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd)
{
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
ictx->got_new_events = true;
if (!cmd)
2011-04-25 10:38:46 +02:00
return 0;
if (cmd->id == MP_CMD_SET_MOUSE_POS)
ictx->mouse_event_counter++;
queue_add(&ictx->control_cmd_queue, cmd, false);
2011-04-25 10:38:46 +02:00
return 1;
}
/**
* \param peek_only when set, the returned command stays in the queue.
* Do not free the returned cmd whe you set this!
*/
mp_cmd_t *mp_input_get_cmd(struct input_ctx *ictx, int time, int peek_only)
{
if (async_quit_request) {
struct mp_cmd *cmd = mp_input_parse_cmd(bstr0("quit 1"), "");
queue_add(&ictx->control_cmd_queue, cmd, true);
}
2011-04-25 10:38:46 +02:00
if (ictx->control_cmd_queue.first || ictx->key_cmd_queue.first)
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
time = 0;
read_all_events(ictx, time);
struct cmd_queue *queue = &ictx->control_cmd_queue;
if (!queue->first)
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
queue = &ictx->key_cmd_queue;
if (!queue->first) {
struct mp_cmd *repeated = check_autorepeat(ictx);
if (repeated)
queue_add(queue, repeated, false);
}
struct mp_cmd *ret = queue->first;
if (!ret)
return NULL;
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
if (!peek_only)
queue_remove(queue, ret);
2011-04-25 10:38:46 +02:00
return ret;
}
void mp_cmd_free(mp_cmd_t *cmd)
{
talloc_free(cmd);
}
mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd)
{
2011-04-25 10:38:46 +02:00
mp_cmd_t *ret;
int i;
2011-04-25 10:38:46 +02:00
ret = talloc_memdup(NULL, cmd, sizeof(mp_cmd_t));
ret->name = talloc_strdup(ret, cmd->name);
for (i = 0; i < MP_CMD_MAX_ARGS; i++) {
if (cmd->args[i].type.type == &m_option_type_string)
2011-04-25 10:38:46 +02:00
ret->args[i].v.s = talloc_strdup(ret, cmd->args[i].v.s);
}
2011-04-25 10:38:46 +02:00
return ret;
}
int mp_input_get_key_from_name(const char *name)
{
int modifiers = 0;
const char *p;
while ((p = strchr(name, '+'))) {
for (struct key_name *m = modifier_names; m->name; m++)
if (!bstrcasecmp(bstr0(m->name),
(struct bstr){(char *)name, p - name})) {
modifiers |= m->key;
goto found;
}
if (!strcmp(name, "+"))
return '+' + modifiers;
return -1;
2011-04-25 10:38:46 +02:00
found:
name = p + 1;
}
struct bstr bname = bstr0(name);
struct bstr rest;
int code = bstr_decode_utf8(bname, &rest);
if (code >= 0 && rest.len == 0)
return code + modifiers;
if (bstr_startswith0(bname, "0x"))
return strtol(name, NULL, 16) + modifiers;
for (int i = 0; key_names[i].name != NULL; i++) {
if (strcasecmp(key_names[i].name, name) == 0)
return key_names[i].key + modifiers;
}
return -1;
}
2011-04-25 10:38:46 +02:00
static int get_input_from_name(char *name, int *keys)
{
char *end, *ptr;
int n = 0;
ptr = name;
n = 0;
for (end = strchr(ptr, '-'); ptr != NULL; end = strchr(ptr, '-')) {
if (end && end[1] != '\0') {
if (end[1] == '-')
end = &end[1];
end[0] = '\0';
}
keys[n] = mp_input_get_key_from_name(ptr);
if (keys[n] < 0)
return 0;
n++;
if (end && end[1] != '\0' && n < MP_MAX_KEY_DOWN)
ptr = &end[1];
else
break;
}
2011-04-25 10:38:46 +02:00
keys[n] = 0;
return 1;
}
static void bind_keys(struct input_ctx *ictx, bool builtin, bstr section,
const int keys[MP_MAX_KEY_DOWN + 1], bstr command,
const char *loc)
{
2011-04-25 10:38:46 +02:00
int i = 0, j;
struct cmd_bind *bind = NULL;
struct cmd_bind_section *bind_section = NULL;
bind_section = get_bind_section(ictx, builtin, section);
2011-04-25 10:38:46 +02:00
if (bind_section->cmd_binds) {
for (i = 0; bind_section->cmd_binds[i].cmd != NULL; i++) {
for (j = 0; bind_section->cmd_binds[i].input[j] == keys[j] && keys[j] != 0; j++)
/* NOTHING */;
if (keys[j] == 0 && bind_section->cmd_binds[i].input[j] == 0 ) {
bind = &bind_section->cmd_binds[i];
break;
}
}
}
if (!bind) {
bind_section->cmd_binds = talloc_realloc(bind_section,
bind_section->cmd_binds,
struct cmd_bind, i + 2);
memset(&bind_section->cmd_binds[i], 0, 2 * sizeof(struct cmd_bind));
2011-04-25 10:38:46 +02:00
bind = &bind_section->cmd_binds[i];
}
2011-04-25 10:38:46 +02:00
talloc_free(bind->cmd);
bind->cmd = bstrdup0(bind_section->cmd_binds, command);
bind->location = talloc_strdup(bind_section->cmd_binds, loc);
bind->owner = bind_section;
2011-04-25 10:38:46 +02:00
memcpy(bind->input, keys, (MP_MAX_KEY_DOWN + 1) * sizeof(int));
}
static int parse_config(struct input_ctx *ictx, bool builtin, bstr data,
const char *location)
{
int n_binds = 0, keys[MP_MAX_KEY_DOWN + 1];
int line_no = 0;
char *cur_loc = NULL;
while (data.len) {
line_no++;
if (cur_loc)
talloc_free(cur_loc);
cur_loc = talloc_asprintf(NULL, "%s:%d", location, line_no);
bstr line = bstr_strip_linebreaks(bstr_getline(data, &data));
line = bstr_lstrip(line);
if (line.len == 0 || bstr_startswith0(line, "#"))
2011-04-25 10:38:46 +02:00
continue;
struct bstr command;
// Find the key name starting a line
struct bstr keyname = bstr_split(line, WHITESPACE, &command);
command = bstr_strip(command);
if (command.len == 0) {
mp_tmsg(MSGT_INPUT, MSGL_ERR,
"Unfinished key binding: %.*s at %s\n", BSTR_P(line),
cur_loc);
continue;
}
char *name = bstrdup0(NULL, keyname);
if (!get_input_from_name(name, keys)) {
talloc_free(name);
mp_tmsg(MSGT_INPUT, MSGL_ERR,
"Unknown key '%.*s' at %s\n", BSTR_P(keyname), cur_loc);
2011-04-25 10:38:46 +02:00
continue;
}
talloc_free(name);
bstr section = {0};
if (bstr_startswith0(command, "{")) {
int p = bstrchr(command, '}');
if (p != -1) {
section = bstr_strip(bstr_splice(command, 1, p));
command = bstr_lstrip(bstr_cut(command, p + 1));
}
}
bind_keys(ictx, builtin, section, keys, command, cur_loc);
n_binds++;
// Print warnings if invalid commands are encountered.
talloc_free(mp_input_parse_cmd(command, cur_loc));
}
talloc_free(cur_loc);
return n_binds;
}
static int parse_config_file(struct input_ctx *ictx, char *file, bool warn)
{
if (!mp_path_exists(file)) {
mp_msg(MSGT_INPUT, warn ? MSGL_ERR : MSGL_V,
"Input config file %s not found.\n", file);
return 0;
}
stream_t *s = open_stream(file, NULL, NULL);
if (!s) {
mp_msg(MSGT_INPUT, MSGL_ERR, "Can't open input config file %s.\n", file);
return 0;
}
2012-11-01 00:52:07 +01:00
bstr res = stream_read_complete(s, NULL, 1000000, 0);
free_stream(s);
mp_msg(MSGT_INPUT, MSGL_V, "Parsing input config file %s\n", file);
int n_binds = parse_config(ictx, false, res, file);
talloc_free(res.start);
mp_msg(MSGT_INPUT, MSGL_V, "Input config file %s parsed: %d binds\n",
file, n_binds);
return 1;
}
void mp_input_set_section(struct input_ctx *ictx, char *name, int flags)
{
talloc_free(ictx->section);
ictx->section = talloc_strdup(ictx, name ? name : "default");
ictx->section_flags = flags;
}
char *mp_input_get_section(struct input_ctx *ictx)
{
return ictx->section;
}
struct input_ctx *mp_input_init(struct input_conf *input_conf,
bool load_default_conf)
{
struct input_ctx *ictx = talloc_ptrtype(NULL, ictx);
*ictx = (struct input_ctx){
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
.key_fifo_size = input_conf->key_fifo_size,
.ar_state = -1,
2008-04-30 17:57:02 +02:00
.ar_delay = input_conf->ar_delay,
.ar_rate = input_conf->ar_rate,
2009-04-01 01:26:34 +02:00
.default_bindings = input_conf->default_bindings,
.test = input_conf->test,
.wakeup_pipe = {-1, -1},
};
ictx->section = talloc_strdup(ictx, "default");
parse_config(ictx, true, bstr0(builtin_input_conf), "<default>");
#ifndef __MINGW32__
long ret = pipe(ictx->wakeup_pipe);
for (int i = 0; i < 2 && ret >= 0; i++) {
ret = fcntl(ictx->wakeup_pipe[i], F_GETFL);
if (ret < 0)
break;
ret = fcntl(ictx->wakeup_pipe[i], F_SETFL, ret | O_NONBLOCK);
}
if (ret < 0)
mp_msg(MSGT_INPUT, MSGL_ERR,
"Failed to initialize wakeup pipe: %s\n", strerror(errno));
else
mp_input_add_key_fd(ictx, ictx->wakeup_pipe[0], true, read_wakeup,
NULL, NULL);
#endif
bool config_ok = false;
if (input_conf->config_file)
config_ok = parse_config_file(ictx, input_conf->config_file, true);
if (!config_ok && load_default_conf) {
2011-04-25 10:38:46 +02:00
// Try global conf dir
char *file = mp_find_config_file("input.conf");
config_ok = file && parse_config_file(ictx, file, false);
talloc_free(file);
}
if (!config_ok) {
mp_msg(MSGT_INPUT, MSGL_V, "Falling back on default (hardcoded) "
"input config\n");
}
#ifdef CONFIG_JOYSTICK
2011-04-25 10:38:46 +02:00
if (input_conf->use_joystick) {
int fd = mp_input_joystick_init(input_conf->js_dev);
if (fd < 0)
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Can't init input joystick\n");
else
mp_input_add_key_fd(ictx, fd, 1, mp_input_joystick_read,
close, NULL);
2011-04-25 10:38:46 +02:00
}
#endif
#ifdef CONFIG_LIRC
2011-04-25 10:38:46 +02:00
if (input_conf->use_lirc) {
int fd = mp_input_lirc_init();
if (fd > 0)
mp_input_add_cmd_fd(ictx, fd, 0, mp_input_lirc_read,
mp_input_lirc_close);
}
#endif
#ifdef CONFIG_LIRCC
2011-04-25 10:38:46 +02:00
if (input_conf->use_lircc) {
int fd = lircc_init("mpv", NULL);
2011-04-25 10:38:46 +02:00
if (fd >= 0)
mp_input_add_cmd_fd(ictx, fd, 1, NULL, lircc_cleanup);
2011-04-25 10:38:46 +02:00
}
#endif
2011-04-25 10:38:46 +02:00
if (input_conf->in_file) {
int mode = O_RDONLY;
#ifndef __MINGW32__
2011-04-25 10:38:46 +02:00
// Use RDWR for FIFOs to ensure they stay open over multiple accesses.
// Note that on Windows due to how the API works, using RDONLY should
// be ok.
struct stat st;
2011-04-25 10:38:46 +02:00
if (stat(input_conf->in_file, &st) == 0 && S_ISFIFO(st.st_mode))
mode = O_RDWR;
mode |= O_NONBLOCK;
#endif
2011-04-25 10:38:46 +02:00
int in_file_fd = open(input_conf->in_file, mode);
if (in_file_fd >= 0)
mp_input_add_cmd_fd(ictx, in_file_fd, 1, NULL, close);
2011-04-25 10:38:46 +02:00
else
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Can't open %s: %s\n",
input_conf->in_file, strerror(errno));
}
2011-04-25 10:38:46 +02:00
return ictx;
}
static void clear_queue(struct cmd_queue *queue)
{
while (queue->first) {
struct mp_cmd *item = queue->first;
queue_remove(queue, item);
talloc_free(item);
}
}
void mp_input_uninit(struct input_ctx *ictx)
{
if (!ictx)
return;
for (int i = 0; i < ictx->num_key_fd; i++) {
2011-04-25 10:38:46 +02:00
if (ictx->key_fds[i].close_func)
ictx->key_fds[i].close_func(ictx->key_fds[i].fd);
}
for (int i = 0; i < ictx->num_cmd_fd; i++) {
2011-04-25 10:38:46 +02:00
if (ictx->cmd_fds[i].close_func)
ictx->cmd_fds[i].close_func(ictx->cmd_fds[i].fd);
}
for (int i = 0; i < 2; i++) {
if (ictx->wakeup_pipe[i] != -1)
close(ictx->wakeup_pipe[i]);
}
clear_queue(&ictx->key_cmd_queue);
clear_queue(&ictx->control_cmd_queue);
talloc_free(ictx->ar_cmd);
2011-04-25 10:38:46 +02:00
talloc_free(ictx);
}
2011-04-25 10:38:46 +02:00
void mp_input_register_options(m_config_t *cfg)
{
m_config_register_options(cfg, mp_input_opts);
}
static int print_key_list(m_option_t *cfg, char *optname, char *optparam)
{
2011-04-25 10:38:46 +02:00
int i;
printf("\n");
for (i = 0; key_names[i].name != NULL; i++)
printf("%s\n", key_names[i].name);
return M_OPT_EXIT;
}
static int print_cmd_list(m_option_t *cfg, char *optname, char *optparam)
{
2011-04-25 10:38:46 +02:00
const mp_cmd_t *cmd;
int i, j;
for (i = 0; (cmd = &mp_cmds[i])->name != NULL; i++) {
printf("%-20.20s", cmd->name);
for (j = 0; j < MP_CMD_MAX_ARGS && cmd->args[j].type.type; j++) {
const char *type = cmd->args[j].type.type->name;
if (cmd->args[j].optional)
2011-04-25 10:38:46 +02:00
printf(" [%s]", type);
else
printf(" %s", type);
}
printf("\n");
}
return M_OPT_EXIT;
}
void mp_input_wakeup(struct input_ctx *ictx)
{
if (ictx->wakeup_pipe[1] >= 0)
write(ictx->wakeup_pipe[1], &(char){0}, 1);
}
/**
* \param time time to wait for an interruption in milliseconds
*/
int mp_input_check_interrupt(struct input_ctx *ictx, int time)
{
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
for (int i = 0; ; i++) {
if (async_quit_request || queue_has_abort_cmds(&ictx->key_cmd_queue) ||
queue_has_abort_cmds(&ictx->control_cmd_queue)) {
input: rework event reading and command queuing Rework much of the logic related to reading from event sources and queuing commands. The two biggest architecture changes are: - The code buffering keycodes in mp_fifo.c is gone. Instead key input is now immediately fed to input.c and interpreted as commands, and then the commands are buffered instead. - mp_input_get_cmd() now always tries to read every available event from every event source and convert them to (buffered) commands. Before it would only process new events until one new command became available. Some relevant behavior changes: - Before commands could be lost when stream code called mp_input_check_interrupt() which read commands (to see if they were of types that triggered aborts during slow IO tasks) and then threw them away. This was especially an issue if cache was enabled and slow to read. Fixed - now it's possible to check whether there are queued commands which will abort playback of the current file without throwing other commands away. - mp_input_check_interrupt() now prints a message if it returns true. This is especially useful because the failures caused by aborted stream reads can trigger error messages from other code that was doing the read; the new message makes it more obvious what the cause of the subsequent error messages is. - It's now possible to again avoid making stdin non-blocking (which caused some issues) without reintroducing extra latency. The change will be done in a subsequent commit. - Event sources that do not support select() should now have somewhat lower latency in certain situations as they will be checked both before and after select()/sleep in input reading; before the sleep always happened first even if such sources already had queued input. Before the key fifo was also handled in this manner (first key triggered select, but if multiple were read then rest could be delayed; however in most cases this didn't add latency in practice as after central code started doing command handling it queried for further commands with a max sleep time of 0). - Key fifo limiting is more accurate now: it now counts actual commands intead of keycodes, and all queued keys are read immediately from input devices so they can be counted correctly. - Since keypresses are now interpreted immediately, commands which change keybindings will no longer affect following keypresses that have already been read before the command is executed. This should not be an issue in practice with current keybinding behavior.
2011-07-17 03:47:50 +02:00
mp_tmsg(MSGT_INPUT, MSGL_WARN, "Received command to move to "
"another file. Aborting current processing.\n");
return true;
}
if (i)
return false;
read_all_events(ictx, time);
2011-04-25 10:38:46 +02:00
}
}
unsigned int mp_input_get_mouse_event_counter(struct input_ctx *ictx)
{
return ictx->mouse_event_counter;
}