Merge pull request #3816 from myk002/myk_remousify

align mouse button semantics to DF
develop
Myk 2023-09-26 19:09:23 -07:00 committed by GitHub
commit da77be29be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 110 additions and 113 deletions

@ -66,6 +66,7 @@ Template for new versions:
## API
## Lua
- mouse key events are now aligned with internal DF semantics: ``_MOUSE_L`` indicates that the left mouse button has just been pressed and ``_MOUSE_L_DOWN`` indicates that the left mouse button is being held down. similar for ``_MOUSE_R`` and ``_MOUSE_M``. 3rd party scripts may have to adjust.
## Removed

@ -2528,10 +2528,10 @@ Supported callbacks and fields are:
Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience.
``_MOUSE_L, _MOUSE_R, _MOUSE_M``
If the left, right, and/or middle mouse button is being pressed.
If the left, right, and/or middle mouse button was just pressed.
``_MOUSE_L_DOWN, _MOUSE_R_DOWN, _MOUSE_M_DOWN``
If the left, right, and/or middle mouse button was just pressed.
If the left, right, and/or middle mouse button is being held down.
If this method is omitted, the screen is dismissed on reception of the ``LEAVESCREEN`` key.

@ -131,12 +131,12 @@ void DFHack::Lua::GetVector(lua_State *state, std::vector<std::string> &pvec, in
}
}
static bool trigger_inhibit_l_down = false;
static bool trigger_inhibit_r_down = false;
static bool trigger_inhibit_m_down = false;
static bool inhibit_l_down = false;
static bool inhibit_r_down = false;
static bool inhibit_m_down = false;
static bool trigger_inhibit_l = false;
static bool trigger_inhibit_r = false;
static bool trigger_inhibit_m = false;
static bool inhibit_l = false;
static bool inhibit_r = false;
static bool inhibit_m = false;
void DFHack::Lua::PushInterfaceKeys(lua_State *L,
const std::set<df::interface_key> &keys) {
@ -161,32 +161,32 @@ void DFHack::Lua::PushInterfaceKeys(lua_State *L,
}
if (df::global::enabler) {
if (!inhibit_l_down && df::global::enabler->mouse_lbut_down) {
if (!inhibit_l && df::global::enabler->mouse_lbut) {
lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_L_DOWN");
trigger_inhibit_l_down = true;
lua_setfield(L, -2, "_MOUSE_L");
trigger_inhibit_l = true;
}
if (!inhibit_r_down && df::global::enabler->mouse_rbut_down) {
if (!inhibit_r && df::global::enabler->mouse_rbut) {
lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_R_DOWN");
trigger_inhibit_r_down = true;
lua_setfield(L, -2, "_MOUSE_R");
trigger_inhibit_r = true;
}
if (!inhibit_m_down && df::global::enabler->mouse_mbut_down) {
if (!inhibit_m && df::global::enabler->mouse_mbut) {
lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_M_DOWN");
trigger_inhibit_m_down = true;
lua_setfield(L, -2, "_MOUSE_M");
trigger_inhibit_m = true;
}
if (df::global::enabler->mouse_lbut) {
if (df::global::enabler->mouse_lbut_down) {
lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_L");
lua_setfield(L, -2, "_MOUSE_L_DOWN");
}
if (df::global::enabler->mouse_rbut) {
if (df::global::enabler->mouse_rbut_down) {
lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_R");
lua_setfield(L, -2, "_MOUSE_R_DOWN");
}
if (df::global::enabler->mouse_mbut) {
if (df::global::enabler->mouse_mbut_down) {
lua_pushboolean(L, true);
lua_setfield(L, -2, "_MOUSE_M");
lua_setfield(L, -2, "_MOUSE_M_DOWN");
}
}
}
@ -2159,25 +2159,25 @@ void DFHack::Lua::Core::Reset(color_ostream &out, const char *where)
lua_settop(State, 0);
}
if (trigger_inhibit_l_down) {
trigger_inhibit_l_down = false;
inhibit_l_down = true;
if (trigger_inhibit_l) {
trigger_inhibit_l = false;
inhibit_l = true;
}
if (trigger_inhibit_r_down) {
trigger_inhibit_r_down = false;
inhibit_r_down = true;
if (trigger_inhibit_r) {
trigger_inhibit_r = false;
inhibit_r = true;
}
if (trigger_inhibit_m_down) {
trigger_inhibit_m_down = false;
inhibit_m_down = true;
if (trigger_inhibit_m) {
trigger_inhibit_m = false;
inhibit_m = true;
}
if (df::global::enabler) {
if (!df::global::enabler->mouse_lbut)
inhibit_l_down = false;
if (!df::global::enabler->mouse_rbut)
inhibit_r_down = false;
if (!df::global::enabler->mouse_mbut)
inhibit_m_down = false;
if (!df::global::enabler->mouse_lbut_down)
inhibit_l = false;
if (!df::global::enabler->mouse_rbut_down)
inhibit_r = false;
if (!df::global::enabler->mouse_mbut_down)
inhibit_m = false;
}
}

@ -696,16 +696,12 @@ end
DEFAULT_INITIAL_PAUSE = true
local zscreen_inhibit_mouse_l = false
-- ensure underlying DF screens don't also react to handled clicks
function markMouseClicksHandled(keys)
if keys._MOUSE_L_DOWN then
-- note we can't clear mouse_lbut here. otherwise we break dragging,
df.global.enabler.mouse_lbut_down = 0
zscreen_inhibit_mouse_l = true
if keys._MOUSE_L then
df.global.enabler.mouse_lbut = 0
end
if keys._MOUSE_R_DOWN then
if keys._MOUSE_R then
df.global.enabler.mouse_rbut_down = 0
df.global.enabler.mouse_rbut = 0
end
@ -789,7 +785,7 @@ function ZScreen:onInput(keys)
local has_mouse = self:isMouseOver()
if not self:hasFocus() then
if has_mouse and
(keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN or
(keys._MOUSE_L or keys._MOUSE_R or
keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN or
keys.CONTEXT_SCROLL_PAGEUP or keys.CONTEXT_SCROLL_PAGEDOWN) then
self:raise()
@ -804,22 +800,15 @@ function ZScreen:onInput(keys)
return
end
if self.pass_mouse_clicks and keys._MOUSE_L_DOWN and not has_mouse then
if 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_DOWN then
elseif keys.LEAVESCREEN or keys._MOUSE_R then
self:dismiss()
markMouseClicksHandled(keys)
return
else
if zscreen_inhibit_mouse_l then
if keys._MOUSE_L then
return
else
zscreen_inhibit_mouse_l = false
end
end
local passit = self.pass_pause and keys.D_PAUSE
if not passit and self.pass_mouse_clicks then
if keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN or

@ -57,11 +57,11 @@ function MessageBox:onDestroy()
end
function MessageBox:onInput(keys)
if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R then
self:dismiss()
if keys.SELECT and self.on_accept then
self.on_accept()
elseif (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) and self.on_cancel then
elseif (keys.LEAVESCREEN or keys._MOUSE_R) and self.on_cancel then
self.on_cancel()
end
gui.markMouseClicksHandled(keys)
@ -129,7 +129,7 @@ function InputBox:onInput(keys)
self.on_input(self.subviews.edit.text)
end
return true
elseif keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
elseif keys.LEAVESCREEN or keys._MOUSE_R then
self:dismiss()
if self.on_cancel then
self.on_cancel()
@ -231,7 +231,7 @@ function ListBox:getWantedFrameSize()
end
function ListBox:onInput(keys)
if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
if keys.LEAVESCREEN or keys._MOUSE_R then
self:dismiss()
if self.on_cancel then
self.on_cancel()

@ -273,7 +273,7 @@ end
function Panel:onInput(keys)
if self.kbd_get_pos then
if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R then
Panel_end_drag(self, not keys.SELECT and self.saved_frame or nil,
not not keys.SELECT)
return true
@ -281,7 +281,6 @@ function Panel:onInput(keys)
for code in pairs(keys) do
local dx, dy = guidm.get_movement_delta(code, 1, 10)
if dx then
local frame_rect = self.frame_rect
local kbd_pos = self.kbd_get_pos()
kbd_pos.x = kbd_pos.x + dx
kbd_pos.y = kbd_pos.y + dy
@ -292,9 +291,9 @@ function Panel:onInput(keys)
return
end
if self.drag_offset then
if keys._MOUSE_R_DOWN then
if keys._MOUSE_R then
Panel_end_drag(self, self.saved_frame)
elseif keys._MOUSE_L then
elseif keys._MOUSE_L_DOWN then
Panel_update_frame(self, Panel_make_frame(self))
end
return true
@ -302,7 +301,7 @@ function Panel:onInput(keys)
if Panel.super.onInput(self, keys) then
return true
end
if not keys._MOUSE_L_DOWN then return end
if not keys._MOUSE_L then return end
local x,y = self:getMouseFramePos()
if not x then return end
@ -489,7 +488,7 @@ function Panel:onRenderFrame(dc, rect)
dc:seek(pos.x, pos.y):pen(pen):char(string.char(0xDB))
end
if self.drag_offset and not self.kbd_get_pos
and df.global.enabler.mouse_lbut == 0 then
and df.global.enabler.mouse_lbut_down == 0 then
Panel_end_drag(self, nil, true)
end
end
@ -718,7 +717,7 @@ function EditField:onInput(keys)
end
end
if self.key and (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) then
if self.key and (keys.LEAVESCREEN or keys._MOUSE_R) then
self:setText(self.saved_text)
self:setFocus(false)
return true
@ -740,8 +739,8 @@ function EditField:onInput(keys)
end
end
return not not self.key
elseif keys._MOUSE_L then
local mouse_x, mouse_y = self:getMousePos()
elseif keys._MOUSE_L_DOWN then
local mouse_x = self:getMousePos()
if mouse_x then
self:setCursor(self.start_pos + mouse_x - (self.text_offset or 0))
return true
@ -986,7 +985,7 @@ function Scrollbar:onRenderBody(dc)
if self.is_dragging then
scrollbar_do_drag(self)
end
if df.global.enabler.mouse_lbut == 0 then
if df.global.enabler.mouse_lbut_down == 0 then
self.last_scroll_ms = 0
self.is_dragging = false
self.scroll_spec = nil
@ -1023,7 +1022,7 @@ function Scrollbar:onInput(keys)
return true
end
end
if not keys._MOUSE_L_DOWN then return false end
if not keys._MOUSE_L then return false end
local _,y = self:getMousePos()
if not y then return false end
local scroll_spec = nil
@ -1386,11 +1385,11 @@ function Label:onInput(keys)
if self:inputToSubviews(keys) then
return true
end
if keys._MOUSE_L_DOWN and self:getMousePos() and self.on_click then
if keys._MOUSE_L and self:getMousePos() and self.on_click then
self.on_click()
return true
end
if keys._MOUSE_R_DOWN and self:getMousePos() and self.on_rclick then
if keys._MOUSE_R and self:getMousePos() and self.on_rclick then
self.on_rclick()
return true
end
@ -1498,7 +1497,7 @@ end
function HotkeyLabel:onInput(keys)
if HotkeyLabel.super.onInput(self, keys) then
return true
elseif keys._MOUSE_L_DOWN and self:getMousePos() and self.on_activate
elseif keys._MOUSE_L and self:getMousePos() and self.on_activate
and not is_disabled(self) then
self.on_activate()
return true
@ -1658,7 +1657,7 @@ end
function CycleHotkeyLabel:onInput(keys)
if CycleHotkeyLabel.super.onInput(self, keys) then
return true
elseif keys._MOUSE_L_DOWN and self:getMousePos() and not is_disabled(self) then
elseif keys._MOUSE_L and self:getMousePos() and not is_disabled(self) then
self:cycle()
return true
end
@ -1962,7 +1961,7 @@ function List:onInput(keys)
return self:submit()
elseif keys.CUSTOM_SHIFT_ENTER then
return self:submit2()
elseif keys._MOUSE_L_DOWN then
elseif keys._MOUSE_L then
local idx = self:getIdxUnderMouse()
if idx then
local now_ms = dfhack.getTickCount()
@ -2317,7 +2316,7 @@ end
function Tab:onInput(keys)
if Tab.super.onInput(self, keys) then return true end
if keys._MOUSE_L_DOWN and self:getMousePos() then
if keys._MOUSE_L and self:getMousePos() then
self.on_select(self.id)
return true
end
@ -2419,7 +2418,7 @@ local function rangeslider_get_width_per_idx(self)
end
function RangeSlider:onInput(keys)
if not keys._MOUSE_L_DOWN then return false end
if not keys._MOUSE_L then return false end
local x = self:getMousePos()
if not x then return false end
local left_idx, right_idx = self.get_left_idx_fn(), self.get_right_idx_fn()
@ -2527,7 +2526,7 @@ function RangeSlider:onRenderBody(dc, rect)
if self.is_dragging_target then
rangeslider_do_drag(self, width_per_idx)
end
if df.global.enabler.mouse_lbut == 0 then
if df.global.enabler.mouse_lbut_down == 0 then
self.is_dragging_target = nil
self.is_dragging_idx = nil
end

@ -1004,6 +1004,8 @@ dfhack_lua_viewscreen::~dfhack_lua_viewscreen()
void dfhack_lua_viewscreen::render()
{
using df::global::enabler;
if (Screen::isDismissed(this))
{
if (parent)
@ -1011,6 +1013,14 @@ void dfhack_lua_viewscreen::render()
return;
}
if (enabler &&
(enabler->mouse_lbut_down || enabler->mouse_rbut_down || enabler->mouse_mbut_down))
{
// synthesize feed events for held mouse buttons
std::set<df::interface_key> keys;
feed(&keys);
}
dfhack_viewscreen::render();
safe_call_lua(do_render, 0, 0);

@ -127,9 +127,9 @@ function InspectorOverlay:onInput(keys)
if not require('plugins.buildingplan').isPlannedBuilding(dfhack.gui.getSelectedBuilding(true)) then
return false
end
if keys._MOUSE_L_DOWN and mouse_is_over_resume_button(self.frame_parent_rect) then
if keys._MOUSE_L and mouse_is_over_resume_button(self.frame_parent_rect) then
return true
elseif keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN or keys.LEAVESCREEN then
elseif keys._MOUSE_L or keys._MOUSE_R or keys.LEAVESCREEN then
self:reset()
end
return InspectorOverlay.super.onInput(self, keys)

@ -366,10 +366,10 @@ function ItemSelection:submit(choices)
end
function ItemSelection:onInput(keys)
if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
if keys.LEAVESCREEN or keys._MOUSE_R then
self.on_cancel()
return true
elseif keys._MOUSE_L_DOWN then
elseif keys._MOUSE_L then
local list = self.subviews.flist.list
local idx = list:getIdxUnderMouse()
if idx then

@ -272,7 +272,7 @@ function ItemLine:reset()
end
function ItemLine:onInput(keys)
if keys._MOUSE_L_DOWN and self:getMousePos() then
if keys._MOUSE_L and self:getMousePos() then
self.on_select(self.idx)
end
return ItemLine.super.onInput(self, keys)
@ -739,7 +739,7 @@ end
function PlannerOverlay:onInput(keys)
if not is_plannable() then return false end
if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
if keys.LEAVESCREEN or keys._MOUSE_R then
if uibs.selection_pos:isValid() then
uibs.selection_pos:clear()
return true
@ -758,7 +758,7 @@ function PlannerOverlay:onInput(keys)
return true
end
if self:is_minimized() then return false end
if keys._MOUSE_L_DOWN then
if keys._MOUSE_L then
if is_over_options_panel() then return false end
local detect_rect = copyall(self.frame_rect)
detect_rect.height = self.subviews.main.frame_rect.height +
@ -828,7 +828,7 @@ function PlannerOverlay:onInput(keys)
end
end
end
return keys._MOUSE_L or keys.SELECT
return keys._MOUSE_L_DOWN or keys.SELECT
end
function PlannerOverlay:render(dc)

@ -269,24 +269,24 @@ function Menu:onSubmit2(_, choice)
end
function Menu:onInput(keys)
if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
if keys.LEAVESCREEN or keys._MOUSE_R then
return false
elseif keys.KEYBOARD_CURSOR_RIGHT then
self:onSubmit2(self.subviews.list:getSelected())
return true
elseif keys._MOUSE_L_DOWN then
elseif keys._MOUSE_L then
local list = self.subviews.list
local x = list:getMousePos()
if x == 0 then -- clicked on icon
self:onSubmit2(list:getSelected())
df.global.enabler.mouse_lbut = 0
gui.markMouseClicksHandled(keys)
return true
end
if not self:getMouseFramePos() then
self.parent_view:dismiss()
return true
end
df.global.enabler.mouse_lbut = 0
gui.markMouseClicksHandled(keys)
end
self:inputToSubviews(keys)
return true -- we're modal

@ -507,9 +507,6 @@ function feed_viewscreen_widgets(vs_name, vs, keys)
return false
end
gui.markMouseClicksHandled(keys)
if keys._MOUSE_L_DOWN then
df.global.enabler.mouse_lbut = 0
end
return true
end

@ -1148,9 +1148,7 @@ function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn)
end
function SquadAssignmentOverlay:onInput(keys)
if keys._MOUSE_R_DOWN or
keys._MOUSE_L_DOWN and not self:getMouseFramePos()
then
if keys._MOUSE_R or (keys._MOUSE_L and not self:getMouseFramePos()) then
-- if any click is made outside of our window, we may need to refresh our list
self.dirty = true
end

@ -801,10 +801,12 @@ end
function AssignAnimalScreen:onInput(keys)
local handled = AssignAnimalScreen.super.onInput(self, keys)
if not self.is_valid_ui_state() then
view:dismiss()
if view then
view:dismiss()
end
return
end
if keys._MOUSE_L_DOWN then
if keys._MOUSE_L then
-- if any click is made outside of our window, we need to recheck unit properties
local window = self.subviews[1]
if not window:getMouseFramePos() then
@ -818,7 +820,7 @@ function AssignAnimalScreen:onInput(keys)
end
function AssignAnimalScreen:onRenderFrame()
if not self.is_valid_ui_state() then
if view and not self.is_valid_ui_state() then
view:dismiss()
end
end
@ -1072,6 +1074,7 @@ function CageChainOverlay:init()
frame={t=0, l=0, r=0, h=1},
label='DFHack assign',
key='CUSTOM_CTRL_T',
visible=is_valid_building,
on_activate=function() view = view and view:raise() or show_cage_chain_screen() end,
},
}

@ -42,17 +42,17 @@ function test.editfield_click()
expect.eq(5, e.cursor)
mock.patch(e, 'getMousePos', mock.func(0), function()
e:onInput{_MOUSE_L=true}
e:onInput{_MOUSE_L_DOWN=true}
expect.eq(1, e.cursor)
end)
mock.patch(e, 'getMousePos', mock.func(20), function()
e:onInput{_MOUSE_L=true}
e:onInput{_MOUSE_L_DOWN=true}
expect.eq(5, e.cursor, 'should only seek to end of text')
end)
mock.patch(e, 'getMousePos', mock.func(2), function()
e:onInput{_MOUSE_L=true}
e:onInput{_MOUSE_L_DOWN=true}
expect.eq(3, e.cursor)
end)
end

@ -59,37 +59,37 @@ function test.onInput()
s:update(23, 10, 50)
expect.false_(s:onInput{}, 'no mouse down')
expect.false_(s:onInput{_MOUSE_L_DOWN=true}, 'no y coord')
expect.false_(s:onInput{_MOUSE_L=true}, 'no y coord')
spec, y = nil, 0
expect.true_(s:onInput{_MOUSE_L_DOWN=true})
expect.true_(s:onInput{_MOUSE_L=true})
expect.eq('up_small', spec, 'on up arrow')
spec, y = nil, 1
expect.true_(s:onInput{_MOUSE_L_DOWN=true})
expect.true_(s:onInput{_MOUSE_L=true})
expect.eq('up_large', spec, 'on body above bar')
spec, y = nil, 44
expect.true_(s:onInput{_MOUSE_L_DOWN=true})
expect.true_(s:onInput{_MOUSE_L=true})
expect.eq('up_large', spec, 'on body just above bar')
spec, y = nil, 45
expect.true_(s:onInput{_MOUSE_L_DOWN=true})
expect.true_(s:onInput{_MOUSE_L=true})
expect.nil_(spec, 'on top of bar')
spec, y = nil, 63
expect.true_(s:onInput{_MOUSE_L_DOWN=true})
expect.true_(s:onInput{_MOUSE_L=true})
expect.nil_(spec, 'on bottom of bar')
spec, y = nil, 64
expect.true_(s:onInput{_MOUSE_L_DOWN=true})
expect.true_(s:onInput{_MOUSE_L=true})
expect.eq('down_large', spec, 'on body just below bar')
spec, y = nil, 98
expect.true_(s:onInput{_MOUSE_L_DOWN=true})
expect.true_(s:onInput{_MOUSE_L=true})
expect.eq('down_large', spec, 'on body below bar')
spec, y = nil, 99
expect.true_(s:onInput{_MOUSE_L_DOWN=true})
expect.true_(s:onInput{_MOUSE_L=true})
expect.eq('down_small', spec, 'on down arrow')
end

@ -7,7 +7,7 @@ function test.hotkeylabel_click()
local l = widgets.HotkeyLabel{key='SELECT', on_activate=func}
mock.patch(l, 'getMousePos', mock.func(0), function()
l:onInput{_MOUSE_L_DOWN=true}
l:onInput{_MOUSE_L=true}
expect.eq(1, func.call_count)
end)
end
@ -33,7 +33,7 @@ function test.togglehotkeylabel_click()
local l = widgets.ToggleHotkeyLabel{}
expect.true_(l:getOptionValue())
mock.patch(l, 'getMousePos', mock.func(0), function()
l:onInput{_MOUSE_L_DOWN=true}
l:onInput{_MOUSE_L=true}
expect.false_(l:getOptionValue())
end)
end