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