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.
This commit is contained in:
Uoti Urpala 2011-07-17 04:47:50 +03:00
parent 1916b95b8d
commit 82b8f89bae
9 changed files with 225 additions and 228 deletions

View File

@ -988,7 +988,7 @@ const m_option_t mplayer_opts[]={
{"slave", &slave_mode, CONF_TYPE_FLAG,CONF_GLOBAL , 0, 1, NULL},
OPT_MAKE_FLAGS("idle", player_idle_mode, CONF_GLOBAL),
{"use-stdin", "-use-stdin has been renamed to -noconsolecontrols, use that instead.", CONF_TYPE_PRINT, 0, 0, 0, NULL},
OPT_INTRANGE("key-fifo-size", key_fifo_size, CONF_GLOBAL, 2, 65000),
OPT_INTRANGE("key-fifo-size", input.key_fifo_size, CONF_GLOBAL, 2, 65000),
OPT_MAKE_FLAGS("consolecontrols", consolecontrols, CONF_GLOBAL),
{"mouse-movements", &enable_mouse_movements, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL},
{"nomouse-movements", &enable_mouse_movements, CONF_TYPE_FLAG, CONF_GLOBAL, 1, 0, NULL},

View File

@ -32,7 +32,6 @@ void set_default_mplayer_options(struct MPOpts *opts)
.initial_audio_sync = 1,
.term_osd = 1,
.term_osd_esc = "\x1b[A\r\x1b[K",
.key_fifo_size = 7,
.consolecontrols = 1,
.doubleclick_time = 300,
.audio_id = -1,
@ -58,6 +57,7 @@ void set_default_mplayer_options(struct MPOpts *opts)
},
.input = {
.config_file = "input.conf",
.key_fifo_size = 7,
.ar_delay = 100,
.ar_rate = 8,
.use_joystick = 1,

View File

@ -29,6 +29,7 @@
#include <sys/time.h>
#include <fcntl.h>
#include <ctype.h>
#include <assert.h>
#include "input.h"
#include "mp_fifo.h"
@ -550,8 +551,6 @@ static const struct cmd_bind def_cmd_binds[] = {
#define MP_MAX_CMD_FD 10
#endif
#define CMD_QUEUE_SIZE 100
struct input_fd {
int fd;
union {
@ -582,6 +581,13 @@ struct cmd_bind_section {
struct cmd_bind_section *next;
};
struct cmd_queue {
struct mp_cmd *first;
struct mp_cmd *last;
int num_cmds;
int num_abort_cmds;
};
struct input_ctx {
// Autorepeat stuff
short ar_state;
@ -590,6 +596,9 @@ struct input_ctx {
// Autorepeat config
unsigned int ar_delay;
unsigned int ar_rate;
// Maximum number of queued commands from keypresses (limit to avoid
// repeated slow commands piling up)
int key_fifo_size;
// these are the keys currently down
int key_down[MP_MAX_KEY_DOWN];
@ -605,14 +614,18 @@ struct input_ctx {
struct cmd_bind *cmd_binds;
struct cmd_bind *cmd_binds_default;
// 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;
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;
mp_cmd_t *cmd_queue[CMD_QUEUE_SIZE];
unsigned int cmd_queue_length, cmd_queue_start, cmd_queue_end;
struct cmd_queue key_cmd_queue;
struct cmd_queue control_cmd_queue;
};
@ -685,6 +698,46 @@ static char *get_key_combo_name(int *keys, int max)
return ret;
}
static bool is_abort_cmd(int cmd_id)
{
switch (cmd_id) {
case MP_CMD_QUIT:
case MP_CMD_PLAY_TREE_STEP:
case MP_CMD_PLAY_TREE_UP_STEP:
case MP_CMD_PLAY_ALT_SRC_STEP:
return true;
}
return false;
}
static void queue_pop(struct cmd_queue *queue)
{
assert(queue->num_cmds > 0);
struct mp_cmd *cmd = queue->first;
queue->first = cmd->queue_next;
queue->num_cmds--;
queue->num_abort_cmds -= is_abort_cmd(cmd->id);
}
static void queue_add(struct cmd_queue *queue, struct mp_cmd *cmd,
bool at_head)
{
if (!queue->num_cmds) {
queue->first = cmd;
queue->last = cmd;
} else if (at_head) {
queue->first->queue_prev = cmd;
cmd->queue_next = queue->first;
queue->first = cmd;
} else {
queue->last->queue_next = cmd;
cmd->queue_prev = queue->last;
queue->last = cmd;
}
queue->num_cmds++;
queue->num_abort_cmds += is_abort_cmd(cmd->id);
}
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))
@ -1261,193 +1314,199 @@ static mp_cmd_t *check_autorepeat(struct input_ctx *ictx)
return NULL;
}
void mp_input_feed_key(struct input_ctx *ictx, int code)
{
ictx->got_new_events = true;
if (code == MP_INPUT_RELEASE_ALL) {
memset(ictx->key_down, 0, sizeof(ictx->key_down));
ictx->num_key_down = 0;
ictx->last_key_down = 0;
return;
}
struct mp_cmd *cmd = interpret_key(ictx, code);
if (!cmd)
return;
struct cmd_queue *queue = &ictx->key_cmd_queue;
if (queue->num_cmds >= ictx->key_fifo_size &&
(!is_abort_cmd(cmd->id) || queue->num_abort_cmds))
return;
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(text);
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
*/
static mp_cmd_t *read_events(struct input_ctx *ictx, int time)
static void read_events(struct input_ctx *ictx, int time)
{
int i;
int got_cmd = 0;
ictx->got_new_events = false;
struct input_fd *key_fds = ictx->key_fds;
struct input_fd *cmd_fds = ictx->cmd_fds;
for (i = 0; i < ictx->num_key_fd; i++)
for (int i = 0; i < ictx->num_key_fd; i++)
if (key_fds[i].dead) {
mp_input_rm_key_fd(ictx, key_fds[i].fd);
i--;
}
for (i = 0; i < ictx->num_cmd_fd; i++)
} 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++)
if (cmd_fds[i].dead || cmd_fds[i].eof) {
mp_input_rm_cmd_fd(ictx, cmd_fds[i].fd);
i--;
} else if (cmd_fds[i].got_cmd)
got_cmd = 1;
} 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);
if (!got_cmd) {
int max_fd = 0;
for (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 (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;
if (time >= 0) {
tv.tv_sec = time / 1000;
tv.tv_usec = (time % 1000) * 1000;
time_val = &tv;
} else
time_val = NULL;
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);
}
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;
if (time >= 0) {
tv.tv_sec = time / 1000;
tv.tv_usec = (time % 1000) * 1000;
time_val = &tv;
} else
time_val = NULL;
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 (!got_cmd && time)
if (time)
usec_sleep(time * 1000);
#endif
for (i = 0; i < ictx->num_key_fd; i++) {
for (int i = 0; i < ictx->num_key_fd; i++) {
#ifdef HAVE_POSIX_SELECT
if (!key_fds[i].no_select && !FD_ISSET(key_fds[i].fd, &fds))
continue;
#endif
int code;
while (1) {
code = key_fds[i].read_func.key(key_fds[i].ctx, key_fds[i].fd);
if (code < 0) {
if (code == MP_INPUT_RELEASE_ALL) {
memset(ictx->key_down, 0, sizeof(ictx->key_down));
ictx->num_key_down = 0;
ictx->last_key_down = 0;
continue;
}
break;
}
mp_cmd_t *ret = interpret_key(ictx, code);
if (ret)
return ret;
}
if (code == MP_INPUT_ERROR)
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Error on key input "
"file descriptor %d\n", key_fds[i].fd);
else if (code == MP_INPUT_DEAD) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Dead key input on "
"file descriptor %d\n", key_fds[i].fd);
key_fds[i].dead = 1;
}
read_key_fd(ictx, &key_fds[i]);
}
mp_cmd_t *autorepeat_cmd = check_autorepeat(ictx);
if (autorepeat_cmd)
return autorepeat_cmd;
for (i = 0; i < ictx->num_cmd_fd; i++) {
for (int i = 0; i < ictx->num_cmd_fd; i++) {
#ifdef HAVE_POSIX_SELECT
if (!cmd_fds[i].no_select && !FD_ISSET(cmd_fds[i].fd, &fds) &&
!cmd_fds[i].got_cmd)
if (!cmd_fds[i].no_select && !FD_ISSET(cmd_fds[i].fd, &fds))
continue;
#endif
char *cmd;
int r;
while ((r = read_cmd(&cmd_fds[i], &cmd)) >= 0) {
mp_cmd_t *ret = mp_input_parse_cmd(cmd);
talloc_free(cmd);
if (ret)
return ret;
}
if (r == MP_INPUT_ERROR)
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Error on command "
"file descriptor %d\n", cmd_fds[i].fd);
else if (r == MP_INPUT_DEAD)
cmd_fds[i].dead = 1;
read_cmd_fd(ictx, &cmd_fds[i]);
}
return NULL;
}
/* 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_events(struct input_ctx *ictx, int time)
{
while (1) {
read_events(ictx, time);
if (!ictx->got_new_events)
return;
time = 0;
}
}
int mp_input_queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd)
{
if (!cmd || ictx->cmd_queue_length >= CMD_QUEUE_SIZE)
ictx->got_new_events = true;
if (!cmd)
return 0;
ictx->cmd_queue[ictx->cmd_queue_end] = cmd;
ictx->cmd_queue_end = (ictx->cmd_queue_end + 1) % CMD_QUEUE_SIZE;
ictx->cmd_queue_length++;
queue_add(&ictx->control_cmd_queue, cmd, true);
return 1;
}
static mp_cmd_t *get_queued_cmd(struct input_ctx *ictx, int peek_only)
{
mp_cmd_t *ret;
if (ictx->cmd_queue_length == 0)
return NULL;
ret = ictx->cmd_queue[ictx->cmd_queue_start];
if (!peek_only) {
ictx->cmd_queue_length--;
ictx->cmd_queue_start = (ictx->cmd_queue_start + 1) % CMD_QUEUE_SIZE;
}
return ret;
}
/**
* \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)
{
mp_cmd_t *ret = NULL;
struct cmd_filter *cf;
int from_queue;
if (async_quit_request)
return mp_input_parse_cmd("quit 1");
while (1) {
from_queue = 1;
ret = get_queued_cmd(ictx, peek_only);
if (ret)
break;
from_queue = 0;
ret = read_events(ictx, time);
if (!ret) {
from_queue = 1;
ret = get_queued_cmd(ictx, peek_only);
}
break;
}
if (!ret)
return NULL;
for (cf = cmd_filters; cf; cf = cf->next) {
if (cf->filter(ret, cf->ctx)) {
if (peek_only && from_queue)
// The filter ate the cmd, so we remove it from queue
ret = get_queued_cmd(ictx, 0);
mp_cmd_free(ret);
if (ictx->control_cmd_queue.num_cmds || ictx->key_cmd_queue.num_cmds)
time = 0;
read_all_events(ictx, time);
struct mp_cmd *ret;
struct cmd_queue *queue = &ictx->control_cmd_queue;
if (!queue->num_cmds)
queue = &ictx->key_cmd_queue;
if (!queue->num_cmds) {
queue = NULL;
ret = check_autorepeat(ictx);
if (!ret)
return NULL;
} else
ret = queue->first;
for (struct cmd_filter *cf = cmd_filters; cf; cf = cf->next) {
if (cf->filter(ret, cf->ctx)) {
// The filter ate the cmd, so remove it from the queue
if (queue)
queue_pop(queue);
mp_cmd_free(ret);
// Retry with next command
return mp_input_get_cmd(ictx, 0, peek_only);
}
}
if (!from_queue && peek_only)
mp_input_queue_cmd(ictx, ret);
if (!peek_only && queue)
queue_pop(queue);
return ret;
}
@ -1752,6 +1811,7 @@ struct input_ctx *mp_input_init(struct input_conf *input_conf)
{
struct input_ctx *ictx = talloc_ptrtype(NULL, ictx);
*ictx = (struct input_ctx){
.key_fifo_size = input_conf->key_fifo_size,
.ar_state = -1,
.ar_delay = input_conf->ar_delay,
.ar_rate = input_conf->ar_rate,
@ -1917,19 +1977,15 @@ static int print_cmd_list(m_option_t *cfg)
*/
int mp_input_check_interrupt(struct input_ctx *ictx, int time)
{
mp_cmd_t *cmd;
if ((cmd = mp_input_get_cmd(ictx, time, 1)) == NULL)
return 0;
switch (cmd->id) {
case MP_CMD_QUIT:
case MP_CMD_PLAY_TREE_STEP:
case MP_CMD_PLAY_TREE_UP_STEP:
case MP_CMD_PLAY_ALT_SRC_STEP:
// The cmd will be executed when we are back in the main loop
return 1;
for (int i = 0; ; i++) {
if (async_quit_request || ictx->key_cmd_queue.num_abort_cmds ||
ictx->control_cmd_queue.num_abort_cmds) {
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);
}
// remove the cmd from the queue
cmd = mp_input_get_cmd(ictx, time, 0);
mp_cmd_free(cmd);
return 0;
}

View File

@ -202,6 +202,8 @@ typedef struct mp_cmd {
int nargs;
struct mp_cmd_arg args[MP_CMD_MAX_ARGS];
int pausing;
struct mp_cmd *queue_prev;
struct mp_cmd *queue_next;
} mp_cmd_t;
@ -234,6 +236,9 @@ 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);
// Feed a keypress (alternative to being returned from read_func above)
void mp_input_feed_key(struct input_ctx *ictx, int code);
// As for the cmd one you usually don't need this function.
void mp_input_rm_key_fd(struct input_ctx *ictx, int fd);

View File

@ -434,7 +434,7 @@ static int event_fd_callback(void *ctx, int fd)
{
struct vo *vo = ctx;
vo_check_events(vo);
return mplayer_get_key(vo->key_fifo, 0);
return MP_INPUT_NOTHING;
}
int vo_config(struct vo *vo, uint32_t width, uint32_t height,

View File

@ -29,86 +29,23 @@
struct mp_fifo {
struct MPOpts *opts;
int *data;
int readpos;
int size;
int num_entries;
int max_up;
int num_up;
struct input_ctx *input;
int last_key_down;
unsigned last_down_time;
};
struct mp_fifo *mp_fifo_create(struct MPOpts *opts)
struct mp_fifo *mp_fifo_create(struct input_ctx *input, struct MPOpts *opts)
{
struct mp_fifo *fifo = talloc_zero(NULL, struct mp_fifo);
fifo->input = input;
fifo->opts = opts;
/* Typical mouse wheel use will generate a sequence repeating 3 events:
* down, doubleclick, up, down, doubleclick, up, ...
* Normally only one of those event types triggers a command,
* so allow opts->key_fifo_size such repeats.
*/
fifo->max_up = opts->key_fifo_size;
fifo->size = opts->key_fifo_size * 3;
fifo->data = talloc_array_ptrtype(fifo, fifo->data, fifo->size);
return fifo;
}
static bool is_up(int code)
{
return code > 0 && !(code & MP_KEY_DOWN)
&& !(code >= MOUSE_BTN0_DBL && code < MOUSE_BTN_DBL_END);
}
static int fifo_peek(struct mp_fifo *fifo, int offset)
{
return fifo->data[(fifo->readpos + offset) % fifo->size];
}
static int fifo_read(struct mp_fifo *fifo)
{
int code = fifo_peek(fifo, 0);
fifo->readpos += 1;
fifo->readpos %= fifo->size;
fifo->num_entries--;
fifo->num_up -= is_up(code);
assert(fifo->num_entries >= 0);
assert(fifo->num_up >= 0);
return code;
}
static void fifo_write(struct mp_fifo *fifo, int code)
{
fifo->data[(fifo->readpos + fifo->num_entries) % fifo->size] = code;
fifo->num_entries++;
fifo->num_up += is_up(code);
assert(fifo->num_entries <= fifo->size);
assert(fifo->num_up <= fifo->max_up);
}
static void mplayer_put_key_internal(struct mp_fifo *fifo, int code)
{
// Clear key-down state if we're forced to drop entries
if (fifo->num_entries >= fifo->size - 1
|| fifo->num_up >= fifo->max_up) {
if (fifo_peek(fifo, fifo->num_entries - 1) != MP_INPUT_RELEASE_ALL)
fifo_write(fifo, MP_INPUT_RELEASE_ALL);
} else
fifo_write(fifo, code);
}
int mplayer_get_key(void *ctx, int fd)
{
struct mp_fifo *fifo = ctx;
if (!fifo->num_entries)
return MP_INPUT_NOTHING;
return fifo_read(fifo);
}
static void put_double(struct mp_fifo *fifo, int code)
{
if (code >= MOUSE_BTN0 && code < MOUSE_BTN_END)
mplayer_put_key_internal(fifo, code - MOUSE_BTN0 + MOUSE_BTN0_DBL);
mp_input_feed_key(fifo->input, code - MOUSE_BTN0 + MOUSE_BTN0_DBL);
}
void mplayer_put_key(struct mp_fifo *fifo, int code)
@ -120,7 +57,7 @@ void mplayer_put_key(struct mp_fifo *fifo, int code)
&& (code & ~MP_KEY_DOWN) >= MOUSE_BTN0_DBL
&& (code & ~MP_KEY_DOWN) < MOUSE_BTN_DBL_END)
return;
mplayer_put_key_internal(fifo, code);
mp_input_feed_key(fifo->input, code);
if (code & MP_KEY_DOWN) {
code &= ~MP_KEY_DOWN;
if (fifo->last_key_down == code

View File

@ -20,11 +20,11 @@
#define MPLAYER_MP_FIFO_H
struct mp_fifo;
int mplayer_get_key(void *ctx, int fd);
void mplayer_put_key(struct mp_fifo *fifo, int code);
// Can be freed with talloc_free()
struct input_ctx;
struct MPOpts;
struct mp_fifo *mp_fifo_create(struct MPOpts *opts);
struct mp_fifo *mp_fifo_create(struct input_ctx *input, struct MPOpts *opts);
#ifdef IS_OLD_VO

View File

@ -3732,7 +3732,7 @@ static void run_playloop(struct MPContext *mpctx)
static int read_keys(void *ctx, int fd)
{
getch2(ctx);
return mplayer_get_key(ctx, 0);
return MP_INPUT_NOTHING;
}
static bool attachment_is_font(struct demux_attachment *att)
@ -3887,7 +3887,6 @@ int i;
}
}
}
mpctx->key_fifo = mp_fifo_create(opts);
print_version("MPlayer2");
@ -4079,7 +4078,7 @@ if(!codecs_file || !parse_codec_cfg(codecs_file)){
// Init input system
current_module = "init_input";
mpctx->input = mp_input_init(&opts->input);
mp_input_add_key_fd(mpctx->input, -1,0,mplayer_get_key,NULL, mpctx->key_fifo);
mpctx->key_fifo = mp_fifo_create(mpctx->input, opts);
if(slave_mode) {
#if USE_FD0_CMD_SELECT
int flags = fcntl(0, F_GETFL);

View File

@ -59,7 +59,6 @@ typedef struct MPOpts {
char *term_osd_esc;
char *playing_msg;
int player_idle_mode;
int key_fifo_size;
int consolecontrols;
int doubleclick_time;
int list_properties;
@ -123,6 +122,7 @@ typedef struct MPOpts {
struct input_conf {
char *config_file;
int key_fifo_size;
unsigned int ar_delay;
unsigned int ar_rate;
char *js_dev;