Main Page   Data Structures   File List   Data Fields   Globals  

hapi.c

Go to the documentation of this file.
00001 #include "lapi.h"
00002 #include "hapi.h"
00003 //#include <wingdi.h>
00004 
00005 #define eSuspend 1
00006 #define eUnSuspend 2
00007 #define eCleanup 3
00008 
00009 // This is hackish. Breaks with windows 95
00010 #define SPI_GETMOUSESPEED 112
00011 
00012 typedef struct MouseData {
00013       int X, Y;
00014       int dx, dy;
00015       int suspended;
00016       HBITMAP cachebitmap, cursorbitmap;
00017       int hx, hy, cx, cy; /* hotspot, old cache position */
00018       int tx, ty;
00019       int wx, wy, ww, wh;
00020       HDC cache, cursor;
00021       SIZE theSize; /* size of cursor */
00022 } MouseData;
00023 
00024 MouseData *micedata = NULL;
00025 int nummice = -1;
00026 
00027 HANDLE child = NULL;
00028 volatile int mousecount;
00029 volatile HWND mousewindow;
00030 DWORD dwThreadId;
00031 HANDLE datamutex = NULL;
00032 HANDLE canvas = NULL;
00033 HANDLE mutex = NULL;
00034 HANDLE event = NULL;
00035 HANDLE reply = NULL;
00036 
00037 int lastsuspended, lastunsuspended, lastmoved;
00038 
00039 unsigned int events;
00040 volatile int call, parameter;
00041 
00042 int accel[3];
00043 int speed;
00044 int rx, ry;
00045 
00046 HDC tmp = NULL;
00047 
00048 #ifdef HMONITOR
00049 HMONITOR monitor = NULL;
00050 MONITORINFO minfo;
00051 #endif
00052 int mleft, mright, mtop, mbottom;
00053 HDC screen;
00054 
00055 #define abs(x) (max((x),-(x)))
00056 
00057 void __cdecl thehCallback(int number, signed int dx, signed int dy, unsigned int buttons, int suspended) {
00058       int x, y;
00059       x = y = 1;
00060       if (suspended)
00061             lastsuspended = number;
00062       else
00063             lastunsuspended = number;
00064       lastmoved = number;
00065       while (WaitForSingleObjectEx(datamutex, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00066       if (events & ACCELERATE) {
00067             if (accel[2]) {
00068                   if (abs(dx) > accel[0])
00069                         x *= 2;
00070                   if (abs(dy) > accel[0])
00071                         y *= 2;
00072                   if (accel[2] == 2) {
00073                         if (abs(dx) > accel[1])
00074                               x *= 2;
00075                         if (abs(dy) > accel[1])
00076                               y *= 2;
00077                   }
00078             }
00079             dx *= x;
00080             dy *= y;
00081 
00082             if (speed >= 10) {
00083                   dx *= (speed - 6); dy *= (speed - 6);
00084                   dx += rx; dy += ry;
00085                   rx = dx % 4; ry = ry % 4;
00086                   dx /= 4; dy /= 4;
00087             } else {
00088                   switch (speed) {
00089                         case 0:
00090                         case 1:
00091                               dx += rx; dy += ry;
00092                               rx = dx % 32; ry = dy % 32;
00093                               dx /= 32; dy /= 32;
00094                               break;
00095                         case 2:
00096                         case 3:
00097                               dx += rx; dy += ry;
00098                               rx = dx % 16; ry = dy % 16;
00099                               dx /= 16; dy /= 16;
00100                               break;
00101                         case 4:
00102                         case 5:
00103                               dx += rx; dy += ry;
00104                               rx = dx % 4; ry = dy % 4;
00105                               dx /= 4; dy /= 4;
00106                               break;
00107                         case 6:
00108                         case 7:
00109                               dx += rx; dy += ry;
00110                               rx = dx % 2; ry = dy % 2;
00111                               dx /= 2; dy /= 2;
00112                               break;
00113                         case 8:
00114                         case 9:
00115                               dx *= 3; dy *= 3;
00116                               dx += rx; dy += ry;
00117                               rx = dx % 4; ry = dy % 4;
00118                               dx /= 4; dy /= 4;
00119                               break;
00120                   }
00121             }
00122       }
00123 
00124       if ((number <= nummice) && (number > 0)) {
00125             micedata[number - 1].X += dx;
00126             micedata[number - 1].Y += dy;
00127             if (events & CLIP) {
00128                   micedata[number - 1].X = max(mleft, min(mright, micedata[number - 1].X));
00129                   micedata[number - 1].Y = max(mtop, min(mbottom, micedata[number - 1].Y));
00130             }
00131             micedata[number - 1].dx += dx;
00132             micedata[number - 1].dy += dy;
00133       }
00134 
00135       ReleaseMutex(datamutex);
00136       if (mousewindow != NULL) {
00137             WPARAM w = MAKEWPARAM(buttons, ((number & 0xff) << 8) | (((unsigned int) suspended) & 0xff));
00138             LPARAM l = MAKELPARAM(dx, dy);
00139             if (((l && (events & MOVEMENT)) || (buttons && (events & BUTTON))) &&
00140                         ((events & SUSPEND) || (!suspended)))
00141                   PostMessage(mousewindow, WM_USER + 1001, w, l);
00142       }
00143       hUpdateCursors(TRUE);
00144 }
00145 
00146 void __cdecl hLockCanvas() {
00147       while (WaitForSingleObjectEx(canvas, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00148 }
00149 
00150 void __cdecl hUpdateCursors(int useCache) {
00151       if (datamutex == NULL) return;
00152       if (events & CURSOR) {
00153             int i;
00154             while (WaitForSingleObjectEx(datamutex, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00155             if (useCache) {
00156                   if (WaitForSingleObjectEx(canvas, 0, TRUE) != WAIT_OBJECT_0) {
00157                         ReleaseMutex(datamutex);
00158                         return;
00159                   }
00160             } else 
00161                   while (WaitForSingleObjectEx(canvas, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00162 
00163             // Backup background
00164             for (i = 0; i < nummice; ++i) {
00165                   micedata[i].tx = micedata[i].X;
00166                   micedata[i].ty = micedata[i].Y;
00167                   if ((micedata[i].cursor)) {
00168                         if (useCache) {
00169                               micedata[i].wx = min(micedata[i].cx, micedata[i].tx) - micedata[i].hx;
00170                               micedata[i].wy = min(micedata[i].cy, micedata[i].ty) - micedata[i].hy;
00171                               micedata[i].ww = abs(micedata[i].cx - micedata[i].tx) + micedata[i].theSize.cx;
00172                               micedata[i].wh = abs(micedata[i].cy - micedata[i].ty) + micedata[i].theSize.cy;
00173                         } else {
00174                               micedata[i].wx = micedata[i].tx - micedata[i].hx;
00175                               micedata[i].wy = micedata[i].ty - micedata[i].hy;
00176                               micedata[i].ww = micedata[i].theSize.cx;
00177                               micedata[i].wh = micedata[i].theSize.cy;
00178                         }
00179                         BitBlt(tmp, micedata[i].wx, micedata[i].wy, micedata[i].ww, micedata[i].wh, screen, micedata[i].wx, micedata[i].wy, SRCCOPY);
00180                   }
00181             }
00182             // Apply cache
00183             if (useCache)
00184                   for (i = 0; i < nummice; ++i)
00185                         BitBlt(tmp, micedata[i].cx - micedata[i].hx, micedata[i].cy - micedata[i].hy, micedata[i].theSize.cx, micedata[i].theSize.cy, micedata[i].cache, 0, 0, SRCCOPY);
00186             // Get new cache
00187             for (i = 0; i < nummice; ++i)
00188                   BitBlt(micedata[i].cache, 0, 0, micedata[i].theSize.cx, micedata[i].theSize.cy, tmp, micedata[i].tx - micedata[i].hx, micedata[i].ty - micedata[i].hy, SRCCOPY);
00189             // MaskBlit in cursors
00190             for (i = 0; i < nummice; ++i) {
00191                   if (!micedata[i].suspended) {
00192                         if (micedata[i].cursor)
00193                               TransparentBlt(tmp, micedata[i].tx - micedata[i].hx, micedata[i].ty - micedata[i].hy, micedata[i].theSize.cx, micedata[i].theSize.cy, micedata[i].cursor, 0, 0, micedata[i].theSize.cx, micedata[i].theSize.cy, RGB(255, 0, 205));
00194                         BitBlt(screen, micedata[i].wx, micedata[i].wy, micedata[i].ww, micedata[i].wh, tmp, micedata[i].wx, micedata[i].wy, SRCCOPY);
00195                         micedata[i].cx = micedata[i].tx;
00196                         micedata[i].cy = micedata[i].ty;
00197                   }
00198             }
00199             ReleaseMutex(canvas);
00200             ReleaseMutex(datamutex);
00201       }
00202 }
00203 
00204 
00205 DWORD WINAPI MainThread(LPVOID lpParameter) {
00206       int loop = TRUE;
00207       lRegisterCallback(thehCallback);
00208       parameter = lGetMice(mousecount);
00209       SetEvent(reply);
00210       while (loop) {
00211             if (WaitForSingleObjectEx(event, INFINITE, TRUE) == WAIT_OBJECT_0) {
00212                   switch (call) {
00213                         case eSuspend:
00214                               lSuspendMouse(parameter);
00215                               break;
00216                         case eUnSuspend:
00217                               lUnSuspendMouse(parameter);
00218                               break;
00219                         case eCleanup:
00220                               lUnGetAllMice();
00221                               lUnRegisterCallback();
00222                               loop = FALSE;
00223                         default: /* do nothing */;
00224                   }
00225                   ResetEvent(event);
00226                   SetEvent(reply);
00227             }
00228 #if 0
00229             hUpdateCursors(TRUE);
00230 #endif
00231       }
00232       return 0;
00233 }
00234 
00235 
00236 // Not thread safe until after first call
00237 int __cdecl hInitialise(int count, HWND window, HDC getscreen, unsigned int getevents) {
00238       int i;
00239       if (event == NULL) {
00240             event = CreateEvent(NULL, TRUE, FALSE, NULL);
00241             reply = CreateEvent(NULL, TRUE, FALSE, NULL);
00242       }
00243       if (datamutex == NULL) {
00244             datamutex = CreateMutex(NULL, TRUE, NULL);
00245       }
00246       if (mutex == NULL) {
00247             mutex = CreateMutex(NULL, TRUE, NULL);
00248             canvas = CreateMutex(NULL, FALSE, NULL);
00249       }
00250       if (child == NULL) {
00251             mousecount = count;
00252             mousewindow = window;
00253             child = CreateThread(NULL, 0, MainThread, NULL, 0, &dwThreadId);
00254       }
00255       if (child == NULL) {
00256             MessageBox(window, "Could not create mouse thread!", "Error!", MB_OK | MB_ICONEXCLAMATION);
00257             ReleaseMutex(mutex);
00258             return 0;
00259       }
00260 
00261       //    SetThreadPriority(child, THREAD_PRIORITY_HIGHEST);
00262       SetThreadPriority(child, 5);
00263       events = getevents;
00264 
00265       // Get acceleration information
00266       SystemParametersInfo(SPI_GETMOUSE, 0, accel, 0);
00267 #ifdef SPI_GETMOUSESPEED
00268       SystemParametersInfo(SPI_GETMOUSESPEED, 0, &speed, 0);
00269 #else
00270       speed = 10;
00271 #endif
00272       rx = ry = 0;
00273 
00274       // Get monitor info
00275       if (events & CURSOR) {
00276             if (getscreen)
00277                   screen = getscreen;
00278             else
00279                   screen = CreateDC("DISPLAY", NULL, NULL, NULL);
00280 #ifdef HMONITOR
00281             monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY);
00282             minfo.cbSize = sizeof(MONITORINFO);
00283             GetMonitorInfo(monitor, &minfo);
00284             mleft = minfo.rcMonitor.left;
00285             mright = minfo.rcMonitor.right;
00286             mtop = minfo.rcMonitor.top;
00287             mbottom = minfo.rcMonitor.bottom;
00288 #else
00289             mleft = 0;
00290             mtop = 0;
00291             mright = GetDeviceCaps(screen, HORZRES);
00292             mbottom = GetDeviceCaps(screen, VERTRES);
00293 #endif
00294       } else
00295             events &= (~CLIP);
00296 
00297       while (WaitForSingleObjectEx(reply, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00298       nummice = count = parameter;
00299       if (micedata != NULL) free(micedata);
00300       micedata = malloc(sizeof(MouseData) * nummice);
00301       for (i = 0; i < nummice; ++i) {
00302             micedata[i].X = micedata[i].Y = micedata[i].dx = micedata[i].dy =
00303                   micedata[i].hx = micedata[i].hy = micedata[i].suspended = 0;
00304             micedata[i].cursor = 0;
00305             micedata[i].cache = 0;
00306       }
00307       ReleaseMutex(datamutex);
00308       ResetEvent(reply);
00309       ReleaseMutex(mutex);
00310       return count;
00311 }
00312 
00313 void __cdecl hSuspendMouse(int number) {
00314       if (mutex == NULL) return;
00315       while (WaitForSingleObjectEx(mutex, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00316       lastsuspended = lastmoved = number;
00317       lastunsuspended = -1;
00318       if ((child != NULL) && (number <= nummice) && (number > 0)) {
00319             micedata[number - 1].suspended = 1;
00320             parameter = number;
00321             call = eSuspend;
00322             SetEvent(event);
00323             while (WaitForSingleObjectEx(reply, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00324             ResetEvent(reply);
00325       }
00326       ReleaseMutex(mutex);
00327 }
00328 
00329 void __cdecl hUnSuspendMouse(int number) {
00330       if (mutex == NULL) return;
00331       lastunsuspended = lastmoved = number;
00332       lastsuspended = -1;
00333       while (WaitForSingleObjectEx(mutex, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00334       if ((child != NULL) && (number <= nummice) && (number > 0)) {
00335             micedata[number - 1].suspended = 0;
00336             parameter = number;
00337             call = eUnSuspend;
00338             SetEvent(event);
00339             while (WaitForSingleObjectEx(reply, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00340             ResetEvent(reply);
00341       }
00342       ReleaseMutex(mutex);
00343 }
00344 
00345 void __cdecl hCleanup(void) {
00346       if (mutex == NULL) return;
00347       while (WaitForSingleObjectEx(mutex, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00348       if (child != NULL) {
00349             call = eCleanup;
00350             SetEvent(event);
00351             while (WaitForSingleObjectEx(reply, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00352             ResetEvent(reply);
00353             /* TODO clean up cursors */
00354             CloseHandle(child); child = NULL;
00355       }
00356       ReleaseMutex(mutex);
00357 }
00358 
00359 void __cdecl hGetRelativePosition(int number, hPOINT* p) {
00360       if ((datamutex == NULL) || (p == NULL)) return;
00361       while (WaitForSingleObjectEx(datamutex, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00362       if ((number <= nummice) && (number > 0)) {
00363             p->x = micedata[number - 1].dx;
00364             p->y = micedata[number - 1].dy;
00365             micedata[number - 1].dx -= p->x;
00366             micedata[number - 1].dy -= p->y;
00367       }
00368       ReleaseMutex(datamutex);
00369 }
00370 
00371 void __cdecl hGetAbsolutePosition(int number, hPOINT* p) {
00372       if ((datamutex == NULL) || (p == NULL)) return;
00373       while (WaitForSingleObjectEx(datamutex, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00374       if ((number <= nummice) && (number > 0))
00375             p->x = micedata[number - 1].X;
00376       p->y = micedata[number - 1].Y;
00377       ReleaseMutex(datamutex);
00378 }
00379 
00380 void __cdecl hSetAbsolutePosition(int number, hPOINT p) {
00381       if (datamutex == NULL) return;
00382       while (WaitForSingleObjectEx(datamutex, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00383       if ((number <= nummice) && (number > 0)) {
00384             micedata[number - 1].X = max(mleft, min(mright, p.x));
00385             micedata[number - 1].Y = max(mtop, min(mbottom, p.y));
00386       }
00387       ReleaseMutex(datamutex);
00388 }
00389 
00390 void __cdecl hSetCursor(int number, hPOINT p, HBITMAP cursor, BYTE r, BYTE g, BYTE b) {
00391       while (WaitForSingleObjectEx(datamutex, INFINITE, TRUE) != WAIT_OBJECT_0) ;
00392       if ((number <= nummice) && (number > 0)) {
00393             if (micedata[number - 1].cursor) {
00394                   DeleteDC(micedata[number - 1].cursor);
00395                   DeleteObject(micedata[number - 1].cursorbitmap);
00396                   micedata[number - 1].cursor = NULL;
00397                   micedata[number - 1].cursorbitmap = NULL;
00398                   hUpdateCursors(TRUE);
00399                   DeleteDC(micedata[number - 1].cache);
00400                   DeleteObject(micedata[number - 1].cachebitmap);
00401                   micedata[number - 1].cache = NULL;
00402                   micedata[number - 1].cachebitmap = NULL;
00403             }
00404             micedata[number - 1].hx = p.x;
00405             micedata[number - 1].hy = p.y;
00406             if (cursor) {
00407                   micedata[number - 1].cursor = CreateCompatibleDC(screen);
00408                   micedata[number - 1].cache = CreateCompatibleDC(screen);
00409                   if (tmp == NULL) {
00410                         tmp = CreateCompatibleDC(screen);
00411                         SelectObject(tmp, CreateCompatibleBitmap(screen, GetDeviceCaps(screen, HORZRES), GetDeviceCaps(screen, VERTRES)));
00412                   }
00413                   micedata[number - 1].theSize.cx = 18; // FIXME
00414                   micedata[number - 1].theSize.cy = 18; // FIXME
00415 
00416                   // FIXME: Memoryleak
00417                   micedata[number - 1].cursorbitmap = CreateCompatibleBitmap(screen, micedata[number - 1].theSize.cx, micedata[number - 1].theSize.cy);
00418                   micedata[number - 1].cachebitmap = CreateCompatibleBitmap(screen, micedata[number - 1].theSize.cx, micedata[number - 1].theSize.cy);
00419 
00420                   SelectObject(micedata[number - 1].cursor, cursor);
00421                   SelectObject(micedata[number - 1].cache, micedata[number - 1].cachebitmap);
00422 
00423                   BitBlt(micedata[number - 1].cache, 0, 0, micedata[number - 1].theSize.cx, micedata[number - 1].theSize.cy, micedata[number - 1].cursor, 0, 0, SRCCOPY);
00424                   SelectObject(micedata[number - 1].cursor, micedata[number - 1].cursorbitmap);
00425 
00426                   FillRgn(micedata[number - 1].cursor, CreateRectRgn(0, 0, micedata[number - 1].theSize.cx, micedata[number - 1].theSize.cy), CreateSolidBrush(RGB(r, g, b)));
00427                   TransparentBlt(micedata[number - 1].cursor, 0, 0, micedata[number - 1].theSize.cx, micedata[number - 1].theSize.cy, micedata[number - 1].cache, 0, 0, micedata[number - 1].theSize.cx, micedata[number - 1].theSize.cy, RGB(255, 0, 204));
00428 
00429                   BitBlt(micedata[number - 1].cache, 0, 0, micedata[number - 1].theSize.cx, micedata[number - 1].theSize.cy, screen, 0, 0, WHITENESS);
00430                   micedata[number - 1].cx = -10 - micedata[number - 1].theSize.cx - p.x;
00431                   micedata[number - 1].cy = -10 - micedata[number - 1].theSize.cy - p.y;
00432             }
00433       }
00434       hUpdateCursors(TRUE);
00435       ReleaseMutex(datamutex);
00436 }
00437 
00438 int __cdecl hGetLastSuspended(void) {
00439       int i = lastsuspended;
00440       lastsuspended = -1;
00441       return i;
00442 }
00443 
00444 int __cdecl hGetLastUnSuspended(void) {
00445       int i = lastunsuspended;
00446       lastunsuspended = -1;
00447       return i;
00448 }
00449 
00450 int __cdecl hGetLastMoved(void) {
00451       int i = lastmoved;
00452       lastmoved = -1;
00453       return i;
00454 }
00455 

Generated on Mon Jan 12 21:47:21 2004 for CPNMouse by doxygen1.2.18