From 5d295400d25b5fe14bce27262af6e4ba7e68a3d9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 1 Oct 2023 16:28:18 -0700 Subject: [PATCH] centralize management of mouse state --- ci/test.lua | 3 --- docs/dev/Lua API.rst | 8 +++++++ library/include/modules/Screen.h | 1 + library/lua/gui.lua | 40 +++++++++++++------------------- library/lua/gui/dialogs.lua | 18 +++----------- library/modules/Screen.cpp | 18 +++++++++++++- plugins/lua/hotkeys.lua | 2 -- plugins/lua/overlay.lua | 1 - plugins/overlay.cpp | 2 +- 9 files changed, 46 insertions(+), 47 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index 372d8f262..9a7c0d345 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -222,9 +222,6 @@ local function click_top_title_button(scr) df.global.gps.mouse_y = (sh // 2) + 3 end df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y - df.global.enabler.tracking_on = 1 - df.global.enabler.mouse_lbut = 1 - df.global.enabler.mouse_lbut_down = 1 gui.simulateInput(scr, '_MOUSE_L') end diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 6eeb2dbe7..99dcabf7e 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3952,6 +3952,14 @@ Misc of keycodes to *true* or *false*. For instance, it is possible to use the table passed as argument to ``onInput``. + You can send mouse clicks as will by setting the ``_MOUSE_L`` key or other + mouse-related pseudo-keys documented with the ``screen:onInput(keys)`` + function above. Note that if you are simulating a click at a specific spot on + the screen, you must set ``df.global.gps.mouse_x`` and + ``df.global.gps.mouse_y`` if you are clicking on the interface layer or + ``df.global.gps.precise_mouse_x`` and ``df.global.gps.precise_mouse_y`` if + you are clickin on the map. + * ``mkdims_xy(x1,y1,x2,y2)`` Returns a table containing the arguments as fields, and also ``width`` and diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index 681398f89..96f1f6642 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -391,6 +391,7 @@ namespace DFHack virtual ~dfhack_lua_viewscreen(); static df::viewscreen *get_pointer(lua_State *L, int idx, bool make); + static void markInputAsHandled(); virtual bool is_lua_screen() { return true; } virtual bool isFocused() { return !defocused; } diff --git a/library/lua/gui.lua b/library/lua/gui.lua index ba49e0cdc..bb29124a5 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -15,8 +15,8 @@ TRANSPARENT_PEN = to_pen{tile=0, ch=0} KEEP_LOWER_PEN = to_pen{ch=32, fg=0, bg=0, keep_lower=true} local MOUSE_KEYS = { - _MOUSE_L = true, - _MOUSE_R = true, + _MOUSE_L = function(is_set) df.global.enabler.mouse_lbut = is_set and 1 or 0 end, + _MOUSE_R = function(is_set) df.global.enabler.mouse_rbut = is_set and 1 or 0 end, _MOUSE_M = true, _MOUSE_L_DOWN = true, _MOUSE_R_DOWN = true, @@ -27,7 +27,7 @@ local FAKE_INPUT_KEYS = copyall(MOUSE_KEYS) FAKE_INPUT_KEYS._STRING = true function simulateInput(screen,...) - local keys = {} + local keys, enabled_mouse_keys = {}, {} local function push_key(arg) local kv = arg if type(arg) == 'string' then @@ -35,6 +35,10 @@ function simulateInput(screen,...) if kv == nil and not FAKE_INPUT_KEYS[arg] then error('Invalid keycode: '..arg) end + if MOUSE_KEYS[arg] then + df.global.enabler.tracking_on = 1 + enabled_mouse_keys[arg] = true + end end if type(kv) == 'number' then keys[#keys+1] = kv @@ -57,6 +61,11 @@ function simulateInput(screen,...) end end end + for mk, fn in pairs(MOUSE_KEYS) do + if type(fn) == 'function' then + fn(enabled_mouse_keys[mk]) + end + end dscreen._doSimulateInput(screen, keys) end @@ -696,17 +705,6 @@ end DEFAULT_INITIAL_PAUSE = true --- ensure underlying DF screens don't also react to handled clicks -function markMouseClicksHandled(keys) - if keys._MOUSE_L then - df.global.enabler.mouse_lbut = 0 - end - if keys._MOUSE_R then - df.global.enabler.mouse_rbut_down = 0 - df.global.enabler.mouse_rbut = 0 - end -end - ZScreen = defclass(ZScreen, Screen) ZScreen.ATTRS{ defocusable=true, @@ -791,23 +789,17 @@ function ZScreen:onInput(keys) self:raise() else self:sendInputToParent(keys) - return + return true end end if ZScreen.super.onInput(self, keys) then - markMouseClicksHandled(keys) - return - end - - if self.pass_mouse_clicks and keys._MOUSE_L and not has_mouse then + -- noop + elseif self.pass_mouse_clicks and keys._MOUSE_L and not has_mouse then self.defocused = self.defocusable self:sendInputToParent(keys) - return elseif keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() - markMouseClicksHandled(keys) - return else local passit = self.pass_pause and keys.D_PAUSE if not passit and self.pass_mouse_clicks then @@ -829,8 +821,8 @@ function ZScreen:onInput(keys) if passit then self:sendInputToParent(keys) end - return end + return true end function ZScreen:raise() diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua index 5778cc767..7a0f86b3f 100644 --- a/library/lua/gui/dialogs.lua +++ b/library/lua/gui/dialogs.lua @@ -64,13 +64,9 @@ function MessageBox:onInput(keys) elseif (keys.LEAVESCREEN or keys._MOUSE_R) and self.on_cancel then self.on_cancel() end - gui.markMouseClicksHandled(keys) - return true - end - if self:inputToSubviews(keys) then - gui.markMouseClicksHandled(keys) return true end + return self:inputToSubviews(keys) end function showMessage(title, text, tcolor, on_close) @@ -137,13 +133,9 @@ function InputBox:onInput(keys) if self.on_cancel then self.on_cancel() end - gui.markMouseClicksHandled(keys) - return true - end - if self:inputToSubviews(keys) then - gui.markMouseClicksHandled(keys) return true end + return self:inputToSubviews(keys) end function showInputPrompt(title, text, tcolor, input, on_input, on_cancel, min_width) @@ -242,13 +234,9 @@ function ListBox:onInput(keys) if self.on_cancel then self.on_cancel() end - gui.markMouseClicksHandled(keys) - return true - end - if self:inputToSubviews(keys) then - gui.markMouseClicksHandled(keys) return true end + return self:inputToSubviews(keys) end function showListPrompt(title, text, tcolor, choices, on_select, on_cancel, min_width, filter) diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index a5b347493..dee7e2b75 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -956,6 +956,18 @@ int dfhack_lua_viewscreen::do_notify(lua_State *L) return 1; } +void dfhack_lua_viewscreen::markInputAsHandled() { + if (!enabler) + return; + + // clear text buffer + enabler->last_text_input[0] = '\0'; + + // mark clicked mouse buttons as handled + enabler->mouse_lbut = 0; + enabler->mouse_rbut = 0; +} + int dfhack_lua_viewscreen::do_input(lua_State *L) { auto self = get_self(L); @@ -977,7 +989,11 @@ int dfhack_lua_viewscreen::do_input(lua_State *L) lua_pushvalue(L, -2); Lua::PushInterfaceKeys(L, Screen::normalize_text_keys(*keys)); - lua_call(L, 2, 0); + lua_call(L, 2, 1); + if (lua_toboolean(L, -1)) + markInputAsHandled(); + lua_pop(L, 1); + self->update_focus(L, -1); return 0; } diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 6335de5e5..4c33f93ca 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -280,14 +280,12 @@ function Menu:onInput(keys) local x = list:getMousePos() if x == 0 then -- clicked on icon self:onSubmit2(list:getSelected()) - gui.markMouseClicksHandled(keys) return true end if not self:getMouseFramePos() then self.parent_view:dismiss() return true end - gui.markMouseClicksHandled(keys) end self:inputToSubviews(keys) return true -- we're modal diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index cd5286d0d..9751561a8 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -506,7 +506,6 @@ function feed_viewscreen_widgets(vs_name, vs, keys) not _feed_viewscreen_widgets('all', nil, keys) then return false end - gui.markMouseClicksHandled(keys) return true end diff --git a/plugins/overlay.cpp b/plugins/overlay.cpp index 3fec6091b..c94397956 100644 --- a/plugins/overlay.cpp +++ b/plugins/overlay.cpp @@ -86,7 +86,7 @@ struct viewscreen_overlay : T { if (!input_is_handled) INTERPOSE_NEXT(feed)(input); else - enabler->last_text_input[0] = '\0'; + dfhack_lua_viewscreen::markInputAsHandled(); } DEFINE_VMETHOD_INTERPOSE(void, render, ()) { INTERPOSE_NEXT(render)();