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