|
|
1.1 ! root 1: /* $Id: mouse.c,v 1.22 2004/11/18 01:29:04 rswindell 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: ! 36: #include <genwrap.h> ! 37: #include <semwrap.h> ! 38: #include <threadwrap.h> ! 39: #include <link_list.h> ! 40: ! 41: #include "mouse.h" ! 42: ! 43: #define MSEC_CLOCK() (msclock()*MSCLOCKS_PER_SEC/1000) ! 44: ! 45: enum { ! 46: MOUSE_NOSTATE ! 47: ,MOUSE_SINGLEPRESSED ! 48: ,MOUSE_CLICKED ! 49: ,MOUSE_DOUBLEPRESSED ! 50: ,MOUSE_DOUBLECLICKED ! 51: ,MOUSE_TRIPLEPRESSED ! 52: ,MOUSE_TRIPLECLICKED ! 53: ,MOUSE_QUADPRESSED ! 54: ,MOUSE_QUADCLICKED ! 55: ,MOUSE_DRAGSTARTED ! 56: }; ! 57: ! 58: pthread_mutex_t in_mutex; ! 59: pthread_mutex_t out_mutex; ! 60: sem_t in_sem; ! 61: ! 62: struct in_mouse_event { ! 63: int event; ! 64: int x; ! 65: int y; ! 66: clock_t ts; ! 67: void *nextevent; ! 68: }; ! 69: ! 70: struct out_mouse_event { ! 71: int event; ! 72: int bstate; ! 73: int kbsm; /* Known button state mask */ ! 74: int startx; ! 75: int starty; ! 76: int endx; ! 77: int endy; ! 78: void *nextevent; ! 79: }; ! 80: ! 81: struct mouse_state { ! 82: int buttonstate; /* Current state of all buttons - bitmap */ ! 83: int knownbuttonstatemask; /* Mask of buttons that have done something since ! 84: * We started watching... the rest are actually in ! 85: * an unknown state */ ! 86: int button_state[3]; /* Expanded state of each button */ ! 87: int button_x[3]; /* Start X/Y position of the current state */ ! 88: int button_y[3]; ! 89: clock_t timeout[3]; /* Button event timeouts (timespecs ie: time of expiry) */ ! 90: int curx; /* Current X position */ ! 91: int cury; /* Current Y position */ ! 92: int events; /* Currently enabled events */ ! 93: int click_timeout; /* Timeout between press and release events for a click (ms) */ ! 94: int multi_timeout; /* Timeout after a click for detection of multi clicks (ms) */ ! 95: int click_drift; /* Allowed "drift" during a click event */ ! 96: link_list_t input; ! 97: link_list_t output; ! 98: }; ! 99: ! 100: struct mouse_state state; ! 101: int mouse_events=0; ! 102: static mouse_initialized=0; ! 103: ! 104: void init_mouse(void) ! 105: { ! 106: memset(&state,0,sizeof(state)); ! 107: state.click_timeout=0; ! 108: state.multi_timeout=300; ! 109: listInit(&state.input,0); ! 110: listInit(&state.output,0); ! 111: pthread_mutex_init(&in_mutex,NULL); ! 112: pthread_mutex_init(&out_mutex,NULL); ! 113: sem_init(&in_sem,0,0); ! 114: mouse_initialized=1; ! 115: } ! 116: ! 117: int ciomouse_setevents(int events) ! 118: { ! 119: mouse_events=events; ! 120: return mouse_events; ! 121: } ! 122: ! 123: int ciomouse_addevents(int events) ! 124: { ! 125: mouse_events |= events; ! 126: return mouse_events; ! 127: } ! 128: ! 129: int ciomouse_delevents(int events) ! 130: { ! 131: mouse_events &= ~events; ! 132: return mouse_events; ! 133: } ! 134: ! 135: int ciomouse_addevent(int event) ! 136: { ! 137: mouse_events |= (1<<event); ! 138: return mouse_events; ! 139: } ! 140: ! 141: int ciomouse_delevent(int event) ! 142: { ! 143: mouse_events &= ~(1<<event); ! 144: return mouse_events; ! 145: } ! 146: ! 147: void ciomouse_gotevent(int event, int x, int y) ! 148: { ! 149: struct in_mouse_event *ime; ! 150: ! 151: while(!mouse_initialized) ! 152: SLEEP(1); ! 153: ime=(struct in_mouse_event *)malloc(sizeof(struct in_mouse_event)); ! 154: ime->ts=MSEC_CLOCK(); ! 155: ime->event=event; ! 156: ime->x=x; ! 157: ime->y=y; ! 158: ime->nextevent=NULL; ! 159: ! 160: pthread_mutex_lock(&in_mutex); ! 161: ! 162: listPushNode(&state.input,ime); ! 163: ! 164: pthread_mutex_unlock(&in_mutex); ! 165: sem_post(&in_sem); ! 166: } ! 167: ! 168: void add_outevent(int event, int x, int y) ! 169: { ! 170: struct out_mouse_event *ome; ! 171: int but=0; ! 172: ! 173: if(!(mouse_events & 1<<event)) ! 174: return; ! 175: ome=(struct out_mouse_event *)malloc(sizeof(struct out_mouse_event)); ! 176: ! 177: but=CIOLIB_BUTTON_NUMBER(event); ! 178: ome->event=event; ! 179: ome->bstate=state.buttonstate; ! 180: ome->kbsm=state.knownbuttonstatemask; ! 181: ome->startx=but?state.button_x[but-1]:state.curx; ! 182: ome->starty=but?state.button_y[but-1]:state.cury; ! 183: ome->endx=x; ! 184: ome->endy=y; ! 185: ome->nextevent=(struct out_mouse_event *)NULL; ! 186: ! 187: pthread_mutex_lock(&out_mutex); ! 188: ! 189: listPushNode(&state.output,ome); ! 190: ! 191: pthread_mutex_unlock(&out_mutex); ! 192: } ! 193: ! 194: int more_multies(int button, int clicks) ! 195: { ! 196: switch(clicks) { ! 197: case 1: ! 198: if(mouse_events & (1<<CIOLIB_BUTTON_DBL_CLICK(button))) ! 199: return(1); ! 200: case 2: ! 201: if(mouse_events & (1<<CIOLIB_BUTTON_TRPL_CLICK(button))) ! 202: return(1); ! 203: case 3: ! 204: if(mouse_events & (1<<CIOLIB_BUTTON_QUAD_CLICK(button))) ! 205: return(1); ! 206: } ! 207: return(0); ! 208: } ! 209: ! 210: void ciolib_mouse_thread(void *data) ! 211: { ! 212: int timedout; ! 213: int timeout_button=0; ! 214: int but; ! 215: int delay; ! 216: clock_t ttime=0; ! 217: ! 218: init_mouse(); ! 219: while(1) { ! 220: timedout=0; ! 221: if(timeout_button) { ! 222: delay=state.timeout[timeout_button-1]-MSEC_CLOCK(); ! 223: if(delay<=0) { ! 224: timedout=1; ! 225: } ! 226: else { ! 227: timedout=sem_trywait_block(&in_sem,delay); ! 228: } ! 229: } ! 230: else { ! 231: sem_wait(&in_sem); ! 232: } ! 233: if(timedout) { ! 234: state.timeout[timeout_button-1]=0; ! 235: switch(state.button_state[timeout_button-1]) { ! 236: case MOUSE_SINGLEPRESSED: ! 237: /* Press event */ ! 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_CLICKED: ! 241: /* Click Event */ ! 242: add_outevent(CIOLIB_BUTTON_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); ! 243: break; ! 244: case MOUSE_DOUBLEPRESSED: ! 245: /* Click event, then press event */ ! 246: add_outevent(CIOLIB_BUTTON_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_DOUBLECLICKED: ! 250: /* Double-click event */ ! 251: add_outevent(CIOLIB_BUTTON_DBL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); ! 252: break; ! 253: case MOUSE_TRIPLEPRESSED: ! 254: /* Double-click event, then press event */ ! 255: add_outevent(CIOLIB_BUTTON_DBL_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_TRIPLECLICKED: ! 259: /* Triple-click event */ ! 260: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); ! 261: break; ! 262: case MOUSE_QUADPRESSED: ! 263: /* Triple-click evetn then press event */ ! 264: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); ! 265: add_outevent(CIOLIB_BUTTON_PRESS(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); ! 266: break; ! 267: case MOUSE_QUADCLICKED: ! 268: add_outevent(CIOLIB_BUTTON_QUAD_CLICK(timeout_button),state.button_x[timeout_button-1],state.button_y[timeout_button-1]); ! 269: /* Quad click event (This doesn't need a timeout does it? */ ! 270: break; ! 271: } ! 272: state.button_state[timeout_button-1]=MOUSE_NOSTATE; ! 273: } ! 274: else { ! 275: struct in_mouse_event *in; ! 276: ! 277: pthread_mutex_lock(&in_mutex); ! 278: in=listShiftNode(&state.input); ! 279: pthread_mutex_unlock(&in_mutex); ! 280: if(in==NULL) ! 281: continue; ! 282: but=CIOLIB_BUTTON_NUMBER(in->event); ! 283: switch(CIOLIB_BUTTON_BASE(in->event)) { ! 284: case CIOLIB_MOUSE_MOVE: ! 285: if(in->x==state.curx ! 286: && in->y==state.cury) ! 287: break; ! 288: add_outevent(CIOLIB_MOUSE_MOVE,in->x,in->y); ! 289: for(but=1;but<=3;but++) { ! 290: switch(state.button_state[but-1]) { ! 291: case MOUSE_NOSTATE: ! 292: if(state.buttonstate & CIOLIB_BUTTON(but)) { ! 293: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); ! 294: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); ! 295: state.button_state[but-1]=MOUSE_DRAGSTARTED; ! 296: } ! 297: break; ! 298: case MOUSE_SINGLEPRESSED: ! 299: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); ! 300: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); ! 301: state.button_state[but-1]=MOUSE_DRAGSTARTED; ! 302: break; ! 303: case MOUSE_CLICKED: ! 304: add_outevent(CIOLIB_BUTTON_CLICK(but),state.button_x[but-1],state.button_y[but-1]); ! 305: state.button_state[but-1]=MOUSE_NOSTATE; ! 306: break; ! 307: case MOUSE_DOUBLEPRESSED: ! 308: add_outevent(CIOLIB_BUTTON_CLICK(but),state.button_x[but-1],state.button_y[but-1]); ! 309: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); ! 310: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); ! 311: state.button_state[but-1]=MOUSE_DRAGSTARTED; ! 312: break; ! 313: case MOUSE_DOUBLECLICKED: ! 314: add_outevent(CIOLIB_BUTTON_DBL_CLICK(but),state.button_x[but-1],state.button_y[but-1]); ! 315: state.button_state[but-1]=MOUSE_NOSTATE; ! 316: break; ! 317: case MOUSE_TRIPLEPRESSED: ! 318: add_outevent(CIOLIB_BUTTON_DBL_CLICK(but),state.button_x[but-1],state.button_y[but-1]); ! 319: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); ! 320: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); ! 321: state.button_state[but-1]=MOUSE_DRAGSTARTED; ! 322: break; ! 323: case MOUSE_TRIPLECLICKED: ! 324: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(but),state.button_x[but-1],state.button_y[but-1]); ! 325: state.button_state[but-1]=MOUSE_NOSTATE; ! 326: break; ! 327: case MOUSE_QUADPRESSED: ! 328: add_outevent(CIOLIB_BUTTON_TRPL_CLICK(but),state.button_x[but-1],state.button_y[but-1]); ! 329: add_outevent(CIOLIB_BUTTON_DRAG_START(but),state.button_x[but-1],state.button_y[but-1]); ! 330: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); ! 331: state.button_state[but-1]=MOUSE_DRAGSTARTED; ! 332: break; ! 333: case MOUSE_DRAGSTARTED: ! 334: add_outevent(CIOLIB_BUTTON_DRAG_MOVE(but),in->x,in->y); ! 335: break; ! 336: } ! 337: } ! 338: break; ! 339: case CIOLIB_BUTTON_1_PRESS: ! 340: state.buttonstate|=1<<(but-1); ! 341: state.knownbuttonstatemask|=1<<(but-1); ! 342: switch(state.button_state[but-1]) { ! 343: case MOUSE_NOSTATE: ! 344: state.button_state[but-1]=MOUSE_SINGLEPRESSED; ! 345: state.button_x[but-1]=in->x; ! 346: state.button_y[but-1]=in->y; ! 347: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout; ! 348: if(state.timeout[but-1]==0) ! 349: state.timeout[but-1]=1; ! 350: if(state.click_timeout==0) ! 351: state.timeout[but-1]=0; ! 352: break; ! 353: case MOUSE_CLICKED: ! 354: state.button_state[but-1]=MOUSE_DOUBLEPRESSED; ! 355: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout; ! 356: if(state.timeout[but-1]==0) ! 357: state.timeout[but-1]=1; ! 358: if(state.click_timeout==0) ! 359: state.timeout[but-1]=0; ! 360: break; ! 361: case MOUSE_DOUBLECLICKED: ! 362: state.button_state[but-1]=MOUSE_TRIPLEPRESSED; ! 363: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout; ! 364: if(state.timeout[but-1]==0) ! 365: state.timeout[but-1]=1; ! 366: if(state.click_timeout==0) ! 367: state.timeout[but-1]=0; ! 368: break; ! 369: case MOUSE_TRIPLECLICKED: ! 370: state.button_state[but-1]=MOUSE_QUADPRESSED; ! 371: state.timeout[but-1]=MSEC_CLOCK()+state.click_timeout; ! 372: if(state.timeout[but-1]==0) ! 373: state.timeout[but-1]=1; ! 374: if(state.click_timeout==0) ! 375: state.timeout[but-1]=0; ! 376: break; ! 377: } ! 378: break; ! 379: case CIOLIB_BUTTON_1_RELEASE: ! 380: state.buttonstate&= ~(1<<(but-1)); ! 381: state.knownbuttonstatemask|=1<<(but-1); ! 382: switch(state.button_state[but-1]) { ! 383: case MOUSE_NOSTATE: ! 384: state.button_x[but-1]=in->x; ! 385: state.button_y[but-1]=in->y; ! 386: add_outevent(CIOLIB_BUTTON_RELEASE(but),state.button_x[but-1],state.button_y[but-1]); ! 387: break; ! 388: case MOUSE_SINGLEPRESSED: ! 389: state.button_state[but-1]=MOUSE_CLICKED; ! 390: state.timeout[but-1]=more_multies(but,1)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK(); ! 391: if(state.timeout[but-1]==0) ! 392: state.timeout[but-1]=1; ! 393: break; ! 394: case MOUSE_DOUBLEPRESSED: ! 395: state.button_state[but-1]=MOUSE_DOUBLECLICKED; ! 396: state.timeout[but-1]=more_multies(but,2)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK(); ! 397: if(state.timeout[but-1]==0) ! 398: state.timeout[but-1]=1; ! 399: break; ! 400: case MOUSE_TRIPLEPRESSED: ! 401: state.button_state[but-1]=MOUSE_TRIPLECLICKED; ! 402: state.timeout[but-1]=more_multies(but,3)?MSEC_CLOCK()+state.multi_timeout:MSEC_CLOCK(); ! 403: if(state.timeout[but-1]==0) ! 404: state.timeout[but-1]=1; ! 405: break; ! 406: case MOUSE_QUADPRESSED: ! 407: state.button_state[but-1]=MOUSE_NOSTATE; ! 408: add_outevent(CIOLIB_BUTTON_QUAD_CLICK(but),state.button_x[but-1],state.button_y[but-1]); ! 409: state.timeout[but-1]=0; ! 410: if(state.timeout[but-1]==0) ! 411: state.timeout[but-1]=1; ! 412: break; ! 413: case MOUSE_DRAGSTARTED: ! 414: add_outevent(CIOLIB_BUTTON_DRAG_END(but),in->x,in->y); ! 415: state.button_state[but-1]=0; ! 416: } ! 417: } ! 418: state.curx=in->x; ! 419: state.cury=in->y; ! 420: ! 421: free(in); ! 422: } ! 423: ! 424: timeout_button=0; ! 425: for(but=1;but<=3;but++) { ! 426: if(state.button_state[but-1]!=MOUSE_NOSTATE ! 427: && state.button_state[but-1]!=MOUSE_DRAGSTARTED ! 428: && state.timeout[but-1]!=0 ! 429: && (timeout_button==0 || state.timeout[but-1]<ttime)) { ! 430: ttime=state.timeout[but-1]; ! 431: timeout_button=but; ! 432: } ! 433: } ! 434: } ! 435: } ! 436: ! 437: int mouse_pending(void) ! 438: { ! 439: while(!mouse_initialized) ! 440: SLEEP(1); ! 441: return(listCountNodes(&state.output)); ! 442: } ! 443: ! 444: int ciolib_getmouse(struct mouse_event *mevent) ! 445: { ! 446: int retval=0; ! 447: ! 448: while(!mouse_initialized) ! 449: SLEEP(1); ! 450: if(listCountNodes(&state.output)) { ! 451: struct out_mouse_event *out; ! 452: pthread_mutex_lock(&out_mutex); ! 453: out=listShiftNode(&state.output); ! 454: pthread_mutex_unlock(&out_mutex); ! 455: if(out==NULL) ! 456: return(-1); ! 457: mevent->event=out->event; ! 458: mevent->bstate=out->bstate; ! 459: mevent->kbsm=out->kbsm; ! 460: mevent->startx=out->startx; ! 461: mevent->starty=out->starty; ! 462: mevent->endx=out->endx; ! 463: mevent->endy=out->endy; ! 464: free(out); ! 465: } ! 466: else { ! 467: memset(mevent,0,sizeof(struct mouse_event)); ! 468: retval=-1; ! 469: } ! 470: return(retval); ! 471: } ! 472: ! 473: int ciolib_ungetmouse(struct mouse_event *mevent) ! 474: { ! 475: int retval=0; ! 476: struct mouse_event *me; ! 477: ! 478: if((me=(struct mouse_event *)malloc(sizeof(struct mouse_event)))==NULL) ! 479: return(-1); ! 480: memcpy(me,mevent,sizeof(struct mouse_event)); ! 481: pthread_mutex_lock(&out_mutex); ! 482: listAddNode(&state.output,me,FIRST_NODE); ! 483: pthread_mutex_unlock(&out_mutex); ! 484: return(0); ! 485: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.