wineandroid: Add support for mouse events.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2017-06-08 10:16:41 +02:00
parent b0690b13da
commit db742a49c9
4 changed files with 165 additions and 0 deletions

View File

@ -30,6 +30,8 @@
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
@ -51,6 +53,7 @@ public class WineActivity extends Activity
private native String wine_init( String[] cmdline, String[] env );
public native void wine_desktop_changed( int width, int height );
public native void wine_surface_changed( int hwnd, Surface surface );
public native boolean wine_motion_event( int hwnd, int action, int x, int y, int state, int vscroll );
private final String LOGTAG = "wine";
private ProgressDialog progress_dialog;
@ -365,6 +368,12 @@ public void set_surface( SurfaceTexture surftex )
Log.i( LOGTAG, String.format( "set window surface hwnd %08x %s", hwnd, window_surface ));
wine_surface_changed( hwnd, window_surface );
}
public void get_event_pos( MotionEvent event, int[] pos )
{
pos[0] = Math.round( event.getX() + window_view.getLeft() );
pos[1] = Math.round( event.getY() + window_view.getTop() );
}
}
// View used for all Wine windows, backed by a TextureView
@ -411,6 +420,36 @@ public boolean onSurfaceTextureDestroyed( SurfaceTexture surftex )
public void onSurfaceTextureUpdated(SurfaceTexture surftex)
{
}
public boolean onGenericMotionEvent( MotionEvent event )
{
if (window.parent != null) return false; // let the parent handle it
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0)
{
int[] pos = new int[2];
window.get_event_pos( event, pos );
Log.i( LOGTAG, String.format( "view motion event win %08x action %d pos %d,%d buttons %04x view %d,%d",
window.hwnd, event.getAction(), pos[0], pos[1],
event.getButtonState(), getLeft(), getTop() ));
return wine_motion_event( window.hwnd, event.getAction(), pos[0], pos[1],
event.getButtonState(), (int)event.getAxisValue(MotionEvent.AXIS_VSCROLL) );
}
return super.onGenericMotionEvent(event);
}
public boolean onTouchEvent( MotionEvent event )
{
if (window.parent != null) return false; // let the parent handle it
int[] pos = new int[2];
window.get_event_pos( event, pos );
Log.i( LOGTAG, String.format( "view touch event win %08x action %d pos %d,%d buttons %04x view %d,%d",
window.hwnd, event.getAction(), pos[0], pos[1],
event.getButtonState(), getLeft(), getTop() ));
return wine_motion_event( window.hwnd, event.getAction(), pos[0], pos[1],
event.getButtonState(), 0 );
}
}
// The top-level desktop view group

View File

@ -26,6 +26,7 @@
#include <stdlib.h>
#include <jni.h>
#include <android/log.h>
#include <android/input.h>
#include <android/native_window_jni.h>
#include "windef.h"
@ -84,11 +85,14 @@ extern void init_monitors( int width, int height ) DECLSPEC_HIDDEN;
/* JNI entry points */
extern void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height ) DECLSPEC_HIDDEN;
extern void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface ) DECLSPEC_HIDDEN;
extern jboolean motion_event( JNIEnv *env, jobject obj, jint win, jint action,
jint x, jint y, jint state, jint vscroll ) DECLSPEC_HIDDEN;
enum event_type
{
DESKTOP_CHANGED,
SURFACE_CHANGED,
MOTION_EVENT,
};
union event_data
@ -108,6 +112,12 @@ union event_data
unsigned int width;
unsigned int height;
} surface;
struct
{
enum event_type type;
HWND hwnd;
INPUT input;
} motion;
};
int send_event( const union event_data *data );

View File

@ -391,6 +391,7 @@ static const JNINativeMethod methods[] =
{
{ "wine_desktop_changed", "(II)V", desktop_changed },
{ "wine_surface_changed", "(ILandroid/view/Surface;)V", surface_changed },
{ "wine_motion_event", "(IIIIII)Z", motion_event },
};
#define DECL_FUNCPTR(f) typeof(f) * p##f = NULL

View File

@ -252,6 +252,74 @@ void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface )
}
/***********************************************************************
* motion_event
*
* JNI callback, runs in the context of the Java thread.
*/
jboolean motion_event( JNIEnv *env, jobject obj, jint win, jint action, jint x, jint y, jint state, jint vscroll )
{
static LONG button_state;
union event_data data;
int prev_state;
int mask = action & AMOTION_EVENT_ACTION_MASK;
if (!( mask == AMOTION_EVENT_ACTION_DOWN ||
mask == AMOTION_EVENT_ACTION_UP ||
mask == AMOTION_EVENT_ACTION_SCROLL ||
mask == AMOTION_EVENT_ACTION_MOVE ||
mask == AMOTION_EVENT_ACTION_HOVER_MOVE ))
return JNI_FALSE;
prev_state = InterlockedExchange( &button_state, state );
data.type = MOTION_EVENT;
data.motion.hwnd = LongToHandle( win );
data.motion.input.type = INPUT_MOUSE;
data.motion.input.u.mi.dx = x;
data.motion.input.u.mi.dy = y;
data.motion.input.u.mi.mouseData = 0;
data.motion.input.u.mi.time = 0;
data.motion.input.u.mi.dwExtraInfo = 0;
data.motion.input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
switch (action & AMOTION_EVENT_ACTION_MASK)
{
case AMOTION_EVENT_ACTION_DOWN:
if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_PRIMARY)
data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_SECONDARY)
data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
if ((state & ~prev_state) & AMOTION_EVENT_BUTTON_TERTIARY)
data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
if (!(state & ~prev_state)) /* touch event */
data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
break;
case AMOTION_EVENT_ACTION_UP:
if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_PRIMARY)
data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_SECONDARY)
data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
if ((prev_state & ~state) & AMOTION_EVENT_BUTTON_TERTIARY)
data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
if (!(prev_state & ~state)) /* touch event */
data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
break;
case AMOTION_EVENT_ACTION_SCROLL:
data.motion.input.u.mi.dwFlags |= MOUSEEVENTF_WHEEL;
data.motion.input.u.mi.mouseData = vscroll < 0 ? -WHEEL_DELTA : WHEEL_DELTA;
break;
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
break;
default:
return JNI_FALSE;
}
send_event( &data );
return JNI_TRUE;
}
/***********************************************************************
* init_event_queue
*/
@ -328,6 +396,15 @@ static int process_events( DWORD mask )
{
case SURFACE_CHANGED:
break; /* always process it to unblock other threads */
case MOTION_EVENT:
if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|
MOUSEEVENTF_MIDDLEDOWN|MOUSEEVENTF_LEFTUP|
MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
{
if (mask & QS_MOUSEBUTTON) break;
}
else if (mask & QS_MOUSEMOVE) break;
continue; /* skip it */
default:
if (mask & QS_SENDMESSAGE) break;
continue; /* skip it */
@ -355,6 +432,44 @@ static int process_events( DWORD mask )
register_native_window( event->data.surface.hwnd, event->data.surface.window );
break;
case MOTION_EVENT:
{
HWND capture = get_capture_window();
if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN|MOUSEEVENTF_MIDDLEDOWN))
TRACE( "BUTTONDOWN pos %d,%d hwnd %p flags %x\n",
event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
event->data.motion.hwnd, event->data.motion.input.u.mi.dwFlags );
else if (event->data.motion.input.u.mi.dwFlags & (MOUSEEVENTF_LEFTUP|MOUSEEVENTF_RIGHTUP|MOUSEEVENTF_MIDDLEUP))
TRACE( "BUTTONUP pos %d,%d hwnd %p flags %x\n",
event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
event->data.motion.hwnd, event->data.motion.input.u.mi.dwFlags );
else
TRACE( "MOUSEMOVE pos %d,%d hwnd %p flags %x\n",
event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
event->data.motion.hwnd, event->data.motion.input.u.mi.dwFlags );
if (!capture && (event->data.motion.input.u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE))
{
RECT rect;
SetRect( &rect, event->data.motion.input.u.mi.dx, event->data.motion.input.u.mi.dy,
event->data.motion.input.u.mi.dx + 1, event->data.motion.input.u.mi.dy + 1 );
MapWindowPoints( 0, event->data.motion.hwnd, (POINT *)&rect, 2 );
SERVER_START_REQ( update_window_zorder )
{
req->window = wine_server_user_handle( event->data.motion.hwnd );
req->rect.left = rect.left;
req->rect.top = rect.top;
req->rect.right = rect.right;
req->rect.bottom = rect.bottom;
wine_server_call( req );
}
SERVER_END_REQ;
}
__wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input );
}
break;
default:
FIXME( "got event %u\n", event->data.type );
}