Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
3
 * It is copyright by its individual contributors, as recorded in the
4
 * project's Git history.  See COPYING.txt at the top level for license
5
 * terms and a link to the Git history.
6
 */
7
/*
8
 *
9
 * SDL mouse driver
10
 *
11
 */
12
 
13
#include <string.h>
14
#include <SDL.h>
15
 
16
#include "maths.h"
17
#include "timer.h"
18
#include "event.h"
19
#include "window.h"
20
#include "mouse.h"
21
#include "playsave.h"
22
#include "dxxerror.h"
23
#include "args.h"
24
#include "gr.h"
25
 
26
namespace dcx {
27
 
28
namespace {
29
 
30
struct flushable_mouseinfo
31
{
32
        int    delta_x, delta_y, delta_z;
33
        int z;
34
};
35
 
36
struct mouseinfo : flushable_mouseinfo
37
{
38
        int    x,y;
39
        int    cursor_enabled;
40
        fix64  cursor_time;
41
        std::array<fix64, MOUSE_MAX_BUTTONS> time_lastpressed;
42
};
43
 
44
}
45
 
46
static mouseinfo Mouse;
47
 
48
d_event_mousebutton::d_event_mousebutton(const event_type etype, const unsigned b) :
49
        d_event{etype}, button(b)
50
{
51
}
52
 
53
void mouse_init(void)
54
{
55
        Mouse = {};
56
}
57
 
58
void mouse_close(void)
59
{
60
        SDL_ShowCursor(SDL_ENABLE);
61
}
62
 
63
static window_event_result maybe_send_z_move(const unsigned button)
64
{
65
        short dz;
66
        if (button == MBTN_Z_UP)
67
        {
68
                Mouse.delta_z += Z_SENSITIVITY;
69
                Mouse.z += Z_SENSITIVITY;
70
                dz = Z_SENSITIVITY;
71
        }
72
        else if (button == MBTN_Z_DOWN)
73
        {
74
                Mouse.delta_z -= Z_SENSITIVITY;
75
                Mouse.z -= Z_SENSITIVITY;
76
                dz = -1*Z_SENSITIVITY;
77
        }
78
        else
79
                return window_event_result::ignored;
80
        const d_event_mouse_moved event{EVENT_MOUSE_MOVED, 0, 0, dz};
81
        return event_send(event);
82
}
83
 
84
static window_event_result send_singleclick(const bool pressed, const unsigned button)
85
{
86
        const d_event_mousebutton event{pressed ? EVENT_MOUSE_BUTTON_DOWN : EVENT_MOUSE_BUTTON_UP, button};
87
        con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_BUTTON_%s, button %d, coords %d,%d,%d",
88
                           pressed ? "DOWN" : "UP", event.button, Mouse.x, Mouse.y, Mouse.z);
89
        return event_send(event);
90
}
91
 
92
static window_event_result maybe_send_doubleclick(const fix64 now, const unsigned button)
93
{
94
        auto &when = Mouse.time_lastpressed[button];
95
        const auto then = when;
96
        when = now;
97
        if (now > then + F1_0/5)
98
                return window_event_result::ignored;
99
        const d_event_mousebutton event{EVENT_MOUSE_DOUBLE_CLICKED, button};
100
        con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_DOUBLE_CLICKED, button %d, coords %d,%d", button, Mouse.x, Mouse.y);
101
        return event_send(event);
102
}
103
 
104
window_event_result mouse_button_handler(const SDL_MouseButtonEvent *const mbe)
105
{
106
        window_event_result highest_result(window_event_result::ignored);
107
 
108
        if (unlikely(CGameArg.CtlNoMouse))
109
                return window_event_result::ignored;
110
        // to bad, SDL buttons use a different mapping as descent expects,
111
        // this is at least true and tested for the first three buttons 
112
        static const std::array<int, 17> button_remap{{
113
                MBTN_LEFT,
114
                MBTN_MIDDLE,
115
                MBTN_RIGHT,
116
                MBTN_Z_UP,
117
                MBTN_Z_DOWN,
118
                MBTN_PITCH_BACKWARD,
119
                MBTN_PITCH_FORWARD,
120
                MBTN_BANK_LEFT,
121
                MBTN_BANK_RIGHT,
122
                MBTN_HEAD_LEFT,
123
                MBTN_HEAD_RIGHT,
124
                MBTN_11,
125
                MBTN_12,
126
                MBTN_13,
127
                MBTN_14,
128
                MBTN_15,
129
                MBTN_16
130
        }};
131
        const unsigned button_idx = mbe->button - 1; // -1 since SDL seems to start counting at 1
132
        if (unlikely(button_idx >= button_remap.size()))
133
                return window_event_result::ignored;
134
 
135
        const auto now = timer_query();
136
        const auto button = button_remap[button_idx];
137
        const auto mbe_state = mbe->state;
138
        Mouse.cursor_time = now;
139
 
140
        const auto pressed = mbe_state != SDL_RELEASED;
141
        if (pressed) {
142
                highest_result = maybe_send_z_move(button);
143
        }
144
        highest_result = std::max(send_singleclick(pressed, button), highest_result);
145
        //Double-click support
146
        if (pressed)
147
        {
148
                highest_result = std::max(maybe_send_doubleclick(now, button), highest_result);
149
        }
150
 
151
        return highest_result;
152
}
153
 
154
window_event_result mouse_motion_handler(const SDL_MouseMotionEvent *const mme)
155
{
156
        Mouse.cursor_time = timer_query();
157
        Mouse.x += mme->xrel;
158
        Mouse.y += mme->yrel;
159
 
160
        // z handled in mouse_button_handler
161
        const d_event_mouse_moved event{EVENT_MOUSE_MOVED, mme->xrel, mme->yrel, 0};
162
 
163
        //con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_MOVED, relative motion %d,%d,%d",
164
        //                 event.dx, event.dy, event.dz);
165
        return event_send(event);
166
}
167
 
168
void mouse_flush()      // clears all mice events...
169
{
170
//      event_poll();
171
        static_cast<flushable_mouseinfo &>(Mouse) = {};
172
        SDL_GetMouseState(&Mouse.x, &Mouse.y); // necessary because polling only gives us the delta.
173
}
174
 
175
//========================================================================
176
void mouse_get_pos( int *x, int *y, int *z )
177
{
178
        //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)
179
        *x=Mouse.x;
180
        *y=Mouse.y;
181
        *z=Mouse.z;
182
}
183
 
184
window_event_result mouse_in_window(window *wind)
185
{
186
        auto &canv = window_get_canvas(*wind);
187
        return  (static_cast<unsigned>(Mouse.x) - canv.cv_bitmap.bm_x <= canv.cv_bitmap.bm_w) &&
188
                        (static_cast<unsigned>(Mouse.y) - canv.cv_bitmap.bm_y <= canv.cv_bitmap.bm_h) ? window_event_result::handled : window_event_result::ignored;
189
}
190
 
191
void mouse_get_delta( int *dx, int *dy, int *dz )
192
{
193
        *dz = Mouse.delta_z;
194
        Mouse.delta_x = 0;
195
        Mouse.delta_y = 0;
196
        Mouse.delta_z = 0;
197
        SDL_GetRelativeMouseState(dx, dy);
198
}
199
 
200
template <bool noactivate>
201
static void mouse_change_cursor()
202
{
203
        Mouse.cursor_enabled = (!noactivate && !CGameArg.CtlNoMouse && !CGameArg.CtlNoCursor);
204
        if (!Mouse.cursor_enabled)
205
                SDL_ShowCursor(SDL_DISABLE);
206
}
207
 
208
void mouse_enable_cursor()
209
{
210
        mouse_change_cursor<false>();
211
}
212
 
213
void mouse_disable_cursor()
214
{
215
        mouse_change_cursor<true>();
216
}
217
 
218
// If we want to display/hide cursor, do so if not already and also hide it automatically after some time.
219
void mouse_cursor_autohide()
220
{
221
        static fix64 hidden_time = 0;
222
 
223
        const auto is_showing = SDL_ShowCursor(SDL_QUERY);
224
        int result;
225
        if (Mouse.cursor_enabled)
226
        {
227
                const auto now = timer_query();
228
                const auto cursor_time = Mouse.cursor_time;
229
                const auto recent_cursor_time = cursor_time + (F1_0*2) >= now;
230
                if (is_showing)
231
                {
232
                        if (recent_cursor_time)
233
                                return;
234
                        hidden_time = now;
235
                        result = SDL_DISABLE;
236
                }
237
                else
238
                {
239
                        if (!(recent_cursor_time && hidden_time + (F1_0/2) < now))
240
                                return;
241
                        result = SDL_ENABLE;
242
                }
243
        }
244
        else
245
        {
246
                if (!is_showing)
247
                        return;
248
                result = SDL_DISABLE;
249
        }
250
        SDL_ShowCursor(result);
251
}
252
 
253
}