|
|
1.1.1.2 ! root 1: /* $Id: mouse.c,v 1.37 2008/06/08 01:42:27 deuce Exp $ */ 1.1 root 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; 1.1.1.2 ! root 100: static int ungot=0; ! 101: pthread_mutex_t unget_mutex; 1.1 root 102: 103: void init_mouse(void) 104: { 105: memset(&state,0,sizeof(state)); 106: state.click_timeout=0; 107: state.multi_timeout=300; 108: listInit(&state.input,LINK_LIST_SEMAPHORE|LINK_LIST_MUTEX); 109: listInit(&state.output,LINK_LIST_SEMAPHORE|LINK_LIST_MUTEX); 1.1.1.2 ! root 110: pthread_mutex_init(&unget_mutex, NULL); 1.1 root 111: ciolib_mouse_initialized=1; 112: } 113: 114: int ciomouse_setevents(int events) 115: { 116: mouse_events=events; 117: return mouse_events; 118: } 119: 120: int ciomouse_addevents(int events) 121: { 122: mouse_events |= events; 123: return mouse_events; 124: } 125: 126: int ciomouse_delevents(int events) 127: { 128: mouse_events &= ~events; 129: return mouse_events; 130: } 131: 132: int ciomouse_addevent(int event) 133: { 134: mouse_events |= (1<<event); 135: return mouse_events; 136: } 137: 138: int ciomouse_delevent(int event) 139: { 140: mouse_events &= ~(1<<event); 141: return mouse_events; 142: } 143: 144: void ciomouse_gotevent(int event, int x, int y) 145: { 146: struct in_mouse_event *ime; 147: 148: while(!ciolib_mouse_initialized) 149: SLEEP(1); 150: ime=(struct in_mouse_event *)malloc(sizeof(struct in_mouse_event)); 151: ime->ts=MSEC_CLOCK(); 152: ime->event=event; 153: ime->x=x; 154: ime->y=y; 155: ime->nextevent=NULL; 156: 157: listPushNode(&state.input,ime); 158: } 159: 160: void add_outevent(int event, int x, int y) 161: { 162: struct out_mouse_event *ome; 163: int but; 164: 165: if(!(mouse_events & 1<<event)) 166: return; 167: ome=(struct out_mouse_event *)malloc(sizeof(struct out_mouse_event)); 168: 169: but=CIOLIB_BUTTON_NUMBER(event); 170: ome->event=event; 171: ome->bstate=state.buttonstate; 172: ome->kbsm=state.knownbuttonstatemask; 173: ome->startx=but?state.button_x[but-1]:state.curx; 174: ome->starty=but?state.button_y[but-1]:state.cury; 175: ome->endx=x; 176: ome->endy=y; 177: ome->nextevent=(struct out_mouse_event *)NULL; 178: 179: listPushNode(&state.output,ome); 180: } 181: 182: int more_multies(int button, int clicks) 183: { 184: switch(clicks) { 185: case 0: 186: if(mouse_events & (1<<CIOLIB_BUTTON_CLICK(button))) 187: return(1); 188: case 1: 189: if(mouse_events & (1<<CIOLIB_BUTTON_DBL_CLICK(button))) 190: return(1); 191: case 2: 192: if(mouse_events & (1<<CIOLIB_BUTTON_TRPL_CLICK(button))) 193: return(1); 194: case 3: 195: if(mouse_events & (1<<CIOLIB_BUTTON_QUAD_CLICK(button))) 196: return(1); 197: } 198: return(0); 199: } 200: 201: void ciolib_mouse_thread(void *data) 202: { 203: int timedout; 204: int timeout_button=0; 205: int but; 206: int delay; 207: clock_t ttime=0; 208: 209: init_mouse(); 210: while(1) { 211: timedout=0; 212: if(timeout_button) { 213: delay=state.timeout[timeout_button-1]-MSEC_CLOCK(); 214: if(delay<=0) { 215: timedout=1; 216: } 217: else { 218: timedout=!listSemTryWaitBlock(&state.input,delay); 219: } 220: } 221: else { 222: listSemWait(&state.input); 223: } 224: if(timedout) { 225: state.timeout[timeout_button-1]=0; 226: switch(state.button_state[timeout_button-1]) { 227: case MOUSE_SINGLEPRESSED: 228: /* Press event */ 229: add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 230: break; 231: case MOUSE_CLICKED: 232: /* Click Event */ 233: add_outevent(CIOLIB_BUTTON_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 234: break; 235: case MOUSE_DOUBLEPRESSED: 236: /* Click event, then press event */ 237: add_outevent(CIOLIB_BUTTON_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 238: add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 239: break; 240: case MOUSE_DOUBLECLICKED: 241: /* Double-click event */ 242: add_outevent(CIOLIB_BUTTON_DBL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 243: break; 244: case MOUSE_TRIPLEPRESSED: 245: /* Double-click event, then press event */ 246: add_outevent(CIOLIB_BUTTON_DBL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 247: add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 248: break; 249: case MOUSE_TRIPLECLICKED: 250: /* Triple-click event */ 251: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 252: break; 253: case MOUSE_QUADPRESSED: 254: /* Triple-click evetn then press event */ 255: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 256: add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 257: break; 258: case MOUSE_QUADCLICKED: 259: add_outevent(CIOLIB_BUTTON_QUAD_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); 260: /* Quad click event (This doesn't need a timeout does it? */ 261: break; 262: } 263: state.button_state[timeout_button-1]=MOUSE_NOSTATE; 264: } 265: else { 266: struct in_mouse_event *in; 267: 268: in=listShiftNode(&state.input); 269: if(in==NULL) { 270: YIELD(); 271: continue; 272: } 273: but=CIOLIB_BUTTON_NUMBER(in->event); 274: switch(CIOLIB_BUTTON_BASE(in->event)) { 275: case CIOLIB_MOUSE_MOVE: 276: if(in->x==state.curx 277: && in->y==state.cury) 278: break; 279: add_outevent(CIOLIB_MOUSE_MOVE,in->x,in->y); 280: for(but=1;but<=3;but++) { 281: switch(state.button_state[but-1]) { 282: case MOUSE_NOSTATE: 283: if(state.buttonstate & CIOLIB_BUTTON(but)) { 284: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); 285: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); 286: state.button_state[but-1]=MOUSE_DRAGSTARTED; 287: } 288: break; 289: case MOUSE_SINGLEPRESSED: 290: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); 291: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); 292: state.button_state[but-1]=MOUSE_DRAGSTARTED; 293: break; 294: case MOUSE_CLICKED: 295: add_outevent(CIOLIB_BUTTON_CLICK(but),state.button_x[but-1],state.button_y[but-1]); 296: state.button_state[but-1]=MOUSE_NOSTATE; 297: break; 298: case MOUSE_DOUBLEPRESSED: 299: add_outevent(CIOLIB_BUTTON_CLICK(but),state.button_x[but-1],state.button_y[but-1]); 300: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); 301: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); 302: state.button_state[but-1]=MOUSE_DRAGSTARTED; 303: break; 304: case MOUSE_DOUBLECLICKED: 305: add_outevent(CIOLIB_BUTTON_DBL_CLICK(but),state.button_x[but-1],state.button_y[but-1]); 306: state.button_state[but-1]=MOUSE_NOSTATE; 307: break; 308: case MOUSE_TRIPLEPRESSED: 309: add_outevent(CIOLIB_BUTTON_DBL_CLICK(but),state.button_x[but-1],state.button_y[but-1]); 310: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); 311: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); 312: state.button_state[but-1]=MOUSE_DRAGSTARTED; 313: break; 314: case MOUSE_TRIPLECLICKED: 315: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(but),state.button_x[but-1],state.button_y[but-1]); 316: state.button_state[but-1]=MOUSE_NOSTATE; 317: break; 318: case MOUSE_QUADPRESSED: 319: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(but),state.button_x[but-1],state.button_y[but-1]); 320: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); 321: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); 322: state.button_state[but-1]=MOUSE_DRAGSTARTED; 323: break; 324: case MOUSE_DRAGSTARTED: 325: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); 326: break; 327: } 328: } 329: break; 330: case CIOLIB_BUTTON_1_PRESS: 331: state.buttonstate|=1<<(but-1); 332: state.knownbuttonstatemask|=1<<(but-1); 333: switch(state.button_state[but-1]) { 334: case MOUSE_NOSTATE: 335: state.button_state[but-1]=MOUSE_SINGLEPRESSED; 336: state.button_x[but-1]=in->x; 337: state.button_y[but-1]=in->y; 338: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout; 339: if(state.timeout[but-1]==0) 340: state.timeout[but-1]=1; 341: if(state.click_timeout==0) 342: state.timeout[but-1]=0; 343: if(!more_multies(but,0)) { 344: add_outevent(CIOLIB_BUTTON_PRESS(but),state.button_x[but-1],state.button_y[but-1]); 345: state.button_state[but-1]=MOUSE_NOSTATE; 346: state.timeout[but-1]=0; 347: } 348: break; 349: case MOUSE_CLICKED: 350: state.button_state[but-1]=MOUSE_DOUBLEPRESSED; 351: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout; 352: if(state.timeout[but-1]==0) 353: state.timeout[but-1]=1; 354: if(state.click_timeout==0) 355: state.timeout[but-1]=0; 356: break; 357: case MOUSE_DOUBLECLICKED: 358: state.button_state[but-1]=MOUSE_TRIPLEPRESSED; 359: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout; 360: if(state.timeout[but-1]==0) 361: state.timeout[but-1]=1; 362: if(state.click_timeout==0) 363: state.timeout[but-1]=0; 364: break; 365: case MOUSE_TRIPLECLICKED: 366: state.button_state[but-1]=MOUSE_QUADPRESSED; 367: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout; 368: if(state.timeout[but-1]==0) 369: state.timeout[but-1]=1; 370: if(state.click_timeout==0) 371: state.timeout[but-1]=0; 372: break; 373: } 374: break; 375: case CIOLIB_BUTTON_1_RELEASE: 376: state.buttonstate&= ~(1<<(but-1)); 377: state.knownbuttonstatemask|=1<<(but-1); 378: switch(state.button_state[but-1]) { 379: case MOUSE_NOSTATE: 380: state.button_x[but-1]=in->x; 381: state.button_y[but-1]=in->y; 382: add_outevent(CIOLIB_BUTTON_RELEASE(but),state.button_x[but-1],state.button_y[but-1]); 383: break; 384: case MOUSE_SINGLEPRESSED: 385: state.button_state[but-1]=MOUSE_CLICKED; 386: state.timeout[but-1]=more_multies(but,1)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK(); 387: if(state.timeout[but-1]==0) 388: state.timeout[but-1]=1; 389: break; 390: case MOUSE_DOUBLEPRESSED: 391: state.button_state[but-1]=MOUSE_DOUBLECLICKED; 392: state.timeout[but-1]=more_multies(but,2)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK(); 393: if(state.timeout[but-1]==0) 394: state.timeout[but-1]=1; 395: break; 396: case MOUSE_TRIPLEPRESSED: 397: state.button_state[but-1]=MOUSE_TRIPLECLICKED; 398: state.timeout[but-1]=more_multies(but,3)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK(); 399: if(state.timeout[but-1]==0) 400: state.timeout[but-1]=1; 401: break; 402: case MOUSE_QUADPRESSED: 403: state.button_state[but-1]=MOUSE_NOSTATE; 404: add_outevent(CIOLIB_BUTTON_QUAD_CLICK(but),state.button_x[but-1],state.button_y[but-1]); 405: state.timeout[but-1]=0; 406: if(state.timeout[but-1]==0) 407: state.timeout[but-1]=1; 408: break; 409: case MOUSE_DRAGSTARTED: 410: add_outevent(CIOLIB_BUTTON_DRAG_END(but),in->x,in->y); 411: state.button_state[but-1]=0; 412: } 413: } 414: state.curx=in->x; 415: state.cury=in->y; 416: 417: free(in); 418: } 419: 420: timeout_button=0; 421: for(but=1;but<=3;but++) { 422: if(state.button_state[but-1]!=MOUSE_NOSTATE 423: && state.button_state[but-1]!=MOUSE_DRAGSTARTED 424: && state.timeout[but-1]!=0 425: && (timeout_button==0 || state.timeout[but-1]<ttime)) { 426: ttime=state.timeout[but-1]; 427: timeout_button=but; 428: } 429: } 430: } 431: } 432: 433: int mouse_trywait(void) 434: { 1.1.1.2 ! root 435: int result; ! 436: 1.1 root 437: while(!ciolib_mouse_initialized) 438: SLEEP(1); 1.1.1.2 ! root 439: while(1) { ! 440: result=listSemTryWait(&state.output); ! 441: pthread_mutex_lock(&unget_mutex); ! 442: if(ungot==0) { ! 443: pthread_mutex_unlock(&unget_mutex); ! 444: return(result); ! 445: } ! 446: ungot--; ! 447: pthread_mutex_unlock(&unget_mutex); ! 448: } 1.1 root 449: } 450: 451: int mouse_wait(void) 452: { 1.1.1.2 ! root 453: int result; ! 454: 1.1 root 455: while(!ciolib_mouse_initialized) 456: SLEEP(1); 1.1.1.2 ! root 457: while(1) { ! 458: result=listSemWait(&state.output); ! 459: pthread_mutex_lock(&unget_mutex); ! 460: if(ungot==0) { ! 461: pthread_mutex_unlock(&unget_mutex); ! 462: return(result); ! 463: } ! 464: ungot--; ! 465: pthread_mutex_unlock(&unget_mutex); ! 466: } 1.1 root 467: } 468: 469: int mouse_pending(void) 470: { 471: while(!ciolib_mouse_initialized) 472: SLEEP(1); 473: return(listCountNodes(&state.output)); 474: } 475: 476: int ciolib_getmouse(struct mouse_event *mevent) 477: { 478: int retval=0; 479: 480: while(!ciolib_mouse_initialized) 481: SLEEP(1); 482: if(listCountNodes(&state.output)) { 483: struct out_mouse_event *out; 484: out=listShiftNode(&state.output); 485: if(out==NULL) 486: return(-1); 487: mevent->event=out->event; 488: mevent->bstate=out->bstate; 489: mevent->kbsm=out->kbsm; 490: mevent->startx=out->startx; 491: mevent->starty=out->starty; 492: mevent->endx=out->endx; 493: mevent->endy=out->endy; 494: free(out); 495: } 496: else { 1.1.1.2 ! root 497: fprintf(stderr,"WARNING: attempt to get a mouse key when none pending!\n"); 1.1 root 498: memset(mevent,0,sizeof(struct mouse_event)); 499: retval=-1; 500: } 501: return(retval); 502: } 503: 504: int ciolib_ungetmouse(struct mouse_event *mevent) 505: { 506: struct mouse_event *me; 507: 508: if((me=(struct mouse_event *)malloc(sizeof(struct mouse_event)))==NULL) 509: return(-1); 510: memcpy(me,mevent,sizeof(struct mouse_event)); 1.1.1.2 ! root 511: pthread_mutex_lock(&unget_mutex); ! 512: if(listInsertNode(&state.output,me)==NULL) { ! 513: pthread_mutex_unlock(&unget_mutex); ! 514: return(FALSE); ! 515: } ! 516: ungot++; ! 517: pthread_mutex_unlock(&unget_mutex); ! 518: return(TRUE); 1.1 root 519: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.