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