|
|
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.