src/video/android/SDL_androidtouch.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 01 Apr 2015 12:14:56 -0400
changeset 9449 a65088766e35
parent 9441 fc7522030729
child 9450 bcb16ffce95b
permissions -rw-r--r--
Android: more separate-mouse-and-touch work.

This avoids a hint lookup for each mouse event we get by setting a static Java
variable from native code during our hint watcher callback.

Also attempts to do the right thing with mouse buttons if you happen to be
on an API14 (Ice Cream Sandwich, Android 4.0) or later device. We still
target API12 (Honeycomb MR1, Android 3.1) for SDL 2.0.4 though.

This isn't tested, so I'm pushing to see what the Android buildbot says. Stand
back, I'm a professional!
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_ANDROID
    24 
    25 #include <android/log.h>
    26 
    27 #include "SDL_hints.h"
    28 #include "SDL_events.h"
    29 #include "SDL_log.h"
    30 #include "SDL_androidtouch.h"
    31 #include "../../events/SDL_mouse_c.h"
    32 #include "../../events/SDL_touch_c.h"
    33 #include "../../core/android/SDL_android.h"
    34 
    35 #define ACTION_DOWN 0
    36 #define ACTION_UP 1
    37 #define ACTION_MOVE 2
    38 #define ACTION_CANCEL 3
    39 #define ACTION_OUTSIDE 4
    40 #define ACTION_POINTER_DOWN 5
    41 #define ACTION_POINTER_UP 6
    42 
    43 static void Android_GetWindowCoordinates(float x, float y,
    44                                          int *window_x, int *window_y)
    45 {
    46     int window_w, window_h;
    47 
    48     SDL_GetWindowSize(Android_Window, &window_w, &window_h);
    49     *window_x = (int)(x * window_w);
    50     *window_y = (int)(y * window_h);
    51 }
    52 
    53 static volatile SDL_bool separate_mouse_and_touch = SDL_FALSE;
    54 
    55 static void
    56 SeparateEventsHintWatcher(void *userdata, const char *name,
    57                           const char *oldValue, const char *newValue)
    58 {
    59     separate_mouse_and_touch = (newValue && (SDL_strcmp(newValue, "1") == 0));
    60     JNIEnv *env = Android_JNI_GetEnv();
    61     jfieldID fid = (*env)->GetStaticFieldID(env, mActivityClass, "mSeparateMouseAndTouch", "Z");
    62     (*env)->SetStaticBooleanField(env, mActivityClass, fid, separate_mouse_and_touch ? JNI_TRUE : JNI_FALSE);
    63 }
    64 
    65 void Android_InitTouch(void)
    66 {
    67     int i;
    68     int* ids;
    69     const int number = Android_JNI_GetTouchDeviceIds(&ids);
    70 
    71     SDL_AddHintCallback(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH,
    72                         SeparateEventsHintWatcher, NULL);
    73 
    74     if (0 < number) {
    75         for (i = 0; i < number; ++i) {
    76             SDL_AddTouch((SDL_TouchID) ids[i], ""); /* no error handling */
    77         }
    78         SDL_free(ids);
    79     }
    80 }
    81 
    82 void Android_QuitTouch(void)
    83 {
    84     SDL_DelHintCallback(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH,
    85                         SeparateEventsHintWatcher, NULL);
    86     separate_mouse_and_touch = SDL_FALSE;
    87 }
    88 
    89 void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p)
    90 {
    91     SDL_TouchID touchDeviceId = 0;
    92     SDL_FingerID fingerId = 0;
    93     int window_x, window_y;
    94     static SDL_FingerID pointerFingerID = 0;
    95 
    96     if (!Android_Window) {
    97         return;
    98     }
    99 
   100     touchDeviceId = (SDL_TouchID)touch_device_id_in;
   101     if (SDL_AddTouch(touchDeviceId, "") < 0) {
   102         SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__);
   103     }
   104 
   105     fingerId = (SDL_FingerID)pointer_finger_id_in;
   106     switch (action) {
   107         case ACTION_DOWN:
   108             /* Primary pointer down */
   109             Android_GetWindowCoordinates(x, y, &window_x, &window_y);
   110             if (!separate_mouse_and_touch) {
   111                 /* send moved event */
   112                 SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
   113                 /* send mouse down event */
   114                 SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
   115             }
   116             pointerFingerID = fingerId;
   117         case ACTION_POINTER_DOWN:
   118             /* Non primary pointer down */
   119             SDL_SendTouch(touchDeviceId, fingerId, SDL_TRUE, x, y, p);
   120             break;
   121 
   122         case ACTION_MOVE:
   123             if (!pointerFingerID) {
   124                 Android_GetWindowCoordinates(x, y, &window_x, &window_y);
   125                 if (!separate_mouse_and_touch) {
   126                     /* send moved event */
   127                     SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
   128                 }
   129             }
   130             SDL_SendTouchMotion(touchDeviceId, fingerId, x, y, p);
   131             break;
   132 
   133         case ACTION_UP:
   134             /* Primary pointer up */
   135             if (!separate_mouse_and_touch) {
   136                 /* send mouse up */
   137                 pointerFingerID = (SDL_FingerID) 0;
   138                 SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
   139             }
   140         case ACTION_POINTER_UP:
   141             /* Non primary pointer up */
   142             SDL_SendTouch(touchDeviceId, fingerId, SDL_FALSE, x, y, p);
   143             break;
   144 
   145         default:
   146             break;
   147     }
   148 }
   149 
   150 #endif /* SDL_VIDEO_DRIVER_ANDROID */
   151 
   152 /* vi: set ts=4 sw=4 expandtab: */