src/events/SDL_mouse.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 01 Mar 2014 09:59:06 -0800
changeset 8269 6e18328e25e0
parent 8149 681eb46b8ac4
child 8776 29aac8b813d9
permissions -rw-r--r--
Fixed bug 2368 - Security Software is blocking RegisterRawInputDevices()

Yamagi

A customer of mine had the strange problem, that SDL_SetRelativeMouseMode() was failing for him on Windows 7. Luckily he was willing to provide some debug informations. We could track this problem down to RegisterRawInputDevices() failing due to security software running on his system (Norton Internet Security to be precise, but there are reports of similar problems with other products. For example [1]). Working around this issue with SDL_WarpMouseInWindow() is easy, and while I don't think that SDL2 can provide an internal workaround it would be really nice and helpfull if this could be documentated somewhere.

1: http://forums.codeguru.com/showthread.php?498374-How-to-run-a-very-long-SQL-statement
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@0
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
icculus@8093
    21
#include "../SDL_internal.h"
slouken@0
    22
slouken@0
    23
/* General mouse handling code for SDL */
slouken@0
    24
slouken@6666
    25
#include "SDL_assert.h"
slouken@8071
    26
#include "SDL_hints.h"
slouken@8066
    27
#include "SDL_timer.h"
slouken@0
    28
#include "SDL_events.h"
slouken@0
    29
#include "SDL_events_c.h"
slouken@1895
    30
#include "default_cursor.h"
slouken@3685
    31
#include "../video/SDL_sysvideo.h"
slouken@0
    32
gabomdq@7678
    33
/* #define DEBUG_MOUSE */
slouken@0
    34
slouken@5371
    35
/* The mouse state */
slouken@4465
    36
static SDL_Mouse SDL_mouse;
slouken@8066
    37
static Uint32 SDL_double_click_time = 500;
slouken@8066
    38
static int SDL_double_click_radius = 1;
slouken@0
    39
jorgen@7089
    40
static int
jorgen@7089
    41
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
slouken@0
    42
slouken@0
    43
/* Public functions */
slouken@1895
    44
int
slouken@1895
    45
SDL_MouseInit(void)
slouken@0
    46
{
slouken@5376
    47
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5376
    48
slouken@5376
    49
    mouse->cursor_shown = SDL_TRUE;
slouken@5376
    50
slouken@1895
    51
    return (0);
slouken@1123
    52
}
slouken@0
    53
slouken@5405
    54
void
slouken@5405
    55
SDL_SetDefaultCursor(SDL_Cursor * cursor)
slouken@5405
    56
{
slouken@5405
    57
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5405
    58
slouken@5405
    59
    mouse->def_cursor = cursor;
slouken@5405
    60
    if (!mouse->cur_cursor) {
slouken@5405
    61
        SDL_SetCursor(cursor);
slouken@5405
    62
    }
slouken@5405
    63
}
slouken@5405
    64
slouken@5371
    65
SDL_Mouse *
slouken@5371
    66
SDL_GetMouse(void)
slouken@5371
    67
{
slouken@5371
    68
    return &SDL_mouse;
slouken@5371
    69
}
slouken@5371
    70
slouken@8066
    71
void
slouken@8066
    72
SDL_SetDoubleClickTime(Uint32 interval)
slouken@8066
    73
{
slouken@8066
    74
    SDL_double_click_time = interval;
slouken@8066
    75
}
slouken@8066
    76
slouken@4465
    77
SDL_Window *
slouken@4465
    78
SDL_GetMouseFocus(void)
slouken@2710
    79
{
slouken@5371
    80
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@2940
    81
slouken@4465
    82
    return mouse->focus;
slouken@0
    83
}
slouken@0
    84
slouken@1895
    85
void
slouken@6666
    86
SDL_ResetMouse(void)
slouken@6666
    87
{
slouken@6666
    88
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6666
    89
    Uint8 i;
slouken@6666
    90
slouken@6666
    91
#ifdef DEBUG_MOUSE
slouken@6666
    92
    printf("Resetting mouse\n");
slouken@6666
    93
#endif
slouken@6666
    94
    for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
slouken@6666
    95
        if (mouse->buttonstate & SDL_BUTTON(i)) {
slouken@6950
    96
            SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
slouken@6666
    97
        }
slouken@6666
    98
    }
slouken@6666
    99
    SDL_assert(mouse->buttonstate == 0);
slouken@6666
   100
}
slouken@6666
   101
slouken@6666
   102
void
slouken@4465
   103
SDL_SetMouseFocus(SDL_Window * window)
slouken@0
   104
{
slouken@5371
   105
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   106
slouken@4465
   107
    if (mouse->focus == window) {
slouken@1895
   108
        return;
slouken@1895
   109
    }
slouken@1895
   110
slouken@6829
   111
    /* Actually, this ends up being a bad idea, because most operating
slouken@6829
   112
       systems have an implicit grab when you press the mouse button down
slouken@6829
   113
       so you can drag things out of the window and then get the mouse up
slouken@6829
   114
       when it happens.  So, #if 0...
slouken@6829
   115
    */
slouken@6829
   116
#if 0
slouken@6666
   117
    if (mouse->focus && !window) {
slouken@6666
   118
        /* We won't get anymore mouse messages, so reset mouse state */
slouken@6666
   119
        SDL_ResetMouse();
slouken@6666
   120
    }
slouken@6829
   121
#endif
slouken@6666
   122
slouken@1895
   123
    /* See if the current window has lost focus */
slouken@1895
   124
    if (mouse->focus) {
slouken@4465
   125
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
slouken@1895
   126
    }
slouken@1895
   127
slouken@3685
   128
    mouse->focus = window;
slouken@1895
   129
slouken@1895
   130
    if (mouse->focus) {
slouken@4465
   131
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
slouken@1895
   132
    }
slouken@6666
   133
slouken@6666
   134
    /* Update cursor visibility */
slouken@6666
   135
    SDL_SetCursor(NULL);
slouken@6666
   136
}
slouken@6666
   137
slouken@6666
   138
/* Check to see if we need to synthesize focus events */
slouken@6666
   139
static SDL_bool
slouken@6673
   140
SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
slouken@6666
   141
{
slouken@6666
   142
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6666
   143
    int w, h;
slouken@6666
   144
    SDL_bool inWindow;
slouken@6666
   145
slouken@6666
   146
    SDL_GetWindowSize(window, &w, &h);
slouken@6666
   147
    if (x < 0 || y < 0 || x >= w || y >= h) {
slouken@6666
   148
        inWindow = SDL_FALSE;
slouken@6666
   149
    } else {
slouken@6666
   150
        inWindow = SDL_TRUE;
slouken@6666
   151
    }
slouken@6667
   152
slouken@6667
   153
/* Linux doesn't give you mouse events outside your window unless you grab
slouken@6667
   154
   the pointer.
slouken@6667
   155
slouken@6667
   156
   Windows doesn't give you mouse events outside your window unless you call
slouken@6667
   157
   SetCapture().
slouken@6667
   158
slouken@6667
   159
   Both of these are slightly scary changes, so for now we'll punt and if the
slouken@6667
   160
   mouse leaves the window you'll lose mouse focus and reset button state.
slouken@6667
   161
*/
slouken@6667
   162
#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
slouken@6666
   163
    if (!inWindow && !buttonstate) {
slouken@6667
   164
#else
slouken@6667
   165
    if (!inWindow) {
slouken@6667
   166
#endif
slouken@6666
   167
        if (window == mouse->focus) {
slouken@6666
   168
#ifdef DEBUG_MOUSE
jorgen@7089
   169
            printf("Mouse left window, synthesizing move & focus lost event\n");
slouken@6666
   170
#endif
jorgen@7089
   171
            SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@6666
   172
            SDL_SetMouseFocus(NULL);
slouken@6666
   173
        }
slouken@6666
   174
        return SDL_FALSE;
slouken@6666
   175
    }
slouken@6666
   176
slouken@6666
   177
    if (window != mouse->focus) {
slouken@6666
   178
#ifdef DEBUG_MOUSE
jorgen@7097
   179
         printf("Mouse entered window, synthesizing focus gain & move event\n");
slouken@6666
   180
#endif
jorgen@7097
   181
         SDL_SetMouseFocus(window);
jorgen@7097
   182
         SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@6666
   183
    }
slouken@6666
   184
    return SDL_TRUE;
slouken@1895
   185
}
slouken@1895
   186
slouken@1895
   187
int
slouken@6950
   188
SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
slouken@1895
   189
{
jorgen@7089
   190
    if (window && !relative) {
jorgen@7089
   191
        SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7089
   192
        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
jorgen@7089
   193
            return 0;
jorgen@7089
   194
        }
jorgen@7089
   195
    }
jorgen@7089
   196
jorgen@7089
   197
    return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
jorgen@7089
   198
}
jorgen@7089
   199
jorgen@7089
   200
static int
jorgen@7089
   201
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
jorgen@7089
   202
{
slouken@5371
   203
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   204
    int posted;
slouken@1895
   205
    int xrel;
slouken@1895
   206
    int yrel;
slouken@2860
   207
    int x_max = 0, y_max = 0;
slouken@1895
   208
slouken@8071
   209
    if (mouse->relative_mode_warp) {
slouken@8071
   210
        int center_x = 0, center_y = 0;
slouken@8071
   211
        SDL_GetWindowSize(window, &center_x, &center_y);
slouken@8071
   212
        center_x /= 2;
slouken@8071
   213
        center_y /= 2;
slouken@8071
   214
        if (x == center_x && y == center_y) {
slouken@8071
   215
            mouse->last_x = center_x;
slouken@8071
   216
            mouse->last_y = center_y;
slouken@8071
   217
            return 0;
slouken@8071
   218
        }
slouken@8071
   219
        SDL_WarpMouseInWindow(window, center_x, center_y);
slouken@8071
   220
    }
slouken@8071
   221
slouken@2842
   222
    if (relative) {
slouken@2842
   223
        xrel = x;
slouken@2842
   224
        yrel = y;
slouken@8071
   225
        x = (mouse->last_x + xrel);
slouken@8071
   226
        y = (mouse->last_y + yrel);
slouken@2842
   227
    } else {
slouken@2860
   228
        xrel = x - mouse->last_x;
slouken@2860
   229
        yrel = y - mouse->last_y;
slouken@2842
   230
    }
slouken@2710
   231
slouken@1895
   232
    /* Drop events that don't change state */
slouken@1895
   233
    if (!xrel && !yrel) {
slouken@6666
   234
#ifdef DEBUG_MOUSE
slouken@1895
   235
        printf("Mouse event didn't change state - dropped!\n");
slouken@1895
   236
#endif
slouken@1895
   237
        return 0;
slouken@1895
   238
    }
slouken@1895
   239
slouken@2710
   240
    /* Update internal mouse coordinates */
slouken@8071
   241
    if (!mouse->relative_mode) {
slouken@1895
   242
        mouse->x = x;
slouken@1895
   243
        mouse->y = y;
slouken@2710
   244
    } else {
slouken@2860
   245
        mouse->x += xrel;
slouken@2860
   246
        mouse->y += yrel;
slouken@2860
   247
    }
slouken@2849
   248
slouken@2860
   249
    SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
slouken@5370
   250
    --x_max;
slouken@5370
   251
    --y_max;
slouken@2849
   252
slouken@2860
   253
    /* make sure that the pointers find themselves inside the windows */
slouken@5370
   254
    if (mouse->x > x_max) {
slouken@2860
   255
        mouse->x = x_max;
slouken@5370
   256
    }
slouken@5370
   257
    if (mouse->x < 0) {
slouken@2860
   258
        mouse->x = 0;
slouken@1895
   259
    }
slouken@2860
   260
slouken@5370
   261
    if (mouse->y > y_max) {
slouken@2860
   262
        mouse->y = y_max;
slouken@5370
   263
    }
slouken@5370
   264
    if (mouse->y < 0) {
slouken@2860
   265
        mouse->y = 0;
slouken@2860
   266
    }
slouken@2860
   267
slouken@1895
   268
    mouse->xdelta += xrel;
slouken@1895
   269
    mouse->ydelta += yrel;
slouken@1895
   270
slouken@1895
   271
    /* Move the mouse cursor, if needed */
slouken@1895
   272
    if (mouse->cursor_shown && !mouse->relative_mode &&
slouken@1895
   273
        mouse->MoveCursor && mouse->cur_cursor) {
slouken@1895
   274
        mouse->MoveCursor(mouse->cur_cursor);
slouken@1895
   275
    }
slouken@1895
   276
slouken@1895
   277
    /* Post the event, if desired */
slouken@1895
   278
    posted = 0;
slouken@4465
   279
    if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
slouken@1895
   280
        SDL_Event event;
slouken@1895
   281
        event.motion.type = SDL_MOUSEMOTION;
slouken@4465
   282
        event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   283
        event.motion.which = mouseID;
slouken@1895
   284
        event.motion.state = mouse->buttonstate;
slouken@1895
   285
        event.motion.x = mouse->x;
slouken@1895
   286
        event.motion.y = mouse->y;
slouken@1895
   287
        event.motion.xrel = xrel;
slouken@1895
   288
        event.motion.yrel = yrel;
slouken@1895
   289
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   290
    }
slouken@6666
   291
    /* Use unclamped values if we're getting events outside the window */
slouken@6666
   292
    mouse->last_x = x;
slouken@6666
   293
    mouse->last_y = y;
slouken@1895
   294
    return posted;
slouken@1895
   295
}
slouken@1895
   296
slouken@8066
   297
static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
slouken@8066
   298
{
slouken@8066
   299
    if (button >= mouse->num_clickstates) {
slouken@8066
   300
        int i, count = button + 1;
slouken@8066
   301
        mouse->clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
slouken@8066
   302
        if (!mouse->clickstate) {
slouken@8066
   303
            return NULL;
slouken@8066
   304
        }
slouken@8066
   305
slouken@8066
   306
        for (i = mouse->num_clickstates; i < count; ++i) {
slouken@8066
   307
            SDL_zero(mouse->clickstate[i]);
slouken@8066
   308
        }
slouken@8066
   309
        mouse->num_clickstates = count;
slouken@8066
   310
    }
slouken@8066
   311
    return &mouse->clickstate[button];
slouken@8066
   312
}
slouken@8066
   313
slouken@1895
   314
int
slouken@6950
   315
SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
slouken@1895
   316
{
slouken@5371
   317
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   318
    int posted;
slouken@4429
   319
    Uint32 type;
slouken@6673
   320
    Uint32 buttonstate = mouse->buttonstate;
slouken@8066
   321
    SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
slouken@8066
   322
    Uint8 click_count;
slouken@4484
   323
slouken@1895
   324
    /* Figure out which event to perform */
slouken@1895
   325
    switch (state) {
slouken@1895
   326
    case SDL_PRESSED:
slouken@1895
   327
        type = SDL_MOUSEBUTTONDOWN;
slouken@6666
   328
        buttonstate |= SDL_BUTTON(button);
slouken@1895
   329
        break;
slouken@1895
   330
    case SDL_RELEASED:
slouken@1895
   331
        type = SDL_MOUSEBUTTONUP;
slouken@6666
   332
        buttonstate &= ~SDL_BUTTON(button);
slouken@1895
   333
        break;
slouken@1895
   334
    default:
slouken@1895
   335
        /* Invalid state -- bail */
slouken@1895
   336
        return 0;
slouken@1895
   337
    }
slouken@1895
   338
slouken@6666
   339
    /* We do this after calculating buttonstate so button presses gain focus */
slouken@6666
   340
    if (window && state == SDL_PRESSED) {
slouken@6666
   341
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   342
    }
slouken@6666
   343
slouken@6666
   344
    if (buttonstate == mouse->buttonstate) {
slouken@6666
   345
        /* Ignore this event, no state change */
slouken@6666
   346
        return 0;
slouken@6666
   347
    }
slouken@6666
   348
    mouse->buttonstate = buttonstate;
slouken@6666
   349
slouken@8066
   350
    if (clickstate) {
slouken@8066
   351
        if (state == SDL_PRESSED) {
slouken@8066
   352
            Uint32 now = SDL_GetTicks();
slouken@8066
   353
slouken@8066
   354
            if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) ||
slouken@8066
   355
                SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius ||
slouken@8066
   356
                SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) {
slouken@8066
   357
                clickstate->click_count = 0;
slouken@8066
   358
            }
slouken@8066
   359
            clickstate->last_timestamp = now;
slouken@8066
   360
            clickstate->last_x = mouse->x;
slouken@8066
   361
            clickstate->last_y = mouse->y;
slouken@8066
   362
            if (clickstate->click_count < 255) {
slouken@8066
   363
                ++clickstate->click_count;
slouken@8066
   364
            }
slouken@8066
   365
        }
slouken@8066
   366
        click_count = clickstate->click_count;
slouken@8066
   367
    } else {
slouken@8066
   368
        click_count = 1;
slouken@8066
   369
    }
slouken@8066
   370
slouken@1895
   371
    /* Post the event, if desired */
slouken@1895
   372
    posted = 0;
slouken@4429
   373
    if (SDL_GetEventState(type) == SDL_ENABLE) {
slouken@1895
   374
        SDL_Event event;
slouken@1895
   375
        event.type = type;
slouken@6950
   376
        event.button.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   377
        event.button.which = mouseID;
slouken@1895
   378
        event.button.state = state;
slouken@1895
   379
        event.button.button = button;
slouken@8066
   380
        event.button.clicks = click_count;
slouken@1895
   381
        event.button.x = mouse->x;
slouken@1895
   382
        event.button.y = mouse->y;
slouken@1895
   383
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   384
    }
slouken@6666
   385
slouken@6666
   386
    /* We do this after dispatching event so button releases can lose focus */
slouken@6666
   387
    if (window && state == SDL_RELEASED) {
slouken@6666
   388
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
slouken@6666
   389
    }
slouken@6666
   390
slouken@1895
   391
    return posted;
slouken@1895
   392
}
slouken@1895
   393
slouken@1895
   394
int
slouken@6950
   395
SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y)
slouken@1895
   396
{
slouken@5371
   397
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   398
    int posted;
slouken@1895
   399
slouken@4484
   400
    if (window) {
slouken@4484
   401
        SDL_SetMouseFocus(window);
slouken@4484
   402
    }
slouken@4484
   403
slouken@4465
   404
    if (!x && !y) {
slouken@1895
   405
        return 0;
slouken@1895
   406
    }
slouken@1895
   407
slouken@1895
   408
    /* Post the event, if desired */
slouken@1895
   409
    posted = 0;
slouken@4429
   410
    if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
slouken@1895
   411
        SDL_Event event;
slouken@1895
   412
        event.type = SDL_MOUSEWHEEL;
slouken@4465
   413
        event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   414
        event.wheel.which = mouseID;
slouken@2152
   415
        event.wheel.x = x;
slouken@2152
   416
        event.wheel.y = y;
slouken@1895
   417
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   418
    }
slouken@1895
   419
    return posted;
slouken@1895
   420
}
slouken@1895
   421
slouken@1895
   422
void
slouken@4465
   423
SDL_MouseQuit(void)
slouken@4465
   424
{
slouken@7493
   425
    SDL_Cursor *cursor, *next;
slouken@7493
   426
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@7493
   427
slouken@8049
   428
    SDL_SetRelativeMouseMode(SDL_FALSE);
slouken@7493
   429
    SDL_ShowCursor(1);
slouken@7493
   430
slouken@7493
   431
    cursor = mouse->cursors;
slouken@7493
   432
    while (cursor) {
slouken@7493
   433
        next = cursor->next;
slouken@7493
   434
        SDL_FreeCursor(cursor);
slouken@7493
   435
        cursor = next;
slouken@7493
   436
    }
slouken@7493
   437
slouken@7493
   438
    if (mouse->def_cursor && mouse->FreeCursor) {
slouken@7493
   439
        mouse->FreeCursor(mouse->def_cursor);
slouken@7493
   440
    }
slouken@7493
   441
slouken@8066
   442
    if (mouse->clickstate) {
slouken@8066
   443
        SDL_free(mouse->clickstate);
slouken@8066
   444
    }
slouken@8066
   445
slouken@7493
   446
    SDL_zerop(mouse);
slouken@4465
   447
}
slouken@4465
   448
slouken@6673
   449
Uint32
slouken@4465
   450
SDL_GetMouseState(int *x, int *y)
slouken@4465
   451
{
slouken@5371
   452
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   453
slouken@4465
   454
    if (x) {
slouken@4465
   455
        *x = mouse->x;
slouken@4465
   456
    }
slouken@4465
   457
    if (y) {
slouken@4465
   458
        *y = mouse->y;
slouken@4465
   459
    }
slouken@4465
   460
    return mouse->buttonstate;
slouken@4465
   461
}
slouken@4465
   462
slouken@6673
   463
Uint32
slouken@4465
   464
SDL_GetRelativeMouseState(int *x, int *y)
slouken@4465
   465
{
slouken@5371
   466
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   467
slouken@4465
   468
    if (x) {
slouken@4465
   469
        *x = mouse->xdelta;
slouken@4465
   470
    }
slouken@4465
   471
    if (y) {
slouken@4465
   472
        *y = mouse->ydelta;
slouken@4465
   473
    }
slouken@4465
   474
    mouse->xdelta = 0;
slouken@4465
   475
    mouse->ydelta = 0;
slouken@4465
   476
    return mouse->buttonstate;
slouken@4465
   477
}
slouken@4465
   478
slouken@4465
   479
void
slouken@3685
   480
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
slouken@1895
   481
{
slouken@5371
   482
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@7191
   483
slouken@7191
   484
    if ( window == NULL )
slouken@7191
   485
        window = mouse->focus;
slouken@7191
   486
slouken@7191
   487
    if ( window == NULL )
slouken@7191
   488
        return;
slouken@1895
   489
slouken@1895
   490
    if (mouse->WarpMouse) {
slouken@5371
   491
        mouse->WarpMouse(window, x, y);
slouken@1895
   492
    } else {
slouken@6950
   493
        SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@1895
   494
    }
slouken@1895
   495
}
slouken@1895
   496
slouken@8071
   497
static SDL_bool
slouken@8071
   498
ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
slouken@8071
   499
{
slouken@8071
   500
    const char *hint;
slouken@8071
   501
slouken@8071
   502
    if (!mouse->SetRelativeMouseMode) {
slouken@8071
   503
        return SDL_TRUE;
slouken@8071
   504
    }
slouken@8071
   505
slouken@8071
   506
    hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
slouken@8071
   507
    if (hint) {
slouken@8071
   508
        if (*hint == '0') {
slouken@8071
   509
            return SDL_FALSE;
slouken@8071
   510
        } else {
slouken@8071
   511
            return SDL_TRUE;
slouken@8071
   512
        }
slouken@8071
   513
    }
slouken@8071
   514
    return SDL_FALSE;
slouken@8071
   515
}
slouken@8071
   516
slouken@4465
   517
int
slouken@4465
   518
SDL_SetRelativeMouseMode(SDL_bool enabled)
slouken@4465
   519
{
slouken@5371
   520
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7107
   521
    SDL_Window *focusWindow = SDL_GetKeyboardFocus();
slouken@4465
   522
slouken@5406
   523
    if (enabled == mouse->relative_mode) {
slouken@5406
   524
        return 0;
slouken@5406
   525
    }
slouken@5406
   526
jorgen@7107
   527
    if (enabled && focusWindow) {
jorgen@7107
   528
        /* Center it in the focused window to prevent clicks from going through
jorgen@7107
   529
         * to background windows.
jorgen@7107
   530
         */
jorgen@7107
   531
        SDL_SetMouseFocus(focusWindow);
jorgen@7107
   532
        SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
jorgen@7107
   533
    }
jorgen@7107
   534
slouken@8071
   535
    /* Set the relative mode */
slouken@8071
   536
    if (!enabled && mouse->relative_mode_warp) {
slouken@8071
   537
        mouse->relative_mode_warp = SDL_FALSE;
slouken@8071
   538
    } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
slouken@8071
   539
        mouse->relative_mode_warp = SDL_TRUE;
slouken@8071
   540
    } else if (mouse->SetRelativeMouseMode(enabled) < 0) {
slouken@8269
   541
        if (enabled) {
slouken@8269
   542
            // Fall back to warp mode if native relative mode failed
slouken@8269
   543
            mouse->relative_mode_warp = SDL_TRUE;
slouken@8269
   544
        }
slouken@5406
   545
    }
slouken@4465
   546
    mouse->relative_mode = enabled;
slouken@4465
   547
slouken@8071
   548
    if (mouse->focus) {
slouken@8071
   549
        SDL_UpdateWindowGrab(mouse->focus);
slouken@8071
   550
slouken@8071
   551
        /* Put the cursor back to where the application expects it */
slouken@8071
   552
        if (!enabled) {
slouken@8071
   553
            SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
slouken@8071
   554
        }
slouken@4465
   555
    }
slouken@4465
   556
slouken@8071
   557
    /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
slouken@5406
   558
    SDL_FlushEvent(SDL_MOUSEMOTION);
slouken@5406
   559
slouken@4465
   560
    /* Update cursor visibility */
slouken@4465
   561
    SDL_SetCursor(NULL);
slouken@4465
   562
slouken@4465
   563
    return 0;
slouken@4465
   564
}
slouken@4465
   565
slouken@4465
   566
SDL_bool
slouken@4465
   567
SDL_GetRelativeMouseMode()
slouken@4465
   568
{
slouken@5371
   569
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   570
slouken@4465
   571
    return mouse->relative_mode;
slouken@4465
   572
}
slouken@4465
   573
slouken@1895
   574
SDL_Cursor *
slouken@1895
   575
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
slouken@1895
   576
                 int w, int h, int hot_x, int hot_y)
slouken@1895
   577
{
slouken@1895
   578
    SDL_Surface *surface;
slouken@1895
   579
    SDL_Cursor *cursor;
slouken@1895
   580
    int x, y;
slouken@1895
   581
    Uint32 *pixel;
slouken@4465
   582
    Uint8 datab = 0, maskb = 0;
slouken@1895
   583
    const Uint32 black = 0xFF000000;
slouken@1895
   584
    const Uint32 white = 0xFFFFFFFF;
slouken@1895
   585
    const Uint32 transparent = 0x00000000;
slouken@1895
   586
slouken@1895
   587
    /* Make sure the width is a multiple of 8 */
slouken@1895
   588
    w = ((w + 7) & ~7);
slouken@1895
   589
slouken@1895
   590
    /* Create the surface from a bitmap */
slouken@5473
   591
    surface = SDL_CreateRGBSurface(0, w, h, 32,
slouken@5473
   592
                                   0x00FF0000,
slouken@5473
   593
                                   0x0000FF00,
slouken@5473
   594
                                   0x000000FF,
slouken@5473
   595
                                   0xFF000000);
slouken@1895
   596
    if (!surface) {
slouken@1895
   597
        return NULL;
slouken@1895
   598
    }
slouken@1895
   599
    for (y = 0; y < h; ++y) {
slouken@1895
   600
        pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
slouken@1895
   601
        for (x = 0; x < w; ++x) {
slouken@1895
   602
            if ((x % 8) == 0) {
slouken@1895
   603
                datab = *data++;
slouken@1895
   604
                maskb = *mask++;
slouken@1895
   605
            }
slouken@1895
   606
            if (maskb & 0x80) {
slouken@1895
   607
                *pixel++ = (datab & 0x80) ? black : white;
slouken@1895
   608
            } else {
slouken@1895
   609
                *pixel++ = (datab & 0x80) ? black : transparent;
slouken@1895
   610
            }
slouken@1895
   611
            datab <<= 1;
slouken@1895
   612
            maskb <<= 1;
slouken@1895
   613
        }
slouken@1895
   614
    }
slouken@1895
   615
slouken@5473
   616
    cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
slouken@5473
   617
slouken@5473
   618
    SDL_FreeSurface(surface);
slouken@5473
   619
slouken@5473
   620
    return cursor;
slouken@5473
   621
}
slouken@5473
   622
slouken@5473
   623
SDL_Cursor *
slouken@5473
   624
SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
slouken@5473
   625
{
slouken@5473
   626
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5473
   627
    SDL_Surface *temp = NULL;
slouken@5473
   628
    SDL_Cursor *cursor;
slouken@5473
   629
slouken@5473
   630
    if (!surface) {
slouken@5473
   631
        SDL_SetError("Passed NULL cursor surface");
slouken@5473
   632
        return NULL;
slouken@5473
   633
    }
slouken@5473
   634
slouken@5473
   635
    if (!mouse->CreateCursor) {
slouken@5473
   636
        SDL_SetError("Cursors are not currently supported");
slouken@5473
   637
        return NULL;
slouken@5473
   638
    }
slouken@5473
   639
slouken@5473
   640
    /* Sanity check the hot spot */
slouken@5473
   641
    if ((hot_x < 0) || (hot_y < 0) ||
slouken@5473
   642
        (hot_x >= surface->w) || (hot_y >= surface->h)) {
slouken@5473
   643
        SDL_SetError("Cursor hot spot doesn't lie within cursor");
slouken@5473
   644
        return NULL;
slouken@5473
   645
    }
slouken@5473
   646
slouken@5473
   647
    if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
slouken@5473
   648
        temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
slouken@5473
   649
        if (!temp) {
slouken@5473
   650
            return NULL;
slouken@5473
   651
        }
slouken@5473
   652
        surface = temp;
slouken@5473
   653
    }
slouken@5473
   654
slouken@1895
   655
    cursor = mouse->CreateCursor(surface, hot_x, hot_y);
slouken@1895
   656
    if (cursor) {
slouken@1895
   657
        cursor->next = mouse->cursors;
slouken@1895
   658
        mouse->cursors = cursor;
slouken@1895
   659
    }
slouken@1895
   660
slouken@7720
   661
    SDL_FreeSurface(temp);
slouken@1895
   662
slouken@1895
   663
    return cursor;
slouken@1895
   664
}
slouken@1895
   665
mikesart@6675
   666
SDL_Cursor *
mikesart@6675
   667
SDL_CreateSystemCursor(SDL_SystemCursor id)
mikesart@6675
   668
{
mikesart@6675
   669
    SDL_Mouse *mouse = SDL_GetMouse();
mikesart@6675
   670
    SDL_Cursor *cursor;
mikesart@6675
   671
mikesart@6675
   672
    if (!mouse->CreateSystemCursor) {
mikesart@6675
   673
        SDL_SetError("CreateSystemCursor is not currently supported");
mikesart@6675
   674
        return NULL;
mikesart@6675
   675
    }
mikesart@6675
   676
slouken@7191
   677
    cursor = mouse->CreateSystemCursor(id);
mikesart@6675
   678
    if (cursor) {
mikesart@6675
   679
        cursor->next = mouse->cursors;
mikesart@6675
   680
        mouse->cursors = cursor;
mikesart@6675
   681
    }
mikesart@6675
   682
slouken@7191
   683
    return cursor;
mikesart@6675
   684
}
mikesart@6675
   685
slouken@1895
   686
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
slouken@1895
   687
   if this is desired for any reason.  This is used when setting
slouken@1895
   688
   the video mode and when the SDL window gains the mouse focus.
slouken@1895
   689
 */
slouken@1895
   690
void
slouken@1895
   691
SDL_SetCursor(SDL_Cursor * cursor)
slouken@1895
   692
{
slouken@5371
   693
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   694
slouken@1895
   695
    /* Set the new cursor */
slouken@1895
   696
    if (cursor) {
slouken@1895
   697
        /* Make sure the cursor is still valid for this mouse */
slouken@5405
   698
        if (cursor != mouse->def_cursor) {
slouken@5405
   699
            SDL_Cursor *found;
slouken@5405
   700
            for (found = mouse->cursors; found; found = found->next) {
slouken@5405
   701
                if (found == cursor) {
slouken@5405
   702
                    break;
slouken@5405
   703
                }
slouken@1895
   704
            }
slouken@5405
   705
            if (!found) {
slouken@5405
   706
                SDL_SetError("Cursor not associated with the current mouse");
slouken@5405
   707
                return;
slouken@5405
   708
            }
slouken@1895
   709
        }
slouken@1895
   710
        mouse->cur_cursor = cursor;
slouken@1895
   711
    } else {
ghostunderscore@6301
   712
        if (mouse->focus) {
ghostunderscore@6301
   713
            cursor = mouse->cur_cursor;
ghostunderscore@6301
   714
        } else {
ghostunderscore@6301
   715
            cursor = mouse->def_cursor;
ghostunderscore@6301
   716
        }
slouken@1895
   717
    }
slouken@1895
   718
slouken@1895
   719
    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
slouken@1895
   720
        if (mouse->ShowCursor) {
slouken@1895
   721
            mouse->ShowCursor(cursor);
slouken@1895
   722
        }
slouken@1895
   723
    } else {
slouken@1895
   724
        if (mouse->ShowCursor) {
slouken@1895
   725
            mouse->ShowCursor(NULL);
slouken@1895
   726
        }
slouken@1895
   727
    }
slouken@1895
   728
}
slouken@1895
   729
slouken@1895
   730
SDL_Cursor *
slouken@1895
   731
SDL_GetCursor(void)
slouken@1895
   732
{
slouken@5371
   733
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   734
slouken@1895
   735
    if (!mouse) {
slouken@1895
   736
        return NULL;
slouken@1895
   737
    }
slouken@1895
   738
    return mouse->cur_cursor;
slouken@1895
   739
}
slouken@1895
   740
jorgen@7104
   741
SDL_Cursor *
jorgen@7104
   742
SDL_GetDefaultCursor(void)
jorgen@7104
   743
{
jorgen@7104
   744
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7104
   745
jorgen@7104
   746
    if (!mouse) {
jorgen@7104
   747
        return NULL;
jorgen@7104
   748
    }
jorgen@7104
   749
    return mouse->def_cursor;
jorgen@7104
   750
}
jorgen@7104
   751
slouken@1895
   752
void
slouken@1895
   753
SDL_FreeCursor(SDL_Cursor * cursor)
slouken@1895
   754
{
slouken@5371
   755
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   756
    SDL_Cursor *curr, *prev;
slouken@1895
   757
slouken@1895
   758
    if (!cursor) {
slouken@1895
   759
        return;
slouken@1895
   760
    }
slouken@1895
   761
slouken@1895
   762
    if (cursor == mouse->def_cursor) {
slouken@1895
   763
        return;
slouken@1895
   764
    }
slouken@1895
   765
    if (cursor == mouse->cur_cursor) {
slouken@1895
   766
        SDL_SetCursor(mouse->def_cursor);
slouken@1895
   767
    }
slouken@1895
   768
slouken@1895
   769
    for (prev = NULL, curr = mouse->cursors; curr;
slouken@1895
   770
         prev = curr, curr = curr->next) {
slouken@1895
   771
        if (curr == cursor) {
slouken@1895
   772
            if (prev) {
slouken@1895
   773
                prev->next = curr->next;
slouken@1895
   774
            } else {
slouken@1895
   775
                mouse->cursors = curr->next;
slouken@1895
   776
            }
slouken@1895
   777
slouken@1895
   778
            if (mouse->FreeCursor) {
slouken@1895
   779
                mouse->FreeCursor(curr);
slouken@1895
   780
            }
slouken@1895
   781
            return;
slouken@1895
   782
        }
slouken@1895
   783
    }
slouken@1895
   784
}
slouken@1895
   785
slouken@1895
   786
int
slouken@1895
   787
SDL_ShowCursor(int toggle)
slouken@1895
   788
{
slouken@5371
   789
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   790
    SDL_bool shown;
slouken@1895
   791
slouken@1895
   792
    if (!mouse) {
slouken@1895
   793
        return 0;
slouken@1895
   794
    }
slouken@1895
   795
slouken@1895
   796
    shown = mouse->cursor_shown;
slouken@1895
   797
    if (toggle >= 0) {
slouken@1895
   798
        if (toggle) {
slouken@1895
   799
            mouse->cursor_shown = SDL_TRUE;
slouken@1895
   800
        } else {
slouken@1895
   801
            mouse->cursor_shown = SDL_FALSE;
slouken@1895
   802
        }
slouken@1895
   803
        if (mouse->cursor_shown != shown) {
slouken@1895
   804
            SDL_SetCursor(NULL);
slouken@1895
   805
        }
slouken@1895
   806
    }
slouken@1895
   807
    return shown;
slouken@1895
   808
}
slouken@1895
   809
jorgen@7097
   810
/* vi: set ts=4 sw=4 expandtab: */