Fix remaining input issues with scaled display.

There is a new sdl::get_mouse_state() function that should be used in place
of SDL_GetMouseState() in every case. It returns coordinates relative to
the drawing surface.

With this, the pixel scale option seems to be working without issue.
This commit is contained in:
Tommy 2022-04-16 20:35:25 +12:00
parent d130622b96
commit ab10d4d219
21 changed files with 195 additions and 34 deletions

View file

@ -342,6 +342,7 @@ scripting/mapgen_lua_kernel.cpp
scripting/plugins/context.cpp
scripting/plugins/manager.cpp
sdl/point.cpp
sdl/input.cpp
map_settings.cpp
side_filter.cpp
statistics.cpp

View file

@ -29,6 +29,7 @@
#include "gui/core/event/handler.hpp" // gui2::is_in_dialog
#include "soundsource.hpp"
#include "gui/core/timer.hpp"
#include "sdl/input.hpp" // get_mouse_state
static lg::log_domain log_display("display");
#define ERR_DP LOG_STREAM(err, log_display)
@ -62,7 +63,7 @@ void controller_base::long_touch_callback(int x, int y)
if(long_touch_timer_ != 0 && !get_mouse_handler_base().dragging_started()) {
int x_now;
int y_now;
uint32_t mouse_state = SDL_GetMouseState(&x_now, &y_now);
uint32_t mouse_state = sdl::get_mouse_state(&x_now, &y_now);
#ifdef MOUSE_TOUCH_EMULATION
if(mouse_state & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
@ -385,7 +386,7 @@ void controller_base::play_slice(bool is_delay_enabled)
bool was_scrolling = scrolling_;
int mousex, mousey;
uint8_t mouse_flags = SDL_GetMouseState(&mousex, &mousey);
uint8_t mouse_flags = sdl::get_mouse_state(&mousex, &mousey);
scrolling_ = handle_scroll(mousex, mousey, mouse_flags);

View file

@ -54,6 +54,7 @@
#include "units/animation_component.hpp"
#include "game_config_manager.hpp"
#include "quit_confirmation.hpp"
#include "sdl/input.hpp" // get_mouse_button_mask
#include <functional>
@ -1258,10 +1259,10 @@ void editor_controller::mouse_motion(int x, int y, const bool /*browse*/,
// last_undo is a non-owning pointer. Although it could have other uses, it seems to be
// mainly (only?) used for printing debugging information.
auto last_undo = get_current_map_context().last_undo_action();
if (dragging_left_ && (SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(1)) != 0) {
if (dragging_left_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(1)) != 0) {
if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
a = get_mouse_action().drag_left(*gui_, x, y, partial, last_undo);
} else if (dragging_right_ && (SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(3)) != 0) {
} else if (dragging_right_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(3)) != 0) {
if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
a = get_mouse_action().drag_right(*gui_, x, y, partial, last_undo);
}

View file

@ -24,6 +24,7 @@
#include "editor/action/mouse/mouse_action_select.hpp"
#include "game_config_view.hpp"
#include "sdl/input.hpp" // get_mouse_state
namespace editor {
@ -131,7 +132,7 @@ void editor_toolkit::update_mouse_action_highlights()
{
DBG_ED << __func__ << "\n";
int x, y;
SDL_GetMouseState(&x, &y);
sdl::get_mouse_state(&x, &y);
map_location hex_clicked = gui_.hex_clicked_on(x,y);
get_mouse_action().update_brush_highlights(gui_, hex_clicked);
}

View file

@ -25,6 +25,7 @@
#include "gui/widgets/widget.hpp"
#include "gui/widgets/window.hpp"
#include "sdl/userevent.hpp"
#include "sdl/input.hpp" // get_mouse_button_mask
#include <array>
#include <functional>
@ -529,7 +530,7 @@ void mouse_button<I>::signal_handler_sdl_button_up(
if(mouse_captured_) {
const unsigned mask = SDL_BUTTON_LMASK | SDL_BUTTON_MMASK | SDL_BUTTON_RMASK;
if((SDL_GetMouseState(nullptr, nullptr) & mask) == 0) {
if((sdl::get_mouse_button_mask() & mask) == 0) {
mouse_captured_ = false;
}
@ -662,7 +663,7 @@ distributor::~distributor()
void distributor::initialize_state()
{
const uint32_t button_state = SDL_GetMouseState(nullptr, nullptr);
const uint32_t button_state = sdl::get_mouse_button_mask();
mouse_button_left::initialize_state(button_state);
mouse_button_middle::initialize_state(button_state);

View file

@ -25,6 +25,7 @@
#include "gui/widgets/settings.hpp"
#include "sdl/rect.hpp"
#include "tstring.hpp"
#include "sdl/input.hpp" // get_mouse_location
#include <SDL2/SDL.h>
@ -117,10 +118,7 @@ wfl::map_formula_callable get_screen_size_variables()
point get_mouse_position()
{
int x, y;
SDL_GetMouseState(&x, &y);
return point(x, y);
return sdl::get_mouse_location();
}
std::string debug_truncate(const std::string& text)

View file

@ -61,6 +61,7 @@
#include "video.hpp"
#include "wml_exception.hpp"
#include "sdl/userevent.hpp"
#include "sdl/input.hpp" // get_mouse_button_mask
#include <functional>
@ -551,7 +552,7 @@ int window::show(const bool restore, const unsigned auto_close_timeout)
* return the proper button state. When initializing here all
* works fine.
*/
mouse_button_state_ = SDL_GetMouseState(nullptr, nullptr);
mouse_button_state_ = sdl::get_mouse_button_mask();
mouse_button_state_initialized = true;
}

View file

@ -15,7 +15,6 @@
#include "help/help_browser.hpp"
#include <iostream> // for operator<<, basic_ostream, etc
#include <SDL2/SDL_mouse.h> // for SDL_GetMouseState, etc
#include "cursor.hpp" // for set, CURSOR_TYPE::HYPERLINK, etc
#include "font/constants.hpp" // for relative_size
#include "gettext.hpp" // for _
@ -25,6 +24,7 @@
#include "key.hpp" // for CKey
#include "log.hpp" // for log_scope
#include "sdl/rect.hpp"
#include "sdl/input.hpp" // for get_mouse_state
class CVideo;
struct SDL_Rect;
@ -97,7 +97,7 @@ void help_browser::process_event()
{
CKey key;
int mousex, mousey;
SDL_GetMouseState(&mousex,&mousey);
sdl::get_mouse_state(&mousex,&mousey);
// Fake focus functionality for the menu, only process it if it has focus.
if (sdl::point_in_rect(mousex, mousey, menu_.location())) {
@ -193,7 +193,7 @@ void help_browser::handle_event(const SDL_Event &event)
void help_browser::update_cursor()
{
int mousex, mousey;
SDL_GetMouseState(&mousex,&mousey);
sdl::get_mouse_state(&mousex,&mousey);
const std::string ref = text_area_.ref_at(mousex, mousey);
if (!ref.empty() && !ref_cursor_) {
cursor::set(cursor::HYPERLINK);

View file

@ -19,6 +19,7 @@
#include "help/help_impl.hpp" // for section, topic, topic_list, etc
#include "sound.hpp" // for play_UI_sound
#include "wml_separators.hpp" // for IMG_TEXT_SEPARATOR, etc
#include "sdl/input.hpp" // for get_mouse_state
#include <algorithm> // for find
#include <iostream> // for basic_ostream, operator<<, etc
@ -157,7 +158,7 @@ int help_menu::process()
{
int res = menu::process();
int mousex, mousey;
SDL_GetMouseState(&mousex,&mousey);
sdl::get_mouse_state(&mousex, &mousey);
if (!visible_items_.empty() &&
static_cast<std::size_t>(res) < visible_items_.size()) {

View file

@ -33,6 +33,7 @@
#include "show_dialog.hpp"
#include "../resources.hpp"
#include "../playmp_controller.hpp"
#include "sdl/input.hpp" // get_mouse_state
#include <functional>
@ -421,7 +422,7 @@ void command_executor::show_menu(const std::vector<config>& items_arg, int xloc,
const theme::menu* submenu = gui.get_theme().get_menu_item(items[res]["id"]);
if (submenu) {
int y,x;
SDL_GetMouseState(&x,&y);
sdl::get_mouse_state(&x,&y);
this->show_menu(submenu->items(), x, y, submenu->is_context(), gui);
} else {
const hotkey::hotkey_command& cmd = hotkey::get_hotkey_command(items[res]["id"]);

View file

@ -43,8 +43,8 @@
#include "units/unit.hpp" // for unit
#include "whiteboard/manager.hpp" // for manager, etc
#include "whiteboard/typedefs.hpp" // for whiteboard_lock
#include "sdl/input.hpp" // for get_mouse_state
#include <SDL2/SDL_mouse.h> // for SDL_GetMouseState
#include <cassert> // for assert
#include <new> // for bad_alloc
#include <ostream> // for operator<<, basic_ostream, etc
@ -101,7 +101,7 @@ void mouse_handler::touch_motion(int x, int y, const bool browse, bool update, m
{
// Frankensteining from mouse_motion(), as it has a lot in common, but a lot of differences too.
// Copy-pasted from everywhere. TODO: generalize the two.
SDL_GetMouseState(&x,&y);
sdl::get_mouse_state(&x,&y);
// This is from mouse_handler_base::mouse_motion_default()
tooltips::process(x, y);
@ -130,7 +130,7 @@ void mouse_handler::touch_motion(int x, int y, const bool browse, bool update, m
int my = drag_from_y_;
if(is_dragging() && !dragging_started_) {
if(dragging_touch_) {
SDL_GetMouseState(&mx, &my);
sdl::get_mouse_state(&mx, &my);
const double drag_distance = std::pow(static_cast<double>(drag_from_x_- mx), 2)
+ std::pow(static_cast<double>(drag_from_y_- my), 2);
if(drag_distance > drag_threshold()*drag_threshold()) {
@ -143,7 +143,7 @@ void mouse_handler::touch_motion(int x, int y, const bool browse, bool update, m
const auto found_unit = find_unit(selected_hex_);
bool selected_hex_has_my_unit = found_unit.valid() && found_unit.get_shared_ptr()->side() == side_num_;
if((browse || !found_unit.valid()) && is_dragging() && dragging_started_) {
SDL_GetMouseState(&mx, &my);
sdl::get_mouse_state(&mx, &my);
if(sdl::point_in_rect(x, y, gui().map_area())) {
int dx = drag_from_x_ - mx;
@ -388,7 +388,7 @@ void mouse_handler::mouse_motion(int x, int y, const bool browse, bool update, m
// to highlight all the hexes where the mouse passed.
// Also, sometimes it seems to have one *very* obsolete
// and isolated mouse motion event when using drag&drop
SDL_GetMouseState(&x, &y); // <-- modify x and y
sdl::get_mouse_state(&x, &y); // <-- modify x and y
if(mouse_handler_base::mouse_motion_default(x, y, update)) {
return;
@ -629,7 +629,7 @@ const map_location mouse_handler::hovered_hex() const
{
int x = -1;
int y = -1;
SDL_GetMouseState(&x, &y);
sdl::get_mouse_state(&x, &y);
return gui_->hex_clicked_on(x, y);
}

View file

@ -22,6 +22,7 @@
#include "preferences/general.hpp"
#include "sdl/rect.hpp"
#include "tooltips.hpp"
#include "sdl/input.hpp" // get_mouse_state
static lg::log_domain log_display("display");
#define WRN_DP LOG_STREAM(warn, log_display)
@ -92,7 +93,7 @@ void mouse_handler_base::touch_motion_event(const SDL_TouchFingerEvent& event, c
void mouse_handler_base::mouse_update(const bool browse, map_location loc)
{
int x, y;
SDL_GetMouseState(&x, &y);
sdl::get_mouse_state(&x, &y);
mouse_motion(x, y, browse, true, loc);
}
@ -108,7 +109,7 @@ bool mouse_handler_base::mouse_motion_default(int x, int y, bool /*update*/)
// if the game is run in a window, we could miss a LMB/MMB up event
// if it occurs outside our window.
// thus, we need to check if the LMB/MMB is still down
minimap_scrolling_ = ((SDL_GetMouseState(nullptr, nullptr) & (SDL_BUTTON(SDL_BUTTON_LEFT) | SDL_BUTTON(SDL_BUTTON_MIDDLE))) != 0);
minimap_scrolling_ = ((sdl::get_mouse_button_mask() & (SDL_BUTTON(SDL_BUTTON_LEFT) | SDL_BUTTON(SDL_BUTTON_MIDDLE))) != 0);
if(minimap_scrolling_) {
const map_location& loc = gui().minimap_location_on(x, y);
if(loc.valid()) {
@ -133,7 +134,7 @@ bool mouse_handler_base::mouse_motion_default(int x, int y, bool /*update*/)
int my = drag_from_y_;
if(is_dragging() && !dragging_started_) {
Uint32 mouse_state = dragging_left_ || dragging_right_ ? SDL_GetMouseState(&mx, &my) : 0;
Uint32 mouse_state = dragging_left_ || dragging_right_ ? sdl::get_mouse_state(&mx, &my) : 0;
#ifdef MOUSE_TOUCH_EMULATION
if(dragging_left_ && (mouse_state & SDL_BUTTON(SDL_BUTTON_RIGHT))) {
// Monkey-patch touch controls again to make them look like left button.
@ -311,7 +312,7 @@ void mouse_handler_base::left_drag_end(int /*x*/, int /*y*/, const bool browse)
void mouse_handler_base::mouse_wheel(int scrollx, int scrolly, bool browse)
{
int x, y;
SDL_GetMouseState(&x, &y);
sdl::get_mouse_state(&x, &y);
int movex = scrollx * preferences::scroll_speed();
int movey = scrolly * preferences::scroll_speed();
@ -361,7 +362,7 @@ void mouse_handler_base::right_mouse_up(int x, int y, const bool browse)
void mouse_handler_base::init_dragging(bool& dragging_flag)
{
dragging_flag = true;
SDL_GetMouseState(&drag_from_x_, &drag_from_y_);
sdl::get_mouse_state(&drag_from_x_, &drag_from_y_);
drag_from_hex_ = gui().hex_clicked_on(drag_from_x_, drag_from_y_);
}

View file

@ -41,6 +41,7 @@
#include "tstring.hpp"
#include "game_data.hpp"
#include "game_state.hpp"
#include "sdl/input.hpp" // get_mouse_state
#include <functional>
#include <optional>
@ -184,7 +185,7 @@ int show_story(lua_State* L) {
int show_menu(lua_State* L) {
std::vector<config> items = lua_check<std::vector<config>>(L, 1);
SDL_Rect pos {1,1,1,1};
SDL_GetMouseState(&pos.x, &pos.y);
sdl::get_mouse_state(&pos.x, &pos.y);
int initial = -1;
bool markup = false;

73
src/sdl/input.cpp Normal file
View file

@ -0,0 +1,73 @@
/*
Copyright (C) 2022
by Thomas Iorns <mesilliac@tomanui.nz>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "sdl/input.hpp"
#include "sdl/point.hpp"
#include <SDL2/SDL_mouse.h>
namespace {
SDL_Point drawing_surface_size;
SDL_Point window_size;
}
namespace sdl
{
uint32_t get_mouse_state(int *x, int *y)
{
uint32_t buttons = SDL_GetMouseState(x, y);
if (window_size.x == 0 || window_size.y == 0) {
// This will give bad results, but will not outright crash.
return buttons;
}
if (window_size.x != drawing_surface_size.x) {
*x = (*x * drawing_surface_size.x) / window_size.x;
}
if (window_size.y != drawing_surface_size.y) {
*y = (*y * drawing_surface_size.y) / window_size.y;
}
return buttons;
}
uint32_t get_mouse_button_mask()
{
return SDL_GetMouseState(nullptr, nullptr);
}
SDL_Point get_mouse_location()
{
SDL_Point p;
get_mouse_state(&p.x, &p.y);
return p;
}
void update_input_dimensions(
int draw_width, int draw_height,
int input_width, int input_height
) {
drawing_surface_size.x = draw_width;
drawing_surface_size.y = draw_height;
window_size.x = input_width;
window_size.y = input_height;
}
void update_input_dimensions(SDL_Point draw_size, SDL_Point input_size)
{
drawing_surface_size = draw_size;
window_size = input_size;
}
} // namespace sdl

61
src/sdl/input.hpp Normal file
View file

@ -0,0 +1,61 @@
/*
Copyright (C) 2022
by Thomas Iorns <mesilliac@tomanui.nz>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include <cstdint>
#pragma once
/**
* @file
* Contains functions for cleanly handling SDL input.
*/
struct SDL_Point;
namespace sdl
{
/**
* A wrapper for SDL_GetMouseState that gives coordinates in draw space.
*/
uint32_t get_mouse_state(int *x, int *y);
/** Returns the current mouse button mask */
uint32_t get_mouse_button_mask();
/** Returns the currnet mouse location in draw space. */
SDL_Point get_mouse_location();
/**
* Update the cached drawing area and input area sizes. These correspond to
* the size of the drawing surface in pixels, and the size of the window in
* display coordinates.
*
* This should be called every time the window is resized, or the pixel scale
* multiplier changes.
*
* @param draw_width The width of the drawing surface, in pixels
* @param draw_height The height of the drawing surface, in pixels
* @param input_width The width of the input surface, in display coordinates
* @param input_height The height of the input surface, in display coordinates
*/
void update_input_dimensions(
int draw_width, int draw_height,
int input_width, int input_height
);
void update_input_dimensions(SDL_Point draw_size, SDL_Point input_size);
} // namespace sdl

View file

@ -15,6 +15,7 @@
#include "sdl/surface.hpp"
#include "sdl/window.hpp"
#include "sdl/input.hpp"
#include "sdl/exception.hpp"
@ -69,6 +70,9 @@ window::window(const std::string& title,
fill(0,0,0);
// Now that we have a window and renderer we can scale input correctly.
update_input_dimensions(get_logical_size(), get_size());
render();
}
@ -82,6 +86,7 @@ window::~window()
void window::set_size(const int w, const int h)
{
SDL_SetWindowSize(window_, w, h);
update_input_dimensions(get_logical_size(), get_size());
}
SDL_Point window::get_size()
@ -108,21 +113,25 @@ void window::center()
void window::maximize()
{
SDL_MaximizeWindow(window_);
update_input_dimensions(get_logical_size(), get_size());
}
void window::to_window()
{
SDL_SetWindowFullscreen(window_, 0);
update_input_dimensions(get_logical_size(), get_size());
}
void window::restore()
{
SDL_RestoreWindow(window_);
update_input_dimensions(get_logical_size(), get_size());
}
void window::full_screen()
{
SDL_SetWindowFullscreen(window_, SDL_WINDOW_FULLSCREEN_DESKTOP);
update_input_dimensions(get_logical_size(), get_size());
}
void window::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
@ -157,6 +166,8 @@ uint32_t window::get_flags()
void window::set_minimum_size(int min_w, int min_h)
{
SDL_SetWindowMinimumSize(window_, min_w, min_h);
// Can this change the size of the window?
update_input_dimensions(get_logical_size(), get_size());
}
int window::get_display_index()
@ -168,6 +179,7 @@ void window::set_logical_size(int w, int h)
{
SDL_Renderer* r = SDL_GetRenderer(window_);
SDL_RenderSetLogicalSize(r, w, h);
update_input_dimensions(get_logical_size(), get_size());
}
SDL_Point window::get_logical_size() const

View file

@ -27,6 +27,7 @@
#include "font/sdl_ttf_compat.hpp"
#include "font/standard_colors.hpp"
#include "sdl/rect.hpp"
#include "sdl/input.hpp" // get_mouse_state
static lg::log_domain log_display("display");
#define ERR_DP LOG_STREAM(err, log_display)
@ -64,7 +65,7 @@ dialog_manager::~dialog_manager()
{
is_in_dialog = reset_to;
int mousex, mousey;
SDL_GetMouseState(&mousex, &mousey);
sdl::get_mouse_state(&mousex, &mousey);
SDL_Event pb_event;
pb_event.type = SDL_MOUSEMOTION;
pb_event.motion.state = 0;

View file

@ -25,6 +25,7 @@
#include "sdl/userevent.hpp"
#include "sdl/utils.hpp"
#include "sdl/window.hpp"
#include "sdl/input.hpp"
#ifdef TARGET_OS_OSX
#include "desktop/apple_video.hpp"
@ -254,6 +255,9 @@ void CVideo::update_framebuffer()
drawingSurface->h
);
}
// Update sizes for input conversion.
sdl::update_input_dimensions(lsize.x, lsize.y, wsize.x, wsize.y);
}
void CVideo::init_window()

View file

@ -18,7 +18,7 @@
#include "widgets/scrollarea.hpp"
#include "sdl/rect.hpp"
#include "video.hpp"
#include "sdl/input.hpp" // get_mouse_state
namespace gui {
@ -156,7 +156,7 @@ void scrollarea::handle_event(const SDL_Event& event)
if (event.type == SDL_MOUSEWHEEL) {
const SDL_MouseWheelEvent &ev = event.wheel;
int x, y;
SDL_GetMouseState(&x, &y);
sdl::get_mouse_state(&x, &y);
if (sdl::point_in_rect(x, y, inner_location())) {
if (ev.y > 0) {
scrollbar_.scroll_up();

View file

@ -21,6 +21,7 @@
#include "sdl/rect.hpp"
#include "sdl/utils.hpp"
#include "video.hpp"
#include "sdl/input.hpp" // get_mouse_state
#include <iostream>
@ -278,7 +279,7 @@ void scrollbar::handle_event(const SDL_Event& event)
{
const SDL_MouseWheelEvent& e = event.wheel;
int x, y;
SDL_GetMouseState(&x, &y);
sdl::get_mouse_state(&x, &y);
bool on_groove = sdl::point_in_rect(x, y, groove);
if (on_groove && e.y < 0) {
move_position(scroll_rate_);

View file

@ -24,6 +24,7 @@
#include "sdl/rect.hpp"
#include "serialization/string_utils.hpp"
#include "video.hpp"
#include "sdl/input.hpp" // get_mouse_state
static lg::log_domain log_display("display");
#define WRN_DP LOG_STREAM(warn, log_display)
@ -652,7 +653,7 @@ void textbox::handle_event(const SDL_Event& event, bool was_forwarded)
}
int mousex, mousey;
const uint8_t mousebuttons = SDL_GetMouseState(&mousex,&mousey);
const uint8_t mousebuttons = sdl::get_mouse_state(&mousex,&mousey);
if(!(mousebuttons & SDL_BUTTON(1))) {
grabmouse_ = false;
}