|
|
1.1 root 1: /* $Id: mouse.c,v 1.35 2006/05/29 14:30:37 deuce Exp $ */
2:
3: /****************************************************************************
4: * @format.tab-size 4 (Plain Text/Source Code File Header) *
5: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
6: * *
7: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
8: * *
9: * This library is free software; you can redistribute it and/or *
10: * modify it under the terms of the GNU Lesser General Public License *
11: * as published by the Free Software Foundation; either version 2 *
12: * of the License, or (at your option) any later version. *
13: * See the GNU Lesser General Public License for more details: lgpl.txt or *
14: * http://www.fsf.org/copyleft/lesser.html *
15: * *
16: * Anonymous FTP access to the most recent released source is available at *
17: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
18: * *
19: * Anonymous CVS access to the development source and modification history *
20: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
21: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
22: * (just hit return, no password is necessary) *
23: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
24: * *
25: * For Synchronet coding style and modification guidelines, see *
26: * http://www.synchro.net/source.html *
27: * *
28: * You are encouraged to submit any modifications (preferably in Unix diff *
29: * format) via e-mail to [email protected] *
30: * *
31: * Note: If this box doesn't appear square, then you need to fix your tabs. *
32: ****************************************************************************/
33:
34: #include <stdlib.h>
35: #include <string.h>
36:
37: #include <genwrap.h>
38: #include <semwrap.h>
39: #include <threadwrap.h>
40: #include <link_list.h>
41:
42: #include "mouse.h"
43:
44: #define MSEC_CLOCK() (msclock()*MSCLOCKS_PER_SEC/1000)
45:
46: enum {
47: MOUSE_NOSTATE
48: ,MOUSE_SINGLEPRESSED
49: ,MOUSE_CLICKED
50: ,MOUSE_DOUBLEPRESSED
51: ,MOUSE_DOUBLECLICKED
52: ,MOUSE_TRIPLEPRESSED
53: ,MOUSE_TRIPLECLICKED
54: ,MOUSE_QUADPRESSED
55: ,MOUSE_QUADCLICKED
56: ,MOUSE_DRAGSTARTED
57: };
58:
59: struct in_mouse_event {
60: int event;
61: int x;
62: int y;
63: clock_t ts;
64: void *nextevent;
65: };
66:
67: struct out_mouse_event {
68: int event;
69: int bstate;
70: int kbsm; /* Known button state mask */
71: int startx;
72: int starty;
73: int endx;
74: int endy;
75: void *nextevent;
76: };
77:
78: struct mouse_state {
79: int buttonstate; /* Current state of all buttons - bitmap */
80: int knownbuttonstatemask; /* Mask of buttons that have done something since
81: * We started watching... the rest are actually in
82: * an unknown state */
83: int button_state[3]; /* Expanded state of each button */
84: int button_x[3]; /* Start X/Y position of the current state */
85: int button_y[3];
86: clock_t timeout[3]; /* Button event timeouts (timespecs ie: time of expiry) */
87: int curx; /* Current X position */
88: int cury; /* Current Y position */
89: int events; /* Currently enabled events */
90: int click_timeout; /* Timeout between press and release events for a click (ms) */
91: int multi_timeout; /* Timeout after a click for detection of multi clicks (ms) */
92: int click_drift; /* Allowed "drift" during a click event */
93: link_list_t input;
94: link_list_t output;
95: };
96:
97: struct mouse_state state;
98: int mouse_events=0;
99: int ciolib_mouse_initialized=0;
100:
101: void init_mouse(void)
102: {
103: memset(&state,0,sizeof(state));
104: state.click_timeout=0;
105: state.multi_timeout=300;
106: listInit(&state.input,LINK_LIST_SEMAPHORE|LINK_LIST_MUTEX);
107: listInit(&state.output,LINK_LIST_SEMAPHORE|LINK_LIST_MUTEX);
108: ciolib_mouse_initialized=1;
109: }
110:
111: int ciomouse_setevents(int events)
112: {
113: mouse_events=events;
114: return mouse_events;
115: }
116:
117: int ciomouse_addevents(int events)
118: {
119: mouse_events |= events;
120: return mouse_events;
121: }
122:
123: int ciomouse_delevents(int events)
124: {
125: mouse_events &= ~events;
126: return mouse_events;
127: }
128:
129: int ciomouse_addevent(int event)
130: {
131: mouse_events |= (1<<event);
132: return mouse_events;
133: }
134:
135: int ciomouse_delevent(int event)
136: {
137: mouse_events &= ~(1<<event);
138: return mouse_events;
139: }
140:
141: void ciomouse_gotevent(int event, int x, int y)
142: {
143: struct in_mouse_event *ime;
144:
145: while(!ciolib_mouse_initialized)
146: SLEEP(1);
147: ime=(struct in_mouse_event *)malloc(sizeof(struct in_mouse_event));
148: ime->ts=MSEC_CLOCK();
149: ime->event=event;
150: ime->x=x;
151: ime->y=y;
152: ime->nextevent=NULL;
153:
154: listPushNode(&state.input,ime);
155: }
156:
157: void add_outevent(int event, int x, int y)
158: {
159: struct out_mouse_event *ome;
160: int but;
161:
162: if(!(mouse_events & 1<<event))
163: return;
164: ome=(struct out_mouse_event *)malloc(sizeof(struct out_mouse_event));
165:
166: but=CIOLIB_BUTTON_NUMBER(event);
167: ome->event=event;
168: ome->bstate=state.buttonstate;
169: ome->kbsm=state.knownbuttonstatemask;
170: ome->startx=but?state.button_x[but-1]:state.curx;
171: ome->starty=but?state.button_y[but-1]:state.cury;
172: ome->endx=x;
173: ome->endy=y;
174: ome->nextevent=(struct out_mouse_event *)NULL;
175:
176: listPushNode(&state.output,ome);
177: }
178:
179: int more_multies(int button, int clicks)
180: {
181: switch(clicks) {
182: case 0:
183: if(mouse_events & (1<<CIOLIB_BUTTON_CLICK(button)))
184: return(1);
185: case 1:
186: if(mouse_events & (1<<CIOLIB_BUTTON_DBL_CLICK(button)))
187: return(1);
188: case 2:
189: if(mouse_events & (1<<CIOLIB_BUTTON_TRPL_CLICK(button)))
190: return(1);
191: case 3:
192: if(mouse_events & (1<<CIOLIB_BUTTON_QUAD_CLICK(button)))
193: return(1);
194: }
195: return(0);
196: }
197:
198: void ciolib_mouse_thread(void *data)
199: {
200: int timedout;
201: int timeout_button=0;
202: int but;
203: int delay;
204: clock_t ttime=0;
205:
206: init_mouse();
207: while(1) {
208: timedout=0;
209: if(timeout_button) {
210: delay=state.timeout[timeout_button-1]-MSEC_CLOCK();
211: if(delay<=0) {
212: timedout=1;
213: }
214: else {
215: timedout=!listSemTryWaitBlock(&state.input,delay);
216: }
217: }
218: else {
219: listSemWait(&state.input);
220: }
221: if(timedout) {
222: state.timeout[timeout_button-1]=0;
223: switch(state.button_state[timeout_button-1]) {
224: case MOUSE_SINGLEPRESSED:
225: /* Press event */
226: add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
227: break;
228: case MOUSE_CLICKED:
229: /* Click Event */
230: add_outevent(CIOLIB_BUTTON_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
231: break;
232: case MOUSE_DOUBLEPRESSED:
233: /* Click event, then press event */
234: add_outevent(CIOLIB_BUTTON_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
235: add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
236: break;
237: case MOUSE_DOUBLECLICKED:
238: /* Double-click event */
239: add_outevent(CIOLIB_BUTTON_DBL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
240: break;
241: case MOUSE_TRIPLEPRESSED:
242: /* Double-click event, then press event */
243: add_outevent(CIOLIB_BUTTON_DBL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
244: add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
245: break;
246: case MOUSE_TRIPLECLICKED:
247: /* Triple-click event */
248: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
249: break;
250: case MOUSE_QUADPRESSED:
251: /* Triple-click evetn then press event */
252: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
253: add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
254: break;
255: case MOUSE_QUADCLICKED:
256: add_outevent(CIOLIB_BUTTON_QUAD_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]);
257: /* Quad click event (This doesn't need a timeout does it? */
258: break;
259: }
260: state.button_state[timeout_button-1]=MOUSE_NOSTATE;
261: }
262: else {
263: struct in_mouse_event *in;
264:
265: in=listShiftNode(&state.input);
266: if(in==NULL) {
267: YIELD();
268: continue;
269: }
270: but=CIOLIB_BUTTON_NUMBER(in->event);
271: switch(CIOLIB_BUTTON_BASE(in->event)) {
272: case CIOLIB_MOUSE_MOVE:
273: if(in->x==state.curx
274: && in->y==state.cury)
275: break;
276: add_outevent(CIOLIB_MOUSE_MOVE,in->x,in->y);
277: for(but=1;but<=3;but++) {
278: switch(state.button_state[but-1]) {
279: case MOUSE_NOSTATE:
280: if(state.buttonstate & CIOLIB_BUTTON(but)) {
281: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]);
282: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y);
283: state.button_state[but-1]=MOUSE_DRAGSTARTED;
284: }
285: break;
286: case MOUSE_SINGLEPRESSED:
287: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]);
288: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y);
289: state.button_state[but-1]=MOUSE_DRAGSTARTED;
290: break;
291: case MOUSE_CLICKED:
292: add_outevent(CIOLIB_BUTTON_CLICK(but),state.button_x[but-1],state.button_y[but-1]);
293: state.button_state[but-1]=MOUSE_NOSTATE;
294: break;
295: case MOUSE_DOUBLEPRESSED:
296: add_outevent(CIOLIB_BUTTON_CLICK(but),state.button_x[but-1],state.button_y[but-1]);
297: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]);
298: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y);
299: state.button_state[but-1]=MOUSE_DRAGSTARTED;
300: break;
301: case MOUSE_DOUBLECLICKED:
302: add_outevent(CIOLIB_BUTTON_DBL_CLICK(but),state.button_x[but-1],state.button_y[but-1]);
303: state.button_state[but-1]=MOUSE_NOSTATE;
304: break;
305: case MOUSE_TRIPLEPRESSED:
306: add_outevent(CIOLIB_BUTTON_DBL_CLICK(but),state.button_x[but-1],state.button_y[but-1]);
307: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]);
308: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y);
309: state.button_state[but-1]=MOUSE_DRAGSTARTED;
310: break;
311: case MOUSE_TRIPLECLICKED:
312: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(but),state.button_x[but-1],state.button_y[but-1]);
313: state.button_state[but-1]=MOUSE_NOSTATE;
314: break;
315: case MOUSE_QUADPRESSED:
316: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(but),state.button_x[but-1],state.button_y[but-1]);
317: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]);
318: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y);
319: state.button_state[but-1]=MOUSE_DRAGSTARTED;
320: break;
321: case MOUSE_DRAGSTARTED:
322: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y);
323: break;
324: }
325: }
326: break;
327: case CIOLIB_BUTTON_1_PRESS:
328: state.buttonstate|=1<<(but-1);
329: state.knownbuttonstatemask|=1<<(but-1);
330: switch(state.button_state[but-1]) {
331: case MOUSE_NOSTATE:
332: state.button_state[but-1]=MOUSE_SINGLEPRESSED;
333: state.button_x[but-1]=in->x;
334: state.button_y[but-1]=in->y;
335: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout;
336: if(state.timeout[but-1]==0)
337: state.timeout[but-1]=1;
338: if(state.click_timeout==0)
339: state.timeout[but-1]=0;
340: if(!more_multies(but,0)) {
341: add_outevent(CIOLIB_BUTTON_PRESS(but),state.button_x[but-1],state.button_y[but-1]);
342: state.button_state[but-1]=MOUSE_NOSTATE;
343: state.timeout[but-1]=0;
344: }
345: break;
346: case MOUSE_CLICKED:
347: state.button_state[but-1]=MOUSE_DOUBLEPRESSED;
348: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout;
349: if(state.timeout[but-1]==0)
350: state.timeout[but-1]=1;
351: if(state.click_timeout==0)
352: state.timeout[but-1]=0;
353: break;
354: case MOUSE_DOUBLECLICKED:
355: state.button_state[but-1]=MOUSE_TRIPLEPRESSED;
356: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout;
357: if(state.timeout[but-1]==0)
358: state.timeout[but-1]=1;
359: if(state.click_timeout==0)
360: state.timeout[but-1]=0;
361: break;
362: case MOUSE_TRIPLECLICKED:
363: state.button_state[but-1]=MOUSE_QUADPRESSED;
364: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout;
365: if(state.timeout[but-1]==0)
366: state.timeout[but-1]=1;
367: if(state.click_timeout==0)
368: state.timeout[but-1]=0;
369: break;
370: }
371: break;
372: case CIOLIB_BUTTON_1_RELEASE:
373: state.buttonstate&= ~(1<<(but-1));
374: state.knownbuttonstatemask|=1<<(but-1);
375: switch(state.button_state[but-1]) {
376: case MOUSE_NOSTATE:
377: state.button_x[but-1]=in->x;
378: state.button_y[but-1]=in->y;
379: add_outevent(CIOLIB_BUTTON_RELEASE(but),state.button_x[but-1],state.button_y[but-1]);
380: break;
381: case MOUSE_SINGLEPRESSED:
382: state.button_state[but-1]=MOUSE_CLICKED;
383: state.timeout[but-1]=more_multies(but,1)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK();
384: if(state.timeout[but-1]==0)
385: state.timeout[but-1]=1;
386: break;
387: case MOUSE_DOUBLEPRESSED:
388: state.button_state[but-1]=MOUSE_DOUBLECLICKED;
389: state.timeout[but-1]=more_multies(but,2)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK();
390: if(state.timeout[but-1]==0)
391: state.timeout[but-1]=1;
392: break;
393: case MOUSE_TRIPLEPRESSED:
394: state.button_state[but-1]=MOUSE_TRIPLECLICKED;
395: state.timeout[but-1]=more_multies(but,3)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK();
396: if(state.timeout[but-1]==0)
397: state.timeout[but-1]=1;
398: break;
399: case MOUSE_QUADPRESSED:
400: state.button_state[but-1]=MOUSE_NOSTATE;
401: add_outevent(CIOLIB_BUTTON_QUAD_CLICK(but),state.button_x[but-1],state.button_y[but-1]);
402: state.timeout[but-1]=0;
403: if(state.timeout[but-1]==0)
404: state.timeout[but-1]=1;
405: break;
406: case MOUSE_DRAGSTARTED:
407: add_outevent(CIOLIB_BUTTON_DRAG_END(but),in->x,in->y);
408: state.button_state[but-1]=0;
409: }
410: }
411: state.curx=in->x;
412: state.cury=in->y;
413:
414: free(in);
415: }
416:
417: timeout_button=0;
418: for(but=1;but<=3;but++) {
419: if(state.button_state[but-1]!=MOUSE_NOSTATE
420: && state.button_state[but-1]!=MOUSE_DRAGSTARTED
421: && state.timeout[but-1]!=0
422: && (timeout_button==0 || state.timeout[but-1]<ttime)) {
423: ttime=state.timeout[but-1];
424: timeout_button=but;
425: }
426: }
427: }
428: }
429:
430: int mouse_trywait(void)
431: {
432: while(!ciolib_mouse_initialized)
433: SLEEP(1);
434: return(listSemTryWait(&state.output));
435: }
436:
437: int mouse_wait(void)
438: {
439: while(!ciolib_mouse_initialized)
440: SLEEP(1);
441: return(listSemWait(&state.output));
442: }
443:
444: int mouse_pending(void)
445: {
446: while(!ciolib_mouse_initialized)
447: SLEEP(1);
448: return(listCountNodes(&state.output));
449: }
450:
451: int ciolib_getmouse(struct mouse_event *mevent)
452: {
453: int retval=0;
454:
455: while(!ciolib_mouse_initialized)
456: SLEEP(1);
457: if(listCountNodes(&state.output)) {
458: struct out_mouse_event *out;
459: out=listShiftNode(&state.output);
460: if(out==NULL)
461: return(-1);
462: mevent->event=out->event;
463: mevent->bstate=out->bstate;
464: mevent->kbsm=out->kbsm;
465: mevent->startx=out->startx;
466: mevent->starty=out->starty;
467: mevent->endx=out->endx;
468: mevent->endy=out->endy;
469: free(out);
470: }
471: else {
472: memset(mevent,0,sizeof(struct mouse_event));
473: retval=-1;
474: }
475: return(retval);
476: }
477:
478: int ciolib_ungetmouse(struct mouse_event *mevent)
479: {
480: struct mouse_event *me;
481:
482: if((me=(struct mouse_event *)malloc(sizeof(struct mouse_event)))==NULL)
483: return(-1);
484: memcpy(me,mevent,sizeof(struct mouse_event));
485: return(listInsertNode(&state.output,me)==NULL);
486: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.