cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_windowsmouse.c (8959B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../../SDL_internal.h"
     22
     23#if SDL_VIDEO_DRIVER_WINDOWS
     24
     25#include "SDL_assert.h"
     26#include "SDL_windowsvideo.h"
     27
     28#include "../../events/SDL_mouse_c.h"
     29
     30
     31HCURSOR SDL_cursor = NULL;
     32
     33static int rawInputEnableCount = 0;
     34
     35static int 
     36ToggleRawInput(SDL_bool enabled)
     37{
     38    RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
     39
     40    if (enabled) {
     41        rawInputEnableCount++;
     42        if (rawInputEnableCount > 1) {
     43            return 0;  /* already done. */
     44        }
     45    } else {
     46        if (rawInputEnableCount == 0) {
     47            return 0;  /* already done. */
     48        }
     49        rawInputEnableCount--;
     50        if (rawInputEnableCount > 0) {
     51            return 0;  /* not time to disable yet */
     52        }
     53    }
     54
     55    if (!enabled) {
     56        rawMouse.dwFlags |= RIDEV_REMOVE;
     57    }
     58
     59    /* (Un)register raw input for mice */
     60    if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
     61
     62        /* Only return an error when registering. If we unregister and fail,
     63           then it's probably that we unregistered twice. That's OK. */
     64        if (enabled) {
     65            return SDL_Unsupported();
     66        }
     67    }
     68    return 0;
     69}
     70
     71
     72static SDL_Cursor *
     73WIN_CreateDefaultCursor()
     74{
     75    SDL_Cursor *cursor;
     76
     77    cursor = SDL_calloc(1, sizeof(*cursor));
     78    if (cursor) {
     79        cursor->driverdata = LoadCursor(NULL, IDC_ARROW);
     80    } else {
     81        SDL_OutOfMemory();
     82    }
     83
     84    return cursor;
     85}
     86
     87static SDL_Cursor *
     88WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
     89{
     90    /* msdn says cursor mask has to be padded out to word alignment. Not sure
     91        if that means machine word or WORD, but this handles either case. */
     92    const size_t pad = (sizeof (size_t) * 8);  /* 32 or 64, or whatever. */
     93    SDL_Cursor *cursor;
     94    HICON hicon;
     95    HDC hdc;
     96    BITMAPV4HEADER bmh;
     97    LPVOID pixels;
     98    LPVOID maskbits;
     99    size_t maskbitslen;
    100    ICONINFO ii;
    101
    102    SDL_zero(bmh);
    103    bmh.bV4Size = sizeof(bmh);
    104    bmh.bV4Width = surface->w;
    105    bmh.bV4Height = -surface->h; /* Invert the image */
    106    bmh.bV4Planes = 1;
    107    bmh.bV4BitCount = 32;
    108    bmh.bV4V4Compression = BI_BITFIELDS;
    109    bmh.bV4AlphaMask = 0xFF000000;
    110    bmh.bV4RedMask   = 0x00FF0000;
    111    bmh.bV4GreenMask = 0x0000FF00;
    112    bmh.bV4BlueMask  = 0x000000FF;
    113
    114    maskbitslen = ((surface->w + (pad - (surface->w % pad))) / 8) * surface->h;
    115    maskbits = SDL_stack_alloc(Uint8,maskbitslen);
    116    if (maskbits == NULL) {
    117        SDL_OutOfMemory();
    118        return NULL;
    119    }
    120
    121    /* AND the cursor against full bits: no change. We already have alpha. */
    122    SDL_memset(maskbits, 0xFF, maskbitslen);
    123
    124    hdc = GetDC(NULL);
    125    SDL_zero(ii);
    126    ii.fIcon = FALSE;
    127    ii.xHotspot = (DWORD)hot_x;
    128    ii.yHotspot = (DWORD)hot_y;
    129    ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmh, DIB_RGB_COLORS, &pixels, NULL, 0);
    130    ii.hbmMask = CreateBitmap(surface->w, surface->h, 1, 1, maskbits);
    131    ReleaseDC(NULL, hdc);
    132    SDL_stack_free(maskbits);
    133
    134    SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
    135    SDL_assert(surface->pitch == surface->w * 4);
    136    SDL_memcpy(pixels, surface->pixels, surface->h * surface->pitch);
    137
    138    hicon = CreateIconIndirect(&ii);
    139
    140    DeleteObject(ii.hbmColor);
    141    DeleteObject(ii.hbmMask);
    142
    143    if (!hicon) {
    144        WIN_SetError("CreateIconIndirect()");
    145        return NULL;
    146    }
    147
    148    cursor = SDL_calloc(1, sizeof(*cursor));
    149    if (cursor) {
    150        cursor->driverdata = hicon;
    151    } else {
    152        DestroyIcon(hicon);
    153        SDL_OutOfMemory();
    154    }
    155
    156    return cursor;
    157}
    158
    159static SDL_Cursor *
    160WIN_CreateSystemCursor(SDL_SystemCursor id)
    161{
    162    SDL_Cursor *cursor;
    163    LPCTSTR name;
    164
    165    switch(id)
    166    {
    167    default:
    168        SDL_assert(0);
    169        return NULL;
    170    case SDL_SYSTEM_CURSOR_ARROW:     name = IDC_ARROW; break;
    171    case SDL_SYSTEM_CURSOR_IBEAM:     name = IDC_IBEAM; break;
    172    case SDL_SYSTEM_CURSOR_WAIT:      name = IDC_WAIT; break;
    173    case SDL_SYSTEM_CURSOR_CROSSHAIR: name = IDC_CROSS; break;
    174    case SDL_SYSTEM_CURSOR_WAITARROW: name = IDC_WAIT; break;
    175    case SDL_SYSTEM_CURSOR_SIZENWSE:  name = IDC_SIZENWSE; break;
    176    case SDL_SYSTEM_CURSOR_SIZENESW:  name = IDC_SIZENESW; break;
    177    case SDL_SYSTEM_CURSOR_SIZEWE:    name = IDC_SIZEWE; break;
    178    case SDL_SYSTEM_CURSOR_SIZENS:    name = IDC_SIZENS; break;
    179    case SDL_SYSTEM_CURSOR_SIZEALL:   name = IDC_SIZEALL; break;
    180    case SDL_SYSTEM_CURSOR_NO:        name = IDC_NO; break;
    181    case SDL_SYSTEM_CURSOR_HAND:      name = IDC_HAND; break;
    182    }
    183
    184    cursor = SDL_calloc(1, sizeof(*cursor));
    185    if (cursor) {
    186        HICON hicon;
    187
    188        hicon = LoadCursor(NULL, name);
    189
    190        cursor->driverdata = hicon;
    191    } else {
    192        SDL_OutOfMemory();
    193    }
    194
    195    return cursor;
    196}
    197
    198static void
    199WIN_FreeCursor(SDL_Cursor * cursor)
    200{
    201    HICON hicon = (HICON)cursor->driverdata;
    202
    203    DestroyIcon(hicon);
    204    SDL_free(cursor);
    205}
    206
    207static int
    208WIN_ShowCursor(SDL_Cursor * cursor)
    209{
    210    if (cursor) {
    211        SDL_cursor = (HCURSOR)cursor->driverdata;
    212    } else {
    213        SDL_cursor = NULL;
    214    }
    215    if (SDL_GetMouseFocus() != NULL) {
    216        SetCursor(SDL_cursor);
    217    }
    218    return 0;
    219}
    220
    221static void
    222WIN_WarpMouse(SDL_Window * window, int x, int y)
    223{
    224    SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
    225    HWND hwnd = data->hwnd;
    226    POINT pt;
    227
    228    /* Don't warp the mouse while we're doing a modal interaction */
    229    if (data->in_title_click || data->focus_click_pending) {
    230        return;
    231    }
    232
    233    pt.x = x;
    234    pt.y = y;
    235    ClientToScreen(hwnd, &pt);
    236    SetCursorPos(pt.x, pt.y);
    237}
    238
    239static void
    240WIN_WarpMouseGlobal(int x, int y)
    241{
    242    POINT pt;
    243
    244    pt.x = x;
    245    pt.y = y;
    246    SetCursorPos(pt.x, pt.y);
    247}
    248
    249static int
    250WIN_SetRelativeMouseMode(SDL_bool enabled)
    251{
    252    return ToggleRawInput(enabled);
    253}
    254
    255static int
    256WIN_CaptureMouse(SDL_Window *window)
    257{
    258    if (!window) {
    259        SDL_Window *focusWin = SDL_GetKeyboardFocus();
    260        if (focusWin) {
    261            WIN_OnWindowEnter(SDL_GetVideoDevice(), focusWin);  /* make sure WM_MOUSELEAVE messages are (re)enabled. */
    262        }
    263    }
    264
    265    /* While we were thinking of SetCapture() when designing this API in SDL,
    266       we didn't count on the fact that SetCapture() only tracks while the
    267       left mouse button is held down! Instead, we listen for raw mouse input
    268       and manually query the mouse when it leaves the window. :/ */
    269    return ToggleRawInput(window != NULL);
    270}
    271
    272static Uint32
    273WIN_GetGlobalMouseState(int *x, int *y)
    274{
    275    Uint32 retval = 0;
    276    POINT pt = { 0, 0 };
    277    GetCursorPos(&pt);
    278    *x = (int) pt.x;
    279    *y = (int) pt.y;
    280
    281    retval |= GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0;
    282    retval |= GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0;
    283    retval |= GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_BUTTON_MMASK : 0;
    284    retval |= GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_BUTTON_X1MASK : 0;
    285    retval |= GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_BUTTON_X2MASK : 0;
    286
    287    return retval;
    288}
    289
    290void
    291WIN_InitMouse(_THIS)
    292{
    293    SDL_Mouse *mouse = SDL_GetMouse();
    294
    295    mouse->CreateCursor = WIN_CreateCursor;
    296    mouse->CreateSystemCursor = WIN_CreateSystemCursor;
    297    mouse->ShowCursor = WIN_ShowCursor;
    298    mouse->FreeCursor = WIN_FreeCursor;
    299    mouse->WarpMouse = WIN_WarpMouse;
    300    mouse->WarpMouseGlobal = WIN_WarpMouseGlobal;
    301    mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
    302    mouse->CaptureMouse = WIN_CaptureMouse;
    303    mouse->GetGlobalMouseState = WIN_GetGlobalMouseState;
    304
    305    SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
    306
    307    SDL_SetDoubleClickTime(GetDoubleClickTime());
    308}
    309
    310void
    311WIN_QuitMouse(_THIS)
    312{
    313    SDL_Mouse *mouse = SDL_GetMouse();
    314    if ( mouse->def_cursor ) {
    315        SDL_free(mouse->def_cursor);
    316        mouse->def_cursor = NULL;
    317        mouse->cur_cursor = NULL;
    318    }
    319
    320    if (rawInputEnableCount) {  /* force RAWINPUT off here. */
    321        rawInputEnableCount = 1;
    322        ToggleRawInput(SDL_FALSE);
    323    }
    324}
    325
    326#endif /* SDL_VIDEO_DRIVER_WINDOWS */
    327
    328/* vi: set ts=4 sw=4 expandtab: */