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.
|
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
|
Debugging kittens
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
|||||||
@ -327,6 +327,10 @@ FC_WIDTH_NORMAL: int
|
|||||||
FC_SLANT_ROMAN: int
|
FC_SLANT_ROMAN: int
|
||||||
FC_SLANT_ITALIC: int
|
FC_SLANT_ITALIC: int
|
||||||
BORDERS_PROGRAM: int
|
BORDERS_PROGRAM: int
|
||||||
|
PRESS: int
|
||||||
|
RELEASE: int
|
||||||
|
DRAG: int
|
||||||
|
MOVE: int
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,8 @@
|
|||||||
#include "control-codes.h"
|
#include "control-codes.h"
|
||||||
#include "monotonic.h"
|
#include "monotonic.h"
|
||||||
|
|
||||||
|
extern PyTypeObject Screen_Type;
|
||||||
|
|
||||||
static MouseShape mouse_cursor_shape = BEAM;
|
static MouseShape mouse_cursor_shape = BEAM;
|
||||||
typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction;
|
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*
|
static PyObject*
|
||||||
test_encode_mouse(PyObject *self UNUSED, PyObject *args) {
|
test_encode_mouse(PyObject *self UNUSED, PyObject *args) {
|
||||||
unsigned int x, y;
|
unsigned int x, y;
|
||||||
@ -732,6 +753,7 @@ send_mock_mouse_event_to_window(PyObject *self UNUSED, PyObject *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
|
METHODB(send_mouse_event, METH_VARARGS),
|
||||||
METHODB(test_encode_mouse, METH_VARARGS),
|
METHODB(test_encode_mouse, METH_VARARGS),
|
||||||
METHODB(send_mock_mouse_event_to_window, METH_VARARGS),
|
METHODB(send_mock_mouse_event_to_window, METH_VARARGS),
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
@ -739,6 +761,10 @@ static PyMethodDef module_methods[] = {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
init_mouse(PyObject *module) {
|
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;
|
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,26 +80,25 @@ class TestParser(BaseTest):
|
|||||||
km(modify_key_bytes(base_key, num).decode('ascii')[1:], key)
|
km(modify_key_bytes(base_key, num).decode('ascii')[1:], key)
|
||||||
|
|
||||||
def test_encode_mouse_event(self):
|
def test_encode_mouse_event(self):
|
||||||
PRESS, RELEASE, DRAG, MOVE = range(4)
|
|
||||||
NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL = 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
|
L, M, R = defines.GLFW_MOUSE_BUTTON_LEFT, defines.GLFW_MOUSE_BUTTON_MIDDLE, defines.GLFW_MOUSE_BUTTON_RIGHT
|
||||||
protocol = SGR_PROTOCOL
|
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)
|
return defines.test_encode_mouse(x, y, protocol, button, action, mods)
|
||||||
|
|
||||||
self.ae(enc(), '<0;1;1M')
|
self.ae(enc(), '<0;1;1M')
|
||||||
self.ae(enc(action=RELEASE), '<0;1;1m')
|
self.ae(enc(action=defines.RELEASE), '<0;1;1m')
|
||||||
self.ae(enc(action=MOVE), '<35;1;1M')
|
self.ae(enc(action=defines.MOVE), '<35;1;1M')
|
||||||
self.ae(enc(action=DRAG), '<32;1;1M')
|
self.ae(enc(action=defines.DRAG), '<32;1;1M')
|
||||||
|
|
||||||
self.ae(enc(R), '<2;1;1M')
|
self.ae(enc(R), '<2;1;1M')
|
||||||
self.ae(enc(R, action=RELEASE), '<2;1;1m')
|
self.ae(enc(R, action=defines.RELEASE), '<2;1;1m')
|
||||||
self.ae(enc(R, action=DRAG), '<34;1;1M')
|
self.ae(enc(R, action=defines.DRAG), '<34;1;1M')
|
||||||
|
|
||||||
self.ae(enc(M), '<1;1;1M')
|
self.ae(enc(M), '<1;1;1M')
|
||||||
self.ae(enc(M, action=RELEASE), '<1;1;1m')
|
self.ae(enc(M, action=defines.RELEASE), '<1;1;1m')
|
||||||
self.ae(enc(M, action=DRAG), '<33;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(x=1234, y=5678), '<0;1234;5678M')
|
||||||
self.ae(enc(mods=defines.GLFW_MOD_SHIFT), '<4;1;1M')
|
self.ae(enc(mods=defines.GLFW_MOD_SHIFT), '<4;1;1M')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user