diff --git a/tools/python/src/gui.cpp b/tools/python/src/gui.cpp index 99ebe84a0..1176b5ccf 100644 --- a/tools/python/src/gui.cpp +++ b/tools/python/src/gui.cpp @@ -107,6 +107,78 @@ void add_overlay_pylist ( win.add_overlay(rects, color); } +void wait_for_keypress_char(image_window& win, const char wait_key) { + unsigned long key; + bool is_printable; + while(win.get_next_keypress(key,is_printable)) + { + if (is_printable && (char)key == wait_key) + return; + } +} + +void wait_for_keypress_other(image_window& win, const base_window::non_printable_keyboard_keys wait_key) { + unsigned long key; + bool is_printable; + while(win.get_next_keypress(key,is_printable)) + { + if (!is_printable && key == wait_key) + return; + } +} + +py::object get_next_double_click(image_window& win) { + point p; + if (win.get_next_double_click(p)) + return py::cast(p); + else + return py::none(); +} + +py::object get_next_keypress(image_window& win, bool get_keyboard_modifiers) +{ + unsigned long key; + bool is_printable; + unsigned long state; + + auto state_to_list = [&]() { + py::list mods; + if (state&base_window::KBD_MOD_SHIFT) mods.append(base_window::KBD_MOD_SHIFT); + if (state&base_window::KBD_MOD_CONTROL) mods.append(base_window::KBD_MOD_CONTROL); + if (state&base_window::KBD_MOD_ALT) mods.append(base_window::KBD_MOD_ALT); + if (state&base_window::KBD_MOD_META) mods.append(base_window::KBD_MOD_META); + if (state&base_window::KBD_MOD_CAPS_LOCK) mods.append(base_window::KBD_MOD_CAPS_LOCK); + if (state&base_window::KBD_MOD_NUM_LOCK) mods.append(base_window::KBD_MOD_NUM_LOCK); + if (state&base_window::KBD_MOD_SCROLL_LOCK) mods.append(base_window::KBD_MOD_SCROLL_LOCK); + return mods; + }; + + if(win.get_next_keypress(key, is_printable, state)) + { + if (is_printable) + { + if (get_keyboard_modifiers) + return py::make_tuple((char)key, state_to_list()); + else + return py::cast((char)key); + } + else + { + if (get_keyboard_modifiers) + return py::make_tuple(static_cast(key), state_to_list()); + else + return py::cast(static_cast(key)); + } + } + else + { + if (get_keyboard_modifiers) + return py::make_tuple(py::none(), py::none()); + else + return py::none(); + } +} + template void add_overlay_circle ( image_window& win, @@ -241,7 +313,96 @@ void bind_gui(py::module& m) .def("add_overlay", add_overlay_pylist, py::arg("objects"), py::arg("color")=rgb_pixel(255,0,0), "Adds all the overlayable objects, uses the given color.") .def("wait_until_closed", &type::wait_until_closed, - "This function blocks until the window is closed."); + "This function blocks until the window is closed.") + .def("is_closed", &type::is_closed, + "returns true if this window has been closed, false otherwise. (Note that closed windows do not receive any callbacks at all. They are also not visible on the screen.)") + .def("get_next_double_click", get_next_double_click, + "Blocks until the user double clicks on the image or closes the window. Returns a dlib.point indicating the pixel the user clicked on or None if the window as closed.") + .def("wait_for_keypress", wait_for_keypress_char, py::arg("key"), + "Blocks until the user presses the given key or closes the window.") + .def("wait_for_keypress", wait_for_keypress_other, py::arg("key"), + "Blocks until the user presses the given key or closes the window.") + .def("get_next_keypress", get_next_keypress, py::arg("get_keyboard_modifiers")=false, +"Blocks until the user presses a key on their keyboard or the window is closed. \n\ + \n\ +ensures \n\ + - if (get_keyboard_modifiers==True) then \n\ + - returns a tuple of (key_pressed, keyboard_modifiers_active) \n\ + - else \n\ + - returns just the key that was pressed. \n\ + - The returned key is either a str containing the letter that was pressed, or \n\ + an element of the dlib.non_printable_keyboard_keys enum. \n\ + - keyboard_modifiers_active, if returned, is a list of elements of the \n\ + dlib.keyboard_mod_keys enum. They tell you if a key like shift was being held \n\ + down or not during the button press. \n\ + - If the window is closed before the user presses a key then this function \n\ + returns with all outputs set to None." + /*! + Blocks until the user presses a key on their keyboard or the window is closed. + + ensures + - if (get_keyboard_modifiers==True) then + - returns a tuple of (key_pressed, keyboard_modifiers_active) + - else + - returns just the key that was pressed. + - The returned key is either a str containing the letter that was pressed, or + an element of the dlib.non_printable_keyboard_keys enum. + - keyboard_modifiers_active, if returned, is a list of elements of the + dlib.keyboard_mod_keys enum. They tell you if a key like shift was being held + down or not during the button press. + - If the window is closed before the user presses a key then this function + returns with all outputs set to None. + !*/ + ); } + + py::enum_(m,"non_printable_keyboard_keys") + .value("KEY_BACKSPACE", base_window::KEY_BACKSPACE) + .value("KEY_SHIFT", base_window::KEY_SHIFT) + .value("KEY_CTRL", base_window::KEY_CTRL) + .value("KEY_ALT", base_window::KEY_ALT) + .value("KEY_PAUSE", base_window::KEY_PAUSE) + .value("KEY_CAPS_LOCK", base_window::KEY_CAPS_LOCK) + .value("KEY_ESC", base_window::KEY_ESC) + .value("KEY_PAGE_UP", base_window::KEY_PAGE_UP) + .value("KEY_PAGE_DOWN", base_window::KEY_PAGE_DOWN) + .value("KEY_END", base_window::KEY_END) + .value("KEY_HOME", base_window::KEY_HOME) + .value("KEY_LEFT", base_window::KEY_LEFT) + .value("KEY_RIGHT", base_window::KEY_RIGHT) + .value("KEY_UP", base_window::KEY_UP) + .value("KEY_DOWN", base_window::KEY_DOWN) + .value("KEY_INSERT", base_window::KEY_INSERT) + .value("KEY_DELETE", base_window::KEY_DELETE) + .value("KEY_SCROLL_LOCK", base_window::KEY_SCROLL_LOCK) + .value("KEY_F1", base_window::KEY_F1) + .value("KEY_F2", base_window::KEY_F2) + .value("KEY_F3", base_window::KEY_F3) + .value("KEY_F4", base_window::KEY_F4) + .value("KEY_F5", base_window::KEY_F5) + .value("KEY_F6", base_window::KEY_F6) + .value("KEY_F7", base_window::KEY_F7) + .value("KEY_F8", base_window::KEY_F8) + .value("KEY_F9", base_window::KEY_F9) + .value("KEY_F10", base_window::KEY_F10) + .value("KEY_F11", base_window::KEY_F11) + .value("KEY_F12", base_window::KEY_F12) + .export_values() + // allow someone to compare this enum to a string since the return from get_next_keypress() + // can be either this enum or a string and forcing the user to type check with an if is + // maddening. + .def("__eq__", [](base_window::non_printable_keyboard_keys, const std::string&){ return false; }); + + py::enum_(m,"keyboard_mod_keys") + .value("KBD_MOD_NONE", base_window::KBD_MOD_NONE) + .value("KBD_MOD_SHIFT", base_window::KBD_MOD_SHIFT) + .value("KBD_MOD_CONTROL", base_window::KBD_MOD_CONTROL) + .value("KBD_MOD_ALT", base_window::KBD_MOD_ALT) + .value("KBD_MOD_META", base_window::KBD_MOD_META) + .value("KBD_MOD_CAPS_LOCK", base_window::KBD_MOD_CAPS_LOCK) + .value("KBD_MOD_NUM_LOCK", base_window::KBD_MOD_NUM_LOCK) + .value("KBD_MOD_SCROLL_LOCK", base_window::KBD_MOD_SCROLL_LOCK) + .export_values(); + } #endif