]> git.sesse.net Git - vlc/commitdiff
Add Win32 gestures helper
authorLudovic Fauvet <etix@videolan.org>
Fri, 14 Feb 2014 19:00:48 +0000 (20:00 +0100)
committerJean-Baptiste Kempf <jb@videolan.org>
Sun, 16 Feb 2014 22:51:13 +0000 (23:51 +0100)
This is a helper to take action on touchscreens on Windows 7 or later
It uses the braindead WM_GESTURE API and supports volume, seek (1 and 2
fingers), play/pause (2finger touch) and fullscreen (zoom gesture)

The API is simple so other UI element can use it, notably Qt and the
vouts

This has been edited by jb too

Signed-off-by: Jean-Baptiste Kempf <jb@videolan.org>
modules/control/win32touch.c [new file with mode: 0644]
modules/control/win32touch.h [new file with mode: 0644]

diff --git a/modules/control/win32touch.c b/modules/control/win32touch.c
new file mode 100644 (file)
index 0000000..03d7953
--- /dev/null
@@ -0,0 +1,242 @@
+/*****************************************************************************
+ * win32touch.c: touch gestures recognition
+ *****************************************************************************
+ * Copyright © 2013-2014 VideoLAN
+ *
+ * Authors: Ludovic Fauvet <etix@videolan.org>
+ *          Jean-Baptiste Kempf <jb@videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "win32touch.h"
+
+#include <vlc_keys.h>
+
+#include <assert.h>
+
+LRESULT DecodeGesture( vlc_object_t *p_this, win32_gesture_sys_t *p_gesture,
+                       HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+    if( !p_gesture )
+        return DefWindowProc( hWnd, message, wParam, lParam );
+
+    GESTUREINFO gi;
+    ZeroMemory( &gi, sizeof( GESTUREINFO ) );
+    gi.cbSize = sizeof( GESTUREINFO );
+
+    BOOL bResult  = p_gesture->OurGetGestureInfo((HGESTUREINFO)lParam, &gi);
+    BOOL bHandled = FALSE; /* Needed to release the handle */
+
+    if( bResult )
+    {
+        switch ( gi.dwID )
+        {
+            case GID_BEGIN:
+                /* Set the win32_gesture_sys_t values */
+                p_gesture->i_beginx      = gi.ptsLocation.x;
+                p_gesture->i_beginy      = gi.ptsLocation.y;
+                p_gesture->i_lasty       = -1;
+                p_gesture->b_2fingers    = false;
+                break;
+            case GID_END:
+                if( p_gesture->i_type != 0 &&
+                    p_gesture->i_action == GESTURE_ACTION_JUMP )
+                {
+                    int action_id;
+                    if( p_gesture->i_beginx > gi.ptsLocation.x )
+                    {
+                        if( p_gesture->b_2fingers )
+                            action_id = ACTIONID_JUMP_BACKWARD_MEDIUM;
+                        else
+                            action_id = ACTIONID_JUMP_BACKWARD_SHORT;
+                    }
+                    else
+                    {
+                        if( p_gesture->b_2fingers )
+                            action_id = ACTIONID_JUMP_FORWARD_MEDIUM;
+                        else
+                            action_id = ACTIONID_JUMP_FORWARD_SHORT;
+                    }
+                    var_SetInteger( p_this->p_libvlc, "key-action", action_id );
+                }
+                /* Reset the values */
+                p_gesture->i_action = GESTURE_ACTION_UNDEFINED;
+                p_gesture->i_type = p_gesture->i_beginx = p_gesture->i_beginy = -1;
+                p_gesture->b_2fingers = false;
+                break;
+            case GID_PAN:
+                p_gesture->i_type = GID_PAN;
+                bHandled = TRUE;
+
+                if( (DWORD)gi.ullArguments > 0 )
+                    p_gesture->b_2fingers = true;
+
+                if( p_gesture->i_action == GESTURE_ACTION_UNDEFINED )
+                {
+                    if( abs( p_gesture->i_beginx - gi.ptsLocation.x ) +
+                        abs( p_gesture->i_beginy - gi.ptsLocation.y ) > 50 )
+                    {
+                        if( abs( p_gesture->i_beginx - gi.ptsLocation.x ) >
+                            abs( p_gesture->i_beginy - gi.ptsLocation.y ) )
+                           p_gesture->i_action =  GESTURE_ACTION_JUMP;
+                        else if ( p_gesture->b_2fingers )
+                           p_gesture->i_action = GESTURE_ACTION_BRIGHTNESS;
+                        else
+                           p_gesture->i_action =  GESTURE_ACTION_VOLUME;
+                    }
+                }
+
+                if( p_gesture->i_action == GESTURE_ACTION_VOLUME )
+                {
+                    int offset = p_gesture->i_beginy - gi.ptsLocation.y;
+                    if( offset > 0 )
+                        var_SetInteger( p_this->p_libvlc, "key-action", ACTIONID_VOL_UP );
+                    else
+                        var_SetInteger( p_this->p_libvlc, "key-action", ACTIONID_VOL_DOWN );
+                }
+                else if ( p_gesture->i_action == GESTURE_ACTION_BRIGHTNESS )
+                {
+                    /* Currently unimplemented
+                    if( p_gesture->i_lasty == -1 )
+                        p_gesture->i_lasty = p_gesture->i_beginy;
+
+                    if( p_gesture->i_lasty - p_gesture->i_beginy > 80 )
+                    {
+                        var_SetInteger( p_this->p_libvlc, "key-action", ACTIONID_BRIGHTNESS_DOWN );
+                        p_gesture->i_lasty = gi.ptsLocation.y;
+                    }
+                    else if ( p_gesture->i_lasty - p_gesture->i_beginy < 80 )
+                    {
+                        var_SetInteger( p_this->p_libvlc, "key-action", ACTIONID_BRIGHTNESS_UP );
+                        p_gesture->i_lasty = gi.ptsLocation.y;
+                    } */
+                }
+                break;
+            case GID_TWOFINGERTAP:
+                p_gesture->i_type = GID_TWOFINGERTAP;
+                var_SetInteger( p_this->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE );
+                bHandled = TRUE;
+                break;
+            case GID_ZOOM:
+                p_gesture->i_type = GID_ZOOM;
+                switch( gi.dwFlags )
+                {
+                    case GF_BEGIN:
+                        p_gesture->i_ullArguments = gi.ullArguments;
+                        break;
+                    case GF_END:
+                        {
+                            double k = (double)(gi.ullArguments) /
+                                       (double)(p_gesture->i_ullArguments);
+                            if( k > 1 )
+                                var_SetInteger( p_this->p_libvlc, "key-action",
+                                        ACTIONID_TOGGLE_FULLSCREEN );
+                            else
+                                var_SetInteger( p_this->p_libvlc, "key-action",
+                                        ACTIONID_LEAVE_FULLSCREEN );
+                        }
+                        break;
+                    default:
+                        assert(0);
+                }
+                bHandled = TRUE;
+                break;
+            case WM_VSCROLL:
+                bHandled = TRUE;
+                break;
+            default:
+                break;
+        }
+    }
+    else
+    {
+        DWORD dwErr = GetLastError();
+        if( dwErr > 0 )
+            msg_Err( p_this, "Could not retrieve a valid GESTUREINFO structure" );
+    }
+
+
+    if( bHandled )
+    {
+        /* Close the Handle, if we handled the gesture, a contrario
+         * from the doc example */
+        p_gesture->OurCloseGestureInfoHandle((HGESTUREINFO)lParam);
+        return 0;
+    }
+    else
+        return DefWindowProc( hWnd, message, wParam, lParam );
+}
+
+BOOL InitGestures( HWND hwnd, win32_gesture_sys_t **pp_gesture )
+{
+    BOOL result = FALSE;
+    GESTURECONFIG config = { 0, 0, 0 };
+    config.dwID    = GID_PAN;
+    config.dwWant  = GC_PAN |
+                     GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY |
+                     GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
+    config.dwBlock = GC_PAN_WITH_INERTIA;
+
+    win32_gesture_sys_t *p_gesture = malloc( sizeof(win32_gesture_sys_t) );
+    if( !p_gesture )
+    {
+        *pp_gesture = NULL;
+        return FALSE;
+    }
+
+    HINSTANCE h_user32_dll = LoadLibrary(TEXT("user32.dll"));
+    if( !h_user32_dll )
+    {
+        *pp_gesture = NULL;
+        free( p_gesture );
+        return FALSE;
+    }
+
+    BOOL (WINAPI *OurSetGestureConfig) (HWND, DWORD, UINT, PGESTURECONFIG, UINT);
+    OurSetGestureConfig = (void *)GetProcAddress(h_user32_dll, "SetGestureConfig");
+
+    p_gesture->OurCloseGestureInfoHandle =
+        (void *)GetProcAddress(h_user32_dll, "CloseGestureInfoHandle" );
+    p_gesture->OurGetGestureInfo =
+        (void *)GetProcAddress(h_user32_dll, "GetGestureInfo");
+    if( OurSetGestureConfig )
+    {
+        result = OurSetGestureConfig(
+                hwnd,
+                0,
+                1,
+                &config,
+                sizeof( GESTURECONFIG )
+                );
+    }
+
+    p_gesture->i_type     = 0;
+    p_gesture->b_2fingers = false;
+    p_gesture->i_action   = GESTURE_ACTION_UNDEFINED;
+    p_gesture->i_beginx   = p_gesture->i_beginy = -1;
+    p_gesture->i_lasty    = -1;
+    p_gesture->huser_dll  = h_user32_dll;
+
+    *pp_gesture = p_gesture;
+    return result;
+}
+
+void CloseGestures( win32_gesture_sys_t *p_gesture )
+{
+    if (p_gesture && p_gesture->huser_dll )
+        FreeLibrary( p_gesture->huser_dll );
+    free( p_gesture );
+}
diff --git a/modules/control/win32touch.h b/modules/control/win32touch.h
new file mode 100644 (file)
index 0000000..d3f9128
--- /dev/null
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ * win32touch.c: touch gestures recognition
+ *****************************************************************************
+ * Copyright © 2013-2014 VideoLAN
+ *
+ * Authors: Ludovic Fauvet <etix@videolan.org>
+ *          Jean-Baptiste Kempf <jb@videolan.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_GESTURE_H_
+#define VLC_GESTURE_H_
+
+# ifdef _WIN32_WINNT
+#  undef _WIN32_WINNT
+# endif
+# define _WIN32_WINNT 0x0601
+# include <windows.h>
+# include <winuser.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+#ifndef WM_GESTURE
+# define WM_GESTURE 0x0119
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+    GESTURE_ACTION_UNDEFINED = 0,
+    GESTURE_ACTION_VOLUME,
+    GESTURE_ACTION_JUMP,
+    GESTURE_ACTION_BRIGHTNESS
+};
+
+typedef struct {
+    DWORD       i_type;                 /* Gesture ID */
+    int         i_action;               /* GESTURE_ACTION */
+
+    int         i_beginx;               /* Start X position */
+    int         i_beginy;               /* Start Y position */
+    int         i_lasty;                /* Last known Y position for PAN */
+
+    ULONGLONG   i_ullArguments;         /* Base values to compare between 2 zoom gestures */
+    bool        b_2fingers;             /* Did we detect 2 fingers? */
+
+    HINSTANCE   huser_dll;              /* user32.dll */
+    BOOL (WINAPI * OurCloseGestureInfoHandle)(HGESTUREINFO hGestureInfo);
+    BOOL (WINAPI * OurGetGestureInfo)(HGESTUREINFO hGestureInfo, PGESTUREINFO pGestureInfo);
+} win32_gesture_sys_t;
+
+
+BOOL InitGestures( HWND hwnd, win32_gesture_sys_t **p_gesture );
+
+LRESULT DecodeGesture( vlc_object_t *p_intf, win32_gesture_sys_t *p_gesture,
+        HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
+
+void CloseGestures( win32_gesture_sys_t *p_gesture );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif