forked from aburch/simutrans
-
Notifications
You must be signed in to change notification settings - Fork 1
/
simevent.cc
279 lines (243 loc) · 7.32 KB
/
simevent.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/*
* system-independant event handling routines
* Hj. Malthaner, Jan. 2001
*/
#include "simevent.h"
#include "simsys.h"
#include "tpl/slist_tpl.h"
static int cx = -1; // coordinates of last mouse click event
static int cy = -1; // initialised to "nowhere"
static int control_shift_state = 0; // none pressed
static event_t meta_event(EVENT_NONE); // Knightly : for storing meta-events like double-clicks and triple-clicks
static unsigned int last_meta_class = EVENT_NONE;
static slist_tpl<event_t *> queued_events;
int event_get_last_control_shift()
{
// shift = 1
// ctrl = 2
return control_shift_state & 0x03;
}
unsigned int last_meta_event_get_class()
{
return last_meta_class;
}
/**
* each drag event contains the origin of the first click.
* if the window is being dragged, it is convenient to change this
* so the origin keeps pointing to the window top bar.
* Mainly to prevent copied, double code.
*/
void change_drag_start(int x, int y)
{
cx += x;
cy += y;
}
static void fill_event(event_t* const ev)
{
// Knightly : variables for detecting double-clicks and triple-clicks
const uint32 interval = 400;
static unsigned int prev_ev_class = EVENT_NONE;
static unsigned int prev_ev_code = 0;
static uint32 prev_ev_time = 0;
static unsigned char repeat_count = 0; // number of consecutive sequences of click-release
// for autorepeat buttons we track button state, press time and a repeat time
// code by Niels Roest and Hj. Maltahner
static int pressed_buttons = 0; // assume: at startup no button pressed (needed for some backends)
static uint32 lb_time = 0;
static uint32 repeat_time = 500;
ev->ev_class = EVENT_NONE;
ev->mx = sys_event.mx;
ev->my = sys_event.my;
ev->cx = cx;
ev->cy = cy;
// always put key mod code into event
ev->ev_key_mod = sys_event.key_mod;
control_shift_state = sys_event.key_mod;
switch (sys_event.type) {
case SIM_KEYBOARD:
ev->ev_class = EVENT_KEYBOARD;
ev->ev_code = sys_event.code;
break;
case SIM_MOUSE_BUTTONS:
// press only acknowledged when no buttons are pressed
pressed_buttons = sys_event.mb;
switch (sys_event.code) {
case SIM_MOUSE_LEFTBUTTON:
ev->ev_class = EVENT_CLICK;
pressed_buttons |= MOUSE_LEFTBUTTON;
ev->ev_code = MOUSE_LEFTBUTTON;
ev->cx = cx = sys_event.mx;
ev->cy = cy = sys_event.my;
break;
case SIM_MOUSE_RIGHTBUTTON:
ev->ev_class = EVENT_CLICK;
pressed_buttons |= MOUSE_RIGHTBUTTON;
ev->ev_code = MOUSE_RIGHTBUTTON;
ev->cx = cx = sys_event.mx;
ev->cy = cy = sys_event.my;
break;
case SIM_MOUSE_MIDBUTTON:
ev->ev_class = EVENT_CLICK;
pressed_buttons |= MOUSE_MIDBUTTON;
ev->ev_code = MOUSE_MIDBUTTON;
ev->cx = cx = sys_event.mx;
ev->cy = cy = sys_event.my;
break;
case SIM_MOUSE_WHEELUP:
ev->ev_class = EVENT_CLICK;
ev->ev_code = MOUSE_WHEELUP;
ev->cx = cx = sys_event.mx;
ev->cy = cy = sys_event.my;
break;
case SIM_MOUSE_WHEELDOWN:
ev->ev_class = EVENT_CLICK;
ev->ev_code = MOUSE_WHEELDOWN;
ev->cx = cx = sys_event.mx;
ev->cy = cy = sys_event.my;
break;
case SIM_MOUSE_LEFTUP:
ev->ev_class = EVENT_RELEASE;
ev->ev_code = MOUSE_LEFTBUTTON;
pressed_buttons &= ~MOUSE_LEFTBUTTON;
break;
case SIM_MOUSE_RIGHTUP:
ev->ev_class = EVENT_RELEASE;
ev->ev_code = MOUSE_RIGHTBUTTON;
pressed_buttons &= ~MOUSE_RIGHTBUTTON;
break;
case SIM_MOUSE_MIDUP:
ev->ev_class = EVENT_RELEASE;
ev->ev_code = MOUSE_MIDBUTTON;
pressed_buttons &= ~MOUSE_MIDBUTTON;
break;
}
break;
case SIM_MOUSE_MOVE:
if (sys_event.mb) { // drag
ev->ev_class = EVENT_DRAG;
ev->ev_code = sys_event.mb;
}
else { // move
ev->ev_class = EVENT_MOVE;
ev->ev_code = 0;
}
break;
case SIM_SYSTEM:
ev->ev_class = EVENT_SYSTEM;
ev->ev_code = sys_event.code;
break;
}
// Knightly : check for double-clicks and triple-clicks
const uint32 curr_time = dr_time();
if( ev->ev_class==EVENT_CLICK ) {
if( prev_ev_class==EVENT_RELEASE && prev_ev_code==ev->ev_code && curr_time-prev_ev_time<=interval ) {
// case : a mouse click which forms an unbroken sequence with the previous clicks and releases
prev_ev_class = EVENT_CLICK;
prev_ev_time = curr_time;
}
else {
// case : initial click or broken click-release sequence -> prepare for the start of a new sequence
prev_ev_class = EVENT_CLICK;
prev_ev_code = ev->ev_code;
prev_ev_time = curr_time;
repeat_count = 0;
}
}
else if( ev->ev_class==EVENT_RELEASE && prev_ev_class==EVENT_CLICK && prev_ev_code==ev->ev_code && curr_time-prev_ev_time<=interval ) {
// case : a mouse release which forms an unbroken sequence with the previous clicks and releases
prev_ev_class = EVENT_RELEASE;
prev_ev_time = curr_time;
++repeat_count;
// create meta-events where necessary
if( repeat_count==2 ) {
// case : double-click
meta_event = *ev;
meta_event.ev_class = EVENT_DOUBLE_CLICK;
}
else if( repeat_count==3 ) {
// case : triple-click
meta_event = *ev;
meta_event.ev_class = EVENT_TRIPLE_CLICK;
repeat_count = 0; // reset -> start over again
}
}
else if( ev->ev_class!=EVENT_NONE && prev_ev_class!=EVENT_NONE ) {
// case : broken click-release sequence -> simply reset
prev_ev_class = EVENT_NONE;
prev_ev_code = 0;
prev_ev_time = 0;
repeat_count = 0;
}
if (IS_LEFTCLICK(ev)) {
// remember button press
lb_time = curr_time;
repeat_time = 400;
} else if (pressed_buttons == 0) {
lb_time = 0;
} else { // the else is to prevent race conditions
/* Hajo: this would transform non-left button presses always
* to repeat events. I need right button clicks.
* I have no idea how this can be done cleanly, currently just
* disabling the repeat feature for non-left buttons
*/
if (pressed_buttons == MOUSE_LEFTBUTTON) {
if (curr_time - lb_time > repeat_time) {
repeat_time = 100;
lb_time = curr_time;
ev->ev_class = EVENT_REPEAT;
ev->ev_code = pressed_buttons;
}
}
}
ev->button_state = pressed_buttons;
}
void display_poll_event(event_t* const ev)
{
if( !queued_events.empty() ) {
// We have a queued (injected programatically) event, return it.
event_t *elem = queued_events.remove_first();
*ev = *elem;
delete elem;
return ;
}
// Knightly : if there is any pending meta-event, consume it instead of fetching a new event from the system
if( meta_event.ev_class!=EVENT_NONE ) {
*ev = meta_event;
last_meta_class = meta_event.ev_class;
meta_event.ev_class = EVENT_NONE;
}
else {
last_meta_class = EVENT_NONE;
GetEventsNoWait();
fill_event(ev);
// prepare for next event
sys_event.type = SIM_NOEVENT;
sys_event.code = 0;
}
}
void display_get_event(event_t* const ev)
{
if( !queued_events.empty() ) {
// We have a queued (injected programatically) event, return it.
event_t *elem = queued_events.remove_first();
*ev = *elem;
delete elem;
return ;
}
// Knightly : if there is any pending meta-event, consume it instead of fetching a new event from the system
if( meta_event.ev_class!=EVENT_NONE ) {
*ev = meta_event;
meta_event.ev_class = EVENT_NONE;
}
else {
GetEvents();
fill_event(ev);
// prepare for next event
sys_event.type = SIM_NOEVENT;
sys_event.code = 0;
}
}
void queue_event(event_t *events)
{
queued_events.append(events);
}