Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

mouse.c 19.9 KB
Newer Older
1
/* $Id: mouse.c,v 1.48 2020/06/27 00:04:45 deuce Exp $ */
deuce's avatar
deuce committed
2 3 4 5 6

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
deuce's avatar
deuce committed
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
 *																			*
 * This library is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU Lesser General Public License		*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU Lesser General Public License for more details: lgpl.txt or	*
 * http://www.fsf.org/copyleft/lesser.html									*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

deuce's avatar
deuce committed
34
#include <stdlib.h>
deuce's avatar
deuce committed
35
#include <string.h>
deuce's avatar
deuce committed
36

37 38
#include <genwrap.h>
#include <semwrap.h>
deuce's avatar
deuce committed
39
#include <threadwrap.h>
40
#include <link_list.h>
41

42
#include "ciolib.h"
43

44 45
#define MSEC_CLOCK()	(msclock()*MSCLOCKS_PER_SEC/1000)

46 47 48 49 50 51 52 53 54 55
enum {
	 MOUSE_NOSTATE
	,MOUSE_SINGLEPRESSED
	,MOUSE_CLICKED
	,MOUSE_DOUBLEPRESSED
	,MOUSE_DOUBLECLICKED
	,MOUSE_TRIPLEPRESSED
	,MOUSE_TRIPLECLICKED
	,MOUSE_QUADPRESSED
	,MOUSE_QUADCLICKED
deuce's avatar
deuce committed
56
	,MOUSE_DRAGSTARTED
57 58
};

59 60 61 62
struct in_mouse_event {
	int	event;
	int	x;
	int	y;
63 64
	int	x_res;
	int	y_res;
65 66 67 68 69 70 71 72 73 74 75 76
	clock_t	ts;
	void	*nextevent;
};

struct out_mouse_event {
	int event;
	int bstate;
	int kbsm;		/* Known button state mask */
	int startx;
	int starty;
	int endx;
	int endy;
77 78 79 80
	int startx_res;
	int starty_res;
	int endx_res;
	int endy_res;
81 82 83 84
	void *nextevent;
};

struct mouse_state {
85 86 87 88
	int	buttonstate;			/* Current state of all buttons - bitmap */
	int	knownbuttonstatemask;	/* Mask of buttons that have done something since
								 * We started watching... the rest are actually in
								 * an unknown state */
89 90 91
	int	button_state[5];		/* Expanded state of each button */
	int	button_x[5];			/* Start X/Y position of the current state */
	int	button_y[5];
92 93
	int	button_x_res[5];			/* Start X/Y position of the current state */
	int	button_y_res[5];
94
	clock_t	timeout[5];	/* Button event timeouts (timespecs ie: time of expiry) */
95 96
	int	curx;					/* Current X position */
	int	cury;					/* Current Y position */
97 98
	int	curx_res;					/* Current X position */
	int	cury_res;					/* Current Y position */
99 100 101 102
	int	events;					/* Currently enabled events */
	int	click_timeout;			/* Timeout between press and release events for a click (ms) */
	int	multi_timeout;			/* Timeout after a click for detection of multi clicks (ms) */
	int	click_drift;			/* Allowed "drift" during a click event */
103 104
	link_list_t	input;
	link_list_t	output;
105 106 107
};

struct mouse_state state;
108
uint64_t mouse_events=0;
109
int ciolib_mouse_initialized=0;
110
static int ungot=0;
deuce's avatar
deuce committed
111
pthread_mutex_t unget_mutex;
112

113
void init_mouse(void)
114
{
deuce's avatar
deuce committed
115
	memset(&state,0,sizeof(state));
116
	state.click_timeout=0;
117
	state.multi_timeout=300;
deuce's avatar
deuce committed
118 119
	listInit(&state.input,LINK_LIST_SEMAPHORE|LINK_LIST_MUTEX);
	listInit(&state.output,LINK_LIST_SEMAPHORE|LINK_LIST_MUTEX);
deuce's avatar
deuce committed
120
	pthread_mutex_init(&unget_mutex, NULL);
121
	ciolib_mouse_initialized=1;
122 123
}

124
void mousestate(int *x, int *y, uint8_t *buttons)
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
{
	if (!ciolib_mouse_initialized) {
		if (x)
			*x = -1;
		if (y)
			*y = -1;
		return;
	}
	if (x)
		*x = state.curx;
	if (y)
		*y = state.cury;
	if (buttons)
		*buttons = (state.buttonstate & 0xff);
	return;
}

142
void mousestate_res(int *x, int *y, uint8_t *buttons)
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
{
	if (!ciolib_mouse_initialized) {
		if (x)
			*x = -1;
		if (y)
			*y = -1;
		return;
	}
	if (x)
		*x = state.curx_res;
	if (y)
		*y = state.cury_res;
	if (buttons)
		*buttons = (state.buttonstate & 0xff);
	return;
}

160
uint64_t ciomouse_setevents(uint64_t events)
161
{
deuce's avatar
deuce committed
162 163
	mouse_events=events;
	return mouse_events;
164 165
}

166
uint64_t ciomouse_addevents(uint64_t events)
167
{
deuce's avatar
deuce committed
168 169
	mouse_events |= events;
	return mouse_events;
170 171
}

172
uint64_t ciomouse_delevents(uint64_t events)
173
{
deuce's avatar
deuce committed
174 175
	mouse_events &= ~events;
	return mouse_events;
176 177
}

178
uint64_t ciomouse_addevent(uint64_t event)
179
{
180
	mouse_events |= (UINT64_C(1)<<event);
181 182 183
	return mouse_events;
}

184
uint64_t ciomouse_delevent(uint64_t event)
185
{
186
	mouse_events &= ~(UINT64_C(1)<<event);
187 188 189
	return mouse_events;
}

190
void ciomouse_gotevent(int event, int x, int y, int x_res, int y_res)
191 192 193
{
	struct in_mouse_event *ime;

194
	while(!ciolib_mouse_initialized)
195
		SLEEP(1);
196
	ime=(struct in_mouse_event *)malloc(sizeof(struct in_mouse_event));
deuce's avatar
deuce committed
197 198 199 200 201
	if(ime) {
		ime->ts=MSEC_CLOCK();
		ime->event=event;
		ime->x=x;
		ime->y=y;
202 203
		ime->x_res=x_res;
		ime->y_res=y_res;
deuce's avatar
deuce committed
204 205 206 207
		ime->nextevent=NULL;

		listPushNode(&state.input,ime);
	}
208 209
}

210
void add_outevent(int event, int x, int y, int xres, int yres)
211 212
{
	struct out_mouse_event *ome;
deuce's avatar
deuce committed
213
	int	but;
214

215
	if(!(mouse_events & UINT64_C(1)<<event))
deuce's avatar
deuce committed
216 217
		return;
	ome=(struct out_mouse_event *)malloc(sizeof(struct out_mouse_event));
218

deuce's avatar
deuce committed
219 220 221 222 223 224 225 226 227
	if(ome) {
		but=CIOLIB_BUTTON_NUMBER(event);
		ome->event=event;
		ome->bstate=state.buttonstate;
		ome->kbsm=state.knownbuttonstatemask;
		ome->startx=but?state.button_x[but-1]:state.curx;
		ome->starty=but?state.button_y[but-1]:state.cury;
		ome->endx=x;
		ome->endy=y;
228 229 230 231 232
		ome->startx_res=but ? state.button_x_res[but-1] : state.curx_res;
		ome->starty_res=but ? state.button_y_res[but-1] : state.cury_res;
		ome->endx_res=xres;
		ome->endy_res=yres;

deuce's avatar
deuce committed
233 234 235 236
		ome->nextevent=(struct out_mouse_event *)NULL;

		listPushNode(&state.output,ome);
	}
237 238
}

239
int more_multies(int button, int clicks)
240 241
{
	switch(clicks) {
242
		case 0:
243
			if(mouse_events & (UINT64_C(1)<<CIOLIB_BUTTON_CLICK(button)))
244
				return(1);
245
			/* Fall-through */
246
		case 1:
247
			if(mouse_events & (UINT64_C(1)<<CIOLIB_BUTTON_DBL_CLICK(button)))
248
				return(1);
249
			/* Fall-through */
250
		case 2:
251
			if(mouse_events & (UINT64_C(1)<<CIOLIB_BUTTON_TRPL_CLICK(button)))
252
				return(1);
253
			/* Fall-through */
254
		case 3:
255
			if(mouse_events & (UINT64_C(1)<<CIOLIB_BUTTON_QUAD_CLICK(button)))
256
				return(1);
257
			/* Fall-through */
258 259 260 261
	}
	return(0);
}

262
void ciolib_mouse_thread(void *data)
263
{
deuce's avatar
deuce committed
264 265 266 267 268
	int	timedout;
	int timeout_button=0;
	int but;
	int delay;
	clock_t	ttime=0;
269

deuce's avatar
deuce committed
270
	SetThreadName("Mouse");
deuce's avatar
deuce committed
271
	init_mouse();
272
	while(1) {
deuce's avatar
deuce committed
273 274
		timedout=0;
		if(timeout_button) {
275
			delay=state.timeout[timeout_button-1]-MSEC_CLOCK();
deuce's avatar
deuce committed
276 277 278 279
			if(delay<=0) {
				timedout=1;
			}
			else {
deuce's avatar
deuce committed
280
				timedout=!listSemTryWaitBlock(&state.input,delay);
deuce's avatar
deuce committed
281 282
			}
		}
283
		else {
284
			listSemWait(&state.input);
deuce's avatar
deuce committed
285
		}
deuce's avatar
deuce committed
286 287 288 289 290
		if(timedout) {
			state.timeout[timeout_button-1]=0;
			switch(state.button_state[timeout_button-1]) {
				case MOUSE_SINGLEPRESSED:
					/* Press event */
291
					add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
deuce's avatar
deuce committed
292 293 294
					break;
				case MOUSE_CLICKED:
					/* Click Event */
295
					add_outevent(CIOLIB_BUTTON_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
deuce's avatar
deuce committed
296 297 298
					break;
				case MOUSE_DOUBLEPRESSED:
					/* Click event, then press event */
299 300
					add_outevent(CIOLIB_BUTTON_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
					add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
deuce's avatar
deuce committed
301 302 303
					break;
				case MOUSE_DOUBLECLICKED:
					/* Double-click event */
304
					add_outevent(CIOLIB_BUTTON_DBL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
deuce's avatar
deuce committed
305 306 307
					break;
				case MOUSE_TRIPLEPRESSED:
					/* Double-click event, then press event */
308 309
					add_outevent(CIOLIB_BUTTON_DBL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
					add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
deuce's avatar
deuce committed
310 311 312
					break;
				case MOUSE_TRIPLECLICKED:
					/* Triple-click event */
313
					add_outevent(CIOLIB_BUTTON_TRPL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
deuce's avatar
deuce committed
314 315 316
					break;
				case MOUSE_QUADPRESSED:
					/* Triple-click evetn then press event */
317 318
					add_outevent(CIOLIB_BUTTON_TRPL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
					add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
deuce's avatar
deuce committed
319 320
					break;
				case MOUSE_QUADCLICKED:
321
					add_outevent(CIOLIB_BUTTON_QUAD_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1],state.button_x_res[timeout_button-1],state.button_y_res[timeout_button-1]);
deuce's avatar
deuce committed
322 323 324 325 326 327
					/* Quad click event (This doesn't need a timeout does it? */
					break;
			}
			state.button_state[timeout_button-1]=MOUSE_NOSTATE;
		}
		else {
328
			struct in_mouse_event *in;
329

rswindell's avatar
rswindell committed
330
			in=listShiftNode(&state.input);
331 332 333 334
			if(in==NULL) {
				YIELD();
				continue;
			}
335
			but=CIOLIB_BUTTON_NUMBER(in->event);
336 337 338
			if (in->x < 0)
				in->x = state.curx;
			if (in->y < 0)
339 340 341 342 343
				in->y = state.cury;
			if (in->x_res < 0)
				in->x_res = state.curx_res;
			if (in->y_res < 0)
				in->y_res = state.cury_res;
344

345
			switch(CIOLIB_BUTTON_BASE(in->event)) {
deuce's avatar
deuce committed
346
				case CIOLIB_MOUSE_MOVE:
347 348
					if(in->x==state.curx && in->y==state.cury &&
					    in->x_res==state.curx_res && in->y_res==state.cury_res)
349
						break;
350
					add_outevent(CIOLIB_MOUSE_MOVE,in->x,in->y,in->x_res, in->y_res);
351
					for(but=1;but<=5;but++) {
deuce's avatar
deuce committed
352 353 354
						switch(state.button_state[but-1]) {
							case MOUSE_NOSTATE:
								if(state.buttonstate & CIOLIB_BUTTON(but)) {
355 356
									add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
									add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y, in->x_res, in->y_res);
deuce's avatar
deuce committed
357 358 359 360
									state.button_state[but-1]=MOUSE_DRAGSTARTED;
								}
								break;
							case MOUSE_SINGLEPRESSED:
361 362
								add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
								add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y, in->x_res, in->y_res);
deuce's avatar
deuce committed
363 364 365
								state.button_state[but-1]=MOUSE_DRAGSTARTED;
								break;
							case MOUSE_CLICKED:
366
								add_outevent(CIOLIB_BUTTON_CLICK(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
deuce's avatar
deuce committed
367 368 369
								state.button_state[but-1]=MOUSE_NOSTATE;
								break;
							case MOUSE_DOUBLEPRESSED:
370 371 372
								add_outevent(CIOLIB_BUTTON_CLICK(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
								add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
								add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y, in->x_res, in->y_res);
deuce's avatar
deuce committed
373 374 375
								state.button_state[but-1]=MOUSE_DRAGSTARTED;
								break;
							case MOUSE_DOUBLECLICKED:
376
								add_outevent(CIOLIB_BUTTON_DBL_CLICK(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
deuce's avatar
deuce committed
377 378 379
								state.button_state[but-1]=MOUSE_NOSTATE;
								break;
							case MOUSE_TRIPLEPRESSED:
380 381 382
								add_outevent(CIOLIB_BUTTON_DBL_CLICK(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
								add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
								add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y, in->x_res, in->y_res);
deuce's avatar
deuce committed
383 384 385
								state.button_state[but-1]=MOUSE_DRAGSTARTED;
								break;
							case MOUSE_TRIPLECLICKED:
386
								add_outevent(CIOLIB_BUTTON_TRPL_CLICK(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
deuce's avatar
deuce committed
387 388 389
								state.button_state[but-1]=MOUSE_NOSTATE;
								break;
							case MOUSE_QUADPRESSED:
390 391 392
								add_outevent(CIOLIB_BUTTON_TRPL_CLICK(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
								add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
								add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y, in->x_res, in->y_res);
deuce's avatar
deuce committed
393 394 395
								state.button_state[but-1]=MOUSE_DRAGSTARTED;
								break;
							case MOUSE_DRAGSTARTED:
396
								add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y, in->x_res, in->y_res);
deuce's avatar
deuce committed
397 398 399 400 401 402 403 404 405 406
								break;
						}
					}
					break;
				case CIOLIB_BUTTON_1_PRESS:
					state.buttonstate|=1<<(but-1);
					state.knownbuttonstatemask|=1<<(but-1);
					switch(state.button_state[but-1]) {
						case MOUSE_NOSTATE:
							state.button_state[but-1]=MOUSE_SINGLEPRESSED;
407 408
							state.button_x[but-1]=in->x;
							state.button_y[but-1]=in->y;
409 410
							state.button_x_res[but-1]=in->x_res;
							state.button_y_res[but-1]=in->y_res;
411
							state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout;
412 413 414 415
							if(state.timeout[but-1]==0)
								state.timeout[but-1]=1;
							if(state.click_timeout==0)
								state.timeout[but-1]=0;
416
							if(!more_multies(but,0)) {
417
								add_outevent(CIOLIB_BUTTON_PRESS(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
418 419 420
								state.button_state[but-1]=MOUSE_NOSTATE;
								state.timeout[but-1]=0;
							}
421 422 423
							// Scroll "buttons"...
							if (but > 3)
								state.button_state[but-1] = MOUSE_NOSTATE;
deuce's avatar
deuce committed
424 425 426
							break;
						case MOUSE_CLICKED:
							state.button_state[but-1]=MOUSE_DOUBLEPRESSED;
427
							state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout;
428 429 430 431
							if(state.timeout[but-1]==0)
								state.timeout[but-1]=1;
							if(state.click_timeout==0)
								state.timeout[but-1]=0;
deuce's avatar
deuce committed
432 433 434
							break;
						case MOUSE_DOUBLECLICKED:
							state.button_state[but-1]=MOUSE_TRIPLEPRESSED;
435
							state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout;
436 437 438 439
							if(state.timeout[but-1]==0)
								state.timeout[but-1]=1;
							if(state.click_timeout==0)
								state.timeout[but-1]=0;
deuce's avatar
deuce committed
440 441 442
							break;
						case MOUSE_TRIPLECLICKED:
							state.button_state[but-1]=MOUSE_QUADPRESSED;
443
							state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout;
444 445 446 447
							if(state.timeout[but-1]==0)
								state.timeout[but-1]=1;
							if(state.click_timeout==0)
								state.timeout[but-1]=0;
deuce's avatar
deuce committed
448 449 450 451 452 453 454 455
							break;
					}
					break;
				case CIOLIB_BUTTON_1_RELEASE:
					state.buttonstate&= ~(1<<(but-1));
					state.knownbuttonstatemask|=1<<(but-1);
					switch(state.button_state[but-1]) {
						case MOUSE_NOSTATE:
456 457
							state.button_x[but-1]=in->x;
							state.button_y[but-1]=in->y;
458 459 460
							state.button_x_res[but-1]=in->x_res;
							state.button_y_res[but-1]=in->y_res;
							add_outevent(CIOLIB_BUTTON_RELEASE(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
deuce's avatar
deuce committed
461 462 463
							break;
						case MOUSE_SINGLEPRESSED:
							state.button_state[but-1]=MOUSE_CLICKED;
464
							state.timeout[but-1]=more_multies(but,1)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK();
465 466
							if(state.timeout[but-1]==0)
								state.timeout[but-1]=1;
deuce's avatar
deuce committed
467 468 469
							break;
						case MOUSE_DOUBLEPRESSED:
							state.button_state[but-1]=MOUSE_DOUBLECLICKED;
470
							state.timeout[but-1]=more_multies(but,2)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK();
471 472
							if(state.timeout[but-1]==0)
								state.timeout[but-1]=1;
deuce's avatar
deuce committed
473 474 475
							break;
						case MOUSE_TRIPLEPRESSED:
							state.button_state[but-1]=MOUSE_TRIPLECLICKED;
476
							state.timeout[but-1]=more_multies(but,3)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK();
477 478
							if(state.timeout[but-1]==0)
								state.timeout[but-1]=1;
deuce's avatar
deuce committed
479 480 481
							break;
						case MOUSE_QUADPRESSED:
							state.button_state[but-1]=MOUSE_NOSTATE;
482
							add_outevent(CIOLIB_BUTTON_QUAD_CLICK(but),state.button_x[but-1],state.button_y[but-1],state.button_x_res[but-1],state.button_y_res[but-1]);
deuce's avatar
deuce committed
483
							state.timeout[but-1]=0;
484 485
							if(state.timeout[but-1]==0)
								state.timeout[but-1]=1;
deuce's avatar
deuce committed
486 487
							break;
						case MOUSE_DRAGSTARTED:
488
							add_outevent(CIOLIB_BUTTON_DRAG_END(but),in->x,in->y, in->x_res, in->y_res);
deuce's avatar
deuce committed
489 490 491
							state.button_state[but-1]=0;
					}
			}
492 493
			state.curx=in->x;
			state.cury=in->y;
494 495
			state.curx_res=in->x_res;
			state.cury_res=in->y_res;
496

497
			free(in);
498
		}
499

deuce's avatar
deuce committed
500
		timeout_button=0;
501
		for(but=1;but<=5;but++) {
502
			if(state.button_state[but-1]==MOUSE_DRAGSTARTED &&
503
			    (mouse_events & ((UINT64_C(1)<<CIOLIB_BUTTON_DRAG_START(but)) | (UINT64_C(1)<<CIOLIB_BUTTON_DRAG_MOVE(but)) | (UINT64_C(1)<<CIOLIB_BUTTON_DRAG_END(but)))) == 0)
504 505 506
				state.button_state[but-1] = MOUSE_NOSTATE;
		}

507
		for(but=1;but<=5;but++) {
deuce's avatar
deuce committed
508 509
			if(state.button_state[but-1]!=MOUSE_NOSTATE 
					&& state.button_state[but-1]!=MOUSE_DRAGSTARTED 
510
					&& state.timeout[but-1]!=0
deuce's avatar
deuce committed
511
					&& (timeout_button==0 || state.timeout[but-1]<ttime)) {
deuce's avatar
deuce committed
512 513 514 515 516 517 518
				ttime=state.timeout[but-1];
				timeout_button=but;
			}
		}
	}
}

519
int mouse_trywait(void)
520
{
521 522
	int	result;

523
	while(!ciolib_mouse_initialized)
524
		SLEEP(1);
525 526
	while(1) {
		result=listSemTryWait(&state.output);
deuce's avatar
deuce committed
527 528 529
		pthread_mutex_lock(&unget_mutex);
		if(ungot==0) {
			pthread_mutex_unlock(&unget_mutex);
530
			return(result);
deuce's avatar
deuce committed
531
		}
532
		ungot--;
deuce's avatar
deuce committed
533
		pthread_mutex_unlock(&unget_mutex);
534
	}
535 536
}

537
int mouse_wait(void)
538
{
539 540
	int result;

541
	while(!ciolib_mouse_initialized)
542
		SLEEP(1);
543 544
	while(1) {
		result=listSemWait(&state.output);
deuce's avatar
deuce committed
545 546 547
		pthread_mutex_lock(&unget_mutex);
		if(ungot==0) {
			pthread_mutex_unlock(&unget_mutex);
548
			return(result);
deuce's avatar
deuce committed
549
		}
550
		ungot--;
deuce's avatar
deuce committed
551
		pthread_mutex_unlock(&unget_mutex);
552
	}
553 554
}

555
int mouse_pending(void)
deuce's avatar
deuce committed
556
{
557
	while(!ciolib_mouse_initialized)
558
		SLEEP(1);
559
	return(listCountNodes(&state.output));
deuce's avatar
deuce committed
560 561
}

562
int ciolib_getmouse(struct mouse_event *mevent)
deuce's avatar
deuce committed
563 564 565
{
	int retval=0;

566
	while(!ciolib_mouse_initialized)
567
		SLEEP(1);
568
	if(listCountNodes(&state.output)) {
569
		struct out_mouse_event *out;
rswindell's avatar
rswindell committed
570
		out=listShiftNode(&state.output);
deuce's avatar
deuce committed
571
		if(out==NULL)
572
			return(-1);
573 574 575 576 577 578 579 580
		if(mevent != NULL) {
			mevent->event=out->event;
			mevent->bstate=out->bstate;
			mevent->kbsm=out->kbsm;
			mevent->startx=out->startx;
			mevent->starty=out->starty;
			mevent->endx=out->endx;
			mevent->endy=out->endy;
581 582 583 584
			mevent->startx_res=out->startx_res;
			mevent->starty_res=out->starty_res;
			mevent->endx_res=out->endx_res;
			mevent->endy_res=out->endy_res;
585
		}
586
		free(out);
587
	}
deuce's avatar
deuce committed
588
	else {
deuce's avatar
deuce committed
589
		fprintf(stderr,"WARNING: attempt to get a mouse key when none pending!\n");
590 591
		if(mevent != NULL)
			memset(mevent,0,sizeof(struct mouse_event));
deuce's avatar
deuce committed
592
		retval=-1;
deuce's avatar
deuce committed
593
	}
deuce's avatar
deuce committed
594
	return(retval);
595
}
deuce's avatar
deuce committed
596

597
int ciolib_ungetmouse(struct mouse_event *mevent)
deuce's avatar
deuce committed
598 599 600 601 602 603
{
	struct mouse_event *me;

	if((me=(struct mouse_event *)malloc(sizeof(struct mouse_event)))==NULL)
		return(-1);
	memcpy(me,mevent,sizeof(struct mouse_event));
deuce's avatar
deuce committed
604 605 606
	pthread_mutex_lock(&unget_mutex);
	if(listInsertNode(&state.output,me)==NULL) {
		pthread_mutex_unlock(&unget_mutex);
607
		return(FALSE);
deuce's avatar
deuce committed
608
	}
609
	ungot++;
deuce's avatar
deuce committed
610
	pthread_mutex_unlock(&unget_mutex);
611
	return(TRUE);
deuce's avatar
deuce committed
612
}