Browse Source

emscripten: keep track of pointer lock losses and maybe regrab pointer later.

If an Emscripten app is in relative mouse mode and the user presses Escape
(or whatever is appropriate), then the pointer lock is broken by the browser.

This keeps track of those losses, and next time the user presses a mouse
button down on the canvas, if the app is still meant to be in relative mouse
mode, we will attempt to regrab the pointer.

This makes it much more seamless for things like first-person shooters, and
the app doesn't need any manual intervention.
Ryan C. Gordon 8 years ago
parent
commit
93a6191cdc

+ 17 - 10
src/video/emscripten/SDL_emscriptenevents.c

@@ -297,13 +297,23 @@ Emscripten_ConvertUTF32toUTF8(Uint32 codepoint, char * text)
     return SDL_TRUE;
     return SDL_TRUE;
 }
 }
 
 
+static EM_BOOL
+Emscripten_HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent *changeEvent, void *userData)
+{
+    SDL_WindowData *window_data = (SDL_WindowData *) userData;
+    /* keep track of lock losses, so we can regrab if/when appropriate. */
+    window_data->has_pointer_lock = changeEvent->isActive;
+    return 0;
+}
+
+
 EM_BOOL
 EM_BOOL
 Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
 Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
 {
 {
     SDL_WindowData *window_data = userData;
     SDL_WindowData *window_data = userData;
+    const int isPointerLocked = window_data->has_pointer_lock;
     int mx, my;
     int mx, my;
     static double residualx = 0, residualy = 0;
     static double residualx = 0, residualy = 0;
-    EmscriptenPointerlockChangeEvent pointerlock_status;
 
 
     /* rescale (in case canvas is being scaled)*/
     /* rescale (in case canvas is being scaled)*/
     double client_w, client_h, xscale, yscale;
     double client_w, client_h, xscale, yscale;
@@ -311,10 +321,6 @@ Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent
     xscale = window_data->window->w / client_w;
     xscale = window_data->window->w / client_w;
     yscale = window_data->window->h / client_h;
     yscale = window_data->window->h / client_h;
 
 
-    /* check for pointer lock */
-    int isPointerLockSupported = emscripten_get_pointerlock_status(&pointerlock_status);
-    int isPointerLocked = isPointerLockSupported == EMSCRIPTEN_RESULT_SUCCESS  ? pointerlock_status.isActive : SDL_FALSE;
-
     if (isPointerLocked) {
     if (isPointerLocked) {
         residualx += mouseEvent->movementX * xscale;
         residualx += mouseEvent->movementX * xscale;
         residualy += mouseEvent->movementY * yscale;
         residualy += mouseEvent->movementY * yscale;
@@ -355,6 +361,9 @@ Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEve
     }
     }
 
 
     if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) {
     if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN) {
+        if (SDL_GetMouse()->relative_mode && !window_data->has_pointer_lock) {
+            emscripten_request_pointerlock(NULL, 0);  /* try to regrab lost pointer lock. */
+        }
         sdl_button_state = SDL_PRESSED;
         sdl_button_state = SDL_PRESSED;
         sdl_event_type = SDL_MOUSEBUTTONDOWN;
         sdl_event_type = SDL_MOUSEBUTTONDOWN;
     } else {
     } else {
@@ -371,11 +380,7 @@ Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEven
     SDL_WindowData *window_data = userData;
     SDL_WindowData *window_data = userData;
 
 
     int mx = mouseEvent->canvasX, my = mouseEvent->canvasY;
     int mx = mouseEvent->canvasX, my = mouseEvent->canvasY;
-    EmscriptenPointerlockChangeEvent pointerlock_status;
-
-    /* check for pointer lock */
-    int isPointerLockSupported = emscripten_get_pointerlock_status(&pointerlock_status);
-    int isPointerLocked = isPointerLockSupported == EMSCRIPTEN_RESULT_SUCCESS  ? pointerlock_status.isActive : SDL_FALSE;
+    const int isPointerLocked = window_data->has_pointer_lock;
 
 
     if (!isPointerLocked) {
     if (!isPointerLocked) {
         /* rescale (in case canvas is being scaled)*/
         /* rescale (in case canvas is being scaled)*/
@@ -632,6 +637,8 @@ Emscripten_RegisterEventHandlers(SDL_WindowData *data)
     emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch);
     emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch);
     emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch);
     emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch);
 
 
+    emscripten_set_pointerlockchange_callback(NULL, data, 0, Emscripten_HandlePointerLockChange);
+
     /* Keyboard events are awkward */
     /* Keyboard events are awkward */
     const char *keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
     const char *keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT);
     if (!keyElement) keyElement = "#window";
     if (!keyElement) keyElement = "#window";

+ 2 - 0
src/video/emscripten/SDL_emscriptenvideo.h

@@ -47,6 +47,8 @@ typedef struct SDL_WindowData
 
 
     SDL_bool finger_touching;  /* for mapping touch events to mice */
     SDL_bool finger_touching;  /* for mapping touch events to mice */
     SDL_FingerID first_finger;
     SDL_FingerID first_finger;
+
+    SDL_bool has_pointer_lock;
 } SDL_WindowData;
 } SDL_WindowData;
 
 
 #endif /* _SDL_emscriptenvideo_h */
 #endif /* _SDL_emscriptenvideo_h */