* Improve mouse support in Android. These changes require Android API v12 to compile
authorJoseba García Etxebarria <joseba.gar@gmail.com>
Tue, 24 Mar 2015 20:45:29 +0100
changeset 9438fff5af5de6dd
parent 9437 569cfb86df95
child 9439 0d01b53cdbea
* Improve mouse support in Android. These changes require Android API v12 to compile
android-project/src/org/libsdl/app/SDLActivity.java
include/SDL_hints.h
src/core/android/SDL_android.c
src/video/android/SDL_androidmouse.c
src/video/android/SDL_androidmouse.h
src/video/android/SDL_androidtouch.c
     1.1 --- a/android-project/src/org/libsdl/app/SDLActivity.java	Wed Mar 25 10:19:10 2015 -0400
     1.2 +++ b/android-project/src/org/libsdl/app/SDLActivity.java	Tue Mar 24 20:45:29 2015 +0100
     1.3 @@ -401,6 +401,7 @@
     1.4      public static native void onNativeKeyDown(int keycode);
     1.5      public static native void onNativeKeyUp(int keycode);
     1.6      public static native void onNativeKeyboardFocusLost();
     1.7 +    public static native void onNativeMouse(int button, int action, float x, float y);
     1.8      public static native void onNativeTouch(int touchDevId, int pointerFingerId,
     1.9                                              int action, float x, 
    1.10                                              float y, float p);
    1.11 @@ -1087,8 +1088,8 @@
    1.12          // Dispatch the different events depending on where they come from
    1.13          // Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
    1.14          // So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD
    1.15 -        
    1.16 -        if ( (event.getSource() & 0x00000401) != 0 || /* API 12: SOURCE_GAMEPAD */
    1.17 +
    1.18 +        if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 ||
    1.19                     (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) {
    1.20              if (event.getAction() == KeyEvent.ACTION_DOWN) {
    1.21                  if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
    1.22 @@ -1125,50 +1126,58 @@
    1.23          final int pointerCount = event.getPointerCount();
    1.24          int action = event.getActionMasked();
    1.25          int pointerFingerId;
    1.26 +        int mouseButton;
    1.27          int i = -1;
    1.28          float x,y,p;
    1.29 -        
    1.30 -        switch(action) {
    1.31 -            case MotionEvent.ACTION_MOVE:
    1.32 -                for (i = 0; i < pointerCount; i++) {
    1.33 +
    1.34 +        if (event.getSource() == InputDevice.SOURCE_MOUSE &&
    1.35 +            SDLActivity.nativeGetHint("SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH").equals("1")) {
    1.36 +                mouseButton = 1;    // For Android==12 all mouse buttons are the left button
    1.37 + 
    1.38 +                SDLActivity.onNativeMouse(mouseButton, action, event.getX(0), event.getY(0));
    1.39 +        } else {
    1.40 +            switch(action) {
    1.41 +                case MotionEvent.ACTION_MOVE:
    1.42 +                    for (i = 0; i < pointerCount; i++) {
    1.43 +                        pointerFingerId = event.getPointerId(i);
    1.44 +                        x = event.getX(i) / mWidth;
    1.45 +                        y = event.getY(i) / mHeight;
    1.46 +                        p = event.getPressure(i);
    1.47 +                        SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
    1.48 +                    }
    1.49 +                    break;
    1.50 +                
    1.51 +                case MotionEvent.ACTION_UP:
    1.52 +                case MotionEvent.ACTION_DOWN:
    1.53 +                    // Primary pointer up/down, the index is always zero
    1.54 +                    i = 0;
    1.55 +                case MotionEvent.ACTION_POINTER_UP:
    1.56 +                case MotionEvent.ACTION_POINTER_DOWN:
    1.57 +                    // Non primary pointer up/down
    1.58 +                    if (i == -1) {
    1.59 +                        i = event.getActionIndex();
    1.60 +                    }
    1.61 +                    
    1.62                      pointerFingerId = event.getPointerId(i);
    1.63                      x = event.getX(i) / mWidth;
    1.64                      y = event.getY(i) / mHeight;
    1.65                      p = event.getPressure(i);
    1.66                      SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
    1.67 -                }
    1.68 -                break;
    1.69 -            
    1.70 -            case MotionEvent.ACTION_UP:
    1.71 -            case MotionEvent.ACTION_DOWN:
    1.72 -                // Primary pointer up/down, the index is always zero
    1.73 -                i = 0;
    1.74 -            case MotionEvent.ACTION_POINTER_UP:
    1.75 -            case MotionEvent.ACTION_POINTER_DOWN:
    1.76 -                // Non primary pointer up/down
    1.77 -                if (i == -1) {
    1.78 -                    i = event.getActionIndex();
    1.79 -                }
    1.80 +                    break;
    1.81                  
    1.82 -                pointerFingerId = event.getPointerId(i);
    1.83 -                x = event.getX(i) / mWidth;
    1.84 -                y = event.getY(i) / mHeight;
    1.85 -                p = event.getPressure(i);
    1.86 -                SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
    1.87 -                break;
    1.88 -            
    1.89 -            case MotionEvent.ACTION_CANCEL:
    1.90 -                for (i = 0; i < pointerCount; i++) {
    1.91 -                    pointerFingerId = event.getPointerId(i);
    1.92 -                    x = event.getX(i) / mWidth;
    1.93 -                    y = event.getY(i) / mHeight;
    1.94 -                    p = event.getPressure(i);
    1.95 -                    SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p);
    1.96 -                }
    1.97 -                break;
    1.98 +                case MotionEvent.ACTION_CANCEL:
    1.99 +                    for (i = 0; i < pointerCount; i++) {
   1.100 +                        pointerFingerId = event.getPointerId(i);
   1.101 +                        x = event.getX(i) / mWidth;
   1.102 +                        y = event.getY(i) / mHeight;
   1.103 +                        p = event.getPressure(i);
   1.104 +                        SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p);
   1.105 +                    }
   1.106 +                    break;
   1.107  
   1.108 -            default:
   1.109 -                break;
   1.110 +                default:
   1.111 +                    break;
   1.112 +            }
   1.113          }
   1.114  
   1.115          return true;
   1.116 @@ -1497,11 +1506,47 @@
   1.117      }            
   1.118  }
   1.119  
   1.120 -class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
   1.121 +class SDLGenericMotionListener implements View.OnGenericMotionListener {
   1.122      // Generic Motion (mouse hover, joystick...) events go here
   1.123      // We only have joysticks yet
   1.124      @Override
   1.125      public boolean onGenericMotion(View v, MotionEvent event) {
   1.126 -        return SDLActivity.handleJoystickMotionEvent(event);
   1.127 +        float x, y;
   1.128 +        int mouseButton;
   1.129 +        int action;
   1.130 +
   1.131 +        switch ( event.getSource() ) {
   1.132 +            case InputDevice.SOURCE_JOYSTICK:
   1.133 +            case InputDevice.SOURCE_GAMEPAD:
   1.134 +            case InputDevice.SOURCE_DPAD:
   1.135 +                SDLActivity.handleJoystickMotionEvent(event);
   1.136 +                return true;
   1.137 +
   1.138 +            case InputDevice.SOURCE_MOUSE:
   1.139 +                action = event.getActionMasked();
   1.140 +                switch(event.getActionMasked()) {
   1.141 +                    case MotionEvent.ACTION_SCROLL:
   1.142 +                        x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
   1.143 +                        y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
   1.144 +                        SDLActivity.onNativeMouse(0, action, x, y);
   1.145 +                        return true;
   1.146 +
   1.147 +                    case MotionEvent.ACTION_HOVER_MOVE:
   1.148 +                        x = event.getX(0);
   1.149 +                        y = event.getY(0);
   1.150 +
   1.151 +                        SDLActivity.onNativeMouse(0, action, x, y);
   1.152 +                        return true;
   1.153 +
   1.154 +                    default:
   1.155 +                        break;
   1.156 +                }
   1.157 +
   1.158 +            default:
   1.159 +                break;
   1.160 +        }
   1.161 +
   1.162 +        // Event was not managed
   1.163 +        return false;
   1.164      }
   1.165  }
     2.1 --- a/include/SDL_hints.h	Wed Mar 25 10:19:10 2015 -0400
     2.2 +++ b/include/SDL_hints.h	Tue Mar 24 20:45:29 2015 +0100
     2.3 @@ -532,6 +532,18 @@
     2.4   */
     2.5  #define SDL_HINT_IME_INTERNAL_EDITING "SDL_IME_INTERNAL_EDITING"
     2.6  
     2.7 + /**
     2.8 + * \brief A variable to control whether mouse and touch events are to be treated together or separately
     2.9 + *
    2.10 + * The variable can be set to the following values:
    2.11 + *   "0"       - Mouse events will be handled as touch events, and touch will raise fake mouse
    2.12 + *               events. This is the behaviour of SDL <= 2.0.3. (default)
    2.13 + *   "1"       - Mouse events will be handled separately from pure touch events.
    2.14 + *
    2.15 + * The value of this hint is used at runtime, so it can be changed at any time.
    2.16 + */
    2.17 +#define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH"
    2.18 +
    2.19  /**
    2.20   *  \brief override the binding element for keyboard inputs for Emscripten builds
    2.21   *
     3.1 --- a/src/core/android/SDL_android.c	Wed Mar 25 10:19:10 2015 -0400
     3.2 +++ b/src/core/android/SDL_android.c	Tue Mar 24 20:45:29 2015 +0100
     3.3 @@ -32,6 +32,7 @@
     3.4  
     3.5  #include "../../events/SDL_events_c.h"
     3.6  #include "../../video/android/SDL_androidkeyboard.h"
     3.7 +#include "../../video/android/SDL_androidmouse.h"
     3.8  #include "../../video/android/SDL_androidtouch.h"
     3.9  #include "../../video/android/SDL_androidvideo.h"
    3.10  #include "../../video/android/SDL_androidwindow.h"
    3.11 @@ -293,6 +294,22 @@
    3.12      Android_OnTouch(touch_device_id_in, pointer_finger_id_in, action, x, y, p);
    3.13  }
    3.14  
    3.15 +/* Mouse */
    3.16 +JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeMouse(
    3.17 +                                    JNIEnv* env, jclass jcls,
    3.18 +                                    jint button, jint action, jfloat x, jfloat y)
    3.19 +{
    3.20 +    Android_OnMouse(button, action, x, y);
    3.21 +}
    3.22 +
    3.23 +/* Mouse */
    3.24 +JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeMouse(
    3.25 +                                    JNIEnv* env, jclass jcls,
    3.26 +                                    jint button, jint action, jfloat x, jfloat y)
    3.27 +{
    3.28 +    Android_OnMouse(button, action, x, y);
    3.29 +}
    3.30 +
    3.31  /* Accelerometer */
    3.32  JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeAccel(
    3.33                                      JNIEnv* env, jclass jcls,
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/video/android/SDL_androidmouse.c	Tue Mar 24 20:45:29 2015 +0100
     4.3 @@ -0,0 +1,85 @@
     4.4 +/*
     4.5 +  Simple DirectMedia Layer
     4.6 +  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4.7 +
     4.8 +  This software is provided 'as-is', without any express or implied
     4.9 +  warranty.  In no event will the authors be held liable for any damages
    4.10 +  arising from the use of this software.
    4.11 +
    4.12 +  Permission is granted to anyone to use this software for any purpose,
    4.13 +  including commercial applications, and to alter it and redistribute it
    4.14 +  freely, subject to the following restrictions:
    4.15 +
    4.16 +  1. The origin of this software must not be misrepresented; you must not
    4.17 +     claim that you wrote the original software. If you use this software
    4.18 +     in a product, an acknowledgment in the product documentation would be
    4.19 +     appreciated but is not required.
    4.20 +  2. Altered source versions must be plainly marked as such, and must not be
    4.21 +     misrepresented as being the original software.
    4.22 +  3. This notice may not be removed or altered from any source distribution.
    4.23 +*/
    4.24 +
    4.25 +#include "../../SDL_internal.h"
    4.26 +
    4.27 +#if SDL_VIDEO_DRIVER_ANDROID
    4.28 +
    4.29 +#include "SDL_androidmouse.h"
    4.30 +#include "SDL_Log.h"
    4.31 +
    4.32 +#include "SDL_events.h"
    4.33 +#include "../../events/SDL_mouse_c.h"
    4.34 +
    4.35 +#include "../../core/android/SDL_android.h"
    4.36 +
    4.37 +#define ACTION_DOWN 0
    4.38 +#define ACTION_UP 1
    4.39 +#define ACTION_HOVER_MOVE 7
    4.40 +#define ACTION_SCROLL 8
    4.41 +#define BUTTON_PRIMARY 1
    4.42 +#define BUTTON_SECONDARY 2
    4.43 +#define BUTTON_TERTIARY 4
    4.44 +
    4.45 +void Android_OnMouse( int androidButton, int action, float x, float y) {
    4.46 +    static Uint8 SDLButton;
    4.47 +
    4.48 +    if (!Android_Window) {
    4.49 +        return;
    4.50 +    }
    4.51 +
    4.52 +    switch(action) {
    4.53 +        case ACTION_DOWN:
    4.54 +            // Determine which button originated the event, and store it for ACTION_UP
    4.55 +            SDLButton = SDL_BUTTON_LEFT;
    4.56 +            if (androidButton == BUTTON_SECONDARY) {
    4.57 +                SDLButton = SDL_BUTTON_RIGHT;
    4.58 +            } else if (androidButton == BUTTON_TERTIARY) {
    4.59 +                SDLButton = SDL_BUTTON_MIDDLE;
    4.60 +            }
    4.61 +            SDL_SendMouseMotion(Android_Window, 0, 0, x, y);
    4.62 +            SDL_SendMouseButton(Android_Window, 0, SDL_PRESSED, SDLButton);
    4.63 +            break;
    4.64 +
    4.65 +        case ACTION_UP:
    4.66 +            // Android won't give us the button that originated the ACTION_DOWN event, so we'll
    4.67 +            // assume it's the one we stored
    4.68 +            SDL_SendMouseMotion(Android_Window, 0, 0, x, y);
    4.69 +            SDL_SendMouseButton(Android_Window, 0, SDL_RELEASED, SDLButton);
    4.70 +            break;
    4.71 +
    4.72 +        case ACTION_HOVER_MOVE:
    4.73 +            SDL_SendMouseMotion(Android_Window, 0, 0, x, y);
    4.74 +            break;
    4.75 +
    4.76 +        case ACTION_SCROLL:
    4.77 +            SDL_SendMouseWheel(Android_Window, 0, x, y);
    4.78 +            break;
    4.79 +
    4.80 +        default:
    4.81 +            break;
    4.82 +    }
    4.83 +}
    4.84 +
    4.85 +#endif /* SDL_VIDEO_DRIVER_ANDROID */
    4.86 +
    4.87 +/* vi: set ts=4 sw=4 expandtab: */
    4.88 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/video/android/SDL_androidmouse.h	Tue Mar 24 20:45:29 2015 +0100
     5.3 @@ -0,0 +1,31 @@
     5.4 +/*
     5.5 +  Simple DirectMedia Layer
     5.6 +  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     5.7 +
     5.8 +  This software is provided 'as-is', without any express or implied
     5.9 +  warranty.  In no event will the authors be held liable for any damages
    5.10 +  arising from the use of this software.
    5.11 +
    5.12 +  Permission is granted to anyone to use this software for any purpose,
    5.13 +  including commercial applications, and to alter it and redistribute it
    5.14 +  freely, subject to the following restrictions:
    5.15 +
    5.16 +  1. The origin of this software must not be misrepresented; you must not
    5.17 +     claim that you wrote the original software. If you use this software
    5.18 +     in a product, an acknowledgment in the product documentation would be
    5.19 +     appreciated but is not required.
    5.20 +  2. Altered source versions must be plainly marked as such, and must not be
    5.21 +     misrepresented as being the original software.
    5.22 +  3. This notice may not be removed or altered from any source distribution.
    5.23 +*/
    5.24 +
    5.25 +#ifndef _SDL_androidmouse_h
    5.26 +#define _SDL_androidmouse_h
    5.27 +
    5.28 +#include "SDL_androidvideo.h"
    5.29 +
    5.30 +extern void Android_OnMouse( int button, int action, float x, float y);
    5.31 +
    5.32 +#endif /* _SDL_androidmouse_h */
    5.33 +
    5.34 +/* vi: set ts=4 sw=4 expandtab: */
     6.1 --- a/src/video/android/SDL_androidtouch.c	Wed Mar 25 10:19:10 2015 -0400
     6.2 +++ b/src/video/android/SDL_androidtouch.c	Tue Mar 24 20:45:29 2015 +0100
     6.3 @@ -69,6 +69,7 @@
     6.4      SDL_TouchID touchDeviceId = 0;
     6.5      SDL_FingerID fingerId = 0;
     6.6      int window_x, window_y;
     6.7 +    char * hint;
     6.8      static SDL_FingerID pointerFingerID = 0;
     6.9  
    6.10      if (!Android_Window) {
    6.11 @@ -81,40 +82,47 @@
    6.12      }
    6.13  
    6.14      fingerId = (SDL_FingerID)pointer_finger_id_in;
    6.15 +    hint = SDL_GetHint("SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH");
    6.16      switch (action) {
    6.17          case ACTION_DOWN:
    6.18              /* Primary pointer down */
    6.19              Android_GetWindowCoordinates(x, y, &window_x, &window_y);
    6.20 -            /* send moved event */
    6.21 -            SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
    6.22 -            /* send mouse down event */
    6.23 -            SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
    6.24 +            if ((!hint) || (hint && SDL_strcmp(hint, "1") != 0)) {
    6.25 +                /* send moved event */
    6.26 +                SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
    6.27 +                /* send mouse down event */
    6.28 +                SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
    6.29 +            }
    6.30              pointerFingerID = fingerId;
    6.31          case ACTION_POINTER_DOWN:
    6.32              /* Non primary pointer down */
    6.33              SDL_SendTouch(touchDeviceId, fingerId, SDL_TRUE, x, y, p);
    6.34              break;
    6.35 -            
    6.36 +
    6.37          case ACTION_MOVE:
    6.38              if (!pointerFingerID) {
    6.39                  Android_GetWindowCoordinates(x, y, &window_x, &window_y);
    6.40  
    6.41 -                /* send moved event */
    6.42 -                SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
    6.43 +                if ((!hint) || (hint && SDL_strcmp(hint, "1") != 0)) {
    6.44 +                    /* send moved event */
    6.45 +                    SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y);
    6.46 +                }
    6.47              }
    6.48              SDL_SendTouchMotion(touchDeviceId, fingerId, x, y, p);
    6.49              break;
    6.50 -            
    6.51 +
    6.52          case ACTION_UP:
    6.53              /* Primary pointer up */
    6.54 -            /* send mouse up */
    6.55 -            pointerFingerID = (SDL_FingerID) 0;
    6.56 -            SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
    6.57 +            if ((!hint) || (hint && SDL_strcmp(hint, "1") != 0)) {
    6.58 +                /* send mouse up */
    6.59 +                pointerFingerID = (SDL_FingerID) 0;
    6.60 +                SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
    6.61 +            }
    6.62          case ACTION_POINTER_UP:
    6.63              /* Non primary pointer up */
    6.64              SDL_SendTouch(touchDeviceId, fingerId, SDL_FALSE, x, y, p);
    6.65              break;
    6.66 -            
    6.67 +
    6.68          default:
    6.69              break;
    6.70      }