mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-11-11 01:28:19 +03:00
Add support for sending mouse events from a kitten
This allows you to a control a program running in kitty from a kitten using mouse events. If the program is not receiving mouse events of that type, it is not sent.
This commit is contained in:
parent
b4d08044a0
commit
43af6e3b8a
@ -132,6 +132,32 @@ layout, by simply adding the line::
|
||||
To the ``handle_result()`` function, above.
|
||||
|
||||
|
||||
Sending mouse events
|
||||
--------------------
|
||||
|
||||
If the program running in a window is receiving mouse events you can simulate
|
||||
those using::
|
||||
|
||||
from kitty.fast_data_types import send_mouse_event
|
||||
send_mouse_event(screen, x, y, button, action, mods)
|
||||
|
||||
``screen`` is the ``screen`` attribute of the window you want to send the event
|
||||
to. ``x`` and ``y`` are the 0-indexed coordinates. ``button`` is
|
||||
``GLFW_MOUSE_BUTTON_{button}`` where ``{button}`` is one of ``LEFT``,
|
||||
``RIGHT``, ``MIDDLE`` or a digit from ``1`` to ``8``. ``action`` is one of
|
||||
``PRESS``, ``RELEASE``, ``DRAG`` or ``MOVE``. ``mods`` is a bitmask of
|
||||
``GLFW_MOD_{mod}`` where ``{mod}`` is one of ``SHIFT``, ``CONTROL`` or ``ALT``.
|
||||
All the mentioned constants are imported from ``kitty.fast_data_types``.
|
||||
|
||||
For example, to send a left click at position x: 2, y: 3 to the active window::
|
||||
|
||||
from kitty.fast_data_types import send_mouse_event, GLFW_MOUSE_BUTTON_LEFT, PRESS
|
||||
send_mouse_event(boss.active_window.screen, 2, 3, GLFW_MOUSE_BUTTON_LEFT, PRESS, 0)
|
||||
|
||||
The function will only send the event if the program is receiving events of
|
||||
that type, and will return ``True`` if it sent the event, and ``False`` if not.
|
||||
|
||||
|
||||
Debugging kittens
|
||||
--------------------
|
||||
|
||||
|
@ -327,6 +327,10 @@ FC_WIDTH_NORMAL: int
|
||||
FC_SLANT_ROMAN: int
|
||||
FC_SLANT_ITALIC: int
|
||||
BORDERS_PROGRAM: int
|
||||
PRESS: int
|
||||
RELEASE: int
|
||||
DRAG: int
|
||||
MOVE: int
|
||||
# }}}
|
||||
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "control-codes.h"
|
||||
#include "monotonic.h"
|
||||
|
||||
extern PyTypeObject Screen_Type;
|
||||
|
||||
static MouseShape mouse_cursor_shape = BEAM;
|
||||
typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction;
|
||||
|
||||
@ -698,6 +700,25 @@ scroll_event(double UNUSED xoffset, double yoffset, int flags) {
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
send_mouse_event(PyObject *self UNUSED, PyObject *args) {
|
||||
Screen *screen;
|
||||
unsigned int x, y;
|
||||
int button, action, mods;
|
||||
if (!PyArg_ParseTuple(args, "O!IIiii", &Screen_Type, &screen, &x, &y, &button, &action, &mods)) return NULL;
|
||||
|
||||
MouseTrackingMode mode = screen->modes.mouse_tracking_mode;
|
||||
if (mode == ANY_MODE || (mode == MOTION_MODE && action != MOVE) || (mode == BUTTON_MODE && (action == PRESS || action == RELEASE))) {
|
||||
int sz = encode_mouse_event_impl(x + 1, y + 1, screen->modes.mouse_tracking_protocol, button, action, mods);
|
||||
if (sz > 0) {
|
||||
mouse_event_buf[sz] = 0;
|
||||
write_escape_code_to_child(screen, CSI, mouse_event_buf);
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
test_encode_mouse(PyObject *self UNUSED, PyObject *args) {
|
||||
unsigned int x, y;
|
||||
@ -732,6 +753,7 @@ send_mock_mouse_event_to_window(PyObject *self UNUSED, PyObject *args) {
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
METHODB(send_mouse_event, METH_VARARGS),
|
||||
METHODB(test_encode_mouse, METH_VARARGS),
|
||||
METHODB(send_mock_mouse_event_to_window, METH_VARARGS),
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
@ -739,6 +761,10 @@ static PyMethodDef module_methods[] = {
|
||||
|
||||
bool
|
||||
init_mouse(PyObject *module) {
|
||||
PyModule_AddIntMacro(module, PRESS);
|
||||
PyModule_AddIntMacro(module, RELEASE);
|
||||
PyModule_AddIntMacro(module, DRAG);
|
||||
PyModule_AddIntMacro(module, MOVE);
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -80,26 +80,25 @@ class TestParser(BaseTest):
|
||||
km(modify_key_bytes(base_key, num).decode('ascii')[1:], key)
|
||||
|
||||
def test_encode_mouse_event(self):
|
||||
PRESS, RELEASE, DRAG, MOVE = range(4)
|
||||
NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL = range(4)
|
||||
L, M, R = defines.GLFW_MOUSE_BUTTON_LEFT, defines.GLFW_MOUSE_BUTTON_MIDDLE, defines.GLFW_MOUSE_BUTTON_RIGHT
|
||||
protocol = SGR_PROTOCOL
|
||||
|
||||
def enc(button=L, action=PRESS, mods=0, x=1, y=1):
|
||||
def enc(button=L, action=defines.PRESS, mods=0, x=1, y=1):
|
||||
return defines.test_encode_mouse(x, y, protocol, button, action, mods)
|
||||
|
||||
self.ae(enc(), '<0;1;1M')
|
||||
self.ae(enc(action=RELEASE), '<0;1;1m')
|
||||
self.ae(enc(action=MOVE), '<35;1;1M')
|
||||
self.ae(enc(action=DRAG), '<32;1;1M')
|
||||
self.ae(enc(action=defines.RELEASE), '<0;1;1m')
|
||||
self.ae(enc(action=defines.MOVE), '<35;1;1M')
|
||||
self.ae(enc(action=defines.DRAG), '<32;1;1M')
|
||||
|
||||
self.ae(enc(R), '<2;1;1M')
|
||||
self.ae(enc(R, action=RELEASE), '<2;1;1m')
|
||||
self.ae(enc(R, action=DRAG), '<34;1;1M')
|
||||
self.ae(enc(R, action=defines.RELEASE), '<2;1;1m')
|
||||
self.ae(enc(R, action=defines.DRAG), '<34;1;1M')
|
||||
|
||||
self.ae(enc(M), '<1;1;1M')
|
||||
self.ae(enc(M, action=RELEASE), '<1;1;1m')
|
||||
self.ae(enc(M, action=DRAG), '<33;1;1M')
|
||||
self.ae(enc(M, action=defines.RELEASE), '<1;1;1m')
|
||||
self.ae(enc(M, action=defines.DRAG), '<33;1;1M')
|
||||
|
||||
self.ae(enc(x=1234, y=5678), '<0;1234;5678M')
|
||||
self.ae(enc(mods=defines.GLFW_MOD_SHIFT), '<4;1;1M')
|
||||
|
Loading…
Reference in New Issue
Block a user