2008-12-13 18:28:00 +00:00
|
|
|
/*
|
2015-04-13 07:36:54 +00:00
|
|
|
* This file is part of mpv.
|
2008-12-13 18:28:00 +00:00
|
|
|
*
|
input: change license to LGPL
cehoyos adds the step_property command in 7a71da01d, and it could be
argued that copyright of this still applies to the later add/cycle
commands (a668ae0ff90c4). While I'm not sure if this is really the case,
stay conservative for now and mark these commands as GPL-only. Mark the
command.c code too, although that is not being relicensed yet.
I'm leaving the MP_CMD_* enum items, as they are obviously different.
In commit 116ca0c7682, "veal" (essentially an anonymous author) adds an
"osd_show_property_text" command (well, the commit message says "based
on" that person's code, so it's not clear how much is from him or from
albeu, who agreed to LGPL). This was later merged again with the
"osd_show_text" command, and then all original code was removed in
commit 58cc0f637f, so I claim that no copyright applies anymore. (Though
technically the input.conf addition still might be copyrighted, so I'm
just dropping it to get rid of the thought.)
"kiriuja" added 2f376d1b39 (sub_load etc.) and be54f4813 (switch_audio).
The latter is gone. I would argue that the former is fully rewritten
with commits b7052b431c9 and 0f155921b0. But like in the step_property
case, I will be overly conservative for now, and mark them as GPL-only,
as this is potentially shaky and should be thought through first. (Not
bothering with the command define/enum in the header, as it will be
unused in LGPL mode anyway.)
keycodes.c/h can be GPL, except for commit 2b1f95dcc2f8, which is a
patch by someone who wasn't asked yet. Before doing something radical, I
will wait for a reply.
2017-06-19 11:02:35 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2008-12-13 18:28:00 +00:00
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is distributed in the hope that it will be useful,
|
2008-12-13 18:28:00 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
input: change license to LGPL
cehoyos adds the step_property command in 7a71da01d, and it could be
argued that copyright of this still applies to the later add/cycle
commands (a668ae0ff90c4). While I'm not sure if this is really the case,
stay conservative for now and mark these commands as GPL-only. Mark the
command.c code too, although that is not being relicensed yet.
I'm leaving the MP_CMD_* enum items, as they are obviously different.
In commit 116ca0c7682, "veal" (essentially an anonymous author) adds an
"osd_show_property_text" command (well, the commit message says "based
on" that person's code, so it's not clear how much is from him or from
albeu, who agreed to LGPL). This was later merged again with the
"osd_show_text" command, and then all original code was removed in
commit 58cc0f637f, so I claim that no copyright applies anymore. (Though
technically the input.conf addition still might be copyrighted, so I'm
just dropping it to get rid of the thought.)
"kiriuja" added 2f376d1b39 (sub_load etc.) and be54f4813 (switch_audio).
The latter is gone. I would argue that the former is fully rewritten
with commits b7052b431c9 and 0f155921b0. But like in the step_property
case, I will be overly conservative for now, and mark them as GPL-only,
as this is potentially shaky and should be thought through first. (Not
bothering with the command define/enum in the header, as it will be
unused in LGPL mode anyway.)
keycodes.c/h can be GPL, except for commit 2b1f95dcc2f8, which is a
patch by someone who wasn't asked yet. Before doing something radical, I
will wait for a reply.
2017-06-19 11:02:35 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2008-12-13 18:28:00 +00:00
|
|
|
*
|
input: change license to LGPL
cehoyos adds the step_property command in 7a71da01d, and it could be
argued that copyright of this still applies to the later add/cycle
commands (a668ae0ff90c4). While I'm not sure if this is really the case,
stay conservative for now and mark these commands as GPL-only. Mark the
command.c code too, although that is not being relicensed yet.
I'm leaving the MP_CMD_* enum items, as they are obviously different.
In commit 116ca0c7682, "veal" (essentially an anonymous author) adds an
"osd_show_property_text" command (well, the commit message says "based
on" that person's code, so it's not clear how much is from him or from
albeu, who agreed to LGPL). This was later merged again with the
"osd_show_text" command, and then all original code was removed in
commit 58cc0f637f, so I claim that no copyright applies anymore. (Though
technically the input.conf addition still might be copyrighted, so I'm
just dropping it to get rid of the thought.)
"kiriuja" added 2f376d1b39 (sub_load etc.) and be54f4813 (switch_audio).
The latter is gone. I would argue that the former is fully rewritten
with commits b7052b431c9 and 0f155921b0. But like in the step_property
case, I will be overly conservative for now, and mark them as GPL-only,
as this is potentially shaky and should be thought through first. (Not
bothering with the command define/enum in the header, as it will be
unused in LGPL mode anyway.)
keycodes.c/h can be GPL, except for commit 2b1f95dcc2f8, which is a
patch by someone who wasn't asked yet. Before doing something radical, I
will wait for a reply.
2017-06-19 11:02:35 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2008-12-13 18:28:00 +00:00
|
|
|
*/
|
|
|
|
|
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>
|
2016-09-16 12:25:50 +00:00
|
|
|
#include <math.h>
|
2002-01-30 12:46:03 +00:00
|
|
|
#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>
|
2011-07-17 01:47:50 +00:00
|
|
|
#include <assert.h>
|
2002-01-30 12:46:03 +00:00
|
|
|
|
2012-02-03 07:05:11 +00:00
|
|
|
#include "osdep/io.h"
|
2014-09-09 21:44:38 +00:00
|
|
|
#include "misc/rendezvous.h"
|
2012-02-03 07:05:11 +00:00
|
|
|
|
2002-01-30 12:46:03 +00:00
|
|
|
#include "input.h"
|
2011-04-25 06:43:59 +00:00
|
|
|
#include "keycodes.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"
|
2014-09-27 14:25:29 +00:00
|
|
|
#include "options/m_config.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/m_option.h"
|
|
|
|
#include "options/path.h"
|
2016-01-11 18:03:40 +00:00
|
|
|
#include "mpv_talloc.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/options.h"
|
2014-08-29 10:09:04 +00:00
|
|
|
#include "misc/bstr.h"
|
2019-11-22 23:39:07 +00:00
|
|
|
#include "misc/node.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
|
|
|
|
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
|
|
|
|
|
2023-10-21 02:55:41 +00:00
|
|
|
#define input_lock(ictx) mp_mutex_lock(&ictx->mutex)
|
|
|
|
#define input_unlock(ictx) mp_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
|
2019-11-23 00:09:09 +00:00
|
|
|
char *desc; // human readable description
|
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 {
|
2016-09-20 13:31:25 +00:00
|
|
|
char *owner;
|
2013-12-26 16:10:35 +00:00
|
|
|
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
|
2010-12-19 10:12:20 +00:00
|
|
|
};
|
|
|
|
|
2014-09-10 01:16:43 +00:00
|
|
|
#define MP_MAX_SOURCES 10
|
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;
|
|
|
|
};
|
|
|
|
|
2017-09-02 14:00:52 +00:00
|
|
|
struct wheel_state {
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
double dead_zone_accum;
|
|
|
|
double unit_accum;
|
|
|
|
};
|
|
|
|
|
2008-04-30 04:15:52 +00:00
|
|
|
struct input_ctx {
|
2023-10-21 02:55:41 +00:00
|
|
|
mp_mutex mutex;
|
2013-09-10 06:29:45 +00:00
|
|
|
struct mp_log *log;
|
2013-12-21 18:33:45 +00:00
|
|
|
struct mpv_global *global;
|
2016-09-06 18:09:44 +00:00
|
|
|
struct m_config_cache *opts_cache;
|
2014-07-27 19:53:29 +00:00
|
|
|
struct input_opts *opts;
|
2013-08-26 17:15:35 +00:00
|
|
|
|
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
|
|
|
|
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;
|
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 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;
|
2019-12-25 18:52:19 +00:00
|
|
|
int mouse_hover; // updated on mouse-enter/leave
|
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
|
|
|
|
2014-07-27 19:33:11 +00:00
|
|
|
bool mouse_mangle, mouse_src_mangle;
|
|
|
|
struct mp_rect mouse_src, mouse_dst;
|
|
|
|
|
2017-09-02 14:00:52 +00:00
|
|
|
// Wheel state (MP_WHEEL_*)
|
|
|
|
struct wheel_state wheel_state_y; // MP_WHEEL_UP/MP_WHEEL_DOWN
|
|
|
|
struct wheel_state wheel_state_x; // MP_WHEEL_LEFT/MP_WHEEL_RIGHT
|
|
|
|
struct wheel_state *wheel_current; // The direction currently being scrolled
|
|
|
|
double last_wheel_time; // mp_time_sec() of the last wheel event
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
|
2008-04-30 05:56:45 +00:00
|
|
|
// List of command binding sections
|
2019-11-23 14:00:48 +00:00
|
|
|
struct cmd_bind_section **sections;
|
|
|
|
int num_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
|
|
|
|
2013-05-25 16:31:06 +00:00
|
|
|
unsigned int mouse_event_counter;
|
2013-05-16 21:17:46 +00:00
|
|
|
|
2014-09-10 01:16:43 +00:00
|
|
|
struct mp_input_src *sources[MP_MAX_SOURCES];
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
int num_sources;
|
2008-04-30 10:14:03 +00:00
|
|
|
|
2013-09-01 23:09:52 +00:00
|
|
|
struct cmd_queue cmd_queue;
|
stream: redo playback abort handling
This mechanism originates from MPlayer's way of dealing with blocking
network, but it's still useful. On opening and closing, mpv waits for
network synchronously, and also some obscure commands and use-cases can
lead to such blocking. In these situations, the stream is asynchronously
forced to stop by "interrupting" it.
The old design interrupting I/O was a bit broken: polling with a
callback, instead of actively interrupting it. Change the direction of
this. There is no callback anymore, and the player calls
mp_cancel_trigger() to force the stream to return.
libavformat (via stream_lavf.c) has the old broken design, and fixing it
would require fixing libavformat, which won't happen so quickly. So we
have to keep that part. But everything above the stream layer is
prepared for a better design, and more sophisticated methods than
mp_cancel_test() could be easily introduced.
There's still one problem: commands are still run in the central
playback loop, which we assume can block on I/O in the worst case.
That's not a problem yet, because we simply mark some commands as being
able to stop playback of the current file ("quit" etc.), so input.c
could abort playback as soon as such a command is queued. But there are
also commands abort playback only conditionally, and the logic for that
is in the playback core and thus "unreachable". For example,
"playlist_next" aborts playback only if there's a next file. We don't
want it to always abort playback.
As a quite ugly hack, abort playback only if at least 2 abort commands
are queued - this pretty much happens only if the core is frozen and
doesn't react to input.
2014-09-13 12:23:08 +00:00
|
|
|
|
2016-09-16 12:25:50 +00:00
|
|
|
void (*wakeup_cb)(void *ctx);
|
|
|
|
void *wakeup_ctx;
|
2008-04-30 04:15:52 +00:00
|
|
|
};
|
|
|
|
|
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);
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
static void close_input_sources(struct input_ctx *ictx);
|
2013-12-26 16:41:28 +00:00
|
|
|
|
2014-06-10 23:54:03 +00:00
|
|
|
#define OPT_BASE_STRUCT struct input_opts
|
|
|
|
struct input_opts {
|
|
|
|
char *config_file;
|
|
|
|
int doubleclick_time;
|
2014-09-27 14:25:29 +00:00
|
|
|
// Maximum number of queued commands from keypresses (limit to avoid
|
|
|
|
// repeated slow commands piling up)
|
2014-06-10 23:54:03 +00:00
|
|
|
int key_fifo_size;
|
2014-09-27 14:25:29 +00:00
|
|
|
// Autorepeat config (be aware of mp_input_set_repeat_info())
|
2014-06-10 23:54:03 +00:00
|
|
|
int ar_delay;
|
|
|
|
int ar_rate;
|
2023-02-20 03:32:50 +00:00
|
|
|
bool use_alt_gr;
|
|
|
|
bool use_gamepad;
|
|
|
|
bool use_media_keys;
|
|
|
|
bool default_bindings;
|
|
|
|
bool builtin_bindings;
|
|
|
|
bool enable_mouse_movements;
|
|
|
|
bool vo_key_input;
|
|
|
|
bool test;
|
|
|
|
bool allow_win_drag;
|
2002-02-11 11:42:08 +00:00
|
|
|
};
|
|
|
|
|
2014-06-10 23:54:03 +00:00
|
|
|
const struct m_sub_options input_config = {
|
|
|
|
.opts = (const m_option_t[]) {
|
options: change option macros and all option declarations
Change all OPT_* macros such that they don't define the entire m_option
initializer, and instead expand only to a part of it, which sets certain
fields. This requires changing almost every option declaration, because
they all use these macros. A declaration now always starts with
{"name", ...
followed by designated initializers only (possibly wrapped in macros).
The OPT_* macros now initialize the .offset and .type fields only,
sometimes also .priv and others.
I think this change makes the option macros less tricky. The old code
had to stuff everything into macro arguments (and attempted to allow
setting arbitrary fields by letting the user pass designated
initializers in the vararg parts). Some of this was made messy due to
C99 and C11 not allowing 0-sized varargs with ',' removal. It's also
possible that this change is pointless, other than cosmetic preferences.
Not too happy about some things. For example, the OPT_CHOICE()
indentation I applied looks a bit ugly.
Much of this change was done with regex search&replace, but some places
required manual editing. In particular, code in "obscure" areas (which I
didn't include in compilation) might be broken now.
In wayland_common.c the author of some option declarations confused the
flags parameter with the default value (though the default value was
also properly set below). I fixed this with this change.
2020-03-14 20:28:01 +00:00
|
|
|
{"input-conf", OPT_STRING(config_file), .flags = M_OPT_FILE},
|
|
|
|
{"input-ar-delay", OPT_INT(ar_delay)},
|
|
|
|
{"input-ar-rate", OPT_INT(ar_rate)},
|
|
|
|
{"input-keylist", OPT_PRINT(mp_print_key_list)},
|
|
|
|
{"input-cmdlist", OPT_PRINT(mp_print_cmd_list)},
|
2023-02-20 03:32:50 +00:00
|
|
|
{"input-default-bindings", OPT_BOOL(default_bindings)},
|
|
|
|
{"input-builtin-bindings", OPT_BOOL(builtin_bindings)},
|
|
|
|
{"input-test", OPT_BOOL(test)},
|
options: change option macros and all option declarations
Change all OPT_* macros such that they don't define the entire m_option
initializer, and instead expand only to a part of it, which sets certain
fields. This requires changing almost every option declaration, because
they all use these macros. A declaration now always starts with
{"name", ...
followed by designated initializers only (possibly wrapped in macros).
The OPT_* macros now initialize the .offset and .type fields only,
sometimes also .priv and others.
I think this change makes the option macros less tricky. The old code
had to stuff everything into macro arguments (and attempted to allow
setting arbitrary fields by letting the user pass designated
initializers in the vararg parts). Some of this was made messy due to
C99 and C11 not allowing 0-sized varargs with ',' removal. It's also
possible that this change is pointless, other than cosmetic preferences.
Not too happy about some things. For example, the OPT_CHOICE()
indentation I applied looks a bit ugly.
Much of this change was done with regex search&replace, but some places
required manual editing. In particular, code in "obscure" areas (which I
didn't include in compilation) might be broken now.
In wayland_common.c the author of some option declarations confused the
flags parameter with the default value (though the default value was
also properly set below). I fixed this with this change.
2020-03-14 20:28:01 +00:00
|
|
|
{"input-doubleclick-time", OPT_INT(doubleclick_time),
|
|
|
|
M_RANGE(0, 1000)},
|
2023-02-20 03:32:50 +00:00
|
|
|
{"input-right-alt-gr", OPT_BOOL(use_alt_gr)},
|
options: change option macros and all option declarations
Change all OPT_* macros such that they don't define the entire m_option
initializer, and instead expand only to a part of it, which sets certain
fields. This requires changing almost every option declaration, because
they all use these macros. A declaration now always starts with
{"name", ...
followed by designated initializers only (possibly wrapped in macros).
The OPT_* macros now initialize the .offset and .type fields only,
sometimes also .priv and others.
I think this change makes the option macros less tricky. The old code
had to stuff everything into macro arguments (and attempted to allow
setting arbitrary fields by letting the user pass designated
initializers in the vararg parts). Some of this was made messy due to
C99 and C11 not allowing 0-sized varargs with ',' removal. It's also
possible that this change is pointless, other than cosmetic preferences.
Not too happy about some things. For example, the OPT_CHOICE()
indentation I applied looks a bit ugly.
Much of this change was done with regex search&replace, but some places
required manual editing. In particular, code in "obscure" areas (which I
didn't include in compilation) might be broken now.
In wayland_common.c the author of some option declarations confused the
flags parameter with the default value (though the default value was
also properly set below). I fixed this with this change.
2020-03-14 20:28:01 +00:00
|
|
|
{"input-key-fifo-size", OPT_INT(key_fifo_size), M_RANGE(2, 65000)},
|
2023-02-20 03:32:50 +00:00
|
|
|
{"input-cursor", OPT_BOOL(enable_mouse_movements)},
|
|
|
|
{"input-vo-keyboard", OPT_BOOL(vo_key_input)},
|
|
|
|
{"input-media-keys", OPT_BOOL(use_media_keys)},
|
2019-10-22 14:41:19 +00:00
|
|
|
#if HAVE_SDL2_GAMEPAD
|
2023-02-20 03:32:50 +00:00
|
|
|
{"input-gamepad", OPT_BOOL(use_gamepad)},
|
2014-09-09 22:51:36 +00:00
|
|
|
#endif
|
2023-02-20 03:32:50 +00:00
|
|
|
{"window-dragging", OPT_BOOL(allow_win_drag)},
|
2014-06-10 23:54:03 +00:00
|
|
|
{0}
|
|
|
|
},
|
|
|
|
.size = sizeof(struct input_opts),
|
|
|
|
.defaults = &(const struct input_opts){
|
|
|
|
.key_fifo_size = 7,
|
|
|
|
.doubleclick_time = 300,
|
|
|
|
.ar_delay = 200,
|
|
|
|
.ar_rate = 40,
|
2023-02-20 03:32:50 +00:00
|
|
|
.use_alt_gr = true,
|
|
|
|
.enable_mouse_movements = true,
|
|
|
|
.use_media_keys = true,
|
|
|
|
.default_bindings = true,
|
|
|
|
.builtin_bindings = true,
|
|
|
|
.vo_key_input = true,
|
|
|
|
.allow_win_drag = true,
|
2014-06-10 23:54:03 +00:00
|
|
|
},
|
2016-09-21 13:56:54 +00:00
|
|
|
.change_flags = UPDATE_INPUT,
|
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[] =
|
2023-07-23 22:54:35 +00:00
|
|
|
#include "etc/input.conf.inc"
|
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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-09-12 23:08:35 +00:00
|
|
|
static struct mp_cmd *queue_remove_head(struct cmd_queue *queue)
|
|
|
|
{
|
|
|
|
struct mp_cmd *ret = queue->first;
|
|
|
|
if (ret)
|
|
|
|
queue_remove(queue, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-09-02 00:29:20 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
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);
|
2019-11-22 17:21:33 +00:00
|
|
|
char *stripped = cmd ? cmd->original : bind->cmd;
|
|
|
|
msg = talloc_asprintf_append(msg, " '%s'", stripped);
|
2012-10-13 19:10:20 +00:00
|
|
|
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};
|
2014-10-10 20:58:28 +00:00
|
|
|
mp_cmd_t *res = mp_input_parse_cmd_strv(ictx->log, args);
|
2014-04-18 14:37:27 +00:00
|
|
|
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;
|
2019-11-23 14:00:48 +00:00
|
|
|
for (int n = 0; n < ictx->num_sections; n++) {
|
|
|
|
struct cmd_bind_section *bs = ictx->sections[n];
|
|
|
|
|
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++;
|
2014-08-24 17:17:33 +00:00
|
|
|
if (count > 1)
|
|
|
|
msg = talloc_asprintf_append(msg, "\n");
|
2012-10-13 19:10:20 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!count)
|
|
|
|
msg = talloc_asprintf_append(msg, "(nothing)");
|
|
|
|
|
2014-08-24 17:17:33 +00:00
|
|
|
MP_INFO(ictx, "%s\n", msg);
|
2015-05-25 19:59:44 +00:00
|
|
|
const char *args[] = {"show-text", msg, NULL};
|
2014-10-10 20:58:28 +00:00
|
|
|
mp_cmd_t *res = mp_input_parse_cmd_strv(ictx->log, args);
|
2014-02-19 14:39:59 +00:00
|
|
|
talloc_free(msg);
|
2012-10-13 19:10:20 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2019-11-23 14:00:48 +00:00
|
|
|
static struct cmd_bind_section *find_section(struct input_ctx *ictx,
|
|
|
|
bstr section)
|
|
|
|
{
|
|
|
|
for (int n = 0; n < ictx->num_sections; n++) {
|
|
|
|
struct cmd_bind_section *bs = ictx->sections[n];
|
|
|
|
if (bstr_equals0(section, bs->section))
|
|
|
|
return bs;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2012-09-22 13:17:15 +00:00
|
|
|
if (section.len == 0)
|
|
|
|
section = bstr0("default");
|
2019-11-23 14:00:48 +00:00
|
|
|
struct cmd_bind_section *bind_section = find_section(ictx, section);
|
|
|
|
if (bind_section)
|
|
|
|
return bind_section;
|
|
|
|
bind_section = talloc_ptrtype(ictx, bind_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
|
|
|
*bind_section = (struct cmd_bind_section) {
|
|
|
|
.section = bstrdup0(bind_section, section),
|
2014-11-23 08:10:51 +00:00
|
|
|
.mouse_area = {INT_MIN, INT_MIN, INT_MAX, INT_MAX},
|
|
|
|
.mouse_area_set = 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
|
|
|
};
|
2019-11-23 14:00:48 +00:00
|
|
|
MP_TARRAY_APPEND(ictx, ictx->sections, ictx->num_sections, bind_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++) {
|
2014-09-27 14:25:29 +00:00
|
|
|
if (builtin && !ictx->opts->default_bindings)
|
2013-08-30 00:24:14 +00:00
|
|
|
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;
|
2014-12-04 19:59:01 +00:00
|
|
|
if (best_bind && (s->flags & MP_INPUT_ON_TOP))
|
|
|
|
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
|
|
|
{
|
2014-09-27 14:25:29 +00:00
|
|
|
if (ictx->opts->test)
|
2014-04-18 14:27:02 +00:00
|
|
|
return handle_test(ictx, code);
|
2011-04-25 08:38:46 +00:00
|
|
|
|
2019-11-21 21:22:45 +00:00
|
|
|
struct cmd_bind *cmd = NULL;
|
|
|
|
|
|
|
|
if (MP_KEY_IS_UNICODE(code))
|
|
|
|
cmd = find_any_bind_for_key(ictx, force_section, MP_KEY_ANY_UNICODE);
|
|
|
|
if (!cmd)
|
|
|
|
cmd = find_any_bind_for_key(ictx, force_section, code);
|
2015-12-23 18:13:45 +00:00
|
|
|
if (!cmd)
|
|
|
|
cmd = find_any_bind_for_key(ictx, force_section, MP_KEY_UNMAPPED);
|
|
|
|
if (!cmd) {
|
2015-01-12 11:53:49 +00:00
|
|
|
if (code == MP_KEY_CLOSE_WIN)
|
|
|
|
return mp_input_parse_cmd_strv(ictx->log, (const char*[]){"quit", 0});
|
2013-09-05 22:28:31 +00:00
|
|
|
int msgl = MSGL_WARN;
|
2015-02-18 20:09:35 +00:00
|
|
|
if (MP_KEY_IS_MOUSE_MOVE(code))
|
2017-09-28 09:53:57 +00:00
|
|
|
msgl = MSGL_TRACE;
|
2014-04-18 14:27:02 +00:00
|
|
|
char *key_buf = mp_input_get_key_combo_name(&code, 1);
|
2015-06-29 22:43:16 +00:00
|
|
|
MP_MSG(ictx, msgl, "No key binding 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;
|
2015-12-23 18:10:38 +00:00
|
|
|
ret->key_name = talloc_steal(ret, mp_input_get_key_combo_name(&code, 1));
|
2017-09-28 09:53:57 +00:00
|
|
|
MP_TRACE(ictx, "key '%s' -> '%s' in '%s'\n",
|
|
|
|
ret->key_name, cmd->cmd, ret->input_section);
|
2019-11-21 22:01:56 +00:00
|
|
|
if (MP_KEY_IS_UNICODE(code)) {
|
|
|
|
bstr text = {0};
|
|
|
|
mp_append_utf8_bstr(ret, &text, code);
|
|
|
|
ret->key_text = text.start;
|
|
|
|
}
|
2014-11-23 14:08:49 +00:00
|
|
|
ret->is_mouse_button = code & MP_KEY_EMIT_ON_UP;
|
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);
|
2015-06-29 22:43:16 +00:00
|
|
|
MP_ERR(ictx, "Invalid command for key binding '%s': '%s'\n",
|
2013-09-27 13:30:59 +00:00
|
|
|
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) {
|
2017-09-28 09:53:57 +00:00
|
|
|
MP_TRACE(ictx, "input: switch section %s -> %s\n",
|
|
|
|
old, ictx->mouse_section);
|
2014-09-12 23:08:35 +00:00
|
|
|
mp_input_queue_cmd(ictx, get_cmd_from_keys(ictx, old, MP_KEY_MOUSE_LEAVE));
|
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
|
2014-05-26 19:49:14 +00:00
|
|
|
// the a key-up version of the command associated with the keys that were held
|
2013-12-01 16:59:20 +00:00
|
|
|
// 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
|
|
|
{
|
2014-11-24 15:48:34 +00:00
|
|
|
if (ictx->current_down_cmd && ictx->current_down_cmd->emit_on_up &&
|
|
|
|
(!drop_current || ictx->current_down_cmd->def->on_updown))
|
2013-12-01 16:59:20 +00:00
|
|
|
{
|
input: restore ability to combine mouse buttons
Key bindings are decided on the "down" event, so if the prefix is not
unique, the first/shortest will be used (e.g. when both "a" and "a-b"
are mapped, "a" will always be chosen).
This also breaks combining multiple mouse buttons. But it seems users
expect it to work, and it's indeed a bit strange that it shouldn't work,
as mouse bindings are emitted on the key "up" event, not "down" (if the
shorter binding didn't emit a command yet, why shouldn't it be
combinable).
Deal with this by clearing the key history when a command is actually
emitted, instead of when a command is decided. This means if both
MOUSE_BTN0 and MOUSE_BTN0-MOUSE_BTN1 are mapped, the sequence of holding
down BTN0 and then BTN1 will redecide the current command. On the other
hand, if BTN0 is released before BTN1 is pressed, the command is
emitted, and the key history is deleted. So the BTN1 press will not
trigger BTN0-BTN1.
For normal keys, nothing should change, because commands are emitted on
the "down" event already, so the key history is always cleared.
Might fix #902.
CC: @mpv-player/stable (if this fix is successful)
2014-07-07 16:18:41 +00:00
|
|
|
memset(ictx->key_history, 0, sizeof(ictx->key_history));
|
2014-11-23 14:08:49 +00:00
|
|
|
ictx->current_down_cmd->is_up = true;
|
2014-09-12 23:08:35 +00:00
|
|
|
mp_input_queue_cmd(ictx, ictx->current_down_cmd);
|
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;
|
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-09-02 00:26:41 +00:00
|
|
|
// We don't want the append to the command queue indefinitely, because that
|
2018-05-19 16:44:03 +00:00
|
|
|
// could lead to situations where recovery would take too long.
|
2013-09-02 00:26:41 +00:00
|
|
|
static bool should_drop_cmd(struct input_ctx *ictx, struct mp_cmd *cmd)
|
|
|
|
{
|
|
|
|
struct cmd_queue *queue = &ictx->cmd_queue;
|
2018-05-19 16:44:03 +00:00
|
|
|
return queue_count_cmds(queue) >= ictx->opts->key_fifo_size;
|
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
|
|
|
key_buf_add(ictx->key_history, code);
|
2018-04-30 18:33:05 +00:00
|
|
|
if (cmd && !cmd->def->is_ignore && !should_drop_cmd(ictx, cmd))
|
input: restore ability to combine mouse buttons
Key bindings are decided on the "down" event, so if the prefix is not
unique, the first/shortest will be used (e.g. when both "a" and "a-b"
are mapped, "a" will always be chosen).
This also breaks combining multiple mouse buttons. But it seems users
expect it to work, and it's indeed a bit strange that it shouldn't work,
as mouse bindings are emitted on the key "up" event, not "down" (if the
shorter binding didn't emit a command yet, why shouldn't it be
combinable).
Deal with this by clearing the key history when a command is actually
emitted, instead of when a command is decided. This means if both
MOUSE_BTN0 and MOUSE_BTN0-MOUSE_BTN1 are mapped, the sequence of holding
down BTN0 and then BTN1 will redecide the current command. On the other
hand, if BTN0 is released before BTN1 is pressed, the command is
emitted, and the key history is deleted. So the BTN1 press will not
trigger BTN0-BTN1.
For normal keys, nothing should change, because commands are emitted on
the "down" event already, so the key history is always cleared.
Might fix #902.
CC: @mpv-player/stable (if this fix is successful)
2014-07-07 16:18:41 +00:00
|
|
|
return cmd;
|
|
|
|
talloc_free(cmd);
|
2014-04-19 12:21:57 +00:00
|
|
|
return NULL;
|
2014-04-19 12:11:55 +00:00
|
|
|
}
|
|
|
|
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
static void interpret_key(struct input_ctx *ictx, int code, double scale,
|
|
|
|
int scale_units)
|
2013-07-01 21:54:59 +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;
|
|
|
|
|
2019-11-21 20:29:14 +00:00
|
|
|
if (mp_msg_test(ictx->log, MSGL_TRACE)) {
|
2014-04-18 15:45:41 +00:00
|
|
|
char *key = mp_input_get_key_name(code);
|
2017-09-28 09:53:57 +00:00
|
|
|
MP_TRACE(ictx, "key code=%#x '%s'%s%s\n",
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-09-12 23:08:35 +00:00
|
|
|
if (MP_KEY_DEPENDS_ON_MOUSE_POS(code & ~MP_KEY_MODIFIER_MASK)) {
|
2013-09-02 00:26:41 +00:00
|
|
|
ictx->mouse_event_counter++;
|
2014-09-12 23:08:35 +00:00
|
|
|
mp_input_wakeup(ictx);
|
|
|
|
}
|
2013-09-02 00:26:41 +00:00
|
|
|
|
|
|
|
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);
|
2014-11-23 14:08:49 +00:00
|
|
|
if (cmd) {
|
|
|
|
cmd->is_up_down = true;
|
2014-11-24 15:48:34 +00:00
|
|
|
cmd->emit_on_up = (code & MP_KEY_EMIT_ON_UP) || cmd->def->on_updown;
|
|
|
|
ictx->current_down_cmd = mp_cmd_clone(cmd);
|
2014-11-23 14:08:49 +00:00
|
|
|
}
|
2014-04-18 15:45:41 +00:00
|
|
|
ictx->last_key_down = code;
|
2023-10-11 19:04:52 +00:00
|
|
|
ictx->last_key_down_time = mp_time_ns();
|
2014-04-18 15:45:41 +00:00
|
|
|
ictx->ar_state = 0;
|
2014-09-12 23:02:09 +00:00
|
|
|
mp_input_wakeup(ictx); // possibly start timer for autorepeat
|
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
|
2015-01-23 12:02:42 +00:00
|
|
|
// Mixing press events and up/down with the same key is not supported,
|
|
|
|
// and input sources shouldn't do this, but can happen anyway if
|
|
|
|
// multiple input sources interfere with each others.
|
|
|
|
if (ictx->last_key_down == code)
|
|
|
|
release_down_cmd(ictx, false);
|
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.
|
2014-11-24 15:48:34 +00:00
|
|
|
if (cmd->emit_on_up && !cmd->def->on_updown) {
|
2013-09-02 00:26:41 +00:00
|
|
|
talloc_free(cmd);
|
|
|
|
return;
|
2011-04-25 11:12:04 +00:00
|
|
|
}
|
2013-09-02 00:26:41 +00:00
|
|
|
|
input: restore ability to combine mouse buttons
Key bindings are decided on the "down" event, so if the prefix is not
unique, the first/shortest will be used (e.g. when both "a" and "a-b"
are mapped, "a" will always be chosen).
This also breaks combining multiple mouse buttons. But it seems users
expect it to work, and it's indeed a bit strange that it shouldn't work,
as mouse bindings are emitted on the key "up" event, not "down" (if the
shorter binding didn't emit a command yet, why shouldn't it be
combinable).
Deal with this by clearing the key history when a command is actually
emitted, instead of when a command is decided. This means if both
MOUSE_BTN0 and MOUSE_BTN0-MOUSE_BTN1 are mapped, the sequence of holding
down BTN0 and then BTN1 will redecide the current command. On the other
hand, if BTN0 is released before BTN1 is pressed, the command is
emitted, and the key history is deleted. So the BTN1 press will not
trigger BTN0-BTN1.
For normal keys, nothing should change, because commands are emitted on
the "down" event already, so the key history is always cleared.
Might fix #902.
CC: @mpv-player/stable (if this fix is successful)
2014-07-07 16:18:41 +00:00
|
|
|
memset(ictx->key_history, 0, sizeof(ictx->key_history));
|
|
|
|
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
if (mp_input_is_scalable_cmd(cmd)) {
|
|
|
|
cmd->scale = scale;
|
2017-04-25 08:03:06 +00:00
|
|
|
cmd->scale_units = scale_units;
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
mp_input_queue_cmd(ictx, cmd);
|
|
|
|
} else {
|
|
|
|
// Non-scalable commands won't understand cmd->scale, so synthesize
|
|
|
|
// multiple commands with cmd->scale = 1
|
|
|
|
cmd->scale = 1;
|
2017-04-25 08:03:06 +00:00
|
|
|
cmd->scale_units = 1;
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
// Avoid spamming the player with too many commands
|
2019-10-31 10:24:20 +00:00
|
|
|
scale_units = MPMIN(scale_units, 20);
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
for (int i = 0; i < scale_units - 1; i++)
|
|
|
|
mp_input_queue_cmd(ictx, mp_cmd_clone(cmd));
|
|
|
|
if (scale_units)
|
|
|
|
mp_input_queue_cmd(ictx, cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-02 14:00:52 +00:00
|
|
|
// Pre-processing for MP_WHEEL_* events. If this returns false, the caller
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
// should discard the event.
|
2017-09-02 14:00:52 +00:00
|
|
|
static bool process_wheel(struct input_ctx *ictx, int code, double *scale,
|
|
|
|
int *scale_units)
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
{
|
|
|
|
// Size of the deadzone in scroll units. The user must scroll at least this
|
|
|
|
// much in any direction before their scroll is registered.
|
|
|
|
static const double DEADZONE_DIST = 0.125;
|
|
|
|
// The deadzone accumulator is reset if no scrolls happened in this many
|
|
|
|
// seconds, eg. the user is assumed to have finished scrolling.
|
|
|
|
static const double DEADZONE_SCROLL_TIME = 0.2;
|
|
|
|
// The scale_units accumulator is reset if no scrolls happened in this many
|
|
|
|
// seconds. This value should be fairly large, so commands will still be
|
|
|
|
// sent when the user scrolls slowly.
|
|
|
|
static const double UNIT_SCROLL_TIME = 0.5;
|
|
|
|
|
2017-09-02 14:00:52 +00:00
|
|
|
// Determine which direction is being scrolled
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
double dir;
|
2017-09-02 14:00:52 +00:00
|
|
|
struct wheel_state *state;
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
switch (code) {
|
2017-09-02 14:00:52 +00:00
|
|
|
case MP_WHEEL_UP: dir = -1; state = &ictx->wheel_state_y; break;
|
|
|
|
case MP_WHEEL_DOWN: dir = +1; state = &ictx->wheel_state_y; break;
|
|
|
|
case MP_WHEEL_LEFT: dir = -1; state = &ictx->wheel_state_x; break;
|
|
|
|
case MP_WHEEL_RIGHT: dir = +1; state = &ictx->wheel_state_x; break;
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset accumulators if it's determined that the user finished scrolling
|
|
|
|
double now = mp_time_sec();
|
2017-09-02 14:00:52 +00:00
|
|
|
if (now > ictx->last_wheel_time + DEADZONE_SCROLL_TIME) {
|
|
|
|
ictx->wheel_current = NULL;
|
|
|
|
ictx->wheel_state_y.dead_zone_accum = 0;
|
|
|
|
ictx->wheel_state_x.dead_zone_accum = 0;
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
}
|
2017-09-02 14:00:52 +00:00
|
|
|
if (now > ictx->last_wheel_time + UNIT_SCROLL_TIME) {
|
|
|
|
ictx->wheel_state_y.unit_accum = 0;
|
|
|
|
ictx->wheel_state_x.unit_accum = 0;
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
}
|
2017-09-02 14:00:52 +00:00
|
|
|
ictx->last_wheel_time = now;
|
|
|
|
|
|
|
|
// Process wheel deadzone. A lot of touchpad drivers don't filter scroll
|
|
|
|
// input, which makes it difficult for the user to send WHEEL_UP/DOWN
|
|
|
|
// without accidentally triggering WHEEL_LEFT/RIGHT. We try to fix this by
|
|
|
|
// implementing a deadzone. When the value of either direction breaks out
|
|
|
|
// of the deadzone, events from the other direction will be ignored until
|
|
|
|
// the user finishes scrolling.
|
|
|
|
if (ictx->wheel_current == NULL) {
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
state->dead_zone_accum += *scale * dir;
|
|
|
|
if (state->dead_zone_accum * dir > DEADZONE_DIST) {
|
2017-09-02 14:00:52 +00:00
|
|
|
ictx->wheel_current = state;
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
*scale = state->dead_zone_accum * dir;
|
|
|
|
}
|
|
|
|
}
|
2017-09-02 14:00:52 +00:00
|
|
|
if (ictx->wheel_current != state)
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Determine scale_units. This is incremented every time the accumulated
|
|
|
|
// scale value crosses 1.0. Non-scalable input commands will be ran that
|
|
|
|
// many times.
|
|
|
|
state->unit_accum += *scale * dir;
|
|
|
|
*scale_units = trunc(state->unit_accum * dir);
|
|
|
|
state->unit_accum -= *scale_units * dir;
|
|
|
|
return true;
|
2007-08-25 04:28:11 +00:00
|
|
|
}
|
2002-02-11 11:42:08 +00:00
|
|
|
|
2016-02-04 22:01:15 +00:00
|
|
|
static void mp_input_feed_key(struct input_ctx *ictx, int code, double scale,
|
|
|
|
bool force_mouse)
|
2011-07-17 01:47:50 +00:00
|
|
|
{
|
2014-09-27 14:25:29 +00:00
|
|
|
struct input_opts *opts = ictx->opts;
|
|
|
|
|
2014-08-26 18:39:28 +00:00
|
|
|
code = mp_normalize_keycode(code);
|
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) {
|
2017-09-28 09:53:57 +00:00
|
|
|
MP_TRACE(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;
|
|
|
|
}
|
2016-02-04 22:01:15 +00:00
|
|
|
if (!opts->enable_mouse_movements && MP_KEY_IS_MOUSE(unmod) && !force_mouse)
|
2014-07-27 20:00:55 +00:00
|
|
|
return;
|
2015-02-18 20:09:35 +00:00
|
|
|
if (unmod == MP_KEY_MOUSE_LEAVE || unmod == MP_KEY_MOUSE_ENTER) {
|
2019-12-25 18:52:19 +00:00
|
|
|
ictx->mouse_hover = unmod == MP_KEY_MOUSE_ENTER;
|
2015-02-17 05:50:57 +00:00
|
|
|
update_mouse_section(ictx);
|
2019-12-25 18:52:19 +00:00
|
|
|
|
|
|
|
mp_cmd_t *cmd = get_cmd_from_keys(ictx, NULL, code);
|
|
|
|
if (!cmd) // queue dummy cmd so that mouse-pos can notify observers
|
|
|
|
cmd = mp_input_parse_cmd(ictx, bstr0("ignore"), "<internal>");
|
|
|
|
mp_input_queue_cmd(ictx, cmd);
|
2015-02-17 05:50:57 +00:00
|
|
|
return;
|
2013-09-27 13:33:47 +00:00
|
|
|
}
|
2013-07-02 12:00:24 +00:00
|
|
|
double now = mp_time_sec();
|
|
|
|
// ignore system-doubleclick if we generate these events ourselves
|
2016-03-26 19:03:11 +00:00
|
|
|
if (!force_mouse && opts->doubleclick_time && MP_KEY_IS_MOUSE_BTN_DBL(unmod))
|
2013-07-02 12:00:24 +00:00
|
|
|
return;
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
int units = 1;
|
2017-09-02 14:00:52 +00:00
|
|
|
if (MP_KEY_IS_WHEEL(unmod) && !process_wheel(ictx, unmod, &scale, &units))
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
return;
|
|
|
|
interpret_key(ictx, code, scale, units);
|
2013-07-02 12:00:24 +00:00
|
|
|
if (code & MP_KEY_STATE_DOWN) {
|
|
|
|
code &= ~MP_KEY_STATE_DOWN;
|
2014-09-27 14:25:29 +00:00
|
|
|
if (ictx->last_doubleclick_key_down == code &&
|
|
|
|
now - ictx->last_doubleclick_time < opts->doubleclick_time / 1000.0)
|
2013-07-02 12:00:24 +00:00
|
|
|
{
|
input: use mnemonic names for mouse buttons
mpv's mouse button numbering is based on X11 button numbering, which
allows for an arbitrary number of buttons and includes mouse wheel input
as buttons 3-6. This button numbering was used throughout the codebase
and exposed in input.conf, and it was difficult to remember which
physical button each number actually referred to and which referred to
the scroll wheel.
In practice, PC mice only have between two and five buttons and one or
two scroll wheel axes, which are more or less in the same location and
have more or less the same function. This allows us to use names to
refer to the buttons instead of numbers, which makes input.conf syntax a
lot easier to remember. It also makes the syntax robust to changes in
mpv's underlying numbering. The old MOUSE_BTNx names are still
understood as deprecated aliases of the named buttons.
This changes both the input.conf syntax and the MP_MOUSE_BTNx symbols in
the codebase, since I think both would benefit from using names over
numbers, especially since some platforms don't use X11 button numbering
and handle different mouse buttons in different windowing system events.
This also makes the names shorter, since otherwise they would be pretty
long, and it removes the high-numbered MOUSE_BTNx_DBL names, since they
weren't used.
Names are the same as used in Qt:
https://doc.qt.io/qt-5/qt.html#MouseButton-enum
2017-08-08 11:34:38 +00:00
|
|
|
if (code >= MP_MBTN_LEFT && code <= MP_MBTN_RIGHT) {
|
2017-09-02 14:00:52 +00:00
|
|
|
interpret_key(ictx, code - MP_MBTN_BASE + MP_MBTN_DBL_BASE,
|
input: pre-process MP_AXIS_* input
This adds some logic for pre-processing MP_AXIS_* events before the
corresponding input command is generated.
Firstly, the events are filtered. A lot of touchpad drivers and
operating systems don't seem to filter axis events, which makes it
difficult to use the verical axis (MP_AXIS_UP/MP_AXIS_DOWN) without
accidentally triggering commands bound to the horizontal axis
(MP_AXIS_LEFT/MP_AXIS_RIGHT) and vice-versa. To fix this, a small
deadzone is used. When one axis breaks out of the deadzone, events on
the other axis are ignored until the user stops scrolling (determined by
a timer.)
Secondly, the scale_units value is determined, which is the integer
number of "units" the user has scrolled, as opposed to scale, which is
the fractional number of units. It's determed by accumulating the
fractional scale values. If an axis is bound to a "non-scalable" command
that doesn't understand fractional units, interpret_key() will queue
that many commands, each with scale = 1.0.
2017-04-24 12:10:03 +00:00
|
|
|
1, 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);
|
2016-02-04 22:01:15 +00:00
|
|
|
mp_input_feed_key(ictx, code, 1, false);
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_put_key_artificial(struct input_ctx *ictx, int code)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
mp_input_feed_key(ictx, code, 1, true);
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-02 14:00:52 +00:00
|
|
|
void mp_input_put_wheel(struct input_ctx *ictx, int direction, double value)
|
2013-07-25 16:08:57 +00:00
|
|
|
{
|
2013-11-25 18:31:13 +00:00
|
|
|
if (value == 0.0)
|
|
|
|
return;
|
2013-08-26 17:15:35 +00:00
|
|
|
input_lock(ictx);
|
2016-02-04 22:01:15 +00:00
|
|
|
mp_input_feed_key(ictx, direction, value, false);
|
2013-08-26 17:15:35 +00:00
|
|
|
input_unlock(ictx);
|
2013-07-25 16:08:57 +00:00
|
|
|
}
|
|
|
|
|
2014-07-27 19:33:11 +00:00
|
|
|
void mp_input_set_mouse_transform(struct input_ctx *ictx, struct mp_rect *dst,
|
|
|
|
struct mp_rect *src)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
ictx->mouse_mangle = dst || src;
|
|
|
|
if (ictx->mouse_mangle) {
|
|
|
|
ictx->mouse_dst = *dst;
|
|
|
|
ictx->mouse_src_mangle = !!src;
|
|
|
|
if (ictx->mouse_src_mangle)
|
|
|
|
ictx->mouse_src = *src;
|
|
|
|
}
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
2014-07-27 19:53:29 +00:00
|
|
|
bool mp_input_mouse_enabled(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
bool r = ictx->opts->enable_mouse_movements;
|
|
|
|
input_unlock(ictx);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-10-09 16:28:37 +00:00
|
|
|
bool mp_input_vo_keyboard_enabled(struct input_ctx *ictx)
|
client API, X11: change default keyboard input handling again
Commit 64b7811c tried to do the "right thing" with respect to whether
keyboard input should be enabled or not. It turns out that X11 does
something stupid by design. All modern toolkits work around this native
X11 behavior, but embedding breaks these workarounds.
The only way to handle this correctly is the XEmbed protocol. It needs
to be supported by the toolkit, and probably also some mpv support. But
Qt has inconsistent support for it. In Qt 4, a X11 specific embedding
widget was needed. Qt 5.0 doesn't support it at all. Qt 5.1 apparently
supports it via QWindow, but if it really does, I couldn't get it to
work.
So add a hack instead. The new --input-x11-keyboard option controls
whether mpv should enable keyboard input on the X11 window or not. In
the command line player, it's enabled by default, but in libmpv it's
disabled.
This hack has the same problem as all previous embedding had: move the
mouse outside of the window, and you don't get keyboard input anymore.
Likewise, mpv will steal all keyboard input from the parent application
as long as the mouse is inside of the mpv window.
Also see issue #1090.
2014-09-28 18:11:00 +00:00
|
|
|
{
|
|
|
|
input_lock(ictx);
|
2014-10-09 16:28:37 +00:00
|
|
|
bool r = ictx->opts->vo_key_input;
|
client API, X11: change default keyboard input handling again
Commit 64b7811c tried to do the "right thing" with respect to whether
keyboard input should be enabled or not. It turns out that X11 does
something stupid by design. All modern toolkits work around this native
X11 behavior, but embedding breaks these workarounds.
The only way to handle this correctly is the XEmbed protocol. It needs
to be supported by the toolkit, and probably also some mpv support. But
Qt has inconsistent support for it. In Qt 4, a X11 specific embedding
widget was needed. Qt 5.0 doesn't support it at all. Qt 5.1 apparently
supports it via QWindow, but if it really does, I couldn't get it to
work.
So add a hack instead. The new --input-x11-keyboard option controls
whether mpv should enable keyboard input on the X11 window or not. In
the command line player, it's enabled by default, but in libmpv it's
disabled.
This hack has the same problem as all previous embedding had: move the
mouse outside of the window, and you don't get keyboard input anymore.
Likewise, mpv will steal all keyboard input from the parent application
as long as the mouse is inside of the mpv window.
Also see issue #1090.
2014-09-28 18:11:00 +00:00
|
|
|
input_unlock(ictx);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
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)
|
2016-02-04 22:01:15 +00:00
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
if (ictx->opts->enable_mouse_movements)
|
|
|
|
mp_input_set_mouse_pos_artificial(ictx, x, y);
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_set_mouse_pos_artificial(struct input_ctx *ictx, int x, int y)
|
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-08-26 17:15:35 +00:00
|
|
|
input_lock(ictx);
|
2017-09-28 09:53:57 +00:00
|
|
|
MP_TRACE(ictx, "mouse move %d/%d\n", x, y);
|
2013-08-30 00:30:17 +00:00
|
|
|
|
2016-02-04 22:01:15 +00:00
|
|
|
if (ictx->mouse_vo_x == x && ictx->mouse_vo_y == y) {
|
2014-07-27 19:53:29 +00:00
|
|
|
input_unlock(ictx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-27 19:33:11 +00:00
|
|
|
if (ictx->mouse_mangle) {
|
|
|
|
struct mp_rect *src = &ictx->mouse_src;
|
|
|
|
struct mp_rect *dst = &ictx->mouse_dst;
|
|
|
|
x = MPCLAMP(x, dst->x0, dst->x1) - dst->x0;
|
|
|
|
y = MPCLAMP(y, dst->y0, dst->y1) - dst->y0;
|
|
|
|
if (ictx->mouse_src_mangle) {
|
|
|
|
x = x * 1.0 / (dst->x1 - dst->x0) * (src->x1 - src->x0) + src->x0;
|
|
|
|
y = y * 1.0 / (dst->y1 - dst->y0) * (src->y1 - src->y0) + src->y0;
|
|
|
|
}
|
2017-09-28 09:53:57 +00:00
|
|
|
MP_TRACE(ictx, "-> %d/%d\n", x, y);
|
2014-07-27 19:33:11 +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);
|
|
|
|
}
|
2014-09-12 23:08:35 +00:00
|
|
|
mp_input_queue_cmd(ictx, cmd);
|
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
|
|
|
|
2014-09-10 01:16:43 +00:00
|
|
|
// adjust min time to wait until next repeat event
|
|
|
|
static void adjust_max_wait_time(struct input_ctx *ictx, double *time)
|
2013-07-07 14:53:35 +00:00
|
|
|
{
|
2014-09-27 14:25:29 +00:00
|
|
|
struct input_opts *opts = ictx->opts;
|
|
|
|
if (ictx->last_key_down && opts->ar_rate > 0 && ictx->ar_state >= 0) {
|
2019-10-31 10:24:20 +00:00
|
|
|
*time = MPMIN(*time, 1.0 / opts->ar_rate);
|
|
|
|
*time = MPMIN(*time, opts->ar_delay / 1000.0);
|
2002-01-30 12:46:03 +00:00
|
|
|
}
|
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);
|
2014-09-12 23:08:35 +00:00
|
|
|
if (cmd) {
|
2013-09-02 00:29:20 +00:00
|
|
|
queue_add_tail(&ictx->cmd_queue, cmd);
|
2014-09-12 23:08:35 +00:00
|
|
|
mp_input_wakeup(ictx);
|
|
|
|
}
|
2013-08-26 17:15:35 +00:00
|
|
|
input_unlock(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)
|
|
|
|
{
|
2014-09-27 14:25:29 +00:00
|
|
|
struct input_opts *opts = ictx->opts;
|
|
|
|
|
2013-09-07 23:44:47 +00:00
|
|
|
// No input : autorepeat ?
|
2014-09-27 14:25:29 +00:00
|
|
|
if (opts->ar_rate <= 0 || !ictx->current_down_cmd || !ictx->last_key_down ||
|
2014-09-12 23:08:35 +00:00
|
|
|
(ictx->last_key_down & MP_NO_REPEAT_KEY) ||
|
|
|
|
!mp_input_is_repeatable_cmd(ictx->current_down_cmd))
|
2014-04-18 16:13:58 +00:00
|
|
|
ictx->ar_state = -1; // disable
|
2014-11-24 15:48:34 +00:00
|
|
|
|
2014-04-18 16:13:58 +00:00
|
|
|
if (ictx->ar_state >= 0) {
|
2023-10-11 19:04:52 +00:00
|
|
|
int64_t t = mp_time_ns();
|
|
|
|
if (ictx->last_ar + MP_TIME_S_TO_NS(2) < t)
|
2013-09-07 23:44:47 +00:00
|
|
|
ictx->last_ar = t;
|
|
|
|
// First time : wait delay
|
|
|
|
if (ictx->ar_state == 0
|
2023-10-11 19:04:52 +00:00
|
|
|
&& (t - ictx->last_key_down_time) >= MP_TIME_MS_TO_NS(opts->ar_delay))
|
2013-09-07 23:44:47 +00:00
|
|
|
{
|
|
|
|
ictx->ar_state = 1;
|
2023-10-11 19:04:52 +00:00
|
|
|
ictx->last_ar = ictx->last_key_down_time + MP_TIME_MS_TO_NS(opts->ar_delay);
|
2013-09-07 23:44:47 +00:00
|
|
|
// Then send rate / sec event
|
|
|
|
} else if (ictx->ar_state == 1
|
2023-10-11 19:04:52 +00:00
|
|
|
&& (t - ictx->last_ar) >= 1e9 / opts->ar_rate) {
|
|
|
|
ictx->last_ar += 1e9 / opts->ar_rate;
|
2014-11-24 15:48:34 +00:00
|
|
|
} else {
|
|
|
|
return NULL;
|
2013-09-07 23:44:47 +00:00
|
|
|
}
|
2014-11-24 15:48:34 +00:00
|
|
|
struct mp_cmd *ret = mp_cmd_clone(ictx->current_down_cmd);
|
|
|
|
ret->repeated = true;
|
|
|
|
return ret;
|
2013-09-07 23:44:47 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-09-16 12:25:50 +00:00
|
|
|
double mp_input_get_delay(struct input_ctx *ictx)
|
2014-09-07 18:44:54 +00:00
|
|
|
{
|
|
|
|
input_lock(ictx);
|
2016-09-16 12:25:50 +00:00
|
|
|
double seconds = INFINITY;
|
2014-09-10 01:16:43 +00:00
|
|
|
adjust_max_wait_time(ictx, &seconds);
|
|
|
|
input_unlock(ictx);
|
2016-09-16 12:25:50 +00:00
|
|
|
return seconds;
|
2014-09-10 01:16:43 +00:00
|
|
|
}
|
|
|
|
|
2014-09-20 02:19:41 +00:00
|
|
|
void mp_input_wakeup(struct input_ctx *ictx)
|
2014-09-10 01:16:43 +00:00
|
|
|
{
|
2016-09-16 12:25:50 +00:00
|
|
|
ictx->wakeup_cb(ictx->wakeup_ctx);
|
2014-09-07 18:44:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mp_cmd_t *mp_input_read_cmd(struct input_ctx *ictx)
|
2008-04-30 04:15:52 +00:00
|
|
|
{
|
2013-08-26 17:15:35 +00:00
|
|
|
input_lock(ictx);
|
2014-09-12 23:08:35 +00:00
|
|
|
struct mp_cmd *ret = queue_remove_head(&ictx->cmd_queue);
|
2014-11-24 15:48:34 +00:00
|
|
|
if (!ret)
|
2014-09-12 23:08:35 +00:00
|
|
|
ret = check_autorepeat(ictx);
|
|
|
|
if (ret && ret->mouse_move) {
|
|
|
|
ictx->mouse_x = ret->mouse_x;
|
|
|
|
ictx->mouse_y = ret->mouse_y;
|
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-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
|
|
|
}
|
|
|
|
|
2019-12-25 18:52:19 +00:00
|
|
|
void mp_input_get_mouse_pos(struct input_ctx *ictx, int *x, int *y, int *hover)
|
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-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;
|
2019-12-25 18:52:19 +00:00
|
|
|
*hover = ictx->mouse_hover;
|
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);
|
|
|
|
|
2018-04-26 16:29:19 +00:00
|
|
|
MP_TRACE(ictx, "enable section '%s'\n", name);
|
2013-12-26 16:41:28 +00:00
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-04-26 16:29:19 +00:00
|
|
|
MP_TRACE(ictx, "active section stack:\n");
|
2013-12-26 16:41:28 +00:00
|
|
|
for (int n = 0; n < ictx->num_active_sections; n++) {
|
2018-04-26 16:29:19 +00:00
|
|
|
MP_TRACE(ictx, " %s %d\n", ictx->active_sections[n].name,
|
|
|
|
ictx->active_sections[n].flags);
|
2013-12-26 16:41:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2014-05-20 00:40:00 +00:00
|
|
|
input_lock(ictx);
|
2016-09-21 13:56:54 +00:00
|
|
|
bool r = !ictx->opts->allow_win_drag ||
|
|
|
|
test_mouse(ictx, x, y, MP_INPUT_ALLOW_VO_DRAGGING);
|
2014-05-20 00:40:00 +00:00
|
|
|
input_unlock(ictx);
|
|
|
|
return r;
|
2013-12-26 16:41:28 +00:00
|
|
|
}
|
|
|
|
|
2013-06-22 22:40:35 +00:00
|
|
|
static void bind_dealloc(struct cmd_bind *bind)
|
|
|
|
{
|
|
|
|
talloc_free(bind->cmd);
|
|
|
|
talloc_free(bind->location);
|
2019-11-23 13:14:19 +00:00
|
|
|
talloc_free(bind->desc);
|
2013-06-22 22:40:35 +00:00
|
|
|
}
|
|
|
|
|
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,
|
2016-09-20 13:31:25 +00:00
|
|
|
char *contents, bool builtin, char *owner)
|
2013-12-26 16:41:28 +00:00
|
|
|
{
|
|
|
|
if (!name || !name[0])
|
|
|
|
return; // parse_config() changes semantics with restrict_section==empty
|
|
|
|
input_lock(ictx);
|
2014-12-03 14:44:41 +00:00
|
|
|
// Delete:
|
|
|
|
struct cmd_bind_section *bs = get_bind_section(ictx, bstr0(name));
|
2016-09-20 13:31:25 +00:00
|
|
|
if ((!bs->owner || (owner && strcmp(bs->owner, owner) != 0)) &&
|
|
|
|
strcmp(bs->section, "default") != 0)
|
|
|
|
{
|
|
|
|
talloc_free(bs->owner);
|
|
|
|
bs->owner = talloc_strdup(bs, owner);
|
|
|
|
}
|
2014-12-03 14:44:41 +00:00
|
|
|
remove_binds(bs, builtin);
|
2015-08-05 22:16:17 +00:00
|
|
|
if (contents && contents[0]) {
|
2014-12-03 14:44:41 +00:00
|
|
|
// Redefine:
|
2013-12-26 16:41:28 +00:00
|
|
|
parse_config(ictx, builtin, bstr0(contents), location, name);
|
|
|
|
} else {
|
|
|
|
// Disable:
|
|
|
|
mp_input_disable_section(ictx, name);
|
|
|
|
}
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
2016-09-20 13:31:25 +00:00
|
|
|
void mp_input_remove_sections_by_owner(struct input_ctx *ictx, char *owner)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
2019-11-23 14:00:48 +00:00
|
|
|
for (int n = 0; n < ictx->num_sections; n++) {
|
|
|
|
struct cmd_bind_section *bs = ictx->sections[n];
|
2016-09-20 13:31:25 +00:00
|
|
|
if (bs->owner && owner && strcmp(bs->owner, owner) == 0) {
|
|
|
|
mp_input_disable_section(ictx, bs->section);
|
|
|
|
remove_binds(bs, false);
|
|
|
|
remove_binds(bs, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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,
|
2019-11-23 00:09:09 +00:00
|
|
|
const char *loc, const char *desc)
|
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),
|
2019-11-23 00:09:09 +00:00
|
|
|
.desc = talloc_strdup(bs->binds, desc),
|
2013-06-22 22:40:35 +00:00
|
|
|
.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);
|
2018-04-26 16:29:19 +00:00
|
|
|
MP_TRACE(ictx, "add: section='%s' key='%s'%s cmd='%s' location='%s'\n",
|
|
|
|
bind->owner->section, s, bind->is_builtin ? " builtin" : "",
|
|
|
|
bind->cmd, bind->location);
|
2014-02-17 01:35:16 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-23 00:09:09 +00:00
|
|
|
// Print warnings if invalid commands are encountered.
|
|
|
|
struct mp_cmd *cmd = mp_input_parse_cmd(ictx, command, cur_loc);
|
|
|
|
const char *desc = NULL;
|
|
|
|
if (cmd) {
|
|
|
|
desc = cmd->desc;
|
|
|
|
command = bstr0(cmd->original);
|
|
|
|
}
|
|
|
|
|
|
|
|
bind_keys(ictx, builtin, section, keys, num_keys, command, cur_loc, desc);
|
2011-07-20 01:41:51 +00:00
|
|
|
n_binds++;
|
2012-09-22 04:33:04 +00:00
|
|
|
|
2019-11-23 00:09:09 +00:00
|
|
|
talloc_free(cmd);
|
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);
|
2014-10-29 21:54:03 +00:00
|
|
|
|
stream, demux: redo origin policy thing
mpv has a very weak and very annoying policy that determines whether a
playlist should be used or not. For example, if you play a remote
playlist, you usually don't want it to be able to read local filesystem
entries. (Although for a media player the impact is small I guess.)
It's weak and annoying as in that it does not prevent certain cases
which could be interpreted as bad in some cases, such as allowing
playlists on the local filesystem to reference remote URLs. It probably
barely makes sense, but we just want to exclude some other "definitely
not a good idea" things, all while playlists generally just work, so
whatever.
The policy is:
- from the command line anything is played
- local playlists can reference anything except "unsafe" streams
("unsafe" means special stream inputs like libavfilter graphs)
- remote playlists can reference only remote URLs
- things like "memory://" and archives are "transparent" to this
This commit does... something. It replaces the weird stream flags with a
slightly clearer "origin" value, which is now consequently passed down
and used everywhere. It fixes some deviations from the described policy.
I wanted to force archives to reference only content within them, but
this would probably have been more complicated (or required different
abstractions), and I'm too lazy to figure it out, so archives are now
"transparent" (playlists within archives behave the same outside).
There may be a lot of bugs in this.
This is unfortunately a very noisy commit because:
- every stream open call now needs to pass the origin
- so does every demuxer open call (=> params param. gets mandatory)
- most stream were changed to provide the "origin" value
- the origin value needed to be passed along in a lot of places
- I was too lazy to split the commit
Fixes: #7274
2019-12-20 08:41:42 +00:00
|
|
|
s = stream_create(file, STREAM_ORIGIN_DIRECT | STREAM_READ, NULL, 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
|
|
|
}
|
2014-07-12 19:25:32 +00:00
|
|
|
stream_skip_bom(s);
|
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
|
|
|
}
|
|
|
|
|
2016-09-16 12:25:50 +00:00
|
|
|
struct input_ctx *mp_input_init(struct mpv_global *global,
|
|
|
|
void (*wakeup_cb)(void *ctx),
|
|
|
|
void *wakeup_ctx)
|
2008-04-30 04:15:52 +00:00
|
|
|
{
|
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,
|
2008-04-30 04:15:52 +00:00
|
|
|
.ar_state = -1,
|
2014-09-27 13:47:49 +00:00
|
|
|
.log = mp_log_new(ictx, global->log, "input"),
|
2013-08-30 00:24:14 +00:00
|
|
|
.mouse_section = "default",
|
2016-09-06 18:09:44 +00:00
|
|
|
.opts_cache = m_config_cache_alloc(ictx, global, &input_config),
|
2016-09-16 12:25:50 +00:00
|
|
|
.wakeup_cb = wakeup_cb,
|
|
|
|
.wakeup_ctx = wakeup_ctx,
|
2008-04-30 04:15:52 +00:00
|
|
|
};
|
2013-08-26 17:15:35 +00:00
|
|
|
|
2016-09-06 18:09:44 +00:00
|
|
|
ictx->opts = ictx->opts_cache->opts;
|
|
|
|
|
2023-10-21 02:55:41 +00:00
|
|
|
mp_mutex_init_type(&ictx->mutex, MP_MUTEX_RECURSIVE);
|
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);
|
2012-08-01 20:45:35 +00:00
|
|
|
|
2014-09-27 13:47:49 +00:00
|
|
|
return ictx;
|
|
|
|
}
|
|
|
|
|
2016-09-21 13:56:54 +00:00
|
|
|
static void reload_opts(struct input_ctx *ictx, bool shutdown)
|
2014-09-27 13:47:49 +00:00
|
|
|
{
|
2016-09-06 18:09:44 +00:00
|
|
|
m_config_cache_update(ictx->opts_cache);
|
2014-09-27 13:47:49 +00:00
|
|
|
|
2016-09-21 13:56:54 +00:00
|
|
|
#if HAVE_COCOA
|
|
|
|
struct input_opts *opts = ictx->opts;
|
|
|
|
|
|
|
|
if (ictx->using_cocoa_media_keys != (opts->use_media_keys && !shutdown)) {
|
|
|
|
ictx->using_cocoa_media_keys = !ictx->using_cocoa_media_keys;
|
|
|
|
if (ictx->using_cocoa_media_keys) {
|
|
|
|
cocoa_init_media_keys();
|
|
|
|
} else {
|
|
|
|
cocoa_uninit_media_keys();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_update_opts(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
reload_opts(ictx, false);
|
|
|
|
input_unlock(ictx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mp_input_load_config(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
|
|
|
|
reload_opts(ictx, false);
|
|
|
|
|
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);
|
input: new option: --no-input-builtin-bindings
This is similar to [no-]input-default-bindings, but affects only
builtin bindings (while input-default-bindings affects anything which
config files can override, like scripting mp.add_key_binding).
Arguably, this is what input-default-binding should have always done,
however, it does not.
The reason we add a new option rather than repurpose/modify the
existing option is that it behaves differently enough to raise
concerns that it will break some use cases for existing users:
- The new option is only applied once on startup, while
input-default-bindings can be modified effectively at runtime.
- They affects different sets of bindings, and it's possible that
the set of input-default-bindings is useful enough to keep.
Implementation-wise, both options are trivial, so keeping one or the
other or both doesn't affect code complexity.
It could be argued that it would be useful to make the new option
also effective for runtime changes, however, this opens a can of
worms of how the bindings are stored beyond the initial setup.
TL;DR: it's impossible to differentiate correctly at runtime between
builtin bindings, and those added with mp.add_key_bindings.
The gist is that technically mpv needs/uses two binding "classes":
- weak/builtin bindings - lower priority than config files.
- "user" bindings - config files and "forced" runtime bindings.
input-default-bindings affects the first class trivially, but
input-builtin-bindings would not be able split this class further
at runtime without meaningful changes to a lot of delicate code.
So a new option it is. It should be useful to some libmpv clients
(players) which want to disable mpv's builtin bindings without
breaking mp.add_key_bindings for scripts.
Fixes #8809
(again. the previous fix 8edfe70b only improved the docs, while
now we're actually making the requested behavior possible)
2021-10-06 23:18:19 +00:00
|
|
|
while (ictx->opts->builtin_bindings && builtin.len) {
|
2013-09-01 15:06:11 +00:00
|
|
|
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
|
|
|
|
2013-02-08 22:52:06 +00:00
|
|
|
bool config_ok = false;
|
2016-09-21 13:56:54 +00:00
|
|
|
if (ictx->opts->config_file && ictx->opts->config_file[0])
|
|
|
|
config_ok = parse_config_file(ictx, ictx->opts->config_file, true);
|
2015-09-05 13:33:19 +00:00
|
|
|
if (!config_ok) {
|
2011-04-25 08:38:46 +00:00
|
|
|
// Try global conf dir
|
2014-10-29 21:54:03 +00:00
|
|
|
void *tmp = talloc_new(NULL);
|
|
|
|
char **files = mp_find_all_config_files(tmp, ictx->global, "input.conf");
|
|
|
|
for (int n = 0; files && files[n]; n++)
|
2016-07-04 08:50:00 +00:00
|
|
|
parse_config_file(ictx, files[n], false);
|
2014-10-29 21:54:03 +00:00
|
|
|
talloc_free(tmp);
|
2013-02-08 22:52:06 +00:00
|
|
|
}
|
2002-01-30 12:46:03 +00:00
|
|
|
|
2019-10-22 14:41:19 +00:00
|
|
|
#if HAVE_SDL2_GAMEPAD
|
|
|
|
if (ictx->opts->use_gamepad) {
|
|
|
|
mp_input_sdl_gamepad_add(ictx);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-09-21 13:56:54 +00:00
|
|
|
input_unlock(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;
|
|
|
|
|
2016-09-21 13:56:54 +00:00
|
|
|
input_lock(ictx);
|
|
|
|
reload_opts(ictx, true);
|
|
|
|
input_unlock(ictx);
|
2013-06-02 22:52:40 +00:00
|
|
|
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
close_input_sources(ictx);
|
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);
|
2023-10-21 02:55:41 +00:00
|
|
|
mp_mutex_destroy(&ictx->mutex);
|
2011-04-25 08:38:46 +00:00
|
|
|
talloc_free(ictx);
|
2002-01-30 12:46:03 +00:00
|
|
|
}
|
|
|
|
|
2013-12-01 05:23:39 +00:00
|
|
|
bool mp_input_use_alt_gr(struct input_ctx *ictx)
|
|
|
|
{
|
2016-09-21 13:56:54 +00:00
|
|
|
input_lock(ictx);
|
|
|
|
bool r = ictx->opts->use_alt_gr;
|
|
|
|
input_unlock(ictx);
|
|
|
|
return r;
|
2013-12-01 05:23:39 +00:00
|
|
|
}
|
2013-12-26 16:10:35 +00:00
|
|
|
|
2017-07-25 13:51:40 +00:00
|
|
|
bool mp_input_use_media_keys(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
bool r = ictx->opts->use_media_keys;
|
|
|
|
input_unlock(ictx);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-12-26 16:10:35 +00:00
|
|
|
struct mp_cmd *mp_input_parse_cmd(struct input_ctx *ictx, bstr str,
|
|
|
|
const char *location)
|
|
|
|
{
|
2018-05-01 01:36:39 +00:00
|
|
|
return mp_input_parse_cmd_str(ictx->log, str, location);
|
2013-12-26 16:10:35 +00:00
|
|
|
}
|
2014-01-04 15:59:22 +00:00
|
|
|
|
2014-10-10 20:58:28 +00:00
|
|
|
void mp_input_run_cmd(struct input_ctx *ictx, const char **cmd)
|
2014-01-04 15:59:22 +00:00
|
|
|
{
|
2014-10-10 20:58:28 +00:00
|
|
|
mp_input_queue_cmd(ictx, mp_input_parse_cmd_strv(ictx->log, cmd));
|
2014-01-04 15:59:22 +00:00
|
|
|
}
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
|
2019-09-02 02:06:09 +00:00
|
|
|
void mp_input_bind_key(struct input_ctx *ictx, int key, bstr command)
|
|
|
|
{
|
2019-11-23 14:00:48 +00:00
|
|
|
struct cmd_bind_section *bs = get_bind_section(ictx, (bstr){0});
|
2019-09-02 02:06:09 +00:00
|
|
|
struct cmd_bind *bind = NULL;
|
|
|
|
|
|
|
|
for (int n = 0; n < bs->num_binds; n++) {
|
|
|
|
struct cmd_bind *b = &bs->binds[n];
|
|
|
|
if (bind_matches_key(b, 1, &key) && b->is_builtin == false) {
|
|
|
|
bind = b;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bind) {
|
|
|
|
struct cmd_bind empty = {{0}};
|
|
|
|
MP_TARRAY_APPEND(bs, bs->binds, bs->num_binds, empty);
|
|
|
|
bind = &bs->binds[bs->num_binds - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
bind_dealloc(bind);
|
|
|
|
|
|
|
|
*bind = (struct cmd_bind) {
|
|
|
|
.cmd = bstrdup0(bs->binds, command),
|
|
|
|
.location = talloc_strdup(bs->binds, "keybind-command"),
|
|
|
|
.owner = bs,
|
2023-02-20 05:44:22 +00:00
|
|
|
.is_builtin = false,
|
2019-09-02 02:06:09 +00:00
|
|
|
.num_keys = 1,
|
|
|
|
};
|
|
|
|
memcpy(bind->keys, &key, 1 * sizeof(bind->keys[0]));
|
|
|
|
if (mp_msg_test(ictx->log, MSGL_DEBUG)) {
|
|
|
|
char *s = mp_input_get_key_combo_name(&key, 1);
|
|
|
|
MP_TRACE(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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-22 23:39:07 +00:00
|
|
|
struct mpv_node mp_input_get_bindings(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
input_lock(ictx);
|
|
|
|
struct mpv_node root;
|
|
|
|
node_init(&root, MPV_FORMAT_NODE_ARRAY, NULL);
|
|
|
|
|
2019-11-23 14:00:48 +00:00
|
|
|
for (int x = 0; x < ictx->num_sections; x++) {
|
|
|
|
struct cmd_bind_section *s = ictx->sections[x];
|
2019-11-22 23:39:07 +00:00
|
|
|
int priority = -1;
|
|
|
|
|
|
|
|
for (int i = 0; i < ictx->num_active_sections; i++) {
|
|
|
|
struct active_section *as = &ictx->active_sections[i];
|
|
|
|
if (strcmp(as->name, s->section) == 0) {
|
|
|
|
priority = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int n = 0; n < s->num_binds; n++) {
|
|
|
|
struct cmd_bind *b = &s->binds[n];
|
|
|
|
struct mpv_node *entry = node_array_add(&root, MPV_FORMAT_NODE_MAP);
|
|
|
|
|
|
|
|
int b_priority = priority;
|
|
|
|
if (b->is_builtin && !ictx->opts->default_bindings)
|
|
|
|
b_priority = -1;
|
|
|
|
|
|
|
|
// Try to fixup the weird logic so consumer of this bindings list
|
|
|
|
// does not get too confused.
|
|
|
|
if (b_priority >= 0 && !b->is_builtin)
|
|
|
|
b_priority += ictx->num_active_sections;
|
|
|
|
|
|
|
|
node_map_add_string(entry, "section", s->section);
|
|
|
|
if (s->owner)
|
|
|
|
node_map_add_string(entry, "owner", s->owner);
|
|
|
|
node_map_add_string(entry, "cmd", b->cmd);
|
|
|
|
node_map_add_flag(entry, "is_weak", b->is_builtin);
|
|
|
|
node_map_add_int64(entry, "priority", b_priority);
|
2019-11-23 00:09:09 +00:00
|
|
|
if (b->desc)
|
|
|
|
node_map_add_string(entry, "comment", b->desc);
|
2019-11-22 23:39:07 +00:00
|
|
|
|
|
|
|
char *key = mp_input_get_key_combo_name(b->keys, b->num_keys);
|
|
|
|
node_map_add_string(entry, "key", key);
|
|
|
|
talloc_free(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
input_unlock(ictx);
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
2014-09-09 20:11:45 +00:00
|
|
|
struct mp_input_src_internal {
|
2023-10-21 02:55:41 +00:00
|
|
|
mp_thread thread;
|
2014-09-09 21:44:38 +00:00
|
|
|
bool thread_running;
|
|
|
|
bool init_done;
|
|
|
|
|
2014-09-09 20:11:45 +00:00
|
|
|
char *cmd_buffer;
|
|
|
|
size_t cmd_buffer_size;
|
|
|
|
bool drop;
|
|
|
|
};
|
|
|
|
|
2015-05-26 20:00:25 +00:00
|
|
|
static struct mp_input_src *mp_input_add_src(struct input_ctx *ictx)
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
{
|
|
|
|
input_lock(ictx);
|
2014-09-10 01:16:43 +00:00
|
|
|
if (ictx->num_sources == MP_MAX_SOURCES) {
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
input_unlock(ictx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char name[80];
|
|
|
|
snprintf(name, sizeof(name), "#%d", ictx->num_sources + 1);
|
|
|
|
struct mp_input_src *src = talloc_ptrtype(NULL, src);
|
|
|
|
*src = (struct mp_input_src){
|
|
|
|
.global = ictx->global,
|
|
|
|
.log = mp_log_new(src, ictx->log, name),
|
|
|
|
.input_ctx = ictx,
|
2015-05-26 20:00:25 +00:00
|
|
|
.in = talloc_zero(src, struct mp_input_src_internal),
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ictx->sources[ictx->num_sources++] = src;
|
|
|
|
|
|
|
|
input_unlock(ictx);
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
2015-05-26 20:00:25 +00:00
|
|
|
static void mp_input_src_kill(struct mp_input_src *src);
|
|
|
|
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
static void close_input_sources(struct input_ctx *ictx)
|
|
|
|
{
|
|
|
|
// To avoid lock-order issues, we first remove each source from the context,
|
|
|
|
// and then destroy it.
|
|
|
|
while (1) {
|
|
|
|
input_lock(ictx);
|
|
|
|
struct mp_input_src *src = ictx->num_sources ? ictx->sources[0] : NULL;
|
|
|
|
input_unlock(ictx);
|
|
|
|
if (!src)
|
|
|
|
break;
|
|
|
|
mp_input_src_kill(src);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-26 20:00:25 +00:00
|
|
|
static void mp_input_src_kill(struct mp_input_src *src)
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
{
|
|
|
|
if (!src)
|
|
|
|
return;
|
|
|
|
struct input_ctx *ictx = src->input_ctx;
|
|
|
|
input_lock(ictx);
|
|
|
|
for (int n = 0; n < ictx->num_sources; n++) {
|
|
|
|
if (ictx->sources[n] == src) {
|
|
|
|
MP_TARRAY_REMOVE_AT(ictx->sources, ictx->num_sources, n);
|
|
|
|
input_unlock(ictx);
|
2014-09-14 14:21:04 +00:00
|
|
|
if (src->cancel)
|
|
|
|
src->cancel(src);
|
2014-09-09 21:44:38 +00:00
|
|
|
if (src->in->thread_running)
|
2023-10-21 02:55:41 +00:00
|
|
|
mp_thread_join(src->in->thread);
|
2014-09-14 14:21:04 +00:00
|
|
|
if (src->uninit)
|
|
|
|
src->uninit(src);
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
talloc_free(src);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2023-01-10 18:26:51 +00:00
|
|
|
MP_ASSERT_UNREACHABLE();
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 21:44:38 +00:00
|
|
|
void mp_input_src_init_done(struct mp_input_src *src)
|
|
|
|
{
|
|
|
|
assert(!src->in->init_done);
|
|
|
|
assert(src->in->thread_running);
|
2023-10-22 00:34:42 +00:00
|
|
|
assert(mp_thread_id_equal(mp_thread_get_id(src->in->thread), mp_thread_current_id()));
|
2014-09-09 21:44:38 +00:00
|
|
|
src->in->init_done = true;
|
|
|
|
mp_rendezvous(&src->in->init_done, 0);
|
|
|
|
}
|
|
|
|
|
2023-10-21 02:55:41 +00:00
|
|
|
static MP_THREAD_VOID input_src_thread(void *ptr)
|
2014-09-09 21:44:38 +00:00
|
|
|
{
|
|
|
|
void **args = ptr;
|
|
|
|
struct mp_input_src *src = args[0];
|
|
|
|
void (*loop_fn)(struct mp_input_src *src, void *ctx) = args[1];
|
|
|
|
void *ctx = args[2];
|
|
|
|
|
2023-10-21 02:55:41 +00:00
|
|
|
mp_thread_set_name("input");
|
2014-10-19 21:32:34 +00:00
|
|
|
|
2014-09-09 21:44:38 +00:00
|
|
|
src->in->thread_running = true;
|
|
|
|
|
|
|
|
loop_fn(src, ctx);
|
|
|
|
|
|
|
|
if (!src->in->init_done)
|
|
|
|
mp_rendezvous(&src->in->init_done, -1);
|
|
|
|
|
2023-10-21 02:55:41 +00:00
|
|
|
MP_THREAD_RETURN();
|
2014-09-09 21:44:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int mp_input_add_thread_src(struct input_ctx *ictx, void *ctx,
|
|
|
|
void (*loop_fn)(struct mp_input_src *src, void *ctx))
|
|
|
|
{
|
|
|
|
struct mp_input_src *src = mp_input_add_src(ictx);
|
|
|
|
if (!src)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
void *args[] = {src, loop_fn, ctx};
|
2023-10-21 02:55:41 +00:00
|
|
|
if (mp_thread_create(&src->in->thread, input_src_thread, args)) {
|
2014-09-09 21:44:38 +00:00
|
|
|
mp_input_src_kill(src);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (mp_rendezvous(&src->in->init_done, 0) < 0) {
|
|
|
|
mp_input_src_kill(src);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
#define CMD_BUFFER (4 * 4096)
|
|
|
|
|
|
|
|
void mp_input_src_feed_cmd_text(struct mp_input_src *src, char *buf, size_t len)
|
|
|
|
{
|
2014-09-09 20:11:45 +00:00
|
|
|
struct mp_input_src_internal *in = src->in;
|
|
|
|
if (!in->cmd_buffer)
|
|
|
|
in->cmd_buffer = talloc_size(in, CMD_BUFFER);
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
while (len) {
|
|
|
|
char *next = memchr(buf, '\n', len);
|
|
|
|
bool term = !!next;
|
|
|
|
next = next ? next + 1 : buf + len;
|
|
|
|
size_t copy = next - buf;
|
2014-09-09 20:11:45 +00:00
|
|
|
bool overflow = copy > CMD_BUFFER - in->cmd_buffer_size;
|
|
|
|
if (overflow || in->drop) {
|
|
|
|
in->cmd_buffer_size = 0;
|
|
|
|
in->drop = overflow || !term;
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
MP_WARN(src, "Dropping overlong line.\n");
|
|
|
|
} else {
|
2014-09-09 20:11:45 +00:00
|
|
|
memcpy(in->cmd_buffer + in->cmd_buffer_size, buf, copy);
|
|
|
|
in->cmd_buffer_size += copy;
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
buf += copy;
|
|
|
|
len -= copy;
|
|
|
|
if (term) {
|
2014-09-09 20:11:45 +00:00
|
|
|
bstr s = {in->cmd_buffer, in->cmd_buffer_size};
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
s = bstr_strip(s);
|
2018-05-01 01:36:39 +00:00
|
|
|
struct mp_cmd *cmd = mp_input_parse_cmd_str(src->log, s, "<>");
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
if (cmd)
|
|
|
|
mp_input_queue_cmd(src->input_ctx, cmd);
|
2014-09-09 20:11:45 +00:00
|
|
|
in->cmd_buffer_size = 0;
|
input: redo how --input-file is handled
Abandon the "old" infrastructure for --input-file (mp_input_add_fd(),
select() loop, non-blocking reads). Replace it with something that
starts a reader thread, using blocking input.
This is for the sake of Windows. Windows is a truly insane operating
system, and there's not even a way to read a pipe in a non-blocking
way, or to wait for new input in an interruptible way (like with
poll()). And unfortunately, some want to use pipe to send input to
mpv. There are probably (slightly) better IPC mechanisms available
on Windows, but for the sake of platform uniformity, make this work
again for now.
On Vista+, CancelIoEx() could probably be used. But there's no way on
XP. Also, that function doesn't work on wine, making development
harder. We could forcibly terminate the thread, which might work, but
is unsafe. So what we do is starting a thread, and if we don't want
the pipe input anymore, we just abandon the thread. The thread might
remain blocked forever, but if we exit the process, the kernel will
forcibly kill it. On Unix, just use poll() to handle this.
Unfortunately the code is pretty crappy, but it's ok, because it's late
and I wanted to stop working on this an hour ago.
Tested on wine; might not work on a real Windows.
2014-08-24 21:50:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-19 15:36:37 +00:00
|
|
|
|
|
|
|
void mp_input_set_repeat_info(struct input_ctx *ictx, int rate, int delay)
|
|
|
|
{
|
2014-09-19 15:48:06 +00:00
|
|
|
input_lock(ictx);
|
2014-09-27 14:25:29 +00:00
|
|
|
ictx->opts->ar_rate = rate;
|
|
|
|
ictx->opts->ar_delay = delay;
|
2014-09-19 15:48:06 +00:00
|
|
|
input_unlock(ictx);
|
2014-09-19 15:36:37 +00:00
|
|
|
}
|