src/events/SDL_mouse.c
author Ethan Lee <flibitijibibo@flibitijibibo.com>
Wed, 17 Jul 2019 23:20:57 -0400
changeset 12950 05dddfb66b85
parent 12943 49190e92b7d1
child 12979 bbbb30026158
permissions -rw-r--r--
Copypaste SDL_NSLog to UIKit backend, document it as such
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@12503
     3
  Copyright (C) 1997-2019 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@3685
    30
#include "../video/SDL_sysvideo.h"
slouken@12651
    31
#ifdef __WIN32__
slouken@12651
    32
#include "../core/windows/SDL_windows.h"    // For GetDoubleClickTime()
slouken@12651
    33
#endif
slouken@0
    34
gabomdq@7678
    35
/* #define DEBUG_MOUSE */
slouken@0
    36
slouken@5371
    37
/* The mouse state */
slouken@4465
    38
static SDL_Mouse SDL_mouse;
slouken@0
    39
sylvain@12688
    40
/* for mapping mouse events to touch */
sylvain@12688
    41
static SDL_bool track_mouse_down = SDL_FALSE;
sylvain@12688
    42
jorgen@7089
    43
static int
jorgen@7089
    44
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);
slouken@0
    45
slouken@11284
    46
static void SDLCALL
slouken@12188
    47
SDL_MouseDoubleClickTimeChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@12188
    48
{
slouken@12188
    49
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@12188
    50
slouken@12188
    51
    if (hint && *hint) {
slouken@12188
    52
        mouse->double_click_time = SDL_atoi(hint);
slouken@12188
    53
    } else {
slouken@12188
    54
#ifdef __WIN32__
slouken@12188
    55
        mouse->double_click_time = GetDoubleClickTime();
slouken@12188
    56
#else
slouken@12188
    57
        mouse->double_click_time = 500;
slouken@12188
    58
#endif
slouken@12188
    59
    }
slouken@12188
    60
}
slouken@12188
    61
slouken@12188
    62
static void SDLCALL
slouken@12188
    63
SDL_MouseDoubleClickRadiusChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@12188
    64
{
slouken@12188
    65
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@12188
    66
slouken@12188
    67
    if (hint && *hint) {
slouken@12188
    68
        mouse->double_click_radius = SDL_atoi(hint);
slouken@12188
    69
    } else {
slouken@12188
    70
        mouse->double_click_radius = 32;    /* 32 pixels seems about right for touch interfaces */
slouken@12188
    71
    }
slouken@12188
    72
}
slouken@12188
    73
slouken@12188
    74
static void SDLCALL
slouken@10673
    75
SDL_MouseNormalSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@10673
    76
{
slouken@10673
    77
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@10673
    78
slouken@10676
    79
    if (hint && *hint) {
slouken@10676
    80
        mouse->normal_speed_scale = (float)SDL_atof(hint);
slouken@10676
    81
    } else {
slouken@10676
    82
        mouse->normal_speed_scale = 1.0f;
slouken@10676
    83
    }
slouken@10673
    84
}
slouken@10673
    85
slouken@11284
    86
static void SDLCALL
slouken@10673
    87
SDL_MouseRelativeSpeedScaleChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@10673
    88
{
slouken@10673
    89
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@10673
    90
slouken@10676
    91
    if (hint && *hint) {
slouken@10676
    92
        mouse->relative_speed_scale = (float)SDL_atof(hint);
slouken@10676
    93
    } else {
slouken@10676
    94
        mouse->relative_speed_scale = 1.0f;
slouken@10676
    95
    }
slouken@10673
    96
}
slouken@10673
    97
slouken@11284
    98
static void SDLCALL
slouken@11182
    99
SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
slouken@11182
   100
{
slouken@11182
   101
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
slouken@11182
   102
slouken@11182
   103
    if (hint && (*hint == '0' || SDL_strcasecmp(hint, "false") == 0)) {
slouken@11182
   104
        mouse->touch_mouse_events = SDL_FALSE;
slouken@11182
   105
    } else {
slouken@11182
   106
        mouse->touch_mouse_events = SDL_TRUE;
slouken@11182
   107
    }
slouken@11182
   108
}
slouken@11182
   109
sylvain@12688
   110
static void SDLCALL
sylvain@12688
   111
SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
sylvain@12688
   112
{
sylvain@12688
   113
    SDL_Mouse *mouse = (SDL_Mouse *)userdata;
sylvain@12688
   114
sylvain@12692
   115
    if (hint == NULL || *hint == '\0') {
sylvain@12692
   116
        /* Default */
slouken@12695
   117
#if defined(__ANDROID__) || (defined(__IPHONEOS__) && !defined(__TVOS__))
sylvain@12692
   118
        mouse->mouse_touch_events = SDL_TRUE;
sylvain@12692
   119
#else
sylvain@12692
   120
        mouse->mouse_touch_events = SDL_FALSE;
sylvain@12692
   121
#endif
sylvain@12692
   122
    } else if (*hint == '1' || SDL_strcasecmp(hint, "true") == 0) {
sylvain@12688
   123
        mouse->mouse_touch_events = SDL_TRUE;
sylvain@12688
   124
    } else {
sylvain@12688
   125
        mouse->mouse_touch_events = SDL_FALSE;
sylvain@12688
   126
    }
sylvain@12692
   127
sylvain@12692
   128
    if (mouse->mouse_touch_events) {
sylvain@12692
   129
        SDL_AddTouch(SDL_MOUSE_TOUCHID, SDL_TOUCH_DEVICE_DIRECT, "mouse_input");
sylvain@12692
   130
    }
sylvain@12688
   131
}
sylvain@12688
   132
slouken@0
   133
/* Public functions */
slouken@1895
   134
int
slouken@1895
   135
SDL_MouseInit(void)
slouken@0
   136
{
slouken@5376
   137
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5376
   138
slouken@11607
   139
    SDL_zerop(mouse);
slouken@11607
   140
slouken@12188
   141
    SDL_AddHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_TIME,
slouken@12188
   142
                        SDL_MouseDoubleClickTimeChanged, mouse);
slouken@12188
   143
slouken@12188
   144
    SDL_AddHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS,
slouken@12188
   145
                        SDL_MouseDoubleClickRadiusChanged, mouse);
slouken@12188
   146
slouken@10673
   147
    SDL_AddHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
slouken@10673
   148
                        SDL_MouseNormalSpeedScaleChanged, mouse);
slouken@10673
   149
slouken@10673
   150
    SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE,
slouken@10673
   151
                        SDL_MouseRelativeSpeedScaleChanged, mouse);
slouken@10673
   152
slouken@11182
   153
    SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS,
slouken@11182
   154
                        SDL_TouchMouseEventsChanged, mouse);
slouken@11182
   155
sylvain@12688
   156
    SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
sylvain@12688
   157
                        SDL_MouseTouchEventsChanged, mouse);
sylvain@12688
   158
slouken@12943
   159
    mouse->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */
slouken@12943
   160
slouken@5376
   161
    mouse->cursor_shown = SDL_TRUE;
slouken@5376
   162
slouken@1895
   163
    return (0);
slouken@1123
   164
}
slouken@0
   165
slouken@5405
   166
void
slouken@5405
   167
SDL_SetDefaultCursor(SDL_Cursor * cursor)
slouken@5405
   168
{
slouken@5405
   169
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5405
   170
slouken@5405
   171
    mouse->def_cursor = cursor;
slouken@5405
   172
    if (!mouse->cur_cursor) {
slouken@5405
   173
        SDL_SetCursor(cursor);
slouken@5405
   174
    }
slouken@5405
   175
}
slouken@5405
   176
slouken@5371
   177
SDL_Mouse *
slouken@5371
   178
SDL_GetMouse(void)
slouken@5371
   179
{
slouken@5371
   180
    return &SDL_mouse;
slouken@5371
   181
}
slouken@5371
   182
slouken@4465
   183
SDL_Window *
slouken@4465
   184
SDL_GetMouseFocus(void)
slouken@2710
   185
{
slouken@5371
   186
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@2940
   187
slouken@4465
   188
    return mouse->focus;
slouken@0
   189
}
slouken@0
   190
slouken@10609
   191
#if 0
slouken@1895
   192
void
slouken@6666
   193
SDL_ResetMouse(void)
slouken@6666
   194
{
slouken@6666
   195
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@6666
   196
    Uint8 i;
slouken@6666
   197
slouken@6666
   198
#ifdef DEBUG_MOUSE
slouken@6666
   199
    printf("Resetting mouse\n");
slouken@6666
   200
#endif
slouken@6666
   201
    for (i = 1; i <= sizeof(mouse->buttonstate)*8; ++i) {
slouken@6666
   202
        if (mouse->buttonstate & SDL_BUTTON(i)) {
slouken@6950
   203
            SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, i);
slouken@6666
   204
        }
slouken@6666
   205
    }
slouken@6666
   206
    SDL_assert(mouse->buttonstate == 0);
slouken@6666
   207
}
slouken@10609
   208
#endif
slouken@6666
   209
slouken@6666
   210
void
slouken@4465
   211
SDL_SetMouseFocus(SDL_Window * window)
slouken@0
   212
{
slouken@5371
   213
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   214
slouken@4465
   215
    if (mouse->focus == window) {
slouken@1895
   216
        return;
slouken@1895
   217
    }
slouken@1895
   218
slouken@6829
   219
    /* Actually, this ends up being a bad idea, because most operating
slouken@6829
   220
       systems have an implicit grab when you press the mouse button down
slouken@6829
   221
       so you can drag things out of the window and then get the mouse up
slouken@6829
   222
       when it happens.  So, #if 0...
slouken@6829
   223
    */
slouken@6829
   224
#if 0
slouken@6666
   225
    if (mouse->focus && !window) {
slouken@6666
   226
        /* We won't get anymore mouse messages, so reset mouse state */
slouken@6666
   227
        SDL_ResetMouse();
slouken@6666
   228
    }
slouken@6829
   229
#endif
slouken@6666
   230
slouken@1895
   231
    /* See if the current window has lost focus */
slouken@1895
   232
    if (mouse->focus) {
slouken@4465
   233
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
slouken@1895
   234
    }
slouken@1895
   235
slouken@3685
   236
    mouse->focus = window;
slouken@11258
   237
    mouse->has_position = SDL_FALSE;
slouken@1895
   238
slouken@1895
   239
    if (mouse->focus) {
slouken@4465
   240
        SDL_SendWindowEvent(mouse->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
slouken@1895
   241
    }
slouken@6666
   242
slouken@6666
   243
    /* Update cursor visibility */
slouken@6666
   244
    SDL_SetCursor(NULL);
slouken@6666
   245
}
slouken@6666
   246
slouken@6666
   247
/* Check to see if we need to synthesize focus events */
slouken@6666
   248
static SDL_bool
slouken@12943
   249
SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate, SDL_bool send_mouse_motion)
slouken@6666
   250
{
slouken@6666
   251
    SDL_Mouse *mouse = SDL_GetMouse();
icculus@8927
   252
    SDL_bool inWindow = SDL_TRUE;
slouken@6666
   253
slouken@8983
   254
    if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
icculus@8927
   255
        int w, h;
icculus@8927
   256
        SDL_GetWindowSize(window, &w, &h);
icculus@8927
   257
        if (x < 0 || y < 0 || x >= w || y >= h) {
icculus@8927
   258
            inWindow = SDL_FALSE;
icculus@8927
   259
        }
slouken@6666
   260
    }
slouken@6667
   261
icculus@8783
   262
/* Linux doesn't give you mouse events outside your window unless you grab
icculus@8783
   263
   the pointer.
icculus@8783
   264
icculus@8783
   265
   Windows doesn't give you mouse events outside your window unless you call
icculus@8783
   266
   SetCapture().
icculus@8783
   267
icculus@8783
   268
   Both of these are slightly scary changes, so for now we'll punt and if the
icculus@8783
   269
   mouse leaves the window you'll lose mouse focus and reset button state.
icculus@8783
   270
*/
icculus@8783
   271
#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW
icculus@8783
   272
    if (!inWindow && !buttonstate) {
icculus@8783
   273
#else
slouken@6667
   274
    if (!inWindow) {
icculus@8783
   275
#endif
slouken@6666
   276
        if (window == mouse->focus) {
slouken@6666
   277
#ifdef DEBUG_MOUSE
jorgen@7089
   278
            printf("Mouse left window, synthesizing move & focus lost event\n");
slouken@6666
   279
#endif
slouken@12943
   280
            if (send_mouse_motion) {
slouken@12943
   281
                SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@12943
   282
            }
slouken@6666
   283
            SDL_SetMouseFocus(NULL);
slouken@6666
   284
        }
slouken@6666
   285
        return SDL_FALSE;
slouken@6666
   286
    }
slouken@6666
   287
slouken@6666
   288
    if (window != mouse->focus) {
slouken@6666
   289
#ifdef DEBUG_MOUSE
slouken@11258
   290
        printf("Mouse entered window, synthesizing focus gain & move event\n");
slouken@6666
   291
#endif
slouken@11258
   292
        SDL_SetMouseFocus(window);
slouken@12943
   293
        if (send_mouse_motion) {
slouken@12943
   294
            SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@12943
   295
        }
slouken@6666
   296
    }
slouken@6666
   297
    return SDL_TRUE;
slouken@1895
   298
}
slouken@1895
   299
slouken@1895
   300
int
slouken@6950
   301
SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
slouken@1895
   302
{
jorgen@7089
   303
    if (window && !relative) {
jorgen@7089
   304
        SDL_Mouse *mouse = SDL_GetMouse();
slouken@12943
   305
        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate, (mouseID == SDL_TOUCH_MOUSEID) ? SDL_FALSE : SDL_TRUE)) {
jorgen@7089
   306
            return 0;
jorgen@7089
   307
        }
jorgen@7089
   308
    }
jorgen@7089
   309
jorgen@7089
   310
    return SDL_PrivateSendMouseMotion(window, mouseID, relative, x, y);
jorgen@7089
   311
}
jorgen@7089
   312
jorgen@7089
   313
static int
slouken@10673
   314
GetScaledMouseDelta(float scale, int value, float *accum)
slouken@10673
   315
{
slouken@10673
   316
    if (scale != 1.0f) {
slouken@10673
   317
        *accum += scale * value;
slouken@10673
   318
        if (*accum >= 0.0f) {
slouken@10673
   319
            value = (int)SDL_floor(*accum);
slouken@10673
   320
        } else {
slouken@10673
   321
            value = (int)SDL_ceil(*accum);
slouken@10673
   322
        }
slouken@10673
   323
        *accum -= value;
slouken@10673
   324
    }
slouken@10673
   325
    return value;
slouken@10673
   326
}
slouken@10673
   327
slouken@10673
   328
static int
jorgen@7089
   329
SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y)
jorgen@7089
   330
{
slouken@5371
   331
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   332
    int posted;
slouken@1895
   333
    int xrel;
slouken@1895
   334
    int yrel;
slouken@1895
   335
sylvain@12688
   336
    /* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
sylvain@12688
   337
    if (mouse->mouse_touch_events) {
sylvain@12688
   338
        if (mouseID != SDL_TOUCH_MOUSEID && !relative && track_mouse_down) {
sylvain@12688
   339
            if (window) {
sylvain@12688
   340
                float fx = (float)x / (float)window->w;
sylvain@12688
   341
                float fy = (float)y / (float)window->h;
sylvain@12688
   342
                SDL_SendTouchMotion(SDL_MOUSE_TOUCHID, 0, fx, fy, 1.0f);
sylvain@12688
   343
            }
sylvain@12688
   344
        }
sylvain@12688
   345
    }
sylvain@12688
   346
sylvain@12934
   347
    /* SDL_HINT_TOUCH_MOUSE_EVENTS: if not set, discard synthetic mouse events coming from platform layer */
sylvain@12934
   348
    if (mouse->touch_mouse_events == 0) {
sylvain@12934
   349
        if (mouseID == SDL_TOUCH_MOUSEID) {
sylvain@12934
   350
            return 0;
sylvain@12934
   351
        }
sylvain@12934
   352
    }
sylvain@12934
   353
slouken@11258
   354
    if (mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
slouken@8071
   355
        int center_x = 0, center_y = 0;
slouken@8071
   356
        SDL_GetWindowSize(window, &center_x, &center_y);
slouken@8071
   357
        center_x /= 2;
slouken@8071
   358
        center_y /= 2;
slouken@8071
   359
        if (x == center_x && y == center_y) {
slouken@8071
   360
            mouse->last_x = center_x;
slouken@8071
   361
            mouse->last_y = center_y;
slouken@8071
   362
            return 0;
slouken@8071
   363
        }
slouken@8071
   364
        SDL_WarpMouseInWindow(window, center_x, center_y);
slouken@8071
   365
    }
slouken@8071
   366
slouken@2842
   367
    if (relative) {
slouken@10673
   368
        if (mouse->relative_mode) {
slouken@10673
   369
            x = GetScaledMouseDelta(mouse->relative_speed_scale, x, &mouse->scale_accum_x);
slouken@10673
   370
            y = GetScaledMouseDelta(mouse->relative_speed_scale, y, &mouse->scale_accum_y);
slouken@10673
   371
        } else {
slouken@10673
   372
            x = GetScaledMouseDelta(mouse->normal_speed_scale, x, &mouse->scale_accum_x);
slouken@10673
   373
            y = GetScaledMouseDelta(mouse->normal_speed_scale, y, &mouse->scale_accum_y);
slouken@10673
   374
        }
slouken@2842
   375
        xrel = x;
slouken@2842
   376
        yrel = y;
slouken@8071
   377
        x = (mouse->last_x + xrel);
slouken@8071
   378
        y = (mouse->last_y + yrel);
slouken@2842
   379
    } else {
slouken@2860
   380
        xrel = x - mouse->last_x;
slouken@2860
   381
        yrel = y - mouse->last_y;
slouken@2842
   382
    }
slouken@2710
   383
slouken@1895
   384
    /* Drop events that don't change state */
slouken@1895
   385
    if (!xrel && !yrel) {
slouken@6666
   386
#ifdef DEBUG_MOUSE
slouken@1895
   387
        printf("Mouse event didn't change state - dropped!\n");
slouken@1895
   388
#endif
slouken@1895
   389
        return 0;
slouken@1895
   390
    }
slouken@1895
   391
slouken@11258
   392
    /* Ignore relative motion when first positioning the mouse */
slouken@11258
   393
    if (!mouse->has_position) {
slouken@11258
   394
        xrel = 0;
slouken@11258
   395
        yrel = 0;
slouken@11258
   396
        mouse->has_position = SDL_TRUE;
slouken@11258
   397
    }
slouken@11258
   398
slouken@11258
   399
    /* Ignore relative motion positioning the first touch */
slouken@11258
   400
    if (mouseID == SDL_TOUCH_MOUSEID && !mouse->buttonstate) {
slouken@11258
   401
        xrel = 0;
slouken@11258
   402
        yrel = 0;
slouken@11258
   403
    }
slouken@11258
   404
slouken@2710
   405
    /* Update internal mouse coordinates */
slouken@8071
   406
    if (!mouse->relative_mode) {
slouken@1895
   407
        mouse->x = x;
slouken@1895
   408
        mouse->y = y;
slouken@2710
   409
    } else {
slouken@2860
   410
        mouse->x += xrel;
slouken@2860
   411
        mouse->y += yrel;
slouken@2860
   412
    }
slouken@2849
   413
icculus@8927
   414
    /* make sure that the pointers find themselves inside the windows,
icculus@8927
   415
       unless we have the mouse captured. */
slouken@8983
   416
    if (window && ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0)) {
icculus@8927
   417
        int x_max = 0, y_max = 0;
slouken@2849
   418
icculus@10780
   419
        /* !!! FIXME: shouldn't this be (window) instead of (mouse->focus)? */
icculus@8927
   420
        SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
icculus@8927
   421
        --x_max;
icculus@8927
   422
        --y_max;
slouken@2860
   423
icculus@8927
   424
        if (mouse->x > x_max) {
icculus@8927
   425
            mouse->x = x_max;
icculus@8927
   426
        }
icculus@8927
   427
        if (mouse->x < 0) {
icculus@8927
   428
            mouse->x = 0;
icculus@8927
   429
        }
icculus@8927
   430
icculus@8927
   431
        if (mouse->y > y_max) {
icculus@8927
   432
            mouse->y = y_max;
icculus@8927
   433
        }
icculus@8927
   434
        if (mouse->y < 0) {
icculus@8927
   435
            mouse->y = 0;
icculus@8927
   436
        }
slouken@2860
   437
    }
slouken@2860
   438
slouken@1895
   439
    mouse->xdelta += xrel;
slouken@1895
   440
    mouse->ydelta += yrel;
slouken@1895
   441
slouken@1895
   442
    /* Move the mouse cursor, if needed */
slouken@1895
   443
    if (mouse->cursor_shown && !mouse->relative_mode &&
slouken@1895
   444
        mouse->MoveCursor && mouse->cur_cursor) {
slouken@1895
   445
        mouse->MoveCursor(mouse->cur_cursor);
slouken@1895
   446
    }
slouken@1895
   447
slouken@1895
   448
    /* Post the event, if desired */
slouken@1895
   449
    posted = 0;
slouken@4465
   450
    if (SDL_GetEventState(SDL_MOUSEMOTION) == SDL_ENABLE) {
slouken@1895
   451
        SDL_Event event;
slouken@1895
   452
        event.motion.type = SDL_MOUSEMOTION;
slouken@4465
   453
        event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   454
        event.motion.which = mouseID;
slouken@12943
   455
        /* Set us pending (or clear during a normal mouse movement event) as having triggered */
slouken@12943
   456
        mouse->was_touch_mouse_events = (mouseID == SDL_TOUCH_MOUSEID)? SDL_TRUE : SDL_FALSE;
slouken@1895
   457
        event.motion.state = mouse->buttonstate;
slouken@1895
   458
        event.motion.x = mouse->x;
slouken@1895
   459
        event.motion.y = mouse->y;
slouken@1895
   460
        event.motion.xrel = xrel;
slouken@1895
   461
        event.motion.yrel = yrel;
slouken@1895
   462
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   463
    }
slouken@9448
   464
    if (relative) {
slouken@9448
   465
        mouse->last_x = mouse->x;
slouken@9448
   466
        mouse->last_y = mouse->y;
slouken@9448
   467
    } else {
slouken@9448
   468
        /* Use unclamped values if we're getting events outside the window */
slouken@9448
   469
        mouse->last_x = x;
slouken@9448
   470
        mouse->last_y = y;
slouken@9448
   471
    }
slouken@1895
   472
    return posted;
slouken@1895
   473
}
slouken@1895
   474
slouken@8066
   475
static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
slouken@8066
   476
{
slouken@8066
   477
    if (button >= mouse->num_clickstates) {
slouken@8066
   478
        int i, count = button + 1;
philipp@9334
   479
        SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate));
philipp@9334
   480
        if (!clickstate) {
slouken@8066
   481
            return NULL;
slouken@8066
   482
        }
philipp@9334
   483
        mouse->clickstate = clickstate;
slouken@8066
   484
slouken@8066
   485
        for (i = mouse->num_clickstates; i < count; ++i) {
slouken@8066
   486
            SDL_zero(mouse->clickstate[i]);
slouken@8066
   487
        }
slouken@8066
   488
        mouse->num_clickstates = count;
slouken@8066
   489
    }
slouken@8066
   490
    return &mouse->clickstate[button];
slouken@8066
   491
}
slouken@8066
   492
slime73@10366
   493
static int
slime73@10366
   494
SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks)
slouken@1895
   495
{
slouken@5371
   496
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   497
    int posted;
slouken@4429
   498
    Uint32 type;
slouken@6673
   499
    Uint32 buttonstate = mouse->buttonstate;
slouken@4484
   500
sylvain@12688
   501
    /* SDL_HINT_MOUSE_TOUCH_EVENTS: controlling whether mouse events should generate synthetic touch events */
sylvain@12688
   502
    if (mouse->mouse_touch_events) {
sylvain@12688
   503
        if (mouseID != SDL_TOUCH_MOUSEID && button == SDL_BUTTON_LEFT) {
sylvain@12698
   504
            if (state == SDL_PRESSED) {
sylvain@12698
   505
                track_mouse_down = SDL_TRUE;
sylvain@12698
   506
            } else {
sylvain@12698
   507
                track_mouse_down = SDL_FALSE;
sylvain@12698
   508
            }
sylvain@12688
   509
            if (window) {
sylvain@12688
   510
                float fx = (float)mouse->x / (float)window->w;
sylvain@12688
   511
                float fy = (float)mouse->y / (float)window->h;
sylvain@12688
   512
                SDL_SendTouch(SDL_MOUSE_TOUCHID, 0, track_mouse_down, fx, fy, 1.0f);
sylvain@12688
   513
            }
sylvain@12688
   514
        }
sylvain@12688
   515
    }
sylvain@12688
   516
sylvain@12934
   517
    /* SDL_HINT_TOUCH_MOUSE_EVENTS: if not set, discard synthetic mouse events coming from platform layer */
sylvain@12934
   518
    if (mouse->touch_mouse_events == 0) {
sylvain@12934
   519
        if (mouseID == SDL_TOUCH_MOUSEID) {
sylvain@12934
   520
            return 0;
sylvain@12934
   521
        }
sylvain@12934
   522
    }
sylvain@12934
   523
slouken@1895
   524
    /* Figure out which event to perform */
slouken@1895
   525
    switch (state) {
slouken@1895
   526
    case SDL_PRESSED:
slouken@1895
   527
        type = SDL_MOUSEBUTTONDOWN;
slouken@6666
   528
        buttonstate |= SDL_BUTTON(button);
slouken@1895
   529
        break;
slouken@1895
   530
    case SDL_RELEASED:
slouken@1895
   531
        type = SDL_MOUSEBUTTONUP;
slouken@6666
   532
        buttonstate &= ~SDL_BUTTON(button);
slouken@1895
   533
        break;
slouken@1895
   534
    default:
slouken@1895
   535
        /* Invalid state -- bail */
slouken@1895
   536
        return 0;
slouken@1895
   537
    }
slouken@1895
   538
slouken@6666
   539
    /* We do this after calculating buttonstate so button presses gain focus */
slouken@6666
   540
    if (window && state == SDL_PRESSED) {
slouken@12943
   541
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE);
slouken@6666
   542
    }
slouken@6666
   543
slouken@6666
   544
    if (buttonstate == mouse->buttonstate) {
slouken@6666
   545
        /* Ignore this event, no state change */
slouken@6666
   546
        return 0;
slouken@6666
   547
    }
slouken@6666
   548
    mouse->buttonstate = buttonstate;
slouken@6666
   549
slime73@10366
   550
    if (clicks < 0) {
slime73@10366
   551
        SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
philipp@10390
   552
        if (clickstate) {
philipp@10390
   553
            if (state == SDL_PRESSED) {
philipp@10390
   554
                Uint32 now = SDL_GetTicks();
slouken@8066
   555
slouken@12188
   556
                if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + mouse->double_click_time) ||
slouken@12188
   557
                    SDL_abs(mouse->x - clickstate->last_x) > mouse->double_click_radius ||
slouken@12188
   558
                    SDL_abs(mouse->y - clickstate->last_y) > mouse->double_click_radius) {
philipp@10390
   559
                    clickstate->click_count = 0;
philipp@10390
   560
                }
philipp@10390
   561
                clickstate->last_timestamp = now;
philipp@10390
   562
                clickstate->last_x = mouse->x;
philipp@10390
   563
                clickstate->last_y = mouse->y;
philipp@10390
   564
                if (clickstate->click_count < 255) {
philipp@10390
   565
                    ++clickstate->click_count;
philipp@10390
   566
                }
slouken@8066
   567
            }
philipp@10390
   568
            clicks = clickstate->click_count;
philipp@10390
   569
        } else {
philipp@10390
   570
            clicks = 1;
slouken@8066
   571
        }
slouken@8066
   572
    }
slouken@8066
   573
slouken@1895
   574
    /* Post the event, if desired */
slouken@1895
   575
    posted = 0;
slouken@4429
   576
    if (SDL_GetEventState(type) == SDL_ENABLE) {
slouken@1895
   577
        SDL_Event event;
slouken@1895
   578
        event.type = type;
slouken@6950
   579
        event.button.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   580
        event.button.which = mouseID;
slouken@1895
   581
        event.button.state = state;
slouken@1895
   582
        event.button.button = button;
slime73@10366
   583
        event.button.clicks = (Uint8) SDL_min(clicks, 255);
slouken@1895
   584
        event.button.x = mouse->x;
slouken@1895
   585
        event.button.y = mouse->y;
slouken@1895
   586
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   587
    }
slouken@6666
   588
slouken@6666
   589
    /* We do this after dispatching event so button releases can lose focus */
slouken@6666
   590
    if (window && state == SDL_RELEASED) {
slouken@12943
   591
        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE);
slouken@6666
   592
    }
sylvain@12687
   593
slime73@10366
   594
    return posted;
slime73@10366
   595
}
slouken@6666
   596
slime73@10366
   597
int
slime73@10366
   598
SDL_SendMouseButtonClicks(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks)
slime73@10366
   599
{
slime73@10366
   600
    clicks = SDL_max(clicks, 0);
slime73@10366
   601
    return SDL_PrivateSendMouseButton(window, mouseID, state, button, clicks);
slime73@10366
   602
}
slime73@10366
   603
slime73@10366
   604
int
slime73@10366
   605
SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
slime73@10366
   606
{
slime73@10366
   607
    return SDL_PrivateSendMouseButton(window, mouseID, state, button, -1);
slouken@1895
   608
}
slouken@1895
   609
slouken@1895
   610
int
slouken@11300
   611
SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
slouken@1895
   612
{
slouken@5371
   613
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
   614
    int posted;
slouken@11300
   615
    int integral_x, integral_y;
slouken@1895
   616
slouken@4484
   617
    if (window) {
slouken@4484
   618
        SDL_SetMouseFocus(window);
slouken@4484
   619
    }
slouken@4484
   620
slouken@12466
   621
    if (x == 0.0f && y == 0.0f) {
slouken@1895
   622
        return 0;
slouken@1895
   623
    }
slouken@1895
   624
slouken@11300
   625
    mouse->accumulated_wheel_x += x;
slouken@11300
   626
    if (mouse->accumulated_wheel_x > 0) {
slouken@11300
   627
        integral_x = (int)SDL_floor(mouse->accumulated_wheel_x);
slouken@11300
   628
    } else if (mouse->accumulated_wheel_x < 0) {
slouken@11300
   629
        integral_x = (int)SDL_ceil(mouse->accumulated_wheel_x);
slouken@11300
   630
    } else {
slouken@11300
   631
        integral_x = 0;
slouken@11300
   632
    }
slouken@11300
   633
    mouse->accumulated_wheel_x -= integral_x;
slouken@11300
   634
slouken@11300
   635
    mouse->accumulated_wheel_y += y;
slouken@11300
   636
    if (mouse->accumulated_wheel_y > 0) {
slouken@11300
   637
        integral_y = (int)SDL_floor(mouse->accumulated_wheel_y);
slouken@11300
   638
    } else if (mouse->accumulated_wheel_y < 0) {
slouken@11300
   639
        integral_y = (int)SDL_ceil(mouse->accumulated_wheel_y);
slouken@11300
   640
    } else {
slouken@11300
   641
        integral_y = 0;
slouken@11300
   642
    }
slouken@11300
   643
    mouse->accumulated_wheel_y -= integral_y;
slouken@11300
   644
slouken@1895
   645
    /* Post the event, if desired */
slouken@1895
   646
    posted = 0;
slouken@4429
   647
    if (SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE) {
slouken@1895
   648
        SDL_Event event;
slouken@1895
   649
        event.type = SDL_MOUSEWHEEL;
slouken@4465
   650
        event.wheel.windowID = mouse->focus ? mouse->focus->id : 0;
slouken@6950
   651
        event.wheel.which = mouseID;
slouken@11300
   652
#if 0 /* Uncomment this when it goes in for SDL 2.1 */
slouken@11300
   653
        event.wheel.preciseX = x;
slouken@11300
   654
        event.wheel.preciseY = y;
slouken@11300
   655
#endif
slouken@11300
   656
        event.wheel.x = integral_x;
slouken@11300
   657
        event.wheel.y = integral_y;
urkle@9257
   658
        event.wheel.direction = (Uint32)direction;
slouken@1895
   659
        posted = (SDL_PushEvent(&event) > 0);
slouken@1895
   660
    }
slouken@1895
   661
    return posted;
slouken@1895
   662
}
slouken@1895
   663
slouken@1895
   664
void
slouken@4465
   665
SDL_MouseQuit(void)
slouken@4465
   666
{
slouken@7493
   667
    SDL_Cursor *cursor, *next;
slouken@7493
   668
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@7493
   669
slouken@9161
   670
    if (mouse->CaptureMouse) {
slouken@9161
   671
        SDL_CaptureMouse(SDL_FALSE);
slouken@9161
   672
    }
slouken@8049
   673
    SDL_SetRelativeMouseMode(SDL_FALSE);
slouken@7493
   674
    SDL_ShowCursor(1);
slouken@7493
   675
slouken@7493
   676
    cursor = mouse->cursors;
slouken@7493
   677
    while (cursor) {
slouken@7493
   678
        next = cursor->next;
slouken@7493
   679
        SDL_FreeCursor(cursor);
slouken@7493
   680
        cursor = next;
slouken@7493
   681
    }
slouken@11622
   682
    mouse->cursors = NULL;
sylvain@12620
   683
    mouse->cur_cursor = NULL;
slouken@7493
   684
slouken@7493
   685
    if (mouse->def_cursor && mouse->FreeCursor) {
slouken@7493
   686
        mouse->FreeCursor(mouse->def_cursor);
slouken@11622
   687
        mouse->def_cursor = NULL;
slouken@7493
   688
    }
slouken@7493
   689
slouken@8066
   690
    if (mouse->clickstate) {
slouken@8066
   691
        SDL_free(mouse->clickstate);
slouken@11622
   692
        mouse->clickstate = NULL;
slouken@8066
   693
    }
slouken@8066
   694
slouken@10673
   695
    SDL_DelHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
slouken@10673
   696
                        SDL_MouseNormalSpeedScaleChanged, mouse);
slouken@10673
   697
slouken@10673
   698
    SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE,
slouken@10673
   699
                        SDL_MouseRelativeSpeedScaleChanged, mouse);
slouken@4465
   700
}
slouken@4465
   701
slouken@6673
   702
Uint32
slouken@4465
   703
SDL_GetMouseState(int *x, int *y)
slouken@4465
   704
{
slouken@5371
   705
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   706
slouken@4465
   707
    if (x) {
slouken@4465
   708
        *x = mouse->x;
slouken@4465
   709
    }
slouken@4465
   710
    if (y) {
slouken@4465
   711
        *y = mouse->y;
slouken@4465
   712
    }
slouken@4465
   713
    return mouse->buttonstate;
slouken@4465
   714
}
slouken@4465
   715
slouken@6673
   716
Uint32
slouken@4465
   717
SDL_GetRelativeMouseState(int *x, int *y)
slouken@4465
   718
{
slouken@5371
   719
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   720
slouken@4465
   721
    if (x) {
slouken@4465
   722
        *x = mouse->xdelta;
slouken@4465
   723
    }
slouken@4465
   724
    if (y) {
slouken@4465
   725
        *y = mouse->ydelta;
slouken@4465
   726
    }
slouken@4465
   727
    mouse->xdelta = 0;
slouken@4465
   728
    mouse->ydelta = 0;
slouken@4465
   729
    return mouse->buttonstate;
slouken@4465
   730
}
slouken@4465
   731
icculus@8945
   732
Uint32
icculus@8952
   733
SDL_GetGlobalMouseState(int *x, int *y)
icculus@8945
   734
{
icculus@8945
   735
    SDL_Mouse *mouse = SDL_GetMouse();
icculus@8945
   736
    int tmpx, tmpy;
icculus@8945
   737
icculus@8945
   738
    /* make sure these are never NULL for the backend implementations... */
icculus@8945
   739
    if (!x) {
icculus@8945
   740
        x = &tmpx;
icculus@8945
   741
    }
icculus@8945
   742
    if (!y) {
icculus@8945
   743
        y = &tmpy;
icculus@8945
   744
    }
icculus@8945
   745
icculus@8945
   746
    *x = *y = 0;
icculus@8945
   747
icculus@8952
   748
    if (!mouse->GetGlobalMouseState) {
icculus@8945
   749
        return 0;
icculus@8945
   750
    }
icculus@8945
   751
icculus@8952
   752
    return mouse->GetGlobalMouseState(x, y);
icculus@8945
   753
}
icculus@8945
   754
slouken@4465
   755
void
slouken@3685
   756
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
slouken@1895
   757
{
slouken@5371
   758
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@7191
   759
icculus@8953
   760
    if (window == NULL) {
slouken@7191
   761
        window = mouse->focus;
icculus@8944
   762
    }
slouken@7191
   763
icculus@8953
   764
    if (window == NULL) {
slouken@7191
   765
        return;
icculus@8944
   766
    }
slouken@1895
   767
slouken@1895
   768
    if (mouse->WarpMouse) {
slouken@5371
   769
        mouse->WarpMouse(window, x, y);
slouken@1895
   770
    } else {
slouken@6950
   771
        SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y);
slouken@1895
   772
    }
slouken@1895
   773
}
slouken@1895
   774
icculus@9807
   775
int
slouken@8815
   776
SDL_WarpMouseGlobal(int x, int y)
slouken@8815
   777
{
slouken@8815
   778
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@8815
   779
slouken@8815
   780
    if (mouse->WarpMouseGlobal) {
icculus@9807
   781
        return mouse->WarpMouseGlobal(x, y);
slouken@8815
   782
    }
icculus@9807
   783
icculus@9807
   784
    return SDL_Unsupported();
slouken@8815
   785
}
slouken@8815
   786
slouken@8071
   787
static SDL_bool
slouken@8071
   788
ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
slouken@8071
   789
{
slouken@12753
   790
    if (!mouse->WarpMouse) {
slouken@12753
   791
        /* Need this functionality for relative mode warp implementation */
slouken@12753
   792
        return SDL_FALSE;
slouken@8071
   793
    }
slouken@8071
   794
slouken@10499
   795
    return SDL_GetHintBoolean(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, SDL_FALSE);
slouken@8071
   796
}
slouken@8071
   797
slouken@4465
   798
int
slouken@4465
   799
SDL_SetRelativeMouseMode(SDL_bool enabled)
slouken@4465
   800
{
slouken@5371
   801
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7107
   802
    SDL_Window *focusWindow = SDL_GetKeyboardFocus();
slouken@4465
   803
slouken@5406
   804
    if (enabled == mouse->relative_mode) {
slouken@5406
   805
        return 0;
slouken@5406
   806
    }
slouken@5406
   807
slouken@8071
   808
    /* Set the relative mode */
slouken@8071
   809
    if (!enabled && mouse->relative_mode_warp) {
slouken@8071
   810
        mouse->relative_mode_warp = SDL_FALSE;
slouken@8071
   811
    } else if (enabled && ShouldUseRelativeModeWarp(mouse)) {
slouken@8071
   812
        mouse->relative_mode_warp = SDL_TRUE;
slouken@12753
   813
    } else if (!mouse->SetRelativeMouseMode || mouse->SetRelativeMouseMode(enabled) < 0) {
slouken@8269
   814
        if (enabled) {
philipp@8776
   815
            /* Fall back to warp mode if native relative mode failed */
slouken@12024
   816
            if (!mouse->WarpMouse) {
slouken@12024
   817
                return SDL_SetError("No relative mode implementation available");
slouken@12024
   818
            }
slouken@8269
   819
            mouse->relative_mode_warp = SDL_TRUE;
slouken@8269
   820
        }
slouken@5406
   821
    }
slouken@4465
   822
    mouse->relative_mode = enabled;
slouken@10673
   823
    mouse->scale_accum_x = 0.0f;
slouken@10673
   824
    mouse->scale_accum_y = 0.0f;
slouken@4465
   825
slouken@12886
   826
    if (enabled && focusWindow) {
slouken@12886
   827
        /* Center it in the focused window to prevent clicks from going through
slouken@12886
   828
         * to background windows.
slouken@12886
   829
         */
slouken@12886
   830
        SDL_SetMouseFocus(focusWindow);
slouken@12886
   831
        SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
slouken@12886
   832
    }
slouken@12886
   833
slouken@8071
   834
    if (mouse->focus) {
slouken@8071
   835
        SDL_UpdateWindowGrab(mouse->focus);
slouken@8071
   836
slouken@8071
   837
        /* Put the cursor back to where the application expects it */
slouken@8071
   838
        if (!enabled) {
slouken@8071
   839
            SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y);
slouken@8071
   840
        }
slouken@4465
   841
    }
slouken@4465
   842
slouken@8071
   843
    /* Flush pending mouse motion - ideally we would pump events, but that's not always safe */
slouken@5406
   844
    SDL_FlushEvent(SDL_MOUSEMOTION);
slouken@5406
   845
slouken@4465
   846
    /* Update cursor visibility */
slouken@4465
   847
    SDL_SetCursor(NULL);
slouken@4465
   848
slouken@4465
   849
    return 0;
slouken@4465
   850
}
slouken@4465
   851
slouken@4465
   852
SDL_bool
slouken@4465
   853
SDL_GetRelativeMouseMode()
slouken@4465
   854
{
slouken@5371
   855
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@4465
   856
slouken@4465
   857
    return mouse->relative_mode;
slouken@4465
   858
}
slouken@4465
   859
icculus@8955
   860
int
icculus@8955
   861
SDL_CaptureMouse(SDL_bool enabled)
icculus@8955
   862
{
icculus@8955
   863
    SDL_Mouse *mouse = SDL_GetMouse();
icculus@8955
   864
    SDL_Window *focusWindow;
icculus@8955
   865
    SDL_bool isCaptured;
icculus@8955
   866
icculus@8955
   867
    if (!mouse->CaptureMouse) {
icculus@8955
   868
        return SDL_Unsupported();
icculus@8955
   869
    }
icculus@8955
   870
icculus@8955
   871
    focusWindow = SDL_GetKeyboardFocus();
icculus@8955
   872
icculus@8955
   873
    isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE);
icculus@8955
   874
    if (isCaptured == enabled) {
icculus@8955
   875
        return 0;  /* already done! */
icculus@8955
   876
    }
icculus@8955
   877
icculus@8955
   878
    if (enabled) {
icculus@8955
   879
        if (!focusWindow) {
icculus@8955
   880
            return SDL_SetError("No window has focus");
icculus@8955
   881
        } else if (mouse->CaptureMouse(focusWindow) == -1) {
icculus@8955
   882
            return -1;  /* CaptureMouse() should call SetError */
icculus@8955
   883
        }
icculus@8955
   884
        focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
icculus@8955
   885
    } else {
icculus@8955
   886
        if (mouse->CaptureMouse(NULL) == -1) {
icculus@8955
   887
            return -1;  /* CaptureMouse() should call SetError */
icculus@8955
   888
        }
icculus@8955
   889
        focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
icculus@8955
   890
    }
icculus@8955
   891
icculus@8955
   892
    return 0;
icculus@8955
   893
}
icculus@8955
   894
slouken@1895
   895
SDL_Cursor *
slouken@1895
   896
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
slouken@1895
   897
                 int w, int h, int hot_x, int hot_y)
slouken@1895
   898
{
slouken@1895
   899
    SDL_Surface *surface;
slouken@1895
   900
    SDL_Cursor *cursor;
slouken@1895
   901
    int x, y;
slouken@1895
   902
    Uint32 *pixel;
slouken@4465
   903
    Uint8 datab = 0, maskb = 0;
slouken@1895
   904
    const Uint32 black = 0xFF000000;
slouken@1895
   905
    const Uint32 white = 0xFFFFFFFF;
slouken@1895
   906
    const Uint32 transparent = 0x00000000;
slouken@1895
   907
slouken@1895
   908
    /* Make sure the width is a multiple of 8 */
slouken@1895
   909
    w = ((w + 7) & ~7);
slouken@1895
   910
slouken@1895
   911
    /* Create the surface from a bitmap */
slouken@5473
   912
    surface = SDL_CreateRGBSurface(0, w, h, 32,
slouken@5473
   913
                                   0x00FF0000,
slouken@5473
   914
                                   0x0000FF00,
slouken@5473
   915
                                   0x000000FF,
slouken@5473
   916
                                   0xFF000000);
slouken@1895
   917
    if (!surface) {
slouken@1895
   918
        return NULL;
slouken@1895
   919
    }
slouken@1895
   920
    for (y = 0; y < h; ++y) {
slouken@1895
   921
        pixel = (Uint32 *) ((Uint8 *) surface->pixels + y * surface->pitch);
slouken@1895
   922
        for (x = 0; x < w; ++x) {
slouken@1895
   923
            if ((x % 8) == 0) {
slouken@1895
   924
                datab = *data++;
slouken@1895
   925
                maskb = *mask++;
slouken@1895
   926
            }
slouken@1895
   927
            if (maskb & 0x80) {
slouken@1895
   928
                *pixel++ = (datab & 0x80) ? black : white;
slouken@1895
   929
            } else {
slouken@1895
   930
                *pixel++ = (datab & 0x80) ? black : transparent;
slouken@1895
   931
            }
slouken@1895
   932
            datab <<= 1;
slouken@1895
   933
            maskb <<= 1;
slouken@1895
   934
        }
slouken@1895
   935
    }
slouken@1895
   936
slouken@5473
   937
    cursor = SDL_CreateColorCursor(surface, hot_x, hot_y);
slouken@5473
   938
slouken@5473
   939
    SDL_FreeSurface(surface);
slouken@5473
   940
slouken@5473
   941
    return cursor;
slouken@5473
   942
}
slouken@5473
   943
slouken@5473
   944
SDL_Cursor *
slouken@5473
   945
SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y)
slouken@5473
   946
{
slouken@5473
   947
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5473
   948
    SDL_Surface *temp = NULL;
slouken@5473
   949
    SDL_Cursor *cursor;
slouken@5473
   950
slouken@5473
   951
    if (!surface) {
slouken@5473
   952
        SDL_SetError("Passed NULL cursor surface");
slouken@5473
   953
        return NULL;
slouken@5473
   954
    }
slouken@5473
   955
slouken@5473
   956
    if (!mouse->CreateCursor) {
slouken@5473
   957
        SDL_SetError("Cursors are not currently supported");
slouken@5473
   958
        return NULL;
slouken@5473
   959
    }
slouken@5473
   960
slouken@5473
   961
    /* Sanity check the hot spot */
slouken@5473
   962
    if ((hot_x < 0) || (hot_y < 0) ||
slouken@5473
   963
        (hot_x >= surface->w) || (hot_y >= surface->h)) {
slouken@5473
   964
        SDL_SetError("Cursor hot spot doesn't lie within cursor");
slouken@5473
   965
        return NULL;
slouken@5473
   966
    }
slouken@5473
   967
slouken@5473
   968
    if (surface->format->format != SDL_PIXELFORMAT_ARGB8888) {
slouken@5473
   969
        temp = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0);
slouken@5473
   970
        if (!temp) {
slouken@5473
   971
            return NULL;
slouken@5473
   972
        }
slouken@5473
   973
        surface = temp;
slouken@5473
   974
    }
slouken@5473
   975
slouken@1895
   976
    cursor = mouse->CreateCursor(surface, hot_x, hot_y);
slouken@1895
   977
    if (cursor) {
slouken@1895
   978
        cursor->next = mouse->cursors;
slouken@1895
   979
        mouse->cursors = cursor;
slouken@1895
   980
    }
slouken@1895
   981
slouken@7720
   982
    SDL_FreeSurface(temp);
slouken@1895
   983
slouken@1895
   984
    return cursor;
slouken@1895
   985
}
slouken@1895
   986
mikesart@6675
   987
SDL_Cursor *
mikesart@6675
   988
SDL_CreateSystemCursor(SDL_SystemCursor id)
mikesart@6675
   989
{
mikesart@6675
   990
    SDL_Mouse *mouse = SDL_GetMouse();
mikesart@6675
   991
    SDL_Cursor *cursor;
mikesart@6675
   992
mikesart@6675
   993
    if (!mouse->CreateSystemCursor) {
mikesart@6675
   994
        SDL_SetError("CreateSystemCursor is not currently supported");
mikesart@6675
   995
        return NULL;
mikesart@6675
   996
    }
mikesart@6675
   997
slouken@7191
   998
    cursor = mouse->CreateSystemCursor(id);
mikesart@6675
   999
    if (cursor) {
mikesart@6675
  1000
        cursor->next = mouse->cursors;
mikesart@6675
  1001
        mouse->cursors = cursor;
mikesart@6675
  1002
    }
mikesart@6675
  1003
slouken@7191
  1004
    return cursor;
mikesart@6675
  1005
}
mikesart@6675
  1006
slouken@1895
  1007
/* SDL_SetCursor(NULL) can be used to force the cursor redraw,
slouken@1895
  1008
   if this is desired for any reason.  This is used when setting
slouken@1895
  1009
   the video mode and when the SDL window gains the mouse focus.
slouken@1895
  1010
 */
slouken@1895
  1011
void
slouken@1895
  1012
SDL_SetCursor(SDL_Cursor * cursor)
slouken@1895
  1013
{
slouken@5371
  1014
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
  1015
slouken@1895
  1016
    /* Set the new cursor */
slouken@1895
  1017
    if (cursor) {
slouken@1895
  1018
        /* Make sure the cursor is still valid for this mouse */
slouken@5405
  1019
        if (cursor != mouse->def_cursor) {
slouken@5405
  1020
            SDL_Cursor *found;
slouken@5405
  1021
            for (found = mouse->cursors; found; found = found->next) {
slouken@5405
  1022
                if (found == cursor) {
slouken@5405
  1023
                    break;
slouken@5405
  1024
                }
slouken@1895
  1025
            }
slouken@5405
  1026
            if (!found) {
slouken@5405
  1027
                SDL_SetError("Cursor not associated with the current mouse");
slouken@5405
  1028
                return;
slouken@5405
  1029
            }
slouken@1895
  1030
        }
slouken@1895
  1031
        mouse->cur_cursor = cursor;
slouken@1895
  1032
    } else {
ghostunderscore@6301
  1033
        if (mouse->focus) {
ghostunderscore@6301
  1034
            cursor = mouse->cur_cursor;
ghostunderscore@6301
  1035
        } else {
ghostunderscore@6301
  1036
            cursor = mouse->def_cursor;
ghostunderscore@6301
  1037
        }
slouken@1895
  1038
    }
slouken@1895
  1039
slouken@1895
  1040
    if (cursor && mouse->cursor_shown && !mouse->relative_mode) {
slouken@1895
  1041
        if (mouse->ShowCursor) {
slouken@1895
  1042
            mouse->ShowCursor(cursor);
slouken@1895
  1043
        }
slouken@1895
  1044
    } else {
slouken@1895
  1045
        if (mouse->ShowCursor) {
slouken@1895
  1046
            mouse->ShowCursor(NULL);
slouken@1895
  1047
        }
slouken@1895
  1048
    }
slouken@1895
  1049
}
slouken@1895
  1050
slouken@1895
  1051
SDL_Cursor *
slouken@1895
  1052
SDL_GetCursor(void)
slouken@1895
  1053
{
slouken@5371
  1054
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
  1055
slouken@1895
  1056
    if (!mouse) {
slouken@1895
  1057
        return NULL;
slouken@1895
  1058
    }
slouken@1895
  1059
    return mouse->cur_cursor;
slouken@1895
  1060
}
slouken@1895
  1061
jorgen@7104
  1062
SDL_Cursor *
jorgen@7104
  1063
SDL_GetDefaultCursor(void)
jorgen@7104
  1064
{
jorgen@7104
  1065
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7104
  1066
jorgen@7104
  1067
    if (!mouse) {
jorgen@7104
  1068
        return NULL;
jorgen@7104
  1069
    }
jorgen@7104
  1070
    return mouse->def_cursor;
jorgen@7104
  1071
}
jorgen@7104
  1072
slouken@1895
  1073
void
slouken@1895
  1074
SDL_FreeCursor(SDL_Cursor * cursor)
slouken@1895
  1075
{
slouken@5371
  1076
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
  1077
    SDL_Cursor *curr, *prev;
slouken@1895
  1078
slouken@1895
  1079
    if (!cursor) {
slouken@1895
  1080
        return;
slouken@1895
  1081
    }
slouken@1895
  1082
slouken@1895
  1083
    if (cursor == mouse->def_cursor) {
slouken@1895
  1084
        return;
slouken@1895
  1085
    }
slouken@1895
  1086
    if (cursor == mouse->cur_cursor) {
slouken@1895
  1087
        SDL_SetCursor(mouse->def_cursor);
slouken@1895
  1088
    }
slouken@1895
  1089
slouken@1895
  1090
    for (prev = NULL, curr = mouse->cursors; curr;
slouken@1895
  1091
         prev = curr, curr = curr->next) {
slouken@1895
  1092
        if (curr == cursor) {
slouken@1895
  1093
            if (prev) {
slouken@1895
  1094
                prev->next = curr->next;
slouken@1895
  1095
            } else {
slouken@1895
  1096
                mouse->cursors = curr->next;
slouken@1895
  1097
            }
slouken@1895
  1098
slouken@1895
  1099
            if (mouse->FreeCursor) {
slouken@1895
  1100
                mouse->FreeCursor(curr);
slouken@1895
  1101
            }
slouken@1895
  1102
            return;
slouken@1895
  1103
        }
slouken@1895
  1104
    }
slouken@1895
  1105
}
slouken@1895
  1106
slouken@1895
  1107
int
slouken@1895
  1108
SDL_ShowCursor(int toggle)
slouken@1895
  1109
{
slouken@5371
  1110
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@1895
  1111
    SDL_bool shown;
slouken@1895
  1112
slouken@1895
  1113
    if (!mouse) {
slouken@1895
  1114
        return 0;
slouken@1895
  1115
    }
slouken@1895
  1116
slouken@1895
  1117
    shown = mouse->cursor_shown;
slouken@1895
  1118
    if (toggle >= 0) {
slouken@1895
  1119
        if (toggle) {
slouken@1895
  1120
            mouse->cursor_shown = SDL_TRUE;
slouken@1895
  1121
        } else {
slouken@1895
  1122
            mouse->cursor_shown = SDL_FALSE;
slouken@1895
  1123
        }
slouken@1895
  1124
        if (mouse->cursor_shown != shown) {
slouken@1895
  1125
            SDL_SetCursor(NULL);
slouken@1895
  1126
        }
slouken@1895
  1127
    }
slouken@1895
  1128
    return shown;
slouken@1895
  1129
}
slouken@1895
  1130
jorgen@7097
  1131
/* vi: set ts=4 sw=4 expandtab: */