2008-12-13 18:28:00 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2005-10-25 21:23:45 +00:00
|
|
|
#include "config.h"
|
2002-01-30 12:46:03 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
2009-03-14 21:52:45 +00:00
|
|
|
#include <stdbool.h>
|
2002-01-30 12:46:03 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/types.h>
|
2002-10-22 14:32:17 +00:00
|
|
|
#include <sys/stat.h>
|
2002-02-04 14:48:32 +00:00
|
|
|
#include <sys/time.h>
|
2002-01-30 12:46:03 +00:00
|
|
|
#include <fcntl.h>
|
2002-06-12 10:39:04 +00:00
|
|
|
#include <ctype.h>
|
2013-11-28 18:28:38 +00:00
|
|
|
#include <pthread.h>
|
2011-07-17 01:47:50 +00:00
|
|
|
#include <assert.h>
|
2002-01-30 12:46:03 +00:00
|
|
|
|
2013-02-16 21:51:10 +00:00
|
|
|
#include <libavutil/avstring.h>
|
|
|
|
#include <libavutil/common.h>
|
|
|
|
|
2012-02-03 07:05:11 +00:00
|
|
|
#include "osdep/io.h"
|
|
|
|
|
2002-01-30 12:46:03 +00:00
|
|
|
#include "input.h"
|
2011-04-25 06:43:59 +00:00
|
|
|
#include "keycodes.h"
|
2013-12-26 16:10:35 +00:00
|
|
|
#include "cmd_list.h"
|
|
|
|
#include "cmd_parse.h"
|
2014-01-31 18:50:25 +00:00
|
|
|
#include "osdep/threads.h"
|
2005-10-25 21:23:45 +00:00
|
|
|
#include "osdep/timer.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
|
|
|
#include "common/global.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/m_option.h"
|
|
|
|
#include "options/path.h"
|
2008-04-30 04:15:52 +00:00
|
|
|
#include "talloc.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/options.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "bstr/bstr.h"
|
2012-08-01 19:50:24 +00:00
|
|
|
#include "stream/stream.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/common.h"
|
2002-01-30 12:46:03 +00:00
|
|
|
|
|
|
|
#include "joystick.h"
|
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_LIRC
|
2002-01-31 09:39:11 +00:00
|
|
|
#include "lirc.h"
|
|
|
|
#endif
|
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_COCOA
|
2013-06-02 15:39:05 +00:00
|
|
|
#include "osdep/macosx_events.h"
|
|
|
|
#endif
|
|
|
|
|
2013-09-05 11:02:25 +00:00
|
|
|
#define input_lock(ictx) pthread_mutex_lock(&ictx->mutex)
|
|
|
|
#define input_unlock(ictx) pthread_mutex_unlock(&ictx->mutex)
|
2013-08-13 12:40:17 +00:00
|
|
|
|
2013-08-26 17:15:35 +00:00
|
|
|
#define MP_MAX_KEY_DOWN 4
|
|
|
|
|
2011-07-16 15:17:48 +00:00
|
|
|
struct cmd_bind {
|
2013-06-22 22:07:45 +00:00
|
|
|
int keys[MP_MAX_KEY_DOWN];
|
|
|
|
int num_keys;
|
2011-04-25 08:38:46 +00:00
|
|
|
char *cmd;
|
2012-10-13 19:09:42 +00:00
|
|
|
char *location; // filename/line number of definition
|
2013-06-22 21:26:44 +00:00
|
|
|
bool is_builtin;
|
2012-10-13 19:09:42 +00:00
|
|
|
struct cmd_bind_section *owner;
|
2011-07-16 15:17:48 +00:00
|
|
|
};
|
2008-04-30 06:53:12 +00:00
|
|
|
|
2013-12-26 16:10:35 +00:00
|
|
|
struct cmd_bind_section {
|
|
|
|
struct cmd_bind *binds;
|
|
|
|
int num_binds;
|
|
|
|
char *section;
|
|
|
|
struct mp_rect mouse_area; // set at runtime, if at all
|
|
|
|
bool mouse_area_set; // mouse_area is valid and should be tested
|
|
|
|
struct cmd_bind_section *next;
|
2010-12-19 10:12:20 +00:00
|
|
|
};
|
|
|
|
|
2013-07-07 14:53:35 +00:00
|
|
|
#define MP_MAX_FDS 10
|
2002-01-30 12:46:03 +00:00
|
|
|
|
2011-07-16 15:17:48 +00:00
|
|
|
struct input_fd {
|
2013-09-27 13:30:59 +00:00
|
|
|
struct mp_log *log;
|
2011-04-25 08:38:46 +00:00
|
|
|
int fd;
|
2013-07-07 14:53:35 +00:00
|
|
|
int (*read_key)(void *ctx, int fd);
|
2013-12-21 18:33:45 +00:00
|
|
|
int (*read_cmd)(void *ctx, int fd, char *dest, int size);
|
|
|
|
int (*close_func)(void *ctx, int fd);
|
2011-04-25 08:38:46 +00:00
|
|
|
void *ctx;
|
|
|
|
unsigned eof : 1;
|
|
|
|
unsigned drop : 1;
|
|
|
|
unsigned dead : 1;
|
|
|
|
unsigned got_cmd : 1;
|
2013-07-14 13:37:39 +00:00
|
|
|
unsigned select : 1;
|
2011-04-25 08:38:46 +00:00
|
|
|
// These fields are for the cmd fds.
|
|
|
|
char *buffer;
|
|
|
|
int pos, size;
|
2011-07-16 15:17:48 +00:00
|
|
|
};
|
2002-11-14 23:41:44 +00:00
|
|
|
|
2014-05-01 23:27:17 +00:00
|
|
|
#define MAX_ACTIVE_SECTIONS 50
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
|
|
|
|
struct active_section {
|
|
|
|
char *name;
|
|
|
|
int flags;
|
|
|
|
};
|
|
|
|
|
2011-07-17 01:47:50 +00:00
|
|
|
struct cmd_queue {
|
|
|
|
struct mp_cmd *first;
|
|
|
|
};
|
|
|
|
|
2008-04-30 04:15:52 +00:00
|
|
|
struct input_ctx {
|
2013-08-26 17:15:35 +00:00
|
|
|
pthread_mutex_t mutex;
|
2014-04-15 21:12:01 +00:00
|
|
|
pthread_cond_t wakeup;
|
2014-04-25 17:13:03 +00:00
|
|
|
pthread_t mainthread;
|
|
|
|
bool mainthread_set;
|
2013-09-10 06:29:45 +00:00
|
|
|
struct mp_log *log;
|
2013-12-21 18:33:45 +00:00
|
|
|
struct mpv_global *global;
|
2013-08-26 17:15:35 +00:00
|
|
|
|
2013-12-01 05:23:39 +00:00
|
|
|
bool using_alt_gr;
|
2013-07-27 19:26:00 +00:00
|
|
|
bool using_ar;
|
|
|
|
bool using_cocoa_media_keys;
|
|
|
|
|
2008-04-30 04:15:52 +00:00
|
|
|
// Autorepeat stuff
|
|
|
|
short ar_state;
|
2013-05-25 16:31:06 +00:00
|
|
|
int64_t last_ar;
|
Add initial Lua scripting support
This is preliminary. There are still tons of issues, and any aspect
of scripting may change in the future. I decided to merge this
(preliminary) work now because it makes it easier to develop it, not
because it's done. lua.rst is clear enough about it (plus some
sarcasm).
This requires linking to Lua. Lua has no official pkg-config file, but
there are distribution specific .pc files, all with different names.
Adding a non-pkg-config based configure test was considered, but we'd
rather not.
One major complication is that libquvi links against Lua too, and if
the Lua version is different from mpv's, you will get a crash as soon
as libquvi uses Lua. (libquvi by design always runs when a file is
opened.) I would consider this the problem of distros and whoever
builds mpv, but to make things easier for users, we add a terrible
runtime test to the configure script, which probes whether libquvi
will crash. This is disabled when cross-compiling, but in that case
we hope the user knows what he is doing.
2013-09-25 22:41:14 +00:00
|
|
|
|
2008-04-30 15:57:02 +00:00
|
|
|
// Autorepeat config
|
|
|
|
unsigned int ar_delay;
|
|
|
|
unsigned int ar_rate;
|
2011-07-17 01:47:50 +00:00
|
|
|
// Maximum number of queued commands from keypresses (limit to avoid
|
|
|
|
// repeated slow commands piling up)
|
|
|
|
int key_fifo_size;
|
2008-04-30 05:56:45 +00:00
|
|
|
|
2014-04-18 14:27:02 +00:00
|
|
|
// history of key downs - the newest is in position 0
|
|
|
|
int key_history[MP_MAX_KEY_DOWN];
|
2014-04-18 15:45:41 +00:00
|
|
|
// key code of the last key that triggered MP_KEY_STATE_DOWN
|
|
|
|
int last_key_down;
|
2014-04-18 15:16:33 +00:00
|
|
|
int64_t last_key_down_time;
|
2013-12-01 16:59:20 +00:00
|
|
|
bool current_down_cmd_need_release;
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
struct mp_cmd *current_down_cmd;
|
|
|
|
|
2013-07-02 12:00:24 +00:00
|
|
|
int doubleclick_time;
|
|
|
|
int last_doubleclick_key_down;
|
|
|
|
double last_doubleclick_time;
|
|
|
|
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
// Mouse position on the consumer side (as command.c sees it)
|
|
|
|
int mouse_x, mouse_y;
|
2013-06-19 16:19:45 +00:00
|
|
|
char *mouse_section; // last section to receive mouse event
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
|
|
|
|
// Mouse position on the producer side (as the VO sees it)
|
|
|
|
// Unlike mouse_x/y, this can be used to resolve mouse click bindings.
|
|
|
|
int mouse_vo_x, mouse_vo_y;
|
2008-04-30 07:21:50 +00:00
|
|
|
|
2012-10-13 19:10:20 +00:00
|
|
|
bool test;
|
|
|
|
|
2009-03-31 23:26:34 +00:00
|
|
|
bool default_bindings;
|
2008-04-30 05:56:45 +00:00
|
|
|
// List of command binding sections
|
2011-07-16 15:17:48 +00:00
|
|
|
struct cmd_bind_section *cmd_bind_sections;
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
|
|
|
|
// List currently active command sections
|
|
|
|
struct active_section active_sections[MAX_ACTIVE_SECTIONS];
|
|
|
|
int num_active_sections;
|
2008-04-30 08:06:55 +00:00
|
|
|
|
2011-07-17 01:47:50 +00: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;
|
|
|
|
|
2013-05-25 16:31:06 +00:00
|
|
|
unsigned int mouse_event_counter;
|
2013-05-16 21:17:46 +00:00
|
|
|
|
2013-07-07 14:53:35 +00:00
|
|
|
struct input_fd fds[MP_MAX_FDS];
|
|
|
|
unsigned int num_fds;
|
2008-04-30 10:14:03 +00:00
|
|
|
|
2013-09-01 23:09:52 +00:00
|
|
|
struct cmd_queue cmd_queue;
|
2012-03-25 19:58:48 +00:00
|
|
|
|
input: avoid using wakeup pipe if it's not needed
If input is not waiting for select(), writing to the wakeup pipe is
wasteful, and, if there are many wakeups, might even block the wakeup
threads if the pipe gets full.
However, if it's waiting for select(), the wakup pipe must be used to
unblock the waiting thread. Actually there's a small race condition: we
might determine that the main thread is in select(), and write to the
wakeup pipe (whether we do this while unlocked or locked doesn't really
matter). Then, the main thread might leave select() before reading from
the wakup pipe. This should be harmless, because at worst more wakeups
than needed happen, but never fewer.
2013-12-15 20:33:31 +00:00
|
|
|
bool in_select;
|
2012-03-25 19:58:48 +00:00
|
|
|
int wakeup_pipe[2];
|
2008-04-30 04:15:52 +00:00
|
|
|
};
|
|
|
|
|
2008-01-08 21:40:44 +00:00
|
|
|
int async_quit_request;
|
|
|
|
|
2013-12-26 16:41:28 +00:00
|
|
|
static int parse_config(struct input_ctx *ictx, bool builtin, bstr data,
|
|
|
|
const char *location, const char *restrict_section);
|
|
|
|
|
2013-03-01 10:27:59 +00:00
|
|
|
#define OPT_BASE_STRUCT struct MPOpts
|
|
|
|
|
2002-03-19 13:30:16 +00:00
|
|
|
// Our command line options
|
2013-07-22 22:45:23 +00:00
|
|
|
static const m_option_t input_config[] = {
|
2013-02-08 22:52:06 +00:00
|
|
|
OPT_STRING("conf", input.config_file, CONF_GLOBAL),
|
2011-04-25 08:38:46 +00:00
|
|
|
OPT_INT("ar-delay", input.ar_delay, CONF_GLOBAL),
|
2008-04-30 15:57:02 +00:00
|
|
|
OPT_INT("ar-rate", input.ar_rate, CONF_GLOBAL),
|
2013-12-26 18:22:40 +00:00
|
|
|
OPT_PRINT("keylist", mp_print_key_list),
|
|
|
|
OPT_PRINT("cmdlist", mp_print_cmd_list),
|
2008-04-30 15:57:02 +00:00
|
|
|
OPT_STRING("js-dev", input.js_dev, CONF_GLOBAL),
|
|
|
|
OPT_STRING("file", input.in_file, CONF_GLOBAL),
|
2013-02-08 20:09:18 +00:00
|
|
|
OPT_FLAG("default-bindings", input.default_bindings, CONF_GLOBAL),
|
|
|
|
OPT_FLAG("test", input.test, CONF_GLOBAL),
|
2011-04-25 08:38:46 +00:00
|
|
|
{ NULL, NULL, 0, 0, 0, 0, NULL}
|
2002-02-11 11:42:08 +00:00
|
|
|
};
|
|
|
|
|
2013-07-27 19:26:00 +00:00
|
|
|
const m_option_t mp_input_opts[] = {
|
2013-07-22 22:45:23 +00:00
|
|
|
{ "input", (void *)&input_config, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
|
2013-07-02 12:00:24 +00:00
|
|
|
OPT_INTRANGE("doubleclick-time", input.doubleclick_time, 0, 0, 1000),
|
2014-04-24 15:27:27 +00:00
|
|
|
OPT_FLAG("input-joystick", input.use_joystick, CONF_GLOBAL),
|
|
|
|
OPT_FLAG("input-lirc", input.use_lirc, CONF_GLOBAL),
|
|
|
|
OPT_FLAG("input-right-alt-gr", input.use_alt_gr, CONF_GLOBAL),
|
2013-12-21 18:33:45 +00:00
|
|
|
#if HAVE_LIRC
|
2014-04-24 15:27:27 +00:00
|
|
|
OPT_STRING("input-lirc-conf", input.lirc_configfile, CONF_GLOBAL),
|
2013-12-21 18:33:45 +00:00
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_COCOA
|
2014-04-24 15:27:27 +00:00
|
|
|
OPT_FLAG("input-appleremote", input.use_appleremote, CONF_GLOBAL),
|
|
|
|
OPT_FLAG("input-media-keys", input.use_media_keys, CONF_GLOBAL),
|
2013-06-03 21:02:16 +00:00
|
|
|
#endif
|
2011-04-25 08:38:46 +00:00
|
|
|
{ NULL, NULL, 0, 0, 0, 0, NULL}
|
2002-02-11 11:42:08 +00:00
|
|
|
};
|
2002-02-08 18:10:56 +00:00
|
|
|
|
2012-08-01 20:52:28 +00:00
|
|
|
static const char builtin_input_conf[] =
|
2013-12-17 00:23:09 +00:00
|
|
|
#include "input/input_conf.h"
|
2012-08-01 20:52:28 +00:00
|
|
|
;
|
|
|
|
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
static bool test_rect(struct mp_rect *rc, int x, int y)
|
|
|
|
{
|
|
|
|
return x >= rc->x0 && y >= rc->y0 && x < rc->x1 && y < rc->y1;
|
|
|
|
}
|
|
|
|
|
2012-01-18 01:35:40 +00:00
|
|
|
static int queue_count_cmds(struct cmd_queue *queue)
|
2011-07-17 01:47:50 +00:00
|
|
|
{
|
2012-01-18 01:35:40 +00: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)
|
|
|
|
{
|
2013-08-13 12:40:17 +00:00
|
|
|
bool ret = false;
|
|
|
|
for (struct mp_cmd *cmd = queue->first; cmd; cmd = cmd->queue_next)
|
2014-02-20 12:38:39 +00:00
|
|
|
if (mp_input_is_abort_cmd(cmd)) {
|
2013-08-13 12:40:17 +00:00
|
|
|
ret = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
2011-10-24 00:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-09-02 00:29:20 +00:00
|
|
|
static void queue_add_head(struct cmd_queue *queue, struct mp_cmd *cmd)
|
2011-07-17 01:47:50 +00:00
|
|
|
{
|
2013-09-02 00:29:20 +00:00
|
|
|
cmd->queue_next = queue->first;
|
|
|
|
queue->first = cmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void queue_add_tail(struct cmd_queue *queue, struct mp_cmd *cmd)
|
|
|
|
{
|
|
|
|
struct mp_cmd **p_prev = &queue->first;
|
|
|
|
while (*p_prev)
|
|
|
|
p_prev = &(*p_prev)->queue_next;
|
|
|
|
*p_prev = cmd;
|
|
|
|
cmd->queue_next = NULL;
|
2013-08-13 12:40:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct mp_cmd *queue_peek(struct cmd_queue *queue)
|
|
|
|
{
|
|
|
|
struct mp_cmd *ret = NULL;
|
|
|
|
ret = queue->first;
|
|
|
|
return ret;
|
2011-07-17 01:47:50 +00:00
|
|
|
}
|
|
|
|
|
2013-09-02 00:40:05 +00:00
|
|
|
static struct mp_cmd *queue_peek_tail(struct cmd_queue *queue)
|
|
|
|
{
|
|
|
|
struct mp_cmd *cur = queue->first;
|
|
|
|
while (cur && cur->queue_next)
|
|
|
|
cur = cur->queue_next;
|
|
|
|
return cur;
|
|
|
|
}
|
|
|
|
|
2013-09-27 13:30:59 +00:00
|
|
|
static void append_bind_info(struct input_ctx *ictx, char **pmsg,
|
|
|
|
struct cmd_bind *bind)
|
2012-10-13 19:10:20 +00:00
|
|
|
{
|
|
|
|
char *msg = *pmsg;
|
2013-09-27 13:30:59 +00:00
|
|
|
struct mp_cmd *cmd = mp_input_parse_cmd(ictx, bstr0(bind->cmd),
|
|
|
|
bind->location);
|
2012-10-13 19:10:20 +00:00
|
|
|
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);
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
msg = talloc_asprintf_append(msg, " in %s", bind->location);
|
2013-06-22 21:26:44 +00:00
|
|
|
if (bind->is_builtin)
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
msg = talloc_asprintf_append(msg, " (default)");
|
|
|
|
talloc_free(cmd);
|
2012-10-13 19:10:20 +00:00
|
|
|
*pmsg = msg;
|
|
|
|
}
|
|
|
|
|
2014-04-18 14:27:02 +00:00
|
|
|
static mp_cmd_t *handle_test(struct input_ctx *ictx, int code)
|
2012-10-13 19:10:20 +00:00
|
|
|
{
|
2014-04-18 14:37:27 +00:00
|
|
|
if (code == MP_KEY_CLOSE_WIN) {
|
|
|
|
MP_WARN(ictx,
|
|
|
|
"CLOSE_WIN was received. This pseudo key can be remapped too,\n"
|
|
|
|
"but --input-test will always quit when receiving it.\n");
|
|
|
|
const char *args[] = {"quit", NULL};
|
|
|
|
mp_cmd_t *res = mp_input_parse_cmd_strv(ictx->log, 0, args, "");
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-04-18 14:27:02 +00:00
|
|
|
char *key_buf = mp_input_get_key_combo_name(&code, 1);
|
2014-02-19 14:39:59 +00:00
|
|
|
char *msg = talloc_asprintf(NULL, "Key %s is bound to:\n", key_buf);
|
2012-10-13 19:10:20 +00:00
|
|
|
talloc_free(key_buf);
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
for (struct cmd_bind_section *bs = ictx->cmd_bind_sections;
|
|
|
|
bs; bs = bs->next)
|
|
|
|
{
|
2013-06-22 22:40:35 +00:00
|
|
|
for (int i = 0; i < bs->num_binds; i++) {
|
2014-04-18 14:27:02 +00:00
|
|
|
if (bs->binds[i].num_keys && bs->binds[i].keys[0] == code) {
|
2012-10-13 19:10:20 +00:00
|
|
|
count++;
|
|
|
|
msg = talloc_asprintf_append(msg, "%d. ", count);
|
2013-09-27 13:30:59 +00:00
|
|
|
append_bind_info(ictx, &msg, &bs->binds[i]);
|
2012-10-13 19:10:20 +00:00
|
|
|
msg = talloc_asprintf_append(msg, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!count)
|
|
|
|
msg = talloc_asprintf_append(msg, "(nothing)");
|
|
|
|
|
2013-09-10 06:29:45 +00:00
|
|
|
MP_VERBOSE(ictx, "%s\n", msg);
|
2014-02-19 14:39:59 +00:00
|
|
|
const char *args[] = {"show_text", msg, NULL};
|
|
|
|
mp_cmd_t *res = mp_input_parse_cmd_strv(ictx->log, MP_ON_OSD_MSG, args, "");
|
|
|
|
talloc_free(msg);
|
2012-10-13 19:10:20 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2011-07-16 15:17:48 +00:00
|
|
|
static struct cmd_bind_section *get_bind_section(struct input_ctx *ictx,
|
2013-06-22 21:26:44 +00:00
|
|
|
bstr section)
|
2008-04-30 05:56:45 +00:00
|
|
|
{
|
2011-07-16 15:17:48 +00:00
|
|
|
struct cmd_bind_section *bind_section = ictx->cmd_bind_sections;
|
2011-04-25 08:38:46 +00:00
|
|
|
|
2012-09-22 13:17:15 +00:00
|
|
|
if (section.len == 0)
|
|
|
|
section = bstr0("default");
|
2011-04-25 08:38:46 +00:00
|
|
|
while (bind_section) {
|
2013-06-22 21:26:44 +00:00
|
|
|
if (bstrcmp0(section, bind_section->section) == 0)
|
2011-04-25 08:38:46 +00: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;
|
|
|
|
}
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
*bind_section = (struct cmd_bind_section) {
|
|
|
|
.section = bstrdup0(bind_section, section),
|
|
|
|
};
|
2011-04-25 08:38:46 +00:00
|
|
|
return bind_section;
|
2007-06-07 18:06:53 +00:00
|
|
|
}
|
|
|
|
|
2014-04-18 14:27:02 +00:00
|
|
|
static void key_buf_add(int *buf, int code)
|
|
|
|
{
|
|
|
|
for (int n = MP_MAX_KEY_DOWN - 1; n > 0; n--)
|
|
|
|
buf[n] = buf[n - 1];
|
|
|
|
buf[0] = code;
|
|
|
|
}
|
|
|
|
|
2013-06-22 21:26:44 +00:00
|
|
|
static struct cmd_bind *find_bind_for_key_section(struct input_ctx *ictx,
|
2014-04-18 14:27:02 +00:00
|
|
|
char *section, int code)
|
2013-06-22 21:26:44 +00:00
|
|
|
{
|
|
|
|
struct cmd_bind_section *bs = get_bind_section(ictx, bstr0(section));
|
2013-06-22 22:40:35 +00:00
|
|
|
|
2014-04-18 14:27:02 +00:00
|
|
|
if (!bs->num_binds)
|
2013-06-22 22:40:35 +00:00
|
|
|
return NULL;
|
|
|
|
|
2014-04-18 14:27:02 +00:00
|
|
|
int keys[MP_MAX_KEY_DOWN];
|
|
|
|
memcpy(keys, ictx->key_history, sizeof(keys));
|
|
|
|
key_buf_add(keys, code);
|
|
|
|
|
2014-04-19 12:31:54 +00:00
|
|
|
struct cmd_bind *best = NULL;
|
|
|
|
|
2013-06-22 22:40:35 +00:00
|
|
|
// Prefer user-defined keys over builtin bindings
|
|
|
|
for (int builtin = 0; builtin < 2; builtin++) {
|
2013-08-30 00:24:14 +00:00
|
|
|
if (builtin && !ictx->default_bindings)
|
|
|
|
break;
|
2014-04-19 12:31:54 +00:00
|
|
|
if (best)
|
|
|
|
break;
|
2013-06-22 22:40:35 +00:00
|
|
|
for (int n = 0; n < bs->num_binds; n++) {
|
2014-04-18 14:27:02 +00:00
|
|
|
if (bs->binds[n].is_builtin == (bool)builtin) {
|
|
|
|
struct cmd_bind *b = &bs->binds[n];
|
|
|
|
// we have: keys=[key2 key1 keyX ...]
|
|
|
|
// and: b->keys=[key1 key2] (and may be just a prefix)
|
|
|
|
for (int i = 0; i < b->num_keys; i++) {
|
|
|
|
if (b->keys[i] != keys[b->num_keys - 1 - i])
|
|
|
|
goto skip;
|
|
|
|
}
|
2014-04-19 12:31:54 +00:00
|
|
|
if (!best || b->num_keys >= best->num_keys)
|
|
|
|
best = b;
|
2014-04-18 14:27:02 +00:00
|
|
|
skip: ;
|
|
|
|
}
|
2013-06-22 22:40:35 +00:00
|
|
|
}
|
|
|
|
}
|
2014-04-19 12:31:54 +00:00
|
|
|
return best;
|
2013-06-22 21:26:44 +00:00
|
|
|
}
|
|
|
|
|
2013-03-30 19:07:15 +00:00
|
|
|
static struct cmd_bind *find_any_bind_for_key(struct input_ctx *ictx,
|
2014-04-18 14:27:02 +00:00
|
|
|
char *force_section, int code)
|
2008-04-30 05:56:45 +00:00
|
|
|
{
|
2013-06-22 21:26:44 +00:00
|
|
|
if (force_section)
|
2014-04-18 14:27:02 +00:00
|
|
|
return find_bind_for_key_section(ictx, force_section, code);
|
2013-06-19 16:19:45 +00:00
|
|
|
|
2014-04-18 14:27:02 +00:00
|
|
|
bool use_mouse = MP_KEY_DEPENDS_ON_MOUSE_POS(code);
|
2013-08-30 00:24:14 +00:00
|
|
|
|
|
|
|
// First look whether a mouse section is capturing all mouse input
|
|
|
|
// exclusively (regardless of the active section stack order).
|
2014-04-26 18:27:52 +00:00
|
|
|
if (use_mouse && MP_KEY_IS_MOUSE_BTN_SINGLE(ictx->last_key_down)) {
|
2013-08-30 00:24:14 +00:00
|
|
|
struct cmd_bind *bind =
|
2014-04-18 14:27:02 +00:00
|
|
|
find_bind_for_key_section(ictx, ictx->mouse_section, code);
|
2013-08-30 00:24:14 +00:00
|
|
|
if (bind)
|
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2014-02-17 01:35:00 +00:00
|
|
|
struct cmd_bind *best_bind = NULL;
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
for (int i = ictx->num_active_sections - 1; i >= 0; i--) {
|
2013-06-22 21:26:44 +00:00
|
|
|
struct active_section *s = &ictx->active_sections[i];
|
2014-04-18 14:27:02 +00:00
|
|
|
struct cmd_bind *bind = find_bind_for_key_section(ictx, s->name, code);
|
2013-06-22 21:26:44 +00:00
|
|
|
if (bind) {
|
|
|
|
struct cmd_bind_section *bs = bind->owner;
|
input: don't deliver mouse events if mouse area is not set
This caused the OSC to be always visible at startup on X11:
- EnterNotify event send a mouse event to input.c
- OSC has not completely initialized yet, and no mouse area is set
- mouse event is dispatched to "showhide" OSC section
- OSC becomes visible, regardless of mouse position
Fix this by treating the mouse area as empty if it's not set, instead of
infinite as it was before this commit. This means an input section must
set a mouse area to receive mouse events at all. We also have to change
the default section to receive mouse events with the new behavior.
Also, if MOUSE_MOVE is unmapped (or mapped to something that doesn't
parse), and produces no command, the mouse position wouldn't be updated
(because the mouse position is bound to input commands), so we have to
generate a dummy command in this case.
(This matters only for the OSC, On Screen Controller, which isn't merged
yet, so these changes shouldn't have much effect right now.)
2013-09-05 21:58:51 +00:00
|
|
|
if (!use_mouse || (bs->mouse_area_set && test_rect(&bs->mouse_area,
|
|
|
|
ictx->mouse_vo_x,
|
|
|
|
ictx->mouse_vo_y)))
|
2014-02-17 01:35:00 +00:00
|
|
|
{
|
|
|
|
if (!best_bind || (best_bind->is_builtin && !bind->is_builtin))
|
|
|
|
best_bind = bind;
|
|
|
|
}
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
}
|
2013-06-22 21:26:44 +00:00
|
|
|
if (s->flags & MP_INPUT_EXCLUSIVE)
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
break;
|
2012-08-24 11:29:28 +00:00
|
|
|
}
|
2013-06-19 16:19:45 +00:00
|
|
|
|
2014-02-17 01:35:00 +00:00
|
|
|
return best_bind;
|
2013-03-30 19:07:15 +00:00
|
|
|
}
|
|
|
|
|
2013-06-19 16:19:45 +00:00
|
|
|
static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, char *force_section,
|
2014-04-18 14:27:02 +00:00
|
|
|
int code)
|
2013-03-30 19:07:15 +00:00
|
|
|
{
|
|
|
|
if (ictx->test)
|
2014-04-18 14:27:02 +00:00
|
|
|
return handle_test(ictx, code);
|
2011-04-25 08:38:46 +00:00
|
|
|
|
2014-04-18 14:27:02 +00:00
|
|
|
struct cmd_bind *cmd = find_any_bind_for_key(ictx, force_section, code);
|
2011-04-25 08:38:46 +00:00
|
|
|
if (cmd == NULL) {
|
2013-09-05 22:28:31 +00:00
|
|
|
int msgl = MSGL_WARN;
|
2014-04-18 14:27:02 +00:00
|
|
|
if (code == MP_KEY_MOUSE_MOVE || code == MP_KEY_MOUSE_LEAVE)
|
2013-12-21 20:41:18 +00:00
|
|
|
msgl = MSGL_DEBUG;
|
2014-04-18 14:27:02 +00:00
|
|
|
char *key_buf = mp_input_get_key_combo_name(&code, 1);
|
2013-09-27 13:30:59 +00:00
|
|
|
MP_MSG(ictx, msgl, "No bind found for key '%s'.\n", key_buf);
|
2011-04-25 08:38:46 +00:00
|
|
|
talloc_free(key_buf);
|
|
|
|
return NULL;
|
2002-02-11 11:42:08 +00:00
|
|
|
}
|
2013-09-27 13:30:59 +00:00
|
|
|
mp_cmd_t *ret = mp_input_parse_cmd(ictx, bstr0(cmd->cmd), cmd->location);
|
2013-06-19 16:19:45 +00:00
|
|
|
if (ret) {
|
|
|
|
ret->input_section = cmd->owner->section;
|
2013-12-21 20:49:13 +00:00
|
|
|
if (mp_msg_test(ictx->log, MSGL_DEBUG)) {
|
2014-04-18 14:27:02 +00:00
|
|
|
char *keyname = mp_input_get_key_combo_name(&code, 1);
|
2013-09-10 06:29:45 +00:00
|
|
|
MP_DBG(ictx, "key '%s' -> '%s' in '%s'\n",
|
2013-08-30 00:30:17 +00:00
|
|
|
keyname, cmd->cmd, ret->input_section);
|
|
|
|
talloc_free(keyname);
|
|
|
|
}
|
2013-06-19 16:19:45 +00:00
|
|
|
} else {
|
2014-04-18 14:27:02 +00:00
|
|
|
char *key_buf = mp_input_get_key_combo_name(&code, 1);
|
2013-09-27 13:30:59 +00:00
|
|
|
MP_ERR(ictx, "Invalid command for bound key '%s': '%s'\n",
|
|
|
|
key_buf, cmd->cmd);
|
2011-04-25 08:38:46 +00:00
|
|
|
talloc_free(key_buf);
|
2002-02-24 21:22:12 +00:00
|
|
|
}
|
2011-04-25 08:38:46 +00:00
|
|
|
return ret;
|
2002-02-11 11:42:08 +00:00
|
|
|
}
|
|
|
|
|
2013-08-30 00:24:14 +00:00
|
|
|
static void update_mouse_section(struct input_ctx *ictx)
|
|
|
|
{
|
2013-11-01 12:00:15 +00:00
|
|
|
struct cmd_bind *bind =
|
2014-04-18 14:27:02 +00:00
|
|
|
find_any_bind_for_key(ictx, NULL, MP_KEY_MOUSE_MOVE);
|
2013-08-30 00:24:14 +00:00
|
|
|
|
2013-11-01 12:00:15 +00:00
|
|
|
char *new_section = bind ? bind->owner->section : "default";
|
2013-08-30 00:24:14 +00:00
|
|
|
|
|
|
|
char *old = ictx->mouse_section;
|
|
|
|
ictx->mouse_section = new_section;
|
|
|
|
|
|
|
|
if (strcmp(old, ictx->mouse_section) != 0) {
|
2013-09-10 06:29:45 +00:00
|
|
|
MP_DBG(ictx, "input: switch section %s -> %s\n",
|
2013-08-30 00:30:17 +00:00
|
|
|
old, ictx->mouse_section);
|
2014-04-18 14:27:02 +00:00
|
|
|
struct mp_cmd *cmd = get_cmd_from_keys(ictx, old, MP_KEY_MOUSE_LEAVE);
|
2013-08-30 00:24:14 +00:00
|
|
|
if (cmd)
|
2013-09-02 00:29:20 +00:00
|
|
|
queue_add_tail(&ictx->cmd_queue, cmd);
|
2013-09-07 23:44:47 +00:00
|
|
|
ictx->got_new_events = true;
|
2013-08-30 00:24:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-01 16:59:20 +00:00
|
|
|
// Called when the currently held-down key is released. This (usually) sends
|
|
|
|
// the a key-up versiob of the command associated with the keys that were held
|
|
|
|
// down.
|
|
|
|
// If the drop_current parameter is set to true, then don't send the key-up
|
|
|
|
// command. Unless we've already sent a key-down event, in which case the
|
|
|
|
// input receiver (the player) must get a key-up event, or it would get stuck
|
|
|
|
// thinking a key is still held down.
|
|
|
|
static void release_down_cmd(struct input_ctx *ictx, bool drop_current)
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
{
|
2013-12-01 16:59:20 +00:00
|
|
|
if (ictx->current_down_cmd_need_release)
|
|
|
|
drop_current = false;
|
|
|
|
if (!drop_current && ictx->current_down_cmd &&
|
|
|
|
ictx->current_down_cmd->key_up_follows)
|
|
|
|
{
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
ictx->current_down_cmd->key_up_follows = false;
|
2013-09-02 00:29:20 +00:00
|
|
|
queue_add_tail(&ictx->cmd_queue, ictx->current_down_cmd);
|
2013-09-07 23:44:47 +00:00
|
|
|
ictx->got_new_events = true;
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
} else {
|
|
|
|
talloc_free(ictx->current_down_cmd);
|
|
|
|
}
|
|
|
|
ictx->current_down_cmd = NULL;
|
2013-12-01 16:59:20 +00:00
|
|
|
ictx->current_down_cmd_need_release = false;
|
2014-04-18 15:45:41 +00:00
|
|
|
ictx->last_key_down = 0;
|
2014-04-18 15:16:33 +00:00
|
|
|
ictx->last_key_down_time = 0;
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
ictx->ar_state = -1;
|
2014-04-18 15:45:41 +00:00
|
|
|
update_mouse_section(ictx);
|
2013-07-01 21:54:59 +00:00
|
|
|
}
|
2002-11-14 23:41:44 +00:00
|
|
|
|
2013-12-01 16:34:43 +00:00
|
|
|
// Whether a command shall be sent on both key down and key up events.
|
2013-09-02 00:26:41 +00:00
|
|
|
static bool key_updown_ok(enum mp_command_type cmd)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
Add initial Lua scripting support
This is preliminary. There are still tons of issues, and any aspect
of scripting may change in the future. I decided to merge this
(preliminary) work now because it makes it easier to develop it, not
because it's done. lua.rst is clear enough about it (plus some
sarcasm).
This requires linking to Lua. Lua has no official pkg-config file, but
there are distribution specific .pc files, all with different names.
Adding a non-pkg-config based configure test was considered, but we'd
rather not.
One major complication is that libquvi links against Lua too, and if
the Lua version is different from mpv's, you will get a crash as soon
as libquvi uses Lua. (libquvi by design always runs when a file is
opened.) I would consider this the problem of distros and whoever
builds mpv, but to make things easier for users, we add a terrible
runtime test to the configure script, which probes whether libquvi
will crash. This is disabled when cross-compiling, but in that case
we hope the user knows what he is doing.
2013-09-25 22:41:14 +00:00
|
|
|
case MP_CMD_SCRIPT_DISPATCH:
|
|
|
|
return true;
|
2013-09-02 00:26:41 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't want the append to the command queue indefinitely, because that
|
|
|
|
// could lead to situations where recovery would take too long. On the other
|
|
|
|
// hand, don't drop commands that will abort playback.
|
|
|
|
static bool should_drop_cmd(struct input_ctx *ictx, struct mp_cmd *cmd)
|
|
|
|
{
|
|
|
|
struct cmd_queue *queue = &ictx->cmd_queue;
|
|
|
|
return (queue_count_cmds(queue) >= ictx->key_fifo_size &&
|
2014-02-20 12:38:39 +00:00
|
|
|
(!mp_input_is_abort_cmd(cmd) || queue_has_abort_cmds(queue)));
|
2013-09-02 00:26:41 +00:00
|
|
|
}
|
|
|
|
|
2014-04-19 12:11:55 +00:00
|
|
|
static struct mp_cmd *resolve_key(struct input_ctx *ictx, int code)
|
|
|
|
{
|
|
|
|
update_mouse_section(ictx);
|
|
|
|
struct mp_cmd *cmd = get_cmd_from_keys(ictx, NULL, code);
|
2014-04-19 12:21:57 +00:00
|
|
|
if (cmd && cmd->id != MP_CMD_IGNORE) {
|
|
|
|
memset(ictx->key_history, 0, sizeof(ictx->key_history));
|
|
|
|
if (!should_drop_cmd(ictx, cmd))
|
|
|
|
return cmd;
|
2014-04-19 12:11:55 +00:00
|
|
|
talloc_free(cmd);
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-04-19 12:21:57 +00:00
|
|
|
talloc_free(cmd);
|
|
|
|
key_buf_add(ictx->key_history, code);
|
|
|
|
return NULL;
|
2014-04-19 12:11:55 +00:00
|
|
|
}
|
|
|
|
|
2013-09-02 00:26:41 +00:00
|
|
|
static void interpret_key(struct input_ctx *ictx, int code, double scale)
|
2013-07-01 21:54:59 +00:00
|
|
|
{
|
2010-12-19 10:12:20 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
2013-07-01 21:54:59 +00:00
|
|
|
int unmod = code & ~MP_KEY_MODIFIER_MASK;
|
2012-01-14 13:09:26 +00:00
|
|
|
if (unmod >= 32 && unmod < MP_KEY_BASE)
|
2013-02-12 00:34:04 +00:00
|
|
|
code &= ~MP_KEY_MODIFIER_SHIFT;
|
2010-12-19 10:12:20 +00:00
|
|
|
|
2014-04-18 15:45:41 +00:00
|
|
|
int state = code & (MP_KEY_STATE_DOWN | MP_KEY_STATE_UP);
|
|
|
|
code = code & ~(unsigned)state;
|
|
|
|
|
2013-12-21 20:49:13 +00:00
|
|
|
if (mp_msg_test(ictx->log, MSGL_DEBUG)) {
|
2014-04-18 15:45:41 +00:00
|
|
|
char *key = mp_input_get_key_name(code);
|
2013-09-10 06:29:45 +00:00
|
|
|
MP_DBG(ictx, "key code=%#x '%s'%s%s\n",
|
2014-04-18 15:45:41 +00:00
|
|
|
code, key, (state & MP_KEY_STATE_DOWN) ? " down" : "",
|
|
|
|
(state & MP_KEY_STATE_UP) ? " up" : "");
|
2013-08-30 00:30:17 +00:00
|
|
|
talloc_free(key);
|
|
|
|
}
|
|
|
|
|
2013-09-02 00:26:41 +00:00
|
|
|
if (MP_KEY_DEPENDS_ON_MOUSE_POS(unmod))
|
|
|
|
ictx->mouse_event_counter++;
|
|
|
|
ictx->got_new_events = true;
|
|
|
|
|
|
|
|
struct mp_cmd *cmd = NULL;
|
2013-07-01 21:54:59 +00:00
|
|
|
|
2014-04-18 15:45:41 +00:00
|
|
|
if (state == MP_KEY_STATE_DOWN) {
|
|
|
|
// Protect against VOs which send STATE_DOWN with autorepeat
|
|
|
|
if (ictx->last_key_down == code)
|
2013-09-02 00:26:41 +00:00
|
|
|
return;
|
2013-07-01 21:54:59 +00:00
|
|
|
// Cancel current down-event (there can be only one)
|
2013-12-01 16:59:20 +00:00
|
|
|
release_down_cmd(ictx, true);
|
2014-04-19 12:11:55 +00:00
|
|
|
cmd = resolve_key(ictx, code);
|
|
|
|
if (cmd && (code & MP_KEY_EMIT_ON_UP))
|
|
|
|
cmd->key_up_follows = true;
|
2014-04-18 15:45:41 +00:00
|
|
|
ictx->last_key_down = code;
|
|
|
|
ictx->last_key_down_time = mp_time_us();
|
|
|
|
ictx->ar_state = 0;
|
2013-09-02 00:26:41 +00:00
|
|
|
ictx->current_down_cmd = mp_cmd_clone(cmd);
|
2013-12-01 16:59:20 +00:00
|
|
|
ictx->current_down_cmd_need_release = false;
|
2014-04-18 15:45:41 +00:00
|
|
|
} else if (state == MP_KEY_STATE_UP) {
|
|
|
|
// Most VOs send RELEASE_ALL anyway
|
2014-04-18 16:06:19 +00:00
|
|
|
release_down_cmd(ictx, false);
|
2013-07-01 21:54:59 +00:00
|
|
|
} else {
|
|
|
|
// Press of key with no separate down/up events
|
2014-04-18 15:45:41 +00:00
|
|
|
if (ictx->last_key_down == code) {
|
2013-07-01 21:54:59 +00:00
|
|
|
// Mixing press events and up/down with the same key is not allowed
|
2013-09-27 13:30:59 +00:00
|
|
|
MP_WARN(ictx, "Mixing key presses and up/down.\n");
|
2013-07-01 21:54:59 +00:00
|
|
|
}
|
2014-04-19 12:11:55 +00:00
|
|
|
cmd = resolve_key(ictx, code);
|
2013-09-02 00:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!cmd)
|
|
|
|
return;
|
|
|
|
|
2013-12-01 16:34:43 +00:00
|
|
|
// Don't emit a command on key-down if the key is designed to emit commands
|
|
|
|
// on key-up (like mouse buttons). Also, if the command specifically should
|
|
|
|
// be sent both on key down and key up, still emit the command.
|
2013-09-02 00:26:41 +00:00
|
|
|
if (cmd->key_up_follows && !key_updown_ok(cmd->id)) {
|
|
|
|
talloc_free(cmd);
|
|
|
|
return;
|
2011-04-25 11:12:04 +00:00
|
|
|
}
|
2013-09-02 00:26:41 +00:00
|
|
|
|
|
|
|
cmd->scale = scale;
|
|
|
|
|
2013-12-01 16:59:20 +00:00
|
|
|
if (cmd->key_up_follows)
|
|
|
|
ictx->current_down_cmd_need_release = true;
|
2013-09-02 00:29:20 +00:00
|
|
|
queue_add_tail(&ictx->cmd_queue, cmd);
|
2007-08-25 04:28:11 +00:00
|
|
|
}
|
2002-02-11 11:42:08 +00:00
|
|
|
|
2013-09-07 23:44:47 +00:00
|
|
|
static void mp_input_feed_key(struct input_ctx *ictx, int code, double scale)
|
2011-07-17 01:47:50 +00:00
|
|
|
{
|
2014-04-19 12:11:25 +00:00
|
|
|
int unmod = code & ~MP_KEY_MODIFIER_MASK;
|
2011-07-17 01:47:50 +00:00
|
|
|
if (code == MP_INPUT_RELEASE_ALL) {
|
2013-09-10 06:29:45 +00:00
|
|
|
MP_DBG(ictx, "release all\n");
|
2014-04-18 16:06:19 +00:00
|
|
|
release_down_cmd(ictx, false);
|
2011-07-17 01:47:50 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-04-19 12:11:25 +00:00
|
|
|
if (unmod == MP_KEY_MOUSE_LEAVE) {
|
2013-09-27 13:33:47 +00:00
|
|
|
update_mouse_section(ictx);
|
2014-04-18 14:27:02 +00:00
|
|
|
struct mp_cmd *cmd = get_cmd_from_keys(ictx, NULL, code);
|
2013-09-27 13:33:47 +00:00
|
|
|
if (cmd)
|
|
|
|
queue_add_tail(&ictx->cmd_queue, cmd);
|
|
|
|
ictx->got_new_events = true;
|
|
|
|
return;
|
|
|
|
}
|
2013-07-02 12:00:24 +00:00
|
|
|
double now = mp_time_sec();
|
|
|
|
int doubleclick_time = ictx->doubleclick_time;
|
|
|
|
// ignore system-doubleclick if we generate these events ourselves
|
2013-09-07 23:44:47 +00:00
|
|
|
if (doubleclick_time && MP_KEY_IS_MOUSE_BTN_DBL(unmod))
|
2013-07-02 12:00:24 +00:00
|
|
|
return;
|
2013-09-07 23:44:47 +00:00
|
|
|
interpret_key(ictx, code, scale);
|
2013-07-02 12:00:24 +00:00
|
|
|
if (code & MP_KEY_STATE_DOWN) {
|
|
|
|
code &= ~MP_KEY_STATE_DOWN;
|
|
|
|
if (ictx->last_doubleclick_key_down == code
|
|
|
|
&& now - ictx->last_doubleclick_time < doubleclick_time / 1000.0)
|
|
|
|
{
|
|
|
|
if (code >= MP_MOUSE_BTN0 && code <= MP_MOUSE_BTN2)
|
2013-09-07 23:44:47 +00:00
|
|
|
interpret_key(ictx, code - MP_MOUSE_BTN0 + MP_MOUSE_BTN0_DBL, 1);
|
2013-07-02 12:00:24 +00:00
|
|
|
}
|
|
|
|
ictx->last_doubleclick_key_down = code;
|
|
|
|
ictx->last_doubleclick_time = now;
|
|
|
|
}
|
2013-09-07 23:44:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_put_key(struct input_ctx *ictx, int code)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
mp_input_feed_key(ictx, code, 1);
|
2013-08-26 17:15:35 +00:00
|
|
|
input_unlock(ictx);
|
2013-07-02 12:00:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_put_key_utf8(struct input_ctx *ictx, int mods, struct bstr t)
|
|
|
|
{
|
|
|
|
while (t.len) {
|
|
|
|
int code = bstr_decode_utf8(t, &t);
|
|
|
|
if (code < 0)
|
|
|
|
break;
|
|
|
|
mp_input_put_key(ictx, code | mods);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-25 16:08:57 +00:00
|
|
|
void mp_input_put_axis(struct input_ctx *ictx, int direction, double value)
|
|
|
|
{
|
2013-11-25 18:31:13 +00:00
|
|
|
if (value == 0.0)
|
|
|
|
return;
|
2013-08-26 17:15:35 +00:00
|
|
|
input_lock(ictx);
|
2013-09-07 23:44:47 +00:00
|
|
|
mp_input_feed_key(ictx, direction, value);
|
2013-08-26 17:15:35 +00:00
|
|
|
input_unlock(ictx);
|
2013-07-25 16:08:57 +00:00
|
|
|
}
|
|
|
|
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y)
|
|
|
|
{
|
2013-08-26 17:15:35 +00:00
|
|
|
input_lock(ictx);
|
2013-09-10 06:29:45 +00:00
|
|
|
MP_DBG(ictx, "mouse move %d/%d\n", x, y);
|
2013-08-30 00:30:17 +00:00
|
|
|
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
ictx->mouse_event_counter++;
|
|
|
|
ictx->mouse_vo_x = x;
|
|
|
|
ictx->mouse_vo_y = y;
|
2013-06-19 16:19:45 +00:00
|
|
|
|
2013-08-30 00:24:14 +00:00
|
|
|
update_mouse_section(ictx);
|
2014-04-18 14:27:02 +00:00
|
|
|
struct mp_cmd *cmd = get_cmd_from_keys(ictx, NULL, MP_KEY_MOUSE_MOVE);
|
input: don't deliver mouse events if mouse area is not set
This caused the OSC to be always visible at startup on X11:
- EnterNotify event send a mouse event to input.c
- OSC has not completely initialized yet, and no mouse area is set
- mouse event is dispatched to "showhide" OSC section
- OSC becomes visible, regardless of mouse position
Fix this by treating the mouse area as empty if it's not set, instead of
infinite as it was before this commit. This means an input section must
set a mouse area to receive mouse events at all. We also have to change
the default section to receive mouse events with the new behavior.
Also, if MOUSE_MOVE is unmapped (or mapped to something that doesn't
parse), and produces no command, the mouse position wouldn't be updated
(because the mouse position is bound to input commands), so we have to
generate a dummy command in this case.
(This matters only for the OSC, On Screen Controller, which isn't merged
yet, so these changes shouldn't have much effect right now.)
2013-09-05 21:58:51 +00:00
|
|
|
if (!cmd)
|
2013-09-27 13:30:59 +00:00
|
|
|
cmd = mp_input_parse_cmd(ictx, bstr0("ignore"), "<internal>");
|
2013-06-19 16:19:45 +00:00
|
|
|
|
2013-08-26 17:15:35 +00:00
|
|
|
if (cmd) {
|
|
|
|
cmd->mouse_move = true;
|
|
|
|
cmd->mouse_x = x;
|
|
|
|
cmd->mouse_y = y;
|
2013-09-02 00:26:41 +00:00
|
|
|
if (should_drop_cmd(ictx, cmd)) {
|
|
|
|
talloc_free(cmd);
|
|
|
|
} else {
|
2013-09-02 00:40:05 +00:00
|
|
|
// Coalesce with previous mouse move events (i.e. replace it)
|
|
|
|
struct mp_cmd *tail = queue_peek_tail(&ictx->cmd_queue);
|
|
|
|
if (tail && tail->mouse_move) {
|
|
|
|
queue_remove(&ictx->cmd_queue, tail);
|
|
|
|
talloc_free(tail);
|
|
|
|
}
|
2013-09-02 00:29:20 +00:00
|
|
|
queue_add_tail(&ictx->cmd_queue, cmd);
|
2013-09-07 23:44:47 +00:00
|
|
|
ictx->got_new_events = true;
|
2013-09-02 00:26:41 +00:00
|
|
|
}
|
2013-08-26 17:15:35 +00:00
|
|
|
}
|
|
|
|
input_unlock(ictx);
|
2011-07-17 01:47:50 +00:00
|
|
|
}
|
|
|
|
|
2013-12-26 16:41:28 +00:00
|
|
|
unsigned int mp_input_get_mouse_event_counter(struct input_ctx *ictx)
|
2011-07-17 01:47:50 +00:00
|
|
|
{
|
2013-12-26 16:41:28 +00:00
|
|
|
// Make the frontend always display the mouse cursor (as long as it's not
|
|
|
|
// forced invisible) if mouse input is desired.
|
|
|
|
input_lock(ictx);
|
|
|
|
if (mp_input_test_mouse_active(ictx, ictx->mouse_x, ictx->mouse_y))
|
|
|
|
ictx->mouse_event_counter++;
|
|
|
|
int ret = ictx->mouse_event_counter;
|
|
|
|
input_unlock(ictx);
|
|
|
|
return ret;
|
2011-07-17 01:47:50 +00:00
|
|
|
}
|
2002-01-30 12:46:03 +00:00
|
|
|
|
2013-12-26 16:41:28 +00:00
|
|
|
int input_default_read_cmd(void *ctx, int fd, char *buf, int l)
|
2007-08-25 04:28:11 +00:00
|
|
|
{
|
2013-12-26 16:41:28 +00: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;
|
2013-04-24 15:02:52 +00:00
|
|
|
}
|
2013-07-07 14:53:35 +00:00
|
|
|
}
|
|
|
|
|
2013-12-26 16:41:28 +00:00
|
|
|
int mp_input_add_fd(struct input_ctx *ictx, int unix_fd, int select,
|
|
|
|
int read_cmd_func(void *ctx, int fd, char *dest, int size),
|
|
|
|
int read_key_func(void *ctx, int fd),
|
|
|
|
int close_func(void *ctx, int fd), void *ctx)
|
2013-07-07 14:53:35 +00:00
|
|
|
{
|
2013-12-26 16:41:28 +00:00
|
|
|
if (select && unix_fd < 0) {
|
|
|
|
MP_ERR(ictx, "Invalid fd %d in mp_input_add_fd", unix_fd);
|
|
|
|
return 0;
|
2013-07-07 14:53:35 +00:00
|
|
|
}
|
|
|
|
|
2013-12-26 16:41:28 +00:00
|
|
|
input_lock(ictx);
|
|
|
|
struct input_fd *fd = NULL;
|
|
|
|
if (ictx->num_fds == MP_MAX_FDS) {
|
|
|
|
MP_ERR(ictx, "Too many file descriptors.\n");
|
|
|
|
} else {
|
|
|
|
fd = &ictx->fds[ictx->num_fds];
|
|
|
|
}
|
|
|
|
*fd = (struct input_fd){
|
|
|
|
.log = ictx->log,
|
|
|
|
.fd = unix_fd,
|
|
|
|
.select = select,
|
|
|
|
.read_cmd = read_cmd_func,
|
|
|
|
.read_key = read_key_func,
|
|
|
|
.close_func = close_func,
|
|
|
|
.ctx = ctx,
|
|
|
|
};
|
|
|
|
ictx->num_fds++;
|
|
|
|
input_unlock(ictx);
|
|
|
|
return !!fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mp_input_rm_fd(struct input_ctx *ictx, int fd)
|
|
|
|
{
|
|
|
|
struct input_fd *fds = ictx->fds;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ictx->num_fds; i++) {
|
|
|
|
if (fds[i].fd == fd)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == ictx->num_fds)
|
|
|
|
return;
|
|
|
|
if (fds[i].close_func)
|
|
|
|
fds[i].close_func(fds[i].ctx, fds[i].fd);
|
|
|
|
talloc_free(fds[i].buffer);
|
|
|
|
|
|
|
|
if (i + 1 < ictx->num_fds)
|
|
|
|
memmove(&fds[i], &fds[i + 1],
|
|
|
|
(ictx->num_fds - i - 1) * sizeof(struct input_fd));
|
|
|
|
ictx->num_fds--;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_rm_key_fd(struct input_ctx *ictx, int fd)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
mp_input_rm_fd(ictx, fd);
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MP_CMD_MAX_SIZE 4096
|
|
|
|
|
|
|
|
static int read_cmd(struct input_fd *mp_fd, char **ret)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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_cmd(mp_fd->ctx, 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_ERR(mp_fd, "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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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_ERR(mp_fd, "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;
|
|
|
|
}
|
|
|
|
|
|
|
|
l = end - mp_fd->buffer;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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(ictx, bstr0(text), "<pipe>");
|
|
|
|
talloc_free(text);
|
|
|
|
if (cmd)
|
|
|
|
queue_add_tail(&ictx->cmd_queue, cmd);
|
|
|
|
if (!cmd_fd->got_cmd)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (r == MP_INPUT_ERROR)
|
|
|
|
MP_ERR(ictx, "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_key(key_fd->ctx, key_fd->fd);
|
|
|
|
if (code >= 0 || code == MP_INPUT_RELEASE_ALL) {
|
|
|
|
mp_input_feed_key(ictx, code, 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (code == MP_INPUT_ERROR)
|
|
|
|
MP_ERR(ictx, "Error on key input file descriptor %d\n", key_fd->fd);
|
|
|
|
else if (code == MP_INPUT_DEAD) {
|
|
|
|
MP_ERR(ictx, "Dead key input on file descriptor %d\n", key_fd->fd);
|
|
|
|
key_fd->dead = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void read_fd(struct input_ctx *ictx, struct input_fd *fd)
|
|
|
|
{
|
|
|
|
if (fd->read_cmd) {
|
|
|
|
read_cmd_fd(ictx, fd);
|
|
|
|
} else {
|
|
|
|
read_key_fd(ictx, fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_dead_fds(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < ictx->num_fds; i++) {
|
|
|
|
if (ictx->fds[i].dead) {
|
|
|
|
mp_input_rm_fd(ictx, ictx->fds[i].fd);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if HAVE_POSIX_SELECT
|
2013-07-07 14:53:35 +00:00
|
|
|
|
|
|
|
static void input_wait_read(struct input_ctx *ictx, int time)
|
|
|
|
{
|
2008-04-29 09:24:02 +00:00
|
|
|
fd_set fds;
|
2007-08-25 04:28:11 +00:00
|
|
|
FD_ZERO(&fds);
|
2011-07-17 01:47:50 +00:00
|
|
|
int max_fd = 0;
|
2013-07-07 14:53:35 +00:00
|
|
|
for (int i = 0; i < ictx->num_fds; i++) {
|
2013-07-14 13:37:39 +00:00
|
|
|
if (!ictx->fds[i].select)
|
2011-07-17 01:47:50 +00:00
|
|
|
continue;
|
2013-07-07 14:53:35 +00:00
|
|
|
if (ictx->fds[i].fd > max_fd)
|
|
|
|
max_fd = ictx->fds[i].fd;
|
|
|
|
FD_SET(ictx->fds[i].fd, &fds);
|
2011-07-17 01:47:50 +00:00
|
|
|
}
|
|
|
|
struct timeval tv, *time_val;
|
2013-05-16 21:17:46 +00:00
|
|
|
tv.tv_sec = time / 1000;
|
|
|
|
tv.tv_usec = (time % 1000) * 1000;
|
|
|
|
time_val = &tv;
|
input: avoid using wakeup pipe if it's not needed
If input is not waiting for select(), writing to the wakeup pipe is
wasteful, and, if there are many wakeups, might even block the wakeup
threads if the pipe gets full.
However, if it's waiting for select(), the wakup pipe must be used to
unblock the waiting thread. Actually there's a small race condition: we
might determine that the main thread is in select(), and write to the
wakeup pipe (whether we do this while unlocked or locked doesn't really
matter). Then, the main thread might leave select() before reading from
the wakup pipe. This should be harmless, because at worst more wakeups
than needed happen, but never fewer.
2013-12-15 20:33:31 +00:00
|
|
|
ictx->in_select = true;
|
2013-09-01 20:40:35 +00:00
|
|
|
input_unlock(ictx);
|
2011-07-17 01:47:50 +00:00
|
|
|
if (select(max_fd + 1, &fds, NULL, NULL, time_val) < 0) {
|
|
|
|
if (errno != EINTR)
|
2013-09-27 13:30:59 +00:00
|
|
|
MP_ERR(ictx, "Select error: %s\n", strerror(errno));
|
2011-07-17 01:47:50 +00:00
|
|
|
FD_ZERO(&fds);
|
2007-08-25 04:28:11 +00:00
|
|
|
}
|
2013-09-01 20:40:35 +00:00
|
|
|
input_lock(ictx);
|
input: avoid using wakeup pipe if it's not needed
If input is not waiting for select(), writing to the wakeup pipe is
wasteful, and, if there are many wakeups, might even block the wakeup
threads if the pipe gets full.
However, if it's waiting for select(), the wakup pipe must be used to
unblock the waiting thread. Actually there's a small race condition: we
might determine that the main thread is in select(), and write to the
wakeup pipe (whether we do this while unlocked or locked doesn't really
matter). Then, the main thread might leave select() before reading from
the wakup pipe. This should be harmless, because at worst more wakeups
than needed happen, but never fewer.
2013-12-15 20:33:31 +00:00
|
|
|
ictx->in_select = false;
|
2013-07-07 14:53:35 +00:00
|
|
|
for (int i = 0; i < ictx->num_fds; i++) {
|
2013-07-14 13:37:39 +00:00
|
|
|
if (ictx->fds[i].select && !FD_ISSET(ictx->fds[i].fd, &fds))
|
2013-07-07 14:53:35 +00:00
|
|
|
continue;
|
|
|
|
read_fd(ictx, &ictx->fds[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-25 04:28:11 +00:00
|
|
|
#else
|
2013-07-07 14:53:35 +00:00
|
|
|
|
|
|
|
static void input_wait_read(struct input_ctx *ictx, int time)
|
|
|
|
{
|
2014-04-15 21:12:01 +00:00
|
|
|
if (time > 0) {
|
|
|
|
struct timespec deadline = mpthread_get_deadline(time / 1000.0);
|
|
|
|
pthread_cond_timedwait(&ictx->wakeup, &ictx->mutex, &deadline);
|
|
|
|
}
|
2002-01-30 12:46:03 +00:00
|
|
|
|
2013-07-07 14:53:35 +00:00
|
|
|
for (int i = 0; i < ictx->num_fds; i++)
|
|
|
|
read_fd(ictx, &ictx->fds[i]);
|
|
|
|
}
|
2002-02-20 14:45:18 +00:00
|
|
|
|
2003-04-04 20:56:29 +00:00
|
|
|
#endif
|
2007-08-25 04:28:11 +00:00
|
|
|
|
2013-07-07 14:53:35 +00:00
|
|
|
/**
|
|
|
|
* \param time time to wait at most for an event in milliseconds
|
|
|
|
*/
|
|
|
|
static void read_events(struct input_ctx *ictx, int time)
|
|
|
|
{
|
2014-04-18 16:13:58 +00:00
|
|
|
if (ictx->last_key_down && ictx->ar_rate > 0 && ictx->ar_state >= 0) {
|
2013-07-07 14:53:35 +00:00
|
|
|
time = FFMIN(time, 1000 / ictx->ar_rate);
|
|
|
|
time = FFMIN(time, ictx->ar_delay);
|
2002-01-30 12:46:03 +00:00
|
|
|
}
|
2013-07-07 14:53:35 +00:00
|
|
|
time = FFMAX(time, 0);
|
2013-07-14 13:44:11 +00:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (ictx->got_new_events)
|
|
|
|
time = 0;
|
|
|
|
ictx->got_new_events = false;
|
|
|
|
|
|
|
|
remove_dead_fds(ictx);
|
|
|
|
|
|
|
|
if (time) {
|
|
|
|
for (int i = 0; i < ictx->num_fds; i++) {
|
|
|
|
if (!ictx->fds[i].select)
|
|
|
|
read_fd(ictx, &ictx->fds[i]);
|
|
|
|
}
|
2013-07-07 14:53:35 +00:00
|
|
|
}
|
|
|
|
|
2013-07-14 13:44:11 +00:00
|
|
|
if (ictx->got_new_events)
|
|
|
|
time = 0;
|
2002-01-30 12:46:03 +00:00
|
|
|
|
2013-07-14 13:44:11 +00:00
|
|
|
input_wait_read(ictx, time);
|
|
|
|
|
|
|
|
// Read until all input FDs are empty
|
2011-07-17 01:47:50 +00:00
|
|
|
if (!ictx->got_new_events)
|
2013-07-14 13:44:11 +00:00
|
|
|
break;
|
2011-07-17 01:47:50 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-25 04:28:11 +00:00
|
|
|
|
2011-04-25 08:38:46 +00:00
|
|
|
int mp_input_queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd)
|
2008-04-30 10:00:59 +00:00
|
|
|
{
|
2013-08-26 17:15:35 +00:00
|
|
|
input_lock(ictx);
|
2011-07-17 01:47:50 +00:00
|
|
|
ictx->got_new_events = true;
|
2013-08-26 17:15:35 +00:00
|
|
|
if (cmd)
|
2013-09-02 00:29:20 +00:00
|
|
|
queue_add_tail(&ictx->cmd_queue, cmd);
|
2013-08-26 17:15:35 +00:00
|
|
|
input_unlock(ictx);
|
input: avoid using wakeup pipe if it's not needed
If input is not waiting for select(), writing to the wakeup pipe is
wasteful, and, if there are many wakeups, might even block the wakeup
threads if the pipe gets full.
However, if it's waiting for select(), the wakup pipe must be used to
unblock the waiting thread. Actually there's a small race condition: we
might determine that the main thread is in select(), and write to the
wakeup pipe (whether we do this while unlocked or locked doesn't really
matter). Then, the main thread might leave select() before reading from
the wakup pipe. This should be harmless, because at worst more wakeups
than needed happen, but never fewer.
2013-12-15 20:33:31 +00:00
|
|
|
mp_input_wakeup(ictx);
|
2011-04-25 08:38:46 +00:00
|
|
|
return 1;
|
2002-02-23 21:13:35 +00:00
|
|
|
}
|
|
|
|
|
2013-09-07 23:44:47 +00:00
|
|
|
static mp_cmd_t *check_autorepeat(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
// No input : autorepeat ?
|
2014-04-18 16:13:58 +00:00
|
|
|
if (ictx->ar_rate <= 0 || !ictx->current_down_cmd || !ictx->last_key_down ||
|
|
|
|
(ictx->last_key_down & MP_NO_REPEAT_KEY))
|
|
|
|
ictx->ar_state = -1; // disable
|
|
|
|
if (ictx->ar_state >= 0) {
|
2013-09-07 23:44:47 +00:00
|
|
|
int64_t t = mp_time_us();
|
|
|
|
if (ictx->last_ar + 2000000 < t)
|
|
|
|
ictx->last_ar = t;
|
|
|
|
// First time : wait delay
|
|
|
|
if (ictx->ar_state == 0
|
2014-04-18 15:16:33 +00:00
|
|
|
&& (t - ictx->last_key_down_time) >= ictx->ar_delay * 1000)
|
2013-09-07 23:44:47 +00:00
|
|
|
{
|
|
|
|
ictx->ar_state = 1;
|
2014-04-18 15:16:33 +00:00
|
|
|
ictx->last_ar = ictx->last_key_down_time + ictx->ar_delay * 1000;
|
2013-09-07 23:44:47 +00:00
|
|
|
return mp_cmd_clone(ictx->current_down_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;
|
|
|
|
return mp_cmd_clone(ictx->current_down_cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-10-10 17:39:07 +00:00
|
|
|
/**
|
|
|
|
* \param peek_only when set, the returned command stays in the queue.
|
|
|
|
* Do not free the returned cmd whe you set this!
|
|
|
|
*/
|
2010-04-25 18:47:43 +00:00
|
|
|
mp_cmd_t *mp_input_get_cmd(struct input_ctx *ictx, int time, int peek_only)
|
2008-04-30 04:15:52 +00:00
|
|
|
{
|
2013-08-26 17:15:35 +00:00
|
|
|
input_lock(ictx);
|
2013-02-03 16:43:47 +00:00
|
|
|
if (async_quit_request) {
|
2013-12-15 17:14:15 +00:00
|
|
|
struct mp_cmd *cmd = mp_input_parse_cmd(ictx, bstr0("quit"), "");
|
2013-09-02 00:29:20 +00:00
|
|
|
queue_add_head(&ictx->cmd_queue, cmd);
|
2013-02-03 16:43:47 +00:00
|
|
|
}
|
2011-04-25 08:38:46 +00:00
|
|
|
|
2013-09-01 23:09:52 +00:00
|
|
|
if (ictx->cmd_queue.first)
|
2011-07-17 01:47:50 +00:00
|
|
|
time = 0;
|
2013-12-19 20:31:27 +00:00
|
|
|
read_events(ictx, time);
|
2013-09-01 23:09:52 +00:00
|
|
|
struct cmd_queue *queue = &ictx->cmd_queue;
|
2012-01-18 01:35:40 +00:00
|
|
|
if (!queue->first) {
|
2012-10-14 21:44:49 +00:00
|
|
|
struct mp_cmd *repeated = check_autorepeat(ictx);
|
2013-10-27 23:33:52 +00:00
|
|
|
if (repeated) {
|
|
|
|
repeated->repeated = true;
|
2013-11-28 18:04:16 +00:00
|
|
|
if (repeated->def && repeated->def->allow_auto_repeat) {
|
2013-11-05 23:05:12 +00:00
|
|
|
queue_add_tail(queue, repeated);
|
|
|
|
} else {
|
|
|
|
talloc_free(repeated);
|
|
|
|
}
|
2013-10-27 23:33:52 +00:00
|
|
|
}
|
2012-10-14 21:44:49 +00:00
|
|
|
}
|
2013-08-13 12:40:17 +00:00
|
|
|
struct mp_cmd *ret = queue_peek(queue);
|
2013-08-26 17:15:35 +00:00
|
|
|
if (ret && !peek_only) {
|
2012-10-14 21:44:49 +00:00
|
|
|
queue_remove(queue, ret);
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
if (ret->mouse_move) {
|
|
|
|
ictx->mouse_x = ret->mouse_x;
|
|
|
|
ictx->mouse_y = ret->mouse_y;
|
|
|
|
}
|
|
|
|
}
|
2013-08-26 17:15:35 +00:00
|
|
|
input_unlock(ictx);
|
2011-04-25 08:38:46 +00:00
|
|
|
return ret;
|
2002-01-30 12:46:03 +00:00
|
|
|
}
|
|
|
|
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
void mp_input_get_mouse_pos(struct input_ctx *ictx, int *x, int *y)
|
|
|
|
{
|
2013-08-26 17:15:35 +00:00
|
|
|
input_lock(ictx);
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
*x = ictx->mouse_x;
|
|
|
|
*y = ictx->mouse_y;
|
2013-08-26 17:15:35 +00:00
|
|
|
input_unlock(ictx);
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
}
|
|
|
|
|
2013-12-26 16:41:28 +00:00
|
|
|
// If name is NULL, return "default".
|
|
|
|
// Return a statically allocated name of the section (i.e. return value never
|
|
|
|
// gets deallocated).
|
|
|
|
static char *normalize_section(struct input_ctx *ictx, char *name)
|
|
|
|
{
|
|
|
|
return get_bind_section(ictx, bstr0(name))->section;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_disable_section(struct input_ctx *ictx, char *name)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
name = normalize_section(ictx, name);
|
|
|
|
|
|
|
|
// Remove old section, or make sure it's on top if re-enabled
|
|
|
|
for (int i = ictx->num_active_sections - 1; i >= 0; i--) {
|
|
|
|
struct active_section *as = &ictx->active_sections[i];
|
|
|
|
if (strcmp(as->name, name) == 0) {
|
|
|
|
MP_TARRAY_REMOVE_AT(ictx->active_sections,
|
|
|
|
ictx->num_active_sections, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_enable_section(struct input_ctx *ictx, char *name, int flags)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
name = normalize_section(ictx, name);
|
|
|
|
|
|
|
|
mp_input_disable_section(ictx, name);
|
|
|
|
|
|
|
|
MP_VERBOSE(ictx, "enable section '%s'\n", name);
|
|
|
|
|
|
|
|
if (ictx->num_active_sections < MAX_ACTIVE_SECTIONS) {
|
2014-02-19 14:40:04 +00:00
|
|
|
int top = ictx->num_active_sections;
|
|
|
|
if (!(flags & MP_INPUT_ON_TOP)) {
|
|
|
|
// insert before the first top entry
|
|
|
|
for (top = 0; top < ictx->num_active_sections; top++) {
|
|
|
|
if (ictx->active_sections[top].flags & MP_INPUT_ON_TOP)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (int n = ictx->num_active_sections; n > top; n--)
|
|
|
|
ictx->active_sections[n] = ictx->active_sections[n - 1];
|
|
|
|
}
|
|
|
|
ictx->active_sections[top] = (struct active_section){name, flags};
|
|
|
|
ictx->num_active_sections++;
|
2013-12-26 16:41:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MP_DBG(ictx, "active section stack:\n");
|
|
|
|
for (int n = 0; n < ictx->num_active_sections; n++) {
|
|
|
|
MP_DBG(ictx, " %s %d\n", ictx->active_sections[n].name,
|
|
|
|
ictx->active_sections[n].flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_disable_all_sections(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
ictx->num_active_sections = 0;
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_set_section_mouse_area(struct input_ctx *ictx, char *name,
|
|
|
|
int x0, int y0, int x1, int y1)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
struct cmd_bind_section *s = get_bind_section(ictx, bstr0(name));
|
|
|
|
s->mouse_area = (struct mp_rect){x0, y0, x1, y1};
|
|
|
|
s->mouse_area_set = x0 != x1 && y0 != y1;
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool test_mouse(struct input_ctx *ictx, int x, int y, int rej_flags)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
bool res = false;
|
|
|
|
for (int i = 0; i < ictx->num_active_sections; i++) {
|
|
|
|
struct active_section *as = &ictx->active_sections[i];
|
|
|
|
if (as->flags & rej_flags)
|
|
|
|
continue;
|
|
|
|
struct cmd_bind_section *s = get_bind_section(ictx, bstr0(as->name));
|
|
|
|
if (s->mouse_area_set && test_rect(&s->mouse_area, x, y)) {
|
|
|
|
res = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
input_unlock(ictx);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool mp_input_test_mouse_active(struct input_ctx *ictx, int x, int y)
|
|
|
|
{
|
|
|
|
return test_mouse(ictx, x, y, MP_INPUT_ALLOW_HIDE_CURSOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y)
|
|
|
|
{
|
|
|
|
return test_mouse(ictx, x, y, MP_INPUT_ALLOW_VO_DRAGGING);
|
|
|
|
}
|
|
|
|
|
2013-06-22 22:40:35 +00:00
|
|
|
static void bind_dealloc(struct cmd_bind *bind)
|
|
|
|
{
|
|
|
|
talloc_free(bind->cmd);
|
|
|
|
talloc_free(bind->location);
|
|
|
|
}
|
|
|
|
|
2013-12-26 16:41:28 +00:00
|
|
|
// builtin: if true, remove all builtin binds, else remove all user binds
|
|
|
|
static void remove_binds(struct cmd_bind_section *bs, bool builtin)
|
|
|
|
{
|
|
|
|
for (int n = bs->num_binds - 1; n >= 0; n--) {
|
|
|
|
if (bs->binds[n].is_builtin == builtin) {
|
|
|
|
bind_dealloc(&bs->binds[n]);
|
|
|
|
assert(bs->num_binds >= 1);
|
|
|
|
bs->binds[n] = bs->binds[bs->num_binds - 1];
|
|
|
|
bs->num_binds--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_define_section(struct input_ctx *ictx, char *name, char *location,
|
|
|
|
char *contents, bool builtin)
|
|
|
|
{
|
|
|
|
if (!name || !name[0])
|
|
|
|
return; // parse_config() changes semantics with restrict_section==empty
|
|
|
|
input_lock(ictx);
|
|
|
|
if (contents) {
|
|
|
|
parse_config(ictx, builtin, bstr0(contents), location, name);
|
|
|
|
} else {
|
|
|
|
// Disable:
|
|
|
|
mp_input_disable_section(ictx, name);
|
|
|
|
// Delete:
|
|
|
|
struct cmd_bind_section *bs = get_bind_section(ictx, bstr0(name));
|
|
|
|
remove_binds(bs, builtin);
|
|
|
|
}
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
2014-04-18 14:48:13 +00:00
|
|
|
static bool bind_matches_key(struct cmd_bind *bind, int num_keys, const int *keys)
|
|
|
|
{
|
|
|
|
if (bind->num_keys != num_keys)
|
|
|
|
return false;
|
|
|
|
for (int i = 0; i < num_keys; i++) {
|
|
|
|
if (bind->keys[i] != keys[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-09-22 13:17:15 +00:00
|
|
|
static void bind_keys(struct input_ctx *ictx, bool builtin, bstr section,
|
2013-06-22 22:07:45 +00:00
|
|
|
const int *keys, int num_keys, bstr command,
|
2012-10-13 19:09:42 +00:00
|
|
|
const char *loc)
|
2008-04-30 05:56:45 +00:00
|
|
|
{
|
2013-06-22 22:40:35 +00:00
|
|
|
struct cmd_bind_section *bs = get_bind_section(ictx, section);
|
2011-07-16 15:17:48 +00:00
|
|
|
struct cmd_bind *bind = NULL;
|
2011-04-25 08:38:46 +00:00
|
|
|
|
2013-06-22 22:07:45 +00:00
|
|
|
assert(num_keys <= MP_MAX_KEY_DOWN);
|
|
|
|
|
2013-06-22 22:40:35 +00:00
|
|
|
for (int n = 0; n < bs->num_binds; n++) {
|
|
|
|
struct cmd_bind *b = &bs->binds[n];
|
|
|
|
if (bind_matches_key(b, num_keys, keys) && b->is_builtin == builtin) {
|
|
|
|
bind = b;
|
|
|
|
break;
|
2011-04-25 08:38:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bind) {
|
2013-06-22 22:40:35 +00:00
|
|
|
struct cmd_bind empty = {{0}};
|
|
|
|
MP_TARRAY_APPEND(bs, bs->binds, bs->num_binds, empty);
|
|
|
|
bind = &bs->binds[bs->num_binds - 1];
|
2002-02-24 16:31:27 +00:00
|
|
|
}
|
2013-06-22 22:40:35 +00:00
|
|
|
|
|
|
|
bind_dealloc(bind);
|
|
|
|
|
|
|
|
*bind = (struct cmd_bind) {
|
|
|
|
.cmd = bstrdup0(bs->binds, command),
|
|
|
|
.location = talloc_strdup(bs->binds, loc),
|
|
|
|
.owner = bs,
|
|
|
|
.is_builtin = builtin,
|
|
|
|
.num_keys = num_keys,
|
|
|
|
};
|
2013-06-22 22:07:45 +00:00
|
|
|
memcpy(bind->keys, keys, num_keys * sizeof(bind->keys[0]));
|
2014-02-17 01:35:16 +00:00
|
|
|
if (mp_msg_test(ictx->log, MSGL_DEBUG)) {
|
|
|
|
char *s = mp_input_get_key_combo_name(keys, num_keys);
|
|
|
|
MP_DBG(ictx, "add: section='%s' key='%s'%s cmd='%s' location='%s'\n",
|
|
|
|
bind->owner->section, s, bind->is_builtin ? " builtin" : "",
|
|
|
|
bind->cmd, bind->location);
|
|
|
|
talloc_free(s);
|
|
|
|
}
|
2002-02-24 16:31:27 +00:00
|
|
|
}
|
|
|
|
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
// restrict_section: every entry is forced to this section name
|
|
|
|
// if NULL, load normally and allow any sections
|
2012-10-13 19:09:42 +00:00
|
|
|
static int parse_config(struct input_ctx *ictx, bool builtin, bstr data,
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
const char *location, const char *restrict_section)
|
2008-04-30 05:56:45 +00:00
|
|
|
{
|
2013-06-22 22:07:45 +00:00
|
|
|
int n_binds = 0;
|
2012-10-13 19:09:42 +00:00
|
|
|
int line_no = 0;
|
|
|
|
char *cur_loc = NULL;
|
2011-07-20 01:41:51 +00:00
|
|
|
|
2012-08-01 19:50:24 +00:00
|
|
|
while (data.len) {
|
2012-10-13 19:09:42 +00:00
|
|
|
line_no++;
|
|
|
|
if (cur_loc)
|
|
|
|
talloc_free(cur_loc);
|
|
|
|
cur_loc = talloc_asprintf(NULL, "%s:%d", location, line_no);
|
|
|
|
|
2012-08-01 19:50:24 +00:00
|
|
|
bstr line = bstr_strip_linebreaks(bstr_getline(data, &data));
|
|
|
|
line = bstr_lstrip(line);
|
|
|
|
if (line.len == 0 || bstr_startswith0(line, "#"))
|
2011-04-25 08:38:46 +00:00
|
|
|
continue;
|
2014-02-25 21:09:20 +00:00
|
|
|
if (bstr_eatstart0(&line, "default-bindings ")) {
|
|
|
|
bstr orig = line;
|
|
|
|
bstr_split_tok(line, "#", &line, &(bstr){0});
|
|
|
|
line = bstr_strip(line);
|
|
|
|
if (bstr_equals0(line, "start")) {
|
|
|
|
builtin = true;
|
|
|
|
} else {
|
|
|
|
MP_ERR(ictx, "Broken line: %.*s at %s\n", BSTR_P(orig), cur_loc);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2011-07-20 01:41:51 +00:00
|
|
|
struct bstr command;
|
|
|
|
// Find the key name starting a line
|
2012-08-01 21:41:21 +00:00
|
|
|
struct bstr keyname = bstr_split(line, WHITESPACE, &command);
|
2011-07-20 01:41:51 +00:00
|
|
|
command = bstr_strip(command);
|
|
|
|
if (command.len == 0) {
|
2013-09-27 13:30:59 +00:00
|
|
|
MP_ERR(ictx, "Unfinished key binding: %.*s at %s\n", BSTR_P(line),
|
|
|
|
cur_loc);
|
2011-07-20 01:41:51 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
char *name = bstrdup0(NULL, keyname);
|
2013-06-22 22:07:45 +00:00
|
|
|
int keys[MP_MAX_KEY_DOWN];
|
|
|
|
int num_keys = 0;
|
2013-12-26 16:10:35 +00:00
|
|
|
if (!mp_input_get_keys_from_string(name, MP_MAX_KEY_DOWN, &num_keys, keys))
|
|
|
|
{
|
2011-07-20 01:41:51 +00:00
|
|
|
talloc_free(name);
|
2013-09-27 13:30:59 +00:00
|
|
|
MP_ERR(ictx, "Unknown key '%.*s' at %s\n", BSTR_P(keyname), cur_loc);
|
2011-04-25 08:38:46 +00:00
|
|
|
continue;
|
2010-12-19 10:12:20 +00:00
|
|
|
}
|
2011-07-20 01:41:51 +00:00
|
|
|
talloc_free(name);
|
2012-09-22 13:17:15 +00:00
|
|
|
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
bstr section = bstr0(restrict_section);
|
|
|
|
if (!section.len) {
|
|
|
|
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));
|
|
|
|
}
|
2012-09-22 13:17:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-22 22:07:45 +00:00
|
|
|
bind_keys(ictx, builtin, section, keys, num_keys, command, cur_loc);
|
2011-07-20 01:41:51 +00:00
|
|
|
n_binds++;
|
2012-09-22 04:33:04 +00:00
|
|
|
|
|
|
|
// Print warnings if invalid commands are encountered.
|
2013-09-27 13:30:59 +00:00
|
|
|
talloc_free(mp_input_parse_cmd(ictx, command, cur_loc));
|
2002-01-30 12:46:03 +00:00
|
|
|
}
|
2012-08-01 19:50:24 +00:00
|
|
|
|
2012-10-13 19:09:42 +00:00
|
|
|
talloc_free(cur_loc);
|
|
|
|
|
2012-08-01 19:50:24 +00:00
|
|
|
return n_binds;
|
|
|
|
}
|
|
|
|
|
2013-02-08 22:52:06 +00:00
|
|
|
static int parse_config_file(struct input_ctx *ictx, char *file, bool warn)
|
2012-08-01 19:50:24 +00:00
|
|
|
{
|
2013-12-14 18:50:00 +00:00
|
|
|
int r = 0;
|
|
|
|
void *tmp = talloc_new(NULL);
|
|
|
|
stream_t *s = NULL;
|
|
|
|
|
2013-12-21 19:45:19 +00:00
|
|
|
file = mp_get_user_path(tmp, ictx->global, file);
|
2012-11-15 11:40:39 +00:00
|
|
|
if (!mp_path_exists(file)) {
|
2013-09-10 06:29:45 +00:00
|
|
|
MP_MSG(ictx, warn ? MSGL_ERR : MSGL_V,
|
2013-02-08 22:52:06 +00:00
|
|
|
"Input config file %s not found.\n", file);
|
2013-12-14 18:50:00 +00:00
|
|
|
goto done;
|
2012-11-15 11:40:39 +00:00
|
|
|
}
|
2013-12-21 19:36:45 +00:00
|
|
|
s = stream_open(file, ictx->global);
|
2012-08-01 19:50:24 +00:00
|
|
|
if (!s) {
|
2013-09-10 06:29:45 +00:00
|
|
|
MP_ERR(ictx, "Can't open input config file %s.\n", file);
|
2013-12-14 18:50:00 +00:00
|
|
|
goto done;
|
2012-08-01 19:50:24 +00:00
|
|
|
}
|
2013-12-14 18:50:00 +00:00
|
|
|
bstr data = stream_read_complete(s, tmp, 1000000);
|
2013-12-28 14:06:43 +00:00
|
|
|
if (data.start) {
|
|
|
|
MP_VERBOSE(ictx, "Parsing input config file %s\n", file);
|
|
|
|
int num = parse_config(ictx, false, data, file, NULL);
|
|
|
|
MP_VERBOSE(ictx, "Input config file %s parsed: %d binds\n", file, num);
|
|
|
|
r = 1;
|
|
|
|
} else {
|
|
|
|
MP_ERR(ictx, "Error reading input config file %s\n", file);
|
|
|
|
}
|
2013-12-14 18:50:00 +00:00
|
|
|
|
|
|
|
done:
|
|
|
|
free_stream(s);
|
|
|
|
talloc_free(tmp);
|
|
|
|
return r;
|
2002-01-30 12:46:03 +00:00
|
|
|
}
|
|
|
|
|
2013-12-26 16:41:28 +00:00
|
|
|
static int close_fd(void *ctx, int fd)
|
2008-04-30 05:56:45 +00:00
|
|
|
{
|
2013-12-26 16:41:28 +00:00
|
|
|
return close(fd);
|
2007-06-07 18:06:53 +00:00
|
|
|
}
|
|
|
|
|
2013-12-26 16:41:28 +00:00
|
|
|
#ifndef __MINGW32__
|
|
|
|
static int read_wakeup(void *ctx, int fd)
|
2013-12-21 18:33:45 +00:00
|
|
|
{
|
2013-12-26 16:41:28 +00:00
|
|
|
char buf[100];
|
|
|
|
read(fd, buf, sizeof(buf));
|
|
|
|
return MP_INPUT_NOTHING;
|
2013-12-21 18:33:45 +00:00
|
|
|
}
|
2013-12-26 16:41:28 +00:00
|
|
|
#endif
|
2013-12-21 18:33:45 +00:00
|
|
|
|
2013-09-10 06:29:45 +00:00
|
|
|
struct input_ctx *mp_input_init(struct mpv_global *global)
|
2008-04-30 04:15:52 +00:00
|
|
|
{
|
2013-09-10 06:29:45 +00:00
|
|
|
struct input_conf *input_conf = &global->opts->input;
|
2013-07-27 19:26:00 +00:00
|
|
|
|
2008-04-30 04:15:52 +00:00
|
|
|
struct input_ctx *ictx = talloc_ptrtype(NULL, ictx);
|
|
|
|
*ictx = (struct input_ctx){
|
2013-12-21 18:33:45 +00:00
|
|
|
.global = global,
|
2013-09-10 06:29:45 +00:00
|
|
|
.log = mp_log_new(ictx, global->log, "input"),
|
2011-07-17 01:47:50 +00:00
|
|
|
.key_fifo_size = input_conf->key_fifo_size,
|
2013-07-02 12:00:24 +00:00
|
|
|
.doubleclick_time = input_conf->doubleclick_time,
|
2008-04-30 04:15:52 +00:00
|
|
|
.ar_state = -1,
|
2008-04-30 15:57:02 +00:00
|
|
|
.ar_delay = input_conf->ar_delay,
|
|
|
|
.ar_rate = input_conf->ar_rate,
|
2009-03-31 23:26:34 +00:00
|
|
|
.default_bindings = input_conf->default_bindings,
|
2013-08-30 00:24:14 +00:00
|
|
|
.mouse_section = "default",
|
2012-10-13 19:10:20 +00:00
|
|
|
.test = input_conf->test,
|
2012-03-25 19:58:48 +00:00
|
|
|
.wakeup_pipe = {-1, -1},
|
2008-04-30 04:15:52 +00:00
|
|
|
};
|
2013-08-26 17:15:35 +00:00
|
|
|
|
2014-01-31 18:50:25 +00:00
|
|
|
mpthread_mutex_init_recursive(&ictx->mutex);
|
2014-04-15 21:12:01 +00:00
|
|
|
pthread_cond_init(&ictx->wakeup, NULL);
|
2013-08-26 17:15:35 +00:00
|
|
|
|
input: don't deliver mouse events if mouse area is not set
This caused the OSC to be always visible at startup on X11:
- EnterNotify event send a mouse event to input.c
- OSC has not completely initialized yet, and no mouse area is set
- mouse event is dispatched to "showhide" OSC section
- OSC becomes visible, regardless of mouse position
Fix this by treating the mouse area as empty if it's not set, instead of
infinite as it was before this commit. This means an input section must
set a mouse area to receive mouse events at all. We also have to change
the default section to receive mouse events with the new behavior.
Also, if MOUSE_MOVE is unmapped (or mapped to something that doesn't
parse), and produces no command, the mouse position wouldn't be updated
(because the mouse position is bound to input commands), so we have to
generate a dummy command in this case.
(This matters only for the OSC, On Screen Controller, which isn't merged
yet, so these changes shouldn't have much effect right now.)
2013-09-05 21:58:51 +00:00
|
|
|
// Setup default section, so that it does nothing.
|
|
|
|
mp_input_enable_section(ictx, NULL, MP_INPUT_ALLOW_VO_DRAGGING |
|
|
|
|
MP_INPUT_ALLOW_HIDE_CURSOR);
|
|
|
|
mp_input_set_section_mouse_area(ictx, NULL, INT_MIN, INT_MIN, INT_MAX, INT_MAX);
|
2012-08-01 20:45:35 +00:00
|
|
|
|
2013-09-01 15:06:11 +00:00
|
|
|
// "Uncomment" the default key bindings in etc/input.conf and add them.
|
|
|
|
// All lines that do not start with '# ' are parsed.
|
|
|
|
bstr builtin = bstr0(builtin_input_conf);
|
|
|
|
while (builtin.len) {
|
|
|
|
bstr line = bstr_getline(builtin, &builtin);
|
|
|
|
bstr_eatstart0(&line, "#");
|
|
|
|
if (!bstr_startswith0(line, " "))
|
|
|
|
parse_config(ictx, true, line, "<builtin>", NULL);
|
|
|
|
}
|
2008-04-30 04:15:52 +00:00
|
|
|
|
2012-03-25 19:58:48 +00:00
|
|
|
#ifndef __MINGW32__
|
2013-11-30 21:40:51 +00:00
|
|
|
int ret = pipe(ictx->wakeup_pipe);
|
|
|
|
if (ret == 0) {
|
|
|
|
for (int i = 0; i < 2 && ret >= 0; i++) {
|
|
|
|
mp_set_cloexec(ictx->wakeup_pipe[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)
|
|
|
|
break;
|
|
|
|
}
|
2012-03-25 19:58:48 +00:00
|
|
|
}
|
|
|
|
if (ret < 0)
|
2013-09-10 06:29:45 +00:00
|
|
|
MP_ERR(ictx, "Failed to initialize wakeup pipe: %s\n", strerror(errno));
|
2012-03-25 19:58:48 +00:00
|
|
|
else
|
2013-12-21 18:33:45 +00:00
|
|
|
mp_input_add_fd(ictx, ictx->wakeup_pipe[0], true, NULL, read_wakeup,
|
|
|
|
NULL, NULL);
|
2012-03-25 19:58:48 +00:00
|
|
|
#endif
|
|
|
|
|
2013-02-08 22:52:06 +00:00
|
|
|
bool config_ok = false;
|
|
|
|
if (input_conf->config_file)
|
|
|
|
config_ok = parse_config_file(ictx, input_conf->config_file, true);
|
2013-09-10 06:29:45 +00:00
|
|
|
if (!config_ok && global->opts->load_config) {
|
2011-04-25 08:38:46 +00:00
|
|
|
// Try global conf dir
|
2013-12-21 19:45:19 +00:00
|
|
|
char *file = mp_find_config_file(NULL, global, "input.conf");
|
2013-02-08 22:52:06 +00:00
|
|
|
config_ok = file && parse_config_file(ictx, file, false);
|
|
|
|
talloc_free(file);
|
|
|
|
}
|
|
|
|
if (!config_ok) {
|
2013-12-21 18:33:45 +00:00
|
|
|
MP_VERBOSE(ictx, "Falling back on default (hardcoded) input config\n");
|
2004-08-03 12:21:14 +00:00
|
|
|
}
|
2002-01-30 12:46:03 +00:00
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_JOYSTICK
|
2013-12-21 18:33:45 +00:00
|
|
|
if (input_conf->use_joystick)
|
|
|
|
mp_input_joystick_init(ictx, ictx->log, input_conf->js_dev);
|
2002-01-30 12:46:03 +00:00
|
|
|
#endif
|
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_LIRC
|
2013-12-21 18:33:45 +00:00
|
|
|
if (input_conf->use_lirc)
|
|
|
|
mp_input_lirc_init(ictx, ictx->log, input_conf->lirc_configfile);
|
2002-01-31 09:39:11 +00:00
|
|
|
#endif
|
|
|
|
|
2013-12-01 05:23:39 +00:00
|
|
|
if (input_conf->use_alt_gr) {
|
|
|
|
ictx->using_alt_gr = true;
|
|
|
|
}
|
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_COCOA
|
2014-04-24 15:27:27 +00:00
|
|
|
if (input_conf->use_appleremote) {
|
2013-06-04 20:12:23 +00:00
|
|
|
cocoa_init_apple_remote();
|
2013-07-27 19:26:00 +00:00
|
|
|
ictx->using_ar = true;
|
2013-06-04 20:12:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (input_conf->use_media_keys) {
|
|
|
|
cocoa_init_media_keys();
|
2013-07-27 19:26:00 +00:00
|
|
|
ictx->using_cocoa_media_keys = true;
|
2013-06-02 22:52:40 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-04-25 08:38:46 +00:00
|
|
|
if (input_conf->in_file) {
|
2012-02-03 07:05:11 +00:00
|
|
|
int mode = O_RDONLY;
|
|
|
|
#ifndef __MINGW32__
|
2011-04-25 08:38:46 +00:00
|
|
|
// Use RDWR for FIFOs to ensure they stay open over multiple accesses.
|
2012-02-03 07:05:11 +00:00
|
|
|
// Note that on Windows due to how the API works, using RDONLY should
|
|
|
|
// be ok.
|
|
|
|
struct stat st;
|
2011-04-25 08:38:46 +00:00
|
|
|
if (stat(input_conf->in_file, &st) == 0 && S_ISFIFO(st.st_mode))
|
2012-02-03 07:05:11 +00:00
|
|
|
mode = O_RDWR;
|
|
|
|
mode |= O_NONBLOCK;
|
|
|
|
#endif
|
2011-04-25 08:38:46 +00:00
|
|
|
int in_file_fd = open(input_conf->in_file, mode);
|
|
|
|
if (in_file_fd >= 0)
|
2013-12-21 18:33:45 +00:00
|
|
|
mp_input_add_fd(ictx, in_file_fd, 1, input_default_read_cmd, NULL, close_fd, NULL);
|
2011-04-25 08:38:46 +00:00
|
|
|
else
|
2013-09-27 13:30:59 +00:00
|
|
|
MP_ERR(ictx, "Can't open %s: %s\n", input_conf->in_file,
|
|
|
|
strerror(errno));
|
2011-04-25 08:38:46 +00:00
|
|
|
}
|
2012-04-03 06:13:12 +00:00
|
|
|
|
2011-04-25 08:38:46 +00:00
|
|
|
return ictx;
|
2002-01-31 09:39:11 +00:00
|
|
|
}
|
|
|
|
|
2013-02-03 16:43:47 +00:00
|
|
|
static void clear_queue(struct cmd_queue *queue)
|
|
|
|
{
|
|
|
|
while (queue->first) {
|
|
|
|
struct mp_cmd *item = queue->first;
|
|
|
|
queue_remove(queue, item);
|
|
|
|
talloc_free(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-27 19:26:00 +00:00
|
|
|
void mp_input_uninit(struct input_ctx *ictx)
|
2008-04-30 04:15:52 +00:00
|
|
|
{
|
2008-04-30 06:14:06 +00:00
|
|
|
if (!ictx)
|
|
|
|
return;
|
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_COCOA
|
2013-07-27 19:26:00 +00:00
|
|
|
if (ictx->using_ar) {
|
2013-06-04 20:12:23 +00:00
|
|
|
cocoa_uninit_apple_remote();
|
|
|
|
}
|
|
|
|
|
2013-07-27 19:26:00 +00:00
|
|
|
if (ictx->using_cocoa_media_keys) {
|
2013-06-04 20:12:23 +00:00
|
|
|
cocoa_uninit_media_keys();
|
2013-06-02 22:52:40 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-07-07 14:53:35 +00:00
|
|
|
for (int i = 0; i < ictx->num_fds; i++) {
|
|
|
|
if (ictx->fds[i].close_func)
|
2013-12-21 18:33:45 +00:00
|
|
|
ictx->fds[i].close_func(ictx->fds[i].ctx, ictx->fds[i].fd);
|
2011-04-25 08:38:46 +00:00
|
|
|
}
|
2013-02-03 16:43:47 +00:00
|
|
|
for (int i = 0; i < 2; i++) {
|
2012-03-25 19:58:48 +00:00
|
|
|
if (ictx->wakeup_pipe[i] != -1)
|
|
|
|
close(ictx->wakeup_pipe[i]);
|
2013-02-03 16:43:47 +00:00
|
|
|
}
|
2013-09-01 23:09:52 +00:00
|
|
|
clear_queue(&ictx->cmd_queue);
|
input: handle mouse movement differently
Before this commit, mouse movement events emitted a special command
("set_mouse_pos"), which was specially handled in command.c. This was
once special-cased to the dvdnav and menu code, and did nothing after
libmenu and dvdnav were removed.
Change it so that mouse movement triggers a pseudo-key ("MOUSE_MOVE"),
which then can be bound to an arbitrary command. The mouse position is
now managed in input.c. A command which actually needs the mouse
position can use either mp_input_get_mouse_pos() or mp_get_osd_mouse_pos()
to query it. The former returns raw window-space coordinates, while the
latter returns coordinates transformed to OSD- space. (Both are the same
for most VOs, except vo_xv and vo_x11, which can't render OSD in
window-space. These require extra code for mapping mouse position.)
As of this commit, there is still nothing that uses mouse movement, so
MOUSE_MOVE is mapped to "ignore" to silence warnings when moving the
mouse (much like MOUSE_BTN0).
Extend the concept of input sections. Allow multiple sections to be
active at once, and organize them as stack. Bindings from the top of
the stack are preferred to lower ones.
Each section has a mouse input section associated, inside which mouse
events are associated with the bindings. If the mouse pointer is
outside of a section's mouse area, mouse events will be dispatched to
an input section lower on the stack of active sections. This is intended
for scripting, which is to be added later. Two scripts could occupy
different areas of the screen without conflicting with each other. (If
it turns out that this mechanism is useless, we'll just remove it
again.)
2013-04-26 00:13:30 +00:00
|
|
|
talloc_free(ictx->current_down_cmd);
|
2013-11-28 18:28:38 +00:00
|
|
|
pthread_mutex_destroy(&ictx->mutex);
|
2014-04-15 21:12:01 +00:00
|
|
|
pthread_cond_destroy(&ictx->wakeup);
|
2011-04-25 08:38:46 +00:00
|
|
|
talloc_free(ictx);
|
2002-01-30 12:46:03 +00:00
|
|
|
}
|
|
|
|
|
2012-03-25 19:58:48 +00:00
|
|
|
void mp_input_wakeup(struct input_ctx *ictx)
|
|
|
|
{
|
input: avoid using wakeup pipe if it's not needed
If input is not waiting for select(), writing to the wakeup pipe is
wasteful, and, if there are many wakeups, might even block the wakeup
threads if the pipe gets full.
However, if it's waiting for select(), the wakup pipe must be used to
unblock the waiting thread. Actually there's a small race condition: we
might determine that the main thread is in select(), and write to the
wakeup pipe (whether we do this while unlocked or locked doesn't really
matter). Then, the main thread might leave select() before reading from
the wakup pipe. This should be harmless, because at worst more wakeups
than needed happen, but never fewer.
2013-12-15 20:33:31 +00:00
|
|
|
input_lock(ictx);
|
|
|
|
bool send_wakeup = ictx->in_select;
|
|
|
|
ictx->got_new_events = true;
|
2014-04-15 21:12:01 +00:00
|
|
|
pthread_cond_signal(&ictx->wakeup);
|
input: avoid using wakeup pipe if it's not needed
If input is not waiting for select(), writing to the wakeup pipe is
wasteful, and, if there are many wakeups, might even block the wakeup
threads if the pipe gets full.
However, if it's waiting for select(), the wakup pipe must be used to
unblock the waiting thread. Actually there's a small race condition: we
might determine that the main thread is in select(), and write to the
wakeup pipe (whether we do this while unlocked or locked doesn't really
matter). Then, the main thread might leave select() before reading from
the wakup pipe. This should be harmless, because at worst more wakeups
than needed happen, but never fewer.
2013-12-15 20:33:31 +00:00
|
|
|
input_unlock(ictx);
|
2013-08-26 17:15:35 +00:00
|
|
|
// Safe without locking
|
input: avoid using wakeup pipe if it's not needed
If input is not waiting for select(), writing to the wakeup pipe is
wasteful, and, if there are many wakeups, might even block the wakeup
threads if the pipe gets full.
However, if it's waiting for select(), the wakup pipe must be used to
unblock the waiting thread. Actually there's a small race condition: we
might determine that the main thread is in select(), and write to the
wakeup pipe (whether we do this while unlocked or locked doesn't really
matter). Then, the main thread might leave select() before reading from
the wakup pipe. This should be harmless, because at worst more wakeups
than needed happen, but never fewer.
2013-12-15 20:33:31 +00:00
|
|
|
if (send_wakeup && ictx->wakeup_pipe[1] >= 0)
|
2012-03-25 19:58:48 +00:00
|
|
|
write(ictx->wakeup_pipe[1], &(char){0}, 1);
|
|
|
|
}
|
|
|
|
|
2014-04-15 20:50:16 +00:00
|
|
|
void mp_input_wakeup_nolock(struct input_ctx *ictx)
|
|
|
|
{
|
2014-04-15 21:12:01 +00:00
|
|
|
if (ictx->wakeup_pipe[1] >= 0) {
|
2014-04-15 20:50:16 +00:00
|
|
|
write(ictx->wakeup_pipe[1], &(char){0}, 1);
|
2014-04-15 21:12:01 +00:00
|
|
|
} else {
|
|
|
|
// Not race condition free. Done for the sake of jackaudio+windows.
|
|
|
|
ictx->got_new_events = true;
|
|
|
|
pthread_cond_signal(&ictx->wakeup);
|
|
|
|
}
|
2014-04-15 20:50:16 +00:00
|
|
|
}
|
|
|
|
|
2013-08-26 17:15:35 +00:00
|
|
|
static bool test_abort(struct input_ctx *ictx)
|
|
|
|
{
|
2013-09-01 23:09:52 +00:00
|
|
|
if (async_quit_request || queue_has_abort_cmds(&ictx->cmd_queue)) {
|
2013-09-27 13:30:59 +00:00
|
|
|
MP_WARN(ictx, "Received command to move to another file. "
|
|
|
|
"Aborting current processing.\n");
|
2013-08-26 17:15:35 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-04-25 17:13:03 +00:00
|
|
|
void mp_input_set_main_thread(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
ictx->mainthread = pthread_self();
|
|
|
|
ictx->mainthread_set = true;
|
|
|
|
}
|
|
|
|
|
2014-04-25 17:12:24 +00:00
|
|
|
bool mp_input_check_interrupt(struct input_ctx *ictx)
|
2008-04-30 04:15:52 +00:00
|
|
|
{
|
2013-08-26 17:15:35 +00:00
|
|
|
input_lock(ictx);
|
|
|
|
bool res = test_abort(ictx);
|
2014-04-25 17:13:03 +00:00
|
|
|
if (!res && ictx->mainthread_set &&
|
2014-04-26 14:56:50 +00:00
|
|
|
pthread_equal(ictx->mainthread, pthread_self()))
|
2014-04-25 17:13:03 +00:00
|
|
|
{
|
2014-04-25 17:12:24 +00:00
|
|
|
read_events(ictx, 0);
|
2011-04-25 08:38:46 +00:00
|
|
|
}
|
2013-08-26 17:15:35 +00:00
|
|
|
input_unlock(ictx);
|
|
|
|
return res;
|
2002-10-23 14:46:20 +00:00
|
|
|
}
|
2013-05-16 21:17:46 +00:00
|
|
|
|
2013-12-01 05:23:39 +00:00
|
|
|
bool mp_input_use_alt_gr(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
return ictx->using_alt_gr;
|
|
|
|
}
|
2013-12-26 16:10:35 +00:00
|
|
|
|
|
|
|
struct mp_cmd *mp_input_parse_cmd(struct input_ctx *ictx, bstr str,
|
|
|
|
const char *location)
|
|
|
|
{
|
|
|
|
return mp_input_parse_cmd_(ictx->log, str, location);
|
|
|
|
}
|
2014-01-04 15:59:22 +00:00
|
|
|
|
2014-01-04 18:42:01 +00:00
|
|
|
void mp_input_run_cmd(struct input_ctx *ictx, int def_flags, const char **cmd,
|
2014-01-04 15:59:22 +00:00
|
|
|
const char *location)
|
|
|
|
{
|
2014-01-04 18:42:01 +00:00
|
|
|
mp_cmd_t *cmdt = mp_input_parse_cmd_strv(ictx->log, def_flags, cmd, location);
|
2014-01-04 15:59:22 +00:00
|
|
|
mp_input_queue_cmd(ictx, cmdt);
|
|
|
|
}
|