2014-06-01 17:55:23 +00:00
|
|
|
/*
|
2018-09-02 00:57:29 +00:00
|
|
|
* This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
|
2014-06-01 17:55:23 +00:00
|
|
|
* It is copyright by its individual contributors, as recorded in the
|
|
|
|
* project's Git history. See COPYING.txt at the top level for license
|
|
|
|
* terms and a link to the Git history.
|
|
|
|
*/
|
2006-03-20 17:12:09 +00:00
|
|
|
/*
|
|
|
|
*
|
2008-01-29 14:49:54 +00:00
|
|
|
* SDL mouse driver
|
2006-03-20 17:12:09 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
2013-06-30 02:22:56 +00:00
|
|
|
#include <SDL.h>
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2012-07-01 02:54:33 +00:00
|
|
|
#include "maths.h"
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "timer.h"
|
|
|
|
#include "event.h"
|
2011-10-30 11:09:11 +00:00
|
|
|
#include "window.h"
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "mouse.h"
|
2014-07-20 01:09:55 +00:00
|
|
|
#include "dxxerror.h"
|
2013-03-03 19:41:09 +00:00
|
|
|
#include "args.h"
|
2015-07-25 23:10:45 +00:00
|
|
|
#include "gr.h"
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2022-02-27 14:23:53 +00:00
|
|
|
#include "d_underlying_value.h"
|
|
|
|
|
2015-12-13 18:00:49 +00:00
|
|
|
namespace dcx {
|
2015-12-05 22:57:24 +00:00
|
|
|
|
2015-05-09 17:39:03 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct flushable_mouseinfo
|
|
|
|
{
|
2015-05-09 17:39:03 +00:00
|
|
|
int delta_x, delta_y, delta_z;
|
2015-05-09 17:39:03 +00:00
|
|
|
int z;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mouseinfo : flushable_mouseinfo
|
|
|
|
{
|
|
|
|
int x,y;
|
2010-12-10 23:18:17 +00:00
|
|
|
int cursor_enabled;
|
|
|
|
fix64 cursor_time;
|
2022-02-27 14:23:53 +00:00
|
|
|
enumerated_array<fix64, MOUSE_MAX_BUTTONS, mbtn> time_lastpressed;
|
2015-05-09 17:39:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static mouseinfo Mouse;
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2022-02-27 14:23:53 +00:00
|
|
|
d_event_mousebutton::d_event_mousebutton(const event_type etype, const mbtn b) :
|
2015-11-26 02:56:54 +00:00
|
|
|
d_event{etype}, button(b)
|
2015-05-28 03:08:39 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-07-16 11:07:42 +00:00
|
|
|
void mouse_init(void)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2014-07-04 03:50:00 +00:00
|
|
|
Mouse = {};
|
2010-07-28 17:27:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mouse_close(void)
|
|
|
|
{
|
|
|
|
SDL_ShowCursor(SDL_ENABLE);
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
2022-02-27 14:23:53 +00:00
|
|
|
static window_event_result maybe_send_z_move(const mbtn button)
|
2015-05-28 03:08:38 +00:00
|
|
|
{
|
2016-04-03 17:50:42 +00:00
|
|
|
short dz;
|
2022-02-27 14:23:53 +00:00
|
|
|
if (button == mbtn::z_up)
|
2015-05-28 03:08:38 +00:00
|
|
|
{
|
|
|
|
Mouse.delta_z += Z_SENSITIVITY;
|
|
|
|
Mouse.z += Z_SENSITIVITY;
|
2016-04-03 17:50:42 +00:00
|
|
|
dz = Z_SENSITIVITY;
|
2015-05-28 03:08:38 +00:00
|
|
|
}
|
2022-02-27 14:23:53 +00:00
|
|
|
else if (button == mbtn::z_down)
|
2015-05-28 03:08:38 +00:00
|
|
|
{
|
|
|
|
Mouse.delta_z -= Z_SENSITIVITY;
|
|
|
|
Mouse.z -= Z_SENSITIVITY;
|
2016-04-03 17:50:42 +00:00
|
|
|
dz = -1*Z_SENSITIVITY;
|
2015-05-28 03:08:38 +00:00
|
|
|
}
|
|
|
|
else
|
2016-10-28 06:43:20 +00:00
|
|
|
return window_event_result::ignored;
|
2018-05-12 18:24:19 +00:00
|
|
|
const d_event_mouse_moved event{EVENT_MOUSE_MOVED, 0, 0, dz};
|
2016-10-28 06:43:20 +00:00
|
|
|
return event_send(event);
|
2015-05-28 03:08:38 +00:00
|
|
|
}
|
|
|
|
|
2022-02-27 14:23:53 +00:00
|
|
|
static window_event_result send_singleclick(const bool pressed, const mbtn button)
|
2015-05-28 03:08:38 +00:00
|
|
|
{
|
2015-05-28 03:08:39 +00:00
|
|
|
const d_event_mousebutton event{pressed ? EVENT_MOUSE_BUTTON_DOWN : EVENT_MOUSE_BUTTON_UP, button};
|
2016-04-03 17:50:42 +00:00
|
|
|
con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_BUTTON_%s, button %d, coords %d,%d,%d",
|
2022-02-27 14:23:53 +00:00
|
|
|
pressed ? "DOWN" : "UP", underlying_value(event.button), Mouse.x, Mouse.y, Mouse.z);
|
2016-10-28 06:43:20 +00:00
|
|
|
return event_send(event);
|
2015-05-28 03:08:38 +00:00
|
|
|
}
|
|
|
|
|
2022-02-27 14:23:53 +00:00
|
|
|
static window_event_result maybe_send_doubleclick(const fix64 now, const mbtn button)
|
2015-05-28 03:08:38 +00:00
|
|
|
{
|
|
|
|
auto &when = Mouse.time_lastpressed[button];
|
|
|
|
const auto then = when;
|
|
|
|
when = now;
|
|
|
|
if (now > then + F1_0/5)
|
2016-10-28 06:43:20 +00:00
|
|
|
return window_event_result::ignored;
|
2015-05-28 03:08:39 +00:00
|
|
|
const d_event_mousebutton event{EVENT_MOUSE_DOUBLE_CLICKED, button};
|
2022-02-27 14:23:53 +00:00
|
|
|
con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_DOUBLE_CLICKED, button %d, coords %d,%d", underlying_value(button), Mouse.x, Mouse.y);
|
2016-10-28 06:43:20 +00:00
|
|
|
return event_send(event);
|
2015-05-28 03:08:38 +00:00
|
|
|
}
|
|
|
|
|
2020-05-27 03:07:17 +00:00
|
|
|
window_event_result mouse_button_handler(const SDL_MouseButtonEvent *const mbe)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2016-10-28 06:43:20 +00:00
|
|
|
window_event_result highest_result(window_event_result::ignored);
|
|
|
|
|
2015-07-18 21:01:56 +00:00
|
|
|
if (unlikely(CGameArg.CtlNoMouse))
|
2016-10-28 06:43:20 +00:00
|
|
|
return window_event_result::ignored;
|
2006-03-20 17:12:09 +00:00
|
|
|
// to bad, SDL buttons use a different mapping as descent expects,
|
|
|
|
// this is at least true and tested for the first three buttons
|
2022-02-27 14:23:53 +00:00
|
|
|
static constexpr std::array<mbtn, 17> button_remap{{
|
|
|
|
mbtn::left,
|
|
|
|
mbtn::middle,
|
|
|
|
mbtn::right,
|
|
|
|
mbtn::z_up,
|
|
|
|
mbtn::z_down,
|
|
|
|
mbtn::pitch_backward,
|
|
|
|
mbtn::pitch_forward,
|
|
|
|
mbtn::bank_left,
|
|
|
|
mbtn::bank_right,
|
|
|
|
mbtn::head_left,
|
|
|
|
mbtn::head_right,
|
|
|
|
mbtn::_11,
|
|
|
|
mbtn::_12,
|
|
|
|
mbtn::_13,
|
|
|
|
mbtn::_14,
|
|
|
|
mbtn::_15,
|
|
|
|
mbtn::_16,
|
2014-10-04 18:05:26 +00:00
|
|
|
}};
|
2015-05-28 03:08:38 +00:00
|
|
|
const unsigned button_idx = mbe->button - 1; // -1 since SDL seems to start counting at 1
|
|
|
|
if (unlikely(button_idx >= button_remap.size()))
|
2016-10-28 06:43:20 +00:00
|
|
|
return window_event_result::ignored;
|
2010-07-16 11:07:42 +00:00
|
|
|
|
2015-05-28 03:08:38 +00:00
|
|
|
const auto now = timer_query();
|
2015-05-28 03:08:38 +00:00
|
|
|
const auto button = button_remap[button_idx];
|
|
|
|
const auto mbe_state = mbe->state;
|
2015-05-28 03:08:38 +00:00
|
|
|
Mouse.cursor_time = now;
|
2010-07-16 11:07:42 +00:00
|
|
|
|
2015-05-28 03:08:38 +00:00
|
|
|
const auto pressed = mbe_state != SDL_RELEASED;
|
|
|
|
if (pressed) {
|
2016-10-28 06:43:20 +00:00
|
|
|
highest_result = maybe_send_z_move(button);
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
2016-10-28 06:43:20 +00:00
|
|
|
highest_result = std::max(send_singleclick(pressed, button), highest_result);
|
2011-09-12 03:03:57 +00:00
|
|
|
//Double-click support
|
2015-05-28 03:08:38 +00:00
|
|
|
if (pressed)
|
2011-09-12 03:03:57 +00:00
|
|
|
{
|
2016-10-28 06:43:20 +00:00
|
|
|
highest_result = std::max(maybe_send_doubleclick(now, button), highest_result);
|
2011-09-12 03:03:57 +00:00
|
|
|
}
|
2016-10-28 06:43:20 +00:00
|
|
|
|
|
|
|
return highest_result;
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
2020-05-27 03:07:17 +00:00
|
|
|
window_event_result mouse_motion_handler(const SDL_MouseMotionEvent *const mme)
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2010-12-10 23:18:17 +00:00
|
|
|
Mouse.cursor_time = timer_query();
|
2006-03-20 17:12:09 +00:00
|
|
|
Mouse.x += mme->xrel;
|
|
|
|
Mouse.y += mme->yrel;
|
2011-01-14 09:51:13 +00:00
|
|
|
|
2018-05-12 18:24:19 +00:00
|
|
|
// z handled in mouse_button_handler
|
|
|
|
const d_event_mouse_moved event{EVENT_MOUSE_MOVED, mme->xrel, mme->yrel, 0};
|
2011-01-14 09:51:13 +00:00
|
|
|
|
2013-12-07 00:47:27 +00:00
|
|
|
//con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_MOVED, relative motion %d,%d,%d",
|
2011-01-14 09:51:13 +00:00
|
|
|
// event.dx, event.dy, event.dz);
|
2016-10-28 06:43:20 +00:00
|
|
|
return event_send(event);
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mouse_flush() // clears all mice events...
|
|
|
|
{
|
2010-05-03 10:47:10 +00:00
|
|
|
// event_poll();
|
2015-05-09 17:39:03 +00:00
|
|
|
static_cast<flushable_mouseinfo &>(Mouse) = {};
|
2006-03-20 17:12:09 +00:00
|
|
|
SDL_GetMouseState(&Mouse.x, &Mouse.y); // necessary because polling only gives us the delta.
|
|
|
|
}
|
|
|
|
|
|
|
|
//========================================================================
|
2007-05-14 13:38:44 +00:00
|
|
|
void mouse_get_pos( int *x, int *y, int *z )
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2010-04-03 07:24:50 +00:00
|
|
|
//event_poll(); // Have to assume this is called in event_process, because event_poll can cause a window to close (depending on what the user does)
|
2006-03-20 17:12:09 +00:00
|
|
|
*x=Mouse.x;
|
|
|
|
*y=Mouse.y;
|
|
|
|
*z=Mouse.z;
|
|
|
|
}
|
|
|
|
|
2014-08-06 02:10:49 +00:00
|
|
|
window_event_result mouse_in_window(window *wind)
|
2011-10-30 11:09:11 +00:00
|
|
|
{
|
2020-08-28 00:18:45 +00:00
|
|
|
auto &canv = wind->w_canv;
|
2015-05-09 17:39:03 +00:00
|
|
|
return (static_cast<unsigned>(Mouse.x) - canv.cv_bitmap.bm_x <= canv.cv_bitmap.bm_w) &&
|
|
|
|
(static_cast<unsigned>(Mouse.y) - canv.cv_bitmap.bm_y <= canv.cv_bitmap.bm_h) ? window_event_result::handled : window_event_result::ignored;
|
2011-10-30 11:09:11 +00:00
|
|
|
}
|
|
|
|
|
2007-05-14 13:38:44 +00:00
|
|
|
void mouse_get_delta( int *dx, int *dy, int *dz )
|
2006-03-20 17:12:09 +00:00
|
|
|
{
|
2008-10-16 17:27:02 +00:00
|
|
|
*dz = Mouse.delta_z;
|
|
|
|
Mouse.delta_x = 0;
|
|
|
|
Mouse.delta_y = 0;
|
2009-01-15 20:55:35 +00:00
|
|
|
Mouse.delta_z = 0;
|
2015-05-09 17:39:03 +00:00
|
|
|
SDL_GetRelativeMouseState(dx, dy);
|
2006-03-20 17:12:09 +00:00
|
|
|
}
|
|
|
|
|
2015-05-28 03:08:38 +00:00
|
|
|
template <bool noactivate>
|
|
|
|
static void mouse_change_cursor()
|
2010-07-16 11:07:42 +00:00
|
|
|
{
|
2015-07-18 21:01:56 +00:00
|
|
|
Mouse.cursor_enabled = (!noactivate && !CGameArg.CtlNoMouse && !CGameArg.CtlNoCursor);
|
2010-12-28 18:11:10 +00:00
|
|
|
if (!Mouse.cursor_enabled)
|
2010-07-30 17:59:21 +00:00
|
|
|
SDL_ShowCursor(SDL_DISABLE);
|
2010-07-16 11:07:42 +00:00
|
|
|
}
|
|
|
|
|
2015-05-28 03:08:38 +00:00
|
|
|
void mouse_enable_cursor()
|
|
|
|
{
|
|
|
|
mouse_change_cursor<false>();
|
|
|
|
}
|
|
|
|
|
|
|
|
void mouse_disable_cursor()
|
|
|
|
{
|
|
|
|
mouse_change_cursor<true>();
|
|
|
|
}
|
|
|
|
|
2010-12-28 18:11:10 +00:00
|
|
|
// If we want to display/hide cursor, do so if not already and also hide it automatically after some time.
|
|
|
|
void mouse_cursor_autohide()
|
2010-07-26 18:10:21 +00:00
|
|
|
{
|
2011-02-02 00:36:49 +00:00
|
|
|
static fix64 hidden_time = 0;
|
2010-07-16 11:07:42 +00:00
|
|
|
|
2015-05-09 17:39:03 +00:00
|
|
|
const auto is_showing = SDL_ShowCursor(SDL_QUERY);
|
|
|
|
int result;
|
2010-07-26 18:10:21 +00:00
|
|
|
if (Mouse.cursor_enabled)
|
|
|
|
{
|
2015-05-09 17:39:03 +00:00
|
|
|
const auto now = timer_query();
|
|
|
|
const auto cursor_time = Mouse.cursor_time;
|
|
|
|
const auto recent_cursor_time = cursor_time + (F1_0*2) >= now;
|
|
|
|
if (is_showing)
|
2011-02-02 00:36:49 +00:00
|
|
|
{
|
2015-05-09 17:39:03 +00:00
|
|
|
if (recent_cursor_time)
|
|
|
|
return;
|
|
|
|
hidden_time = now;
|
|
|
|
result = SDL_DISABLE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!(recent_cursor_time && hidden_time + (F1_0/2) < now))
|
|
|
|
return;
|
|
|
|
result = SDL_ENABLE;
|
2011-02-02 00:36:49 +00:00
|
|
|
}
|
2010-07-26 18:10:21 +00:00
|
|
|
}
|
2010-07-28 17:27:35 +00:00
|
|
|
else
|
2010-07-26 18:10:21 +00:00
|
|
|
{
|
2015-05-09 17:39:03 +00:00
|
|
|
if (!is_showing)
|
|
|
|
return;
|
|
|
|
result = SDL_DISABLE;
|
2010-07-26 18:10:21 +00:00
|
|
|
}
|
2015-05-09 17:39:03 +00:00
|
|
|
SDL_ShowCursor(result);
|
2010-07-16 11:07:42 +00:00
|
|
|
}
|
2015-12-05 22:57:24 +00:00
|
|
|
|
|
|
|
}
|