diff options
-rw-r--r-- | system/keymaps/touchscreen.xml | 16 | ||||
-rw-r--r-- | xbmc/Application.cpp | 13 | ||||
-rw-r--r-- | xbmc/guilib/Key.h | 42 | ||||
-rw-r--r-- | xbmc/input/ButtonTranslator.cpp | 170 | ||||
-rw-r--r-- | xbmc/input/ButtonTranslator.h | 9 | ||||
-rw-r--r-- | xbmc/windowing/XBMC_events.h | 11 | ||||
-rw-r--r-- | xbmc/windowing/android/WinEventsAndroid.cpp | 7 |
7 files changed, 250 insertions, 18 deletions
diff --git a/system/keymaps/touchscreen.xml b/system/keymaps/touchscreen.xml new file mode 100644 index 0000000000..fbd934c6b0 --- /dev/null +++ b/system/keymaps/touchscreen.xml @@ -0,0 +1,16 @@ +<keymap> + <global> + <touch> + <tap>LeftClick</tap> + <longpress>RightClick</longpress> + <tap pointers="2">RightClick</tap> + <pan>PanGesture</pan> + </touch> + </global> + <SlideShow> + <touch> + <zoom>ZoomGesture</zoom> + <rotate>RotateGesture</rotate> + </touch> + </SlideShow> +</keymap> diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index cac91dbd34..cd8a5aba3b 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -522,6 +522,19 @@ bool CApplication::OnEvent(XBMC_Event& newEvent) break; case XBMC_APPCOMMAND: return g_application.OnAppCommand(newEvent.appcommand.action); + case XBMC_TOUCH: + { + int windowId = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK; + int actionId = 0; + if (newEvent.touch.action == ACTION_GESTURE_BEGIN || newEvent.touch.action == ACTION_GESTURE_END) + actionId = newEvent.touch.action; + else if (!CButtonTranslator::GetInstance().TranslateTouchAction(windowId, newEvent.touch.action, newEvent.touch.pointers, actionId) || + actionId <= 0) + return false; + + CApplicationMessenger::Get().SendAction(CAction(actionId, 0, newEvent.touch.x, newEvent.touch.y, newEvent.touch.x2, newEvent.touch.y2), WINDOW_INVALID, false); + break; + } } return true; } diff --git a/xbmc/guilib/Key.h b/xbmc/guilib/Key.h index 04a8ff3062..3f7f11f8ca 100644 --- a/xbmc/guilib/Key.h +++ b/xbmc/guilib/Key.h @@ -81,6 +81,9 @@ // 0xD000 -> 0xD0FF is reserved for WM_APPCOMMAND messages #define KEY_APPCOMMAND 0xD000 +// 0xF000 -> 0xF0FF is reserved for mouse actions +#define KEY_TOUCH 0xF000 + #define KEY_INVALID 0xFFFF // actions that we have defined... @@ -293,22 +296,11 @@ #define ACTION_INCREASE_PAR 219 #define ACTION_DECREASE_PAR 220 -#define ACTION_GESTURE_NOTIFY 221 -#define ACTION_GESTURE_BEGIN 222 -#define ACTION_GESTURE_ZOOM 223 //sendaction with point and currentPinchScale (fingers together < 1.0 -> fingers apart > 1.0) -#define ACTION_GESTURE_ROTATE 224 -#define ACTION_GESTURE_PAN 225 -#define ACTION_GESTURE_END 226 #define ACTION_VSHIFT_UP 227 // shift up video image in DVDPlayer #define ACTION_VSHIFT_DOWN 228 // shift down video image in DVDPlayer #define ACTION_PLAYER_PLAYPAUSE 229 // Play/pause. If playing it pauses, if paused it plays. -// The NOOP action can be specified to disable an input event. This is -// useful in user keyboard.xml etc to disable actions specified in the -// system mappings. -#define ACTION_NOOP 999 - #define ACTION_SUBTITLE_VSHIFT_UP 230 // shift up subtitles in DVDPlayer #define ACTION_SUBTITLE_VSHIFT_DOWN 231 // shift down subtitles in DVDPlayer #define ACTION_SUBTITLE_ALIGN 232 // toggle vertical alignment of subtitles @@ -317,6 +309,34 @@ #define ACTION_SWITCH_PLAYER 234 +// touch actions +#define ACTION_TOUCH_TAP 401 +#define ACTION_TOUCH_TAP_TEN 410 +#define ACTION_TOUCH_LONGPRESS 411 +#define ACTION_TOUCH_LONGPRESS_TEN 420 + +#define ACTION_GESTURE_NOTIFY 500 +#define ACTION_GESTURE_BEGIN 501 +#define ACTION_GESTURE_ZOOM 502 //sendaction with point and currentPinchScale (fingers together < 1.0 -> fingers apart > 1.0) +#define ACTION_GESTURE_ROTATE 503 +#define ACTION_GESTURE_PAN 504 + +#define ACTION_GESTURE_SWIPE_LEFT 511 +#define ACTION_GESTURE_SWIPE_LEFT_TEN 520 +#define ACTION_GESTURE_SWIPE_RIGHT 521 +#define ACTION_GESTURE_SWIPE_RIGHT_TEN 530 +#define ACTION_GESTURE_SWIPE_UP 531 +#define ACTION_GESTURE_SWIPE_UP_TEN 540 +#define ACTION_GESTURE_SWIPE_DOWN 541 +#define ACTION_GESTURE_SWIPE_DOWN_TEN 550 +// 5xx is reserved for additional gesture actions +#define ACTION_GESTURE_END 599 + +// The NOOP action can be specified to disable an input event. This is +// useful in user keyboard.xml etc to disable actions specified in the +// system mappings. +#define ACTION_NOOP 999 + // Window ID defines to make the code a bit more readable #define WINDOW_INVALID 9999 #define WINDOW_HOME 10000 diff --git a/xbmc/input/ButtonTranslator.cpp b/xbmc/input/ButtonTranslator.cpp index d5ff66a6e2..8fb69080a2 100644 --- a/xbmc/input/ButtonTranslator.cpp +++ b/xbmc/input/ButtonTranslator.cpp @@ -234,6 +234,17 @@ static const ActionMapping actions[] = {"mousedrag" , ACTION_MOUSE_DRAG}, {"mousemove" , ACTION_MOUSE_MOVE}, + // Touch + {"tap" , ACTION_TOUCH_TAP}, + {"longpress" , ACTION_TOUCH_LONGPRESS}, + {"pangesture" , ACTION_GESTURE_PAN}, + {"zoomgesture" , ACTION_GESTURE_ZOOM}, + {"rotategesture" , ACTION_GESTURE_ROTATE}, + {"swipeleft" , ACTION_GESTURE_SWIPE_LEFT}, + {"swiperight" , ACTION_GESTURE_SWIPE_RIGHT}, + {"swipeup" , ACTION_GESTURE_SWIPE_UP}, + {"swipedown" , ACTION_GESTURE_SWIPE_DOWN}, + // Do nothing action { "noop" , ACTION_NOOP} }; @@ -366,6 +377,19 @@ static const ActionMapping mousecommands[] = { "mousemove", ACTION_MOUSE_MOVE } }; +static const ActionMapping touchcommands[] = +{ + { "tap", ACTION_TOUCH_TAP }, + { "longpress", ACTION_TOUCH_LONGPRESS }, + { "pan", ACTION_GESTURE_PAN }, + { "zoom", ACTION_GESTURE_ZOOM }, + { "rotate", ACTION_GESTURE_ROTATE }, + { "swipeleft", ACTION_GESTURE_SWIPE_LEFT }, + { "swiperight", ACTION_GESTURE_SWIPE_RIGHT }, + { "swipeup", ACTION_GESTURE_SWIPE_UP }, + { "swipedown", ACTION_GESTURE_SWIPE_DOWN } +}; + static const WindowMapping fallbackWindows[] = { { WINDOW_FULLSCREEN_LIVETV, WINDOW_FULLSCREEN_VIDEO }, @@ -841,6 +865,35 @@ bool CButtonTranslator::TranslateJoystickString(int window, const char* szDevice return (action > 0); } +bool CButtonTranslator::TranslateTouchAction(int window, int touchAction, int touchPointers, int &action) +{ + action = 0; + if (touchPointers <= 0) + touchPointers = 1; + + touchAction += touchPointers - 1; + touchAction |= KEY_TOUCH; + + action = GetTouchActionCode(window, touchAction); + if (action <= 0) + action = GetTouchActionCode(-1, touchAction); + + return action > 0; +} + +int CButtonTranslator::GetActionCode(int window, int action) +{ + map<int, buttonMap>::const_iterator it = m_translatorMap.find(window); + if (it == m_translatorMap.end()) + return 0; + + buttonMap::const_iterator it2 = it->second.find(action); + if (it2 == it->second.end()) + return 0; + + return it2->second.id; +} + /* * Translates a joystick input to an action code */ @@ -962,6 +1015,7 @@ void CButtonTranslator::MapAction(uint32_t buttonCode, const char *szAction, but int action = ACTION_NONE; if (!TranslateActionString(szAction, action) || !buttonCode) return; // no valid action, or an invalid buttoncode + // have a valid action, and a valid button - map it. // check to see if we've already got this (button,action) pair defined buttonMap::iterator it = map.find(buttonCode); @@ -1046,6 +1100,16 @@ void CButtonTranslator::MapWindowActions(TiXmlNode *pWindow, int windowID) } } #endif + + if ((pDevice = pWindow->FirstChild("touch")) != NULL) + { + // map touch actions + while (pDevice) + { + MapTouchActions(windowID, pDevice); + pDevice = pDevice->NextSibling("touch"); + } + } } bool CButtonTranslator::TranslateActionString(const char *szAction, int &action) @@ -1366,3 +1430,109 @@ void CButtonTranslator::Clear() m_Loaded = false; } + +uint32_t CButtonTranslator::TranslateTouchCommand(TiXmlElement *pButton, CButtonAction &action) +{ + const char *szButton = pButton->Value(); + if (szButton == NULL || pButton->FirstChild() == NULL) + return ACTION_NONE; + + const char *szAction = pButton->FirstChild()->Value(); + if (szAction == NULL) + return ACTION_NONE; + + CStdString strTouchCommand = szButton; + strTouchCommand.ToLower(); + + std::string strTmp; + if (pButton->QueryStringAttribute("direction", &strTmp) == TIXML_SUCCESS) + strTouchCommand += strTmp; + + uint32_t actionId = ACTION_NONE; + for (unsigned int i = 0; i < sizeof(touchcommands)/sizeof(touchcommands[0]); i++) + { + if (strTouchCommand.Equals(touchcommands[i].name)) + { + actionId = touchcommands[i].action; + break; + } + } + + if (actionId <= ACTION_NONE) + { + CLog::Log(LOGERROR, "%s: Can't find touch command %s", __FUNCTION__, szButton); + return ACTION_NONE; + } + + strTmp.clear(); + if (pButton->QueryStringAttribute("pointers", &strTmp) == TIXML_SUCCESS) + { + int pointers = (int)strtol(strTmp.c_str(), NULL, 0); + if (pointers >= 1) + actionId += pointers - 1; + } + + action.strID = szAction; + if (!TranslateActionString(szAction, action.id) || action.id <= ACTION_NONE) + return ACTION_NONE; + + return actionId | KEY_TOUCH; +} + +void CButtonTranslator::MapTouchActions(int windowID, TiXmlNode *pTouch) +{ + if (pTouch == NULL) + return; + + buttonMap map; + // check if there already is a touch map for the window ID + std::map<int, buttonMap>::iterator it = m_touchMap.find(windowID); + if (it != m_touchMap.end()) + { + // get the existing touch map and remove it from the window mapping + // as it will be inserted later on + map = it->second; + m_touchMap.erase(it); + } + + uint32_t actionId = 0; + TiXmlElement *pTouchElem = pTouch->ToElement(); + if (pTouchElem == NULL) + return; + + TiXmlElement *pButton = pTouchElem->FirstChildElement(); + while (pButton != NULL) + { + CButtonAction action; + actionId = TranslateTouchCommand(pButton, action); + if (actionId > 0) + { + // check if there already is a mapping for the parsed action + // and remove it if necessary + buttonMap::iterator actionIt = map.find(actionId); + if (actionIt != map.end()) + map.erase(actionIt); + + map.insert(std::make_pair(actionId, action)); + } + + pButton = pButton->NextSiblingElement(); + } + + // add the modified touch map with the window ID + if (map.size() > 0) + m_touchMap.insert(std::pair<int, buttonMap>(windowID, map)); +} + +int CButtonTranslator::GetTouchActionCode(int window, int action) +{ + std::map<int, buttonMap>::const_iterator windowIt = m_touchMap.find(window); + if (windowIt == m_touchMap.end()) + return ACTION_NONE; + + buttonMap::const_iterator touchIt = windowIt->second.find(action); + if (touchIt == windowIt->second.end()) + return ACTION_NONE; + + return touchIt->second.id; +} diff --git a/xbmc/input/ButtonTranslator.h b/xbmc/input/ButtonTranslator.h index 79a8c8a818..4fd02be7cb 100644 --- a/xbmc/input/ButtonTranslator.h +++ b/xbmc/input/ButtonTranslator.h @@ -97,6 +97,8 @@ public: bool &fullrange); #endif + bool TranslateTouchAction(int window, int touchAction, int touchPointers, int &action); + private: typedef std::multimap<uint32_t, CButtonAction> buttonMap; // our button map to fill in @@ -105,6 +107,7 @@ private: // m_deviceList contains the list of connected HID devices std::list<CStdString> m_deviceList; + int GetActionCode(int window, int action); int GetActionCode(int window, const CKey &key, CStdString &strAction) const; #if defined(HAS_SDL_JOYSTICK) || defined(HAS_EVENT_SERVER) typedef std::map<int, std::map<int, std::string> > JoystickMap; // <window, <button/axis, action> > @@ -145,6 +148,12 @@ private: std::map<std::string, JoystickMap> m_joystickHatMap; // <joy name, hat map> #endif + void MapTouchActions(int windowID, TiXmlNode *pTouch); + static uint32_t TranslateTouchCommand(TiXmlElement *pButton, CButtonAction &action); + int GetTouchActionCode(int window, int action); + + std::map<int, buttonMap> m_touchMap; + bool m_Loaded; }; diff --git a/xbmc/windowing/XBMC_events.h b/xbmc/windowing/XBMC_events.h index 8ab192894d..f4a188eb92 100644 --- a/xbmc/windowing/XBMC_events.h +++ b/xbmc/windowing/XBMC_events.h @@ -53,6 +53,7 @@ typedef enum { XBMC_VIDEOMOVE, /* User moved the window */ XBMC_VIDEOEXPOSE, /* Screen needs to be redrawn */ XBMC_APPCOMMAND, /* Media commands, such as WM_APPCOMMAND on Windows for media keys. */ + XBMC_TOUCH, XBMC_USEREVENT, XBMC_MAXEVENT = 256 /* XBMC_EventType is represented as uchar */ @@ -179,6 +180,15 @@ typedef struct XBMC_AppCommandEvent { unsigned int action; /* One of ACTION_... */ } XBMC_AppCommandEvent; +/* Mouse motion event structure */ +typedef struct XBMC_TouchEvent { + unsigned char type; /* XBMC_TOUCH */ + int action; /* action ID */ + float x, y; /* The X/Y coordinates of the mouse */ + float x2, y2; /* Additional X/Y coordinates */ + int pointers; /* number of touch pointers */ +} XBMC_TouchEvent; + /* General event structure */ typedef union XBMC_Event { unsigned char type; @@ -197,6 +207,7 @@ typedef union XBMC_Event { XBMC_UserEvent user; XBMC_SysWMEvent syswm; XBMC_AppCommandEvent appcommand; + XBMC_TouchEvent touch; } XBMC_Event; #endif /* _XBMC_events_h */ diff --git a/xbmc/windowing/android/WinEventsAndroid.cpp b/xbmc/windowing/android/WinEventsAndroid.cpp index 8554961a0f..eb7c5078c8 100644 --- a/xbmc/windowing/android/WinEventsAndroid.cpp +++ b/xbmc/windowing/android/WinEventsAndroid.cpp @@ -22,12 +22,8 @@ #include <list> #include "windowing/WinEvents.h" #include "WinEventsAndroid.h" -#include "input/XBMC_vkeys.h" #include "Application.h" -#include "windowing/WindowingFactory.h" #include "threads/CriticalSection.h" -#include "utils/log.h" -#include "guilib/GUIWindowManager.h" static CCriticalSection g_inputCond; @@ -70,9 +66,6 @@ bool CWinEventsAndroid::MessagePump() } ret |= g_application.OnEvent(pumpEvent); - - if (pumpEvent.type == XBMC_MOUSEBUTTONUP) - g_windowManager.SendMessage(GUI_MSG_UNFOCUS_ALL, 0, 0, 0, 0); } return ret; |