diff --git a/buildconfig/stubs/pygame/mouse.pyi b/buildconfig/stubs/pygame/mouse.pyi index 42ea298b45..fcecfeabd9 100644 --- a/buildconfig/stubs/pygame/mouse.pyi +++ b/buildconfig/stubs/pygame/mouse.pyi @@ -13,6 +13,7 @@ def get_pressed(num_buttons: Literal[5]) -> Tuple[bool, bool, bool, bool, bool]: def get_just_pressed() -> Tuple[bool, bool, bool, bool, bool]: ... def get_just_released() -> Tuple[bool, bool, bool, bool, bool]: ... def get_pos() -> Tuple[int, int]: ... +def get_desktop_pos() -> Tuple[float, float]: ... def get_rel() -> Tuple[int, int]: ... @overload def set_pos(pos: Coordinate, /) -> None: ... diff --git a/docs/reST/ref/mouse.rst b/docs/reST/ref/mouse.rst index c01a70997c..a4a4e6e576 100644 --- a/docs/reST/ref/mouse.rst +++ b/docs/reST/ref/mouse.rst @@ -169,6 +169,22 @@ scroll, such as ``which`` (it will tell you what exact mouse device trigger the .. ## pygame.mouse.get_pos ## +.. function:: get_desktop_pos + + | :sl:`get the mouse cursor position relative to the desktop` + | :sg:`get_desktop_pos() -> (x, y)` + + Returns the ``x`` and ``y`` float position of the mouse cursor relative to the + top-left corner of the primary monitor. The position might be negative or exceed + the desktop bounds if multiple monitors are present. + + .. warning:: Due to design constraints it is impossible to retrieve the global + mouse state on Wayland. The relative mouse position is returned instead. + + .. versionadded:: 2.5.2 + + .. ## pygame.mouse.get_desktop_pos ## + .. function:: get_rel | :sl:`get the amount of mouse movement` diff --git a/src_c/doc/mouse_doc.h b/src_c/doc/mouse_doc.h index 77ab749c39..a6f9840ac9 100644 --- a/src_c/doc/mouse_doc.h +++ b/src_c/doc/mouse_doc.h @@ -4,6 +4,7 @@ #define DOC_MOUSE_GETJUSTPRESSED "get_just_pressed() -> (left_button, middle_button, right_button, x1_button, x2_button)\nget the most recently pressed buttons" #define DOC_MOUSE_GETJUSTRELEASED "get_just_released() -> (left_button, middle_button, right_button, x1_button, x2_button)\nget the most recently released buttons" #define DOC_MOUSE_GETPOS "get_pos() -> (x, y)\nget the mouse cursor position" +#define DOC_MOUSE_GETDESKTOPPOS "get_desktop_pos() -> (x, y)\nget the mouse cursor position relative to the desktop" #define DOC_MOUSE_GETREL "get_rel() -> (x, y)\nget the amount of mouse movement" #define DOC_MOUSE_SETPOS "set_pos([x, y], /) -> None\nset the mouse cursor position" #define DOC_MOUSE_SETVISIBLE "set_visible(bool, /) -> bool\nhide or show the mouse cursor" diff --git a/src_c/mouse.c b/src_c/mouse.c index c6af99056e..e32006925a 100644 --- a/src_c/mouse.c +++ b/src_c/mouse.c @@ -100,6 +100,17 @@ mouse_get_pos(PyObject *self, PyObject *_null) return pg_tuple_couple_from_values_int(x, y); } +static PyObject * +mouse_get_desktop_pos(PyObject *self, PyObject *_null) +{ + int x, y; + + VIDEO_INIT_CHECK(); + SDL_GetGlobalMouseState(&x, &y); + + return pg_tuple_couple_from_values_double((double)x, (double)y); +} + static PyObject * mouse_get_rel(PyObject *self, PyObject *_null) { @@ -531,6 +542,8 @@ mouse_set_relative_mode(PyObject *self, PyObject *arg) static PyMethodDef _mouse_methods[] = { {"set_pos", mouse_set_pos, METH_VARARGS, DOC_MOUSE_SETPOS}, {"get_pos", (PyCFunction)mouse_get_pos, METH_NOARGS, DOC_MOUSE_GETPOS}, + {"get_desktop_pos", (PyCFunction)mouse_get_desktop_pos, METH_NOARGS, + DOC_MOUSE_GETDESKTOPPOS}, {"get_rel", (PyCFunction)mouse_get_rel, METH_NOARGS, DOC_MOUSE_GETREL}, {"get_pressed", (PyCFunction)mouse_get_pressed, METH_VARARGS | METH_KEYWORDS, DOC_MOUSE_GETPRESSED}, diff --git a/test/mouse_test.py b/test/mouse_test.py index 3373bd2853..c9001ebdad 100644 --- a/test/mouse_test.py +++ b/test/mouse_test.py @@ -315,6 +315,17 @@ def test_get_pos(self): for value in pos: self.assertIsInstance(value, int) + def test_get_desktop_pos(self): + """Ensures get_desktop_pos returns the correct types.""" + expected_length = 2 + + pos = pygame.mouse.get_desktop_pos() + + self.assertIsInstance(pos, tuple) + self.assertEqual(len(pos), expected_length) + for value in pos: + self.assertIsInstance(value, float) + def test_set_pos__invalid_pos(self): """Ensures set_pos handles invalid positions correctly.""" for invalid_pos in ((1,), [1, 2, 3], 1, "1", (1, "1"), []):