src/video/emscripten/SDL_emscriptenmouse.c
author Sam Lantinga
Fri, 15 Jan 2021 14:36:21 -0800
changeset 14739 a5b970d28bfd
parent 14640 b2b3343a310d
permissions -rw-r--r--
Fixed the screenshot button mapping on third party Bluetooth Nintendo Switch Pro controllers
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_VIDEO_DRIVER_EMSCRIPTEN
    24 
    25 #include <emscripten/emscripten.h>
    26 #include <emscripten/html5.h>
    27 
    28 #include "SDL_emscriptenmouse.h"
    29 #include "SDL_emscriptenvideo.h"
    30 
    31 #include "../../events/SDL_mouse_c.h"
    32 
    33 static SDL_Cursor*
    34 Emscripten_CreateCursorFromString(const char* cursor_str, SDL_bool is_custom)
    35 {
    36     SDL_Cursor* cursor;
    37     Emscripten_CursorData *curdata;
    38 
    39     cursor = SDL_calloc(1, sizeof(SDL_Cursor));
    40     if (cursor) {
    41         curdata = (Emscripten_CursorData *) SDL_calloc(1, sizeof(*curdata));
    42         if (!curdata) {
    43             SDL_OutOfMemory();
    44             SDL_free(cursor);
    45             return NULL;
    46         }
    47 
    48         curdata->system_cursor = cursor_str;
    49         curdata->is_custom = is_custom;
    50         cursor->driverdata = curdata;
    51     }
    52     else {
    53         SDL_OutOfMemory();
    54     }
    55 
    56     return cursor;
    57 }
    58 
    59 static SDL_Cursor*
    60 Emscripten_CreateDefaultCursor()
    61 {
    62     return Emscripten_CreateCursorFromString("default", SDL_FALSE);
    63 }
    64 
    65 static SDL_Cursor*
    66 Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
    67 {
    68     const char *cursor_url = NULL;
    69     SDL_Surface *conv_surf;
    70 
    71     conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
    72 
    73     if (!conv_surf) {
    74         return NULL;
    75     }
    76 
    77     cursor_url = (const char *)EM_ASM_INT({
    78         var w = $0;
    79         var h = $1;
    80         var hot_x = $2;
    81         var hot_y = $3;
    82         var pixels = $4;
    83 
    84         var canvas = document.createElement("canvas");
    85         canvas.width = w;
    86         canvas.height = h;
    87 
    88         var ctx = canvas.getContext("2d");
    89 
    90         var image = ctx.createImageData(w, h);
    91         var data = image.data;
    92         var src = pixels >> 2;
    93         var dst = 0;
    94         var num;
    95         if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) {
    96             // IE10/IE11: ImageData objects are backed by the deprecated CanvasPixelArray,
    97             // not UInt8ClampedArray. These don't have buffers, so we need to revert
    98             // to copying a byte at a time. We do the undefined check because modern
    99             // browsers do not define CanvasPixelArray anymore.
   100             num = data.length;
   101             while (dst < num) {
   102                 var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}};
   103                 data[dst  ] = val & 0xff;
   104                 data[dst+1] = (val >> 8) & 0xff;
   105                 data[dst+2] = (val >> 16) & 0xff;
   106                 data[dst+3] = (val >> 24) & 0xff;
   107                 src++;
   108                 dst += 4;
   109             }
   110         } else {
   111             var data32 = new Int32Array(data.buffer);
   112             num = data32.length;
   113             data32.set(HEAP32.subarray(src, src + num));
   114         }
   115 
   116         ctx.putImageData(image, 0, 0);
   117         var url = hot_x === 0 && hot_y === 0
   118             ? "url(" + canvas.toDataURL() + "), auto"
   119             : "url(" + canvas.toDataURL() + ") " + hot_x + " " + hot_y + ", auto";
   120 
   121         var urlBuf = _malloc(url.length + 1);
   122         stringToUTF8(url, urlBuf, url.length + 1);
   123 
   124         return urlBuf;
   125     }, surface->w, surface->h, hot_x, hot_y, conv_surf->pixels);
   126 
   127     SDL_FreeSurface(conv_surf);
   128 
   129     return Emscripten_CreateCursorFromString(cursor_url, SDL_TRUE);
   130 }
   131 
   132 static SDL_Cursor*
   133 Emscripten_CreateSystemCursor(SDL_SystemCursor id)
   134 {
   135     const char *cursor_name = NULL;
   136 
   137     switch(id) {
   138         case SDL_SYSTEM_CURSOR_ARROW:
   139             cursor_name = "default";
   140             break;
   141         case SDL_SYSTEM_CURSOR_IBEAM:
   142             cursor_name = "text";
   143             break;
   144         case SDL_SYSTEM_CURSOR_WAIT:
   145             cursor_name = "wait";
   146             break;
   147         case SDL_SYSTEM_CURSOR_CROSSHAIR:
   148             cursor_name = "crosshair";
   149             break;
   150         case SDL_SYSTEM_CURSOR_WAITARROW:
   151             cursor_name = "progress";
   152             break;
   153         case SDL_SYSTEM_CURSOR_SIZENWSE:
   154             cursor_name = "nwse-resize";
   155             break;
   156         case SDL_SYSTEM_CURSOR_SIZENESW:
   157             cursor_name = "nesw-resize";
   158             break;
   159         case SDL_SYSTEM_CURSOR_SIZEWE:
   160             cursor_name = "ew-resize";
   161             break;
   162         case SDL_SYSTEM_CURSOR_SIZENS:
   163             cursor_name = "ns-resize";
   164             break;
   165         case SDL_SYSTEM_CURSOR_SIZEALL:
   166             cursor_name = "move";
   167             break;
   168         case SDL_SYSTEM_CURSOR_NO:
   169             cursor_name = "not-allowed";
   170             break;
   171         case SDL_SYSTEM_CURSOR_HAND:
   172             cursor_name = "pointer";
   173             break;
   174         default:
   175             SDL_assert(0);
   176             return NULL;
   177     }
   178 
   179     return Emscripten_CreateCursorFromString(cursor_name, SDL_FALSE);
   180 }
   181 
   182 static void
   183 Emscripten_FreeCursor(SDL_Cursor* cursor)
   184 {
   185     Emscripten_CursorData *curdata;
   186     if (cursor) {
   187         curdata = (Emscripten_CursorData *) cursor->driverdata;
   188 
   189         if (curdata != NULL) {
   190             if (curdata->is_custom) {
   191                 SDL_free((char *)curdata->system_cursor);
   192             }
   193             SDL_free(cursor->driverdata);
   194         }
   195 
   196         SDL_free(cursor);
   197     }
   198 }
   199 
   200 static int
   201 Emscripten_ShowCursor(SDL_Cursor* cursor)
   202 {
   203     Emscripten_CursorData *curdata;
   204     if (SDL_GetMouseFocus() != NULL) {
   205         if(cursor && cursor->driverdata) {
   206             curdata = (Emscripten_CursorData *) cursor->driverdata;
   207 
   208             if(curdata->system_cursor) {
   209                 EM_ASM_INT({
   210                     if (Module['canvas']) {
   211                         Module['canvas'].style['cursor'] = UTF8ToString($0);
   212                     }
   213                     return 0;
   214                 }, curdata->system_cursor);
   215             }
   216         }
   217         else {
   218             EM_ASM(
   219                 if (Module['canvas']) {
   220                     Module['canvas'].style['cursor'] = 'none';
   221                 }
   222             );
   223         }
   224     }
   225     return 0;
   226 }
   227 
   228 static void
   229 Emscripten_WarpMouse(SDL_Window* window, int x, int y)
   230 {
   231     SDL_Unsupported();
   232 }
   233 
   234 static int
   235 Emscripten_SetRelativeMouseMode(SDL_bool enabled)
   236 {
   237     SDL_Window *window;
   238     SDL_WindowData *window_data;
   239 
   240     /* TODO: pointer lock isn't actually enabled yet */
   241     if(enabled) {
   242         window = SDL_GetMouseFocus();
   243         if (window == NULL) {
   244             return -1;
   245         }
   246 
   247         window_data = (SDL_WindowData *) window->driverdata;
   248 
   249         if(emscripten_request_pointerlock(window_data->canvas_id, 1) >= EMSCRIPTEN_RESULT_SUCCESS) {
   250             return 0;
   251         }
   252     } else {
   253         if(emscripten_exit_pointerlock() >= EMSCRIPTEN_RESULT_SUCCESS) {
   254             return 0;
   255         }
   256     }
   257     return -1;
   258 }
   259 
   260 void
   261 Emscripten_InitMouse()
   262 {
   263     SDL_Mouse* mouse = SDL_GetMouse();
   264 
   265     mouse->CreateCursor         = Emscripten_CreateCursor;
   266     mouse->ShowCursor           = Emscripten_ShowCursor;
   267     mouse->FreeCursor           = Emscripten_FreeCursor;
   268     mouse->WarpMouse            = Emscripten_WarpMouse;
   269     mouse->CreateSystemCursor   = Emscripten_CreateSystemCursor;
   270     mouse->SetRelativeMouseMode = Emscripten_SetRelativeMouseMode;
   271 
   272     SDL_SetDefaultCursor(Emscripten_CreateDefaultCursor());
   273 }
   274 
   275 void
   276 Emscripten_FiniMouse()
   277 {
   278 }
   279 
   280 #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
   281 
   282 /* vi: set ts=4 sw=4 expandtab: */
   283