src/events/SDL_mouse.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 23 Dec 2013 17:37:22 -0800
changeset 8071 1ac2db4abe11
parent 8066 658b461d81be
child 8093 b43765095a6f
permissions -rw-r--r--
Added a relative mouse mode that uses mouse warping instead of raw input.
To enable this, set the environment variable SDL_MOUSE_RELATIVE_MODE_WARP to "1"

When mouse relative mode is disabled, put the cursor back where the application expects it to be, instead of where it was when relative mode was enabled.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 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
*/
slouken@1402
    21
#include "SDL_config.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@5406
   541
        return -1;
slouken@5406
   542
    }
slouken@4465
   543
    mouse->relative_mode = enabled;
slouken@4465
   544
slouken@8071
   545
    if (mouse->focus) {
slouken@8071
   546
        SDL_UpdateWindowGrab(mouse->focus);
slouken@8071
   547
slouken@8071
   548
        /* Put the cursor back to where the application expects it */
slouken@8071
   549
        if (!enabled) {
slouken@8071
   550
            SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
slouken@8071
   551
        }
slouken@4465
   552
    }
slouken@4465
   553
slouken@8071
   554
    /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
slouken@5406
   555
    SDL_FlushEvent(SDL_MOUSEMOTION);
slouken@5406
   556
slouken@4465
   557
    /* Update cursor visibility */
slouken@4465
   558
    SDL_SetCursor(NULL);
slouken@4465
   559
slouken@4465
   560
    return 0;
slouken@4465
   561
}
slouken@4465
   562
slouken@4465
   563
SDL_bool
slouken@4465
   564
SDL_GetRelativeMouseMode()
slouken@4465
   565
{
slouken@5371
   566
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   567
slouken@4465
   568
    return mouse->relative_mode;
slouken@4465
   569
}
slouken@4465
   570
slouken@1895
   571
SDL_Cursor *
slouken@1895
   572
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
slouken@1895
   573
                 int w, int h, int hot_x, int hot_y)
slouken@1895
   574
{
slouken@1895
   575
    SDL_Surface *surface;
slouken@1895
   576
    SDL_Cursor *cursor;
slouken@1895
   577
    int x, y;
slouken@1895
   578
    Uint32 *pixel;
slouken@4465
   579
    Uint8 datab = 0, maskb = 0;
slouken@1895
   580
    const Uint32 black = 0xFF000000;
slouken@1895
   581
    const Uint32 white = 0xFFFFFFFF;
slouken@1895
   582
    const Uint32 transparent = 0x00000000;
slouken@1895
   583
slouken@1895
   584
    /* Make sure the width is a multiple of 8 */
slouken@1895
   585
    w = ((w + 7) & ~7);
slouken@1895
   586
slouken@1895
   587
    /* Create the surface from a bitmap */
slouken@5473
   588
    surface = SDL_CreateRGBSurface(0, w, h, 32,
slouken@5473
   589
                                   0x00FF0000,
slouken@5473
   590
                                   0x0000FF00,
slouken@5473
   591
                                   0x000000FF,
slouken@5473
   592
                                   0xFF000000);
slouken@1895
   593
    if (!surface) {
slouken@1895
   594
        return NULL;
slouken@1895
   595
    }
slouken@1895
   596
    for (y = 0; y < h; ++y) {
slouken@1895
   597
        pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
slouken@1895
   598
        for (x = 0; x < w; ++x) {
slouken@1895
   599
            if ((x % 8) == 0) {
slouken@1895
   600
                datab = *data++;
slouken@1895
   601
                maskb = *mask++;
slouken@1895
   602
            }
slouken@1895
   603
            if (maskb & 0x80) {
slouken@1895
   604
                *pixel++ = (datab & 0x80) ? black : white;
slouken@1895
   605
            } else {
slouken@1895
   606
                *pixel++ = (datab & 0x80) ? black : transparent;
slouken@1895
   607
            }
slouken@1895
   608
            datab <<= 1;
slouken@1895
   609
            maskb <<= 1;
slouken@1895
   610
        }
slouken@1895
   611
    }
slouken@1895
   612
slouken@5473
   613
    cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
slouken@5473
   614
slouken@5473
   615
    SDL_FreeSurface(surface);
slouken@5473
   616
slouken@5473
   617
    return cursor;
slouken@5473
   618
}
slouken@5473
   619
slouken@5473
   620
SDL_Cursor *
slouken@5473
   621
SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
slouken@5473
   622
{
slouken@5473
   623
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5473
   624
    SDL_Surface *temp = NULL;
slouken@5473
   625
    SDL_Cursor *cursor;
slouken@5473
   626
slouken@5473
   627
    if (!surface) {
slouken@5473
   628
        SDL_SetError("Passed NULL cursor surface");
slouken@5473
   629
        return NULL;
slouken@5473
   630
    }
slouken@5473
   631
slouken@5473
   632
    if (!mouse->CreateCursor) {
slouken@5473
   633
        SDL_SetError("Cursors are not currently supported");
slouken@5473
   634
        return NULL;
slouken@5473
   635
    }
slouken@5473
   636
slouken@5473
   637
    /* Sanity check the hot spot */
slouken@5473
   638
    if ((hot_x < 0) || (hot_y < 0) ||
slouken@5473
   639
        (hot_x >= surface->w) || (hot_y >= surface->h)) {
slouken@5473
   640
        SDL_SetError("Cursor hot spot doesn't lie within cursor");
slouken@5473
   641
        return NULL;
slouken@5473
   642
    }
slouken@5473
   643
slouken@5473
   644
    if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
slouken@5473
   645
        temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
slouken@5473
   646
        if (!temp) {
slouken@5473
   647
            return NULL;
slouken@5473
   648
        }
slouken@5473
   649
        surface = temp;
slouken@5473
   650
    }
slouken@5473
   651
slouken@1895
   652
    cursor = mouse->CreateCursor(surface, hot_x, hot_y);
slouken@1895
   653
    if (cursor) {
slouken@1895
   654
        cursor->next = mouse->cursors;
slouken@1895
   655
        mouse->cursors = cursor;
slouken@1895
   656
    }
slouken@1895
   657
slouken@7720
   658
    SDL_FreeSurface(temp);
slouken@1895
   659
slouken@1895
   660
    return cursor;
slouken@1895
   661
}
slouken@1895
   662
mikesart@6675
   663
SDL_Cursor *
mikesart@6675
   664
SDL_CreateSystemCursor(SDL_SystemCursor id)
mikesart@6675
   665
{
mikesart@6675
   666
    SDL_Mouse *mouse = SDL_GetMouse();
mikesart@6675
   667
    SDL_Cursor *cursor;
mikesart@6675
   668
mikesart@6675
   669
    if (!mouse->CreateSystemCursor) {
mikesart@6675
   670
        SDL_SetError("CreateSystemCursor is not currently supported");
mikesart@6675
   671
        return NULL;
mikesart@6675
   672
    }
mikesart@6675
   673
slouken@7191
   674
    cursor = mouse->CreateSystemCursor(id);
mikesart@6675
   675
    if (cursor) {
mikesart@6675
   676
        cursor->next = mouse->cursors;
mikesart@6675
   677
        mouse->cursors = cursor;
mikesart@6675
   678
    }
mikesart@6675
   679
slouken@7191
   680
    return cursor;
mikesart@6675
   681
}
mikesart@6675
   682
slouken@1895
   683
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
slouken@1895
   684
   if this is desired for any reason.  This is used when setting
slouken@1895
   685
   the video mode and when the SDL window gains the mouse focus.
slouken@1895
   686
 */
slouken@1895
   687
void
slouken@1895
   688
SDL_SetCursor(SDL_Cursor * cursor)
slouken@1895
   689
{
slouken@5371
   690
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   691
slouken@1895
   692
    /* Set the new cursor */
slouken@1895
   693
    if (cursor) {
slouken@1895
   694
        /* Make sure the cursor is still valid for this mouse */
slouken@5405
   695
        if (cursor != mouse->def_cursor) {
slouken@5405
   696
            SDL_Cursor *found;
slouken@5405
   697
            for (found = mouse->cursors; found; found = found->next) {
slouken@5405
   698
                if (found == cursor) {
slouken@5405
   699
                    break;
slouken@5405
   700
                }
slouken@1895
   701
            }
slouken@5405
   702
            if (!found) {
slouken@5405
   703
                SDL_SetError("Cursor not associated with the current mouse");
slouken@5405
   704
                return;
slouken@5405
   705
            }
slouken@1895
   706
        }
slouken@1895
   707
        mouse->cur_cursor = cursor;
slouken@1895
   708
    } else {
ghostunderscore@6301
   709
        if (mouse->focus) {
ghostunderscore@6301
   710
            cursor = mouse->cur_cursor;
ghostunderscore@6301
   711
        } else {
ghostunderscore@6301
   712
            cursor = mouse->def_cursor;
ghostunderscore@6301
   713
        }
slouken@1895
   714
    }
slouken@1895
   715
slouken@1895
   716
    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
slouken@1895
   717
        if (mouse->ShowCursor) {
slouken@1895
   718
            mouse->ShowCursor(cursor);
slouken@1895
   719
        }
slouken@1895
   720
    } else {
slouken@1895
   721
        if (mouse->ShowCursor) {
slouken@1895
   722
            mouse->ShowCursor(NULL);
slouken@1895
   723
        }
slouken@1895
   724
    }
slouken@1895
   725
}
slouken@1895
   726
slouken@1895
   727
SDL_Cursor *
slouken@1895
   728
SDL_GetCursor(void)
slouken@1895
   729
{
slouken@5371
   730
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   731
slouken@1895
   732
    if (!mouse) {
slouken@1895
   733
        return NULL;
slouken@1895
   734
    }
slouken@1895
   735
    return mouse->cur_cursor;
slouken@1895
   736
}
slouken@1895
   737
jorgen@7104
   738
SDL_Cursor *
jorgen@7104
   739
SDL_GetDefaultCursor(void)
jorgen@7104
   740
{
jorgen@7104
   741
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7104
   742
jorgen@7104
   743
    if (!mouse) {
jorgen@7104
   744
        return NULL;
jorgen@7104
   745
    }
jorgen@7104
   746
    return mouse->def_cursor;
jorgen@7104
   747
}
jorgen@7104
   748
slouken@1895
   749
void
slouken@1895
   750
SDL_FreeCursor(SDL_Cursor * cursor)
slouken@1895
   751
{
slouken@5371
   752
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   753
    SDL_Cursor *curr, *prev;
slouken@1895
   754
slouken@1895
   755
    if (!cursor) {
slouken@1895
   756
        return;
slouken@1895
   757
    }
slouken@1895
   758
slouken@1895
   759
    if (cursor == mouse->def_cursor) {
slouken@1895
   760
        return;
slouken@1895
   761
    }
slouken@1895
   762
    if (cursor == mouse->cur_cursor) {
slouken@1895
   763
        SDL_SetCursor(mouse->def_cursor);
slouken@1895
   764
    }
slouken@1895
   765
slouken@1895
   766
    for (prev = NULL, curr = mouse->cursors; curr;
slouken@1895
   767
         prev = curr, curr = curr->next) {
slouken@1895
   768
        if (curr == cursor) {
slouken@1895
   769
            if (prev) {
slouken@1895
   770
                prev->next = curr->next;
slouken@1895
   771
            } else {
slouken@1895
   772
                mouse->cursors = curr->next;
slouken@1895
   773
            }
slouken@1895
   774
slouken@1895
   775
            if (mouse->FreeCursor) {
slouken@1895
   776
                mouse->FreeCursor(curr);
slouken@1895
   777
            }
slouken@1895
   778
            return;
slouken@1895
   779
        }
slouken@1895
   780
    }
slouken@1895
   781
}
slouken@1895
   782
slouken@1895
   783
int
slouken@1895
   784
SDL_ShowCursor(int toggle)
slouken@1895
   785
{
slouken@5371
   786
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   787
    SDL_bool shown;
slouken@1895
   788
slouken@1895
   789
    if (!mouse) {
slouken@1895
   790
        return 0;
slouken@1895
   791
    }
slouken@1895
   792
slouken@1895
   793
    shown = mouse->cursor_shown;
slouken@1895
   794
    if (toggle >= 0) {
slouken@1895
   795
        if (toggle) {
slouken@1895
   796
            mouse->cursor_shown = SDL_TRUE;
slouken@1895
   797
        } else {
slouken@1895
   798
            mouse->cursor_shown = SDL_FALSE;
slouken@1895
   799
        }
slouken@1895
   800
        if (mouse->cursor_shown != shown) {
slouken@1895
   801
            SDL_SetCursor(NULL);
slouken@1895
   802
        }
slouken@1895
   803
    }
slouken@1895
   804
    return shown;
slouken@1895
   805
}
slouken@1895
   806
jorgen@7097
   807
/* vi: set ts=4 sw=4 expandtab: */