aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in4
-rw-r--r--project/VS2010Express/XBMC.vcxproj21
-rw-r--r--project/VS2010Express/XBMC.vcxproj.filters69
-rw-r--r--system/keymaps/joystick.xml306
-rw-r--r--xbmc/input/ButtonTranslator.cpp42
-rw-r--r--xbmc/input/ButtonTranslator.h1
-rw-r--r--xbmc/input/InputManager.cpp30
-rw-r--r--xbmc/input/InputManager.h12
-rw-r--r--xbmc/input/Key.h32
-rw-r--r--xbmc/input/joysticks/DriverPrimitive.cpp123
-rw-r--r--xbmc/input/joysticks/DriverPrimitive.h141
-rw-r--r--xbmc/input/joysticks/IJoystickButtonMap.h204
-rw-r--r--xbmc/input/joysticks/IJoystickButtonMapper.h59
-rw-r--r--xbmc/input/joysticks/IJoystickDriverHandler.h80
-rw-r--r--xbmc/input/joysticks/IJoystickInputHandler.h97
-rw-r--r--xbmc/input/joysticks/IKeymapHandler.h65
-rw-r--r--xbmc/input/joysticks/JoystickMonitor.cpp65
-rw-r--r--xbmc/input/joysticks/JoystickMonitor.h46
-rw-r--r--xbmc/input/joysticks/JoystickTranslator.cpp61
-rw-r--r--xbmc/input/joysticks/JoystickTranslator.h61
-rw-r--r--xbmc/input/joysticks/JoystickTypes.h109
-rw-r--r--xbmc/input/joysticks/JoystickUtils.h47
-rw-r--r--xbmc/input/joysticks/KeymapHandler.cpp216
-rw-r--r--xbmc/input/joysticks/KeymapHandler.h69
-rw-r--r--xbmc/input/joysticks/Makefile9
-rw-r--r--xbmc/input/joysticks/generic/GenericJoystickButtonMapping.cpp155
-rw-r--r--xbmc/input/joysticks/generic/GenericJoystickButtonMapping.h79
-rw-r--r--xbmc/input/joysticks/generic/GenericJoystickFeatureHandling.cpp222
-rw-r--r--xbmc/input/joysticks/generic/GenericJoystickFeatureHandling.h208
-rw-r--r--xbmc/input/joysticks/generic/GenericJoystickInputHandling.cpp139
-rw-r--r--xbmc/input/joysticks/generic/GenericJoystickInputHandling.h70
-rw-r--r--xbmc/input/joysticks/generic/Makefile8
32 files changed, 2849 insertions, 1 deletions
diff --git a/Makefile.in b/Makefile.in
index 1c559cdb18..6f6745d827 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -153,6 +153,8 @@ INSTALL_FILTER += .*repository\.pvr-ios\.xbmc\.org.*
INSTALL_FILTER += .*repository\.pvr-win32\.xbmc\.org.*
INSTALL_FILTER += .*repository\.pvr-osx.*\.xbmc\.org.*
ifeq (@USE_ANDROID@,1)
+DIRECTORY_ARCHIVES += xbmc/input/joysticks/input_joysticks.a
+DIRECTORY_ARCHIVES += xbmc/input/joysticks/generic/input_joysticks_generic.a
DIRECTORY_ARCHIVES += xbmc/input/linux/input_linux.a
DIRECTORY_ARCHIVES += xbmc/input/touch/input_touch.a
DIRECTORY_ARCHIVES += xbmc/input/touch/generic/input_touch_generic.a
@@ -161,6 +163,8 @@ DIRECTORY_ARCHIVES += xbmc/powermanagement/android/powermanagement_android.a
DIRECTORY_ARCHIVES += xbmc/storage/android/storage_android.a
DIRECTORY_ARCHIVES += xbmc/windowing/X11/windowing_X11.a
else
+DIRECTORY_ARCHIVES += xbmc/input/joysticks/input_joysticks.a
+DIRECTORY_ARCHIVES += xbmc/input/joysticks/generic/input_joysticks_generic.a
DIRECTORY_ARCHIVES += xbmc/input/linux/input_linux.a
DIRECTORY_ARCHIVES += xbmc/input/touch/input_touch.a
DIRECTORY_ARCHIVES += xbmc/input/touch/generic/input_touch_generic.a
diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
index 89b73fbe67..90a292c7ad 100644
--- a/project/VS2010Express/XBMC.vcxproj
+++ b/project/VS2010Express/XBMC.vcxproj
@@ -561,6 +561,13 @@
<ClCompile Include="..\..\xbmc\input\InertialScrollingHandler.cpp" />
<ClCompile Include="..\..\xbmc\input\InputCodingTableKorean.cpp" />
<ClCompile Include="..\..\xbmc\input\InputManager.cpp" />
+ <ClCompile Include="..\..\xbmc\input\joysticks\DriverPrimitive.cpp" />
+ <ClCompile Include="..\..\xbmc\input\joysticks\generic\GenericJoystickButtonMapping.cpp" />
+ <ClCompile Include="..\..\xbmc\input\joysticks\generic\GenericJoystickFeatureHandling.cpp" />
+ <ClCompile Include="..\..\xbmc\input\joysticks\generic\GenericJoystickInputHandling.cpp" />
+ <ClCompile Include="..\..\xbmc\input\joysticks\JoystickMonitor.cpp" />
+ <ClCompile Include="..\..\xbmc\input\joysticks\JoystickTranslator.cpp" />
+ <ClCompile Include="..\..\xbmc\input\joysticks\KeymapHandler.cpp" />
<ClCompile Include="..\..\xbmc\input\Key.cpp" />
<ClCompile Include="..\..\xbmc\input\InputCodingTableBaiduPY.cpp" />
<ClCompile Include="..\..\xbmc\input\InputCodingTableBasePY.cpp" />
@@ -1079,6 +1086,20 @@
<ClInclude Include="..\..\xbmc\input\InputCodingTableKorean.h" />
<ClInclude Include="..\..\xbmc\InfoScanner.h" />
<ClInclude Include="..\..\xbmc\input\InputManager.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\DriverPrimitive.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\generic\GenericJoystickButtonMapping.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\generic\GenericJoystickFeatureHandling.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\generic\GenericJoystickInputHandling.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\IJoystickButtonMap.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\IJoystickButtonMapper.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\IJoystickDriverHandler.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\IJoystickInputHandler.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\IKeymapHandler.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\JoystickMonitor.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\JoystickTranslator.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\JoystickTypes.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\JoystickUtils.h" />
+ <ClInclude Include="..\..\xbmc\input\joysticks\KeymapHandler.h" />
<ClInclude Include="..\..\xbmc\input\Key.h" />
<ClInclude Include="..\..\xbmc\input\KeyboardLayoutManager.h" />
<ClInclude Include="..\..\xbmc\input\InputCodingTable.h" />
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
index c6d6ac0238..c0df7a9354 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -421,6 +421,12 @@
<Filter Include="addons\binary\interfaces\api1\PVR">
<UniqueIdentifier>{c3708f40-3139-4ee9-b8f6-c6bcc22bb1c3}</UniqueIdentifier>
</Filter>
+ <Filter Include="input\joysticks">
+ <UniqueIdentifier>{5d8049b8-4689-4ff0-bf4f-1f0a308e5b44}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="input\joysticks\generic">
+ <UniqueIdentifier>{80a8356f-f3be-46b5-be2e-714a42764ee1}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\xbmc\win32\pch.cpp">
@@ -3328,6 +3334,27 @@
<ClCompile Include="..\..\xbmc\addons\binary\interfaces\AddonInterfaces.cpp">
<Filter>addons\binary\interfaces</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\input\joysticks\DriverPrimitive.cpp">
+ <Filter>input\joysticks</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\xbmc\input\joysticks\JoystickMonitor.cpp">
+ <Filter>input\joysticks</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\xbmc\input\joysticks\JoystickTranslator.cpp">
+ <Filter>input\joysticks</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\xbmc\input\joysticks\KeymapHandler.cpp">
+ <Filter>input\joysticks</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\xbmc\input\joysticks\generic\GenericJoystickButtonMapping.cpp">
+ <Filter>input\joysticks\generic</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\xbmc\input\joysticks\generic\GenericJoystickInputHandling.cpp">
+ <Filter>input\joysticks\generic</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\xbmc\input\joysticks\generic\GenericJoystickFeatureHandling.cpp">
+ <Filter>input\joysticks\generic</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\xbmc\win32\pch.h">
@@ -6434,6 +6461,48 @@
<ClInclude Include="..\..\xbmc\addons\binary\interfaces\IAddonInterface.h">
<Filter>addons\binary\interfaces</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\DriverPrimitive.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\IJoystickButtonMap.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\IJoystickButtonMapper.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\IJoystickDriverHandler.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\IJoystickInputHandler.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\IKeymapHandler.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\JoystickMonitor.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\JoystickTranslator.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\JoystickTypes.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\JoystickUtils.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\KeymapHandler.h">
+ <Filter>input\joysticks</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\generic\GenericJoystickButtonMapping.h">
+ <Filter>input\joysticks\generic</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\generic\GenericJoystickInputHandling.h">
+ <Filter>input\joysticks\generic</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\input\joysticks\generic\GenericJoystickFeatureHandling.h">
+ <Filter>input\joysticks\generic</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc">
diff --git a/system/keymaps/joystick.xml b/system/keymaps/joystick.xml
new file mode 100644
index 0000000000..976223edcc
--- /dev/null
+++ b/system/keymaps/joystick.xml
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<keymap>
+ <global>
+ <joystick>
+ <a>Select</a>
+ <b>Back</b>
+ <x>ContextMenu</x>
+ <y>FullScreen</y>
+ <start>ActivateWindow(PlayerControls)</start>
+ <back>Back</back>
+ <guide>ActivateWindow(Home)</guide>
+ <up>Up</up>
+ <down>Down</down>
+ <right>Right</right>
+ <left>Left</left>
+ <leftthumb>Screenshot</leftthumb>
+ <rightthumb>ActivateWindow(ShutdownMenu)</rightthumb>
+ <lefttrigger>ScrollUp</lefttrigger>
+ <righttrigger>ScrollDown</righttrigger>
+ <leftbumper>ScrollUp</leftbumper>
+ <rightbumper>ScrollDown</rightbumper>
+ <leftstickleft>Left</leftstickleft>
+ <leftstickright>Right</leftstickright>
+ <leftstickup>Up</leftstickup>
+ <leftstickdown>Down</leftstickdown>
+ <rightstickleft>VolumeDown</rightstickleft>
+ <rightstickright>VolumeUp</rightstickright>
+ <rightstickup>VolumeUp</rightstickup>
+ <rightstickdown>VolumeDown</rightstickdown>
+ </joystick>
+ </global>
+ <Home>
+ <joystick>
+ <start>Skin.ToggleSetting(HomeViewToggle)</start>
+ </joystick>
+ </Home>
+ <MyFiles>
+ <joystick>
+ <rightbumper>Highlight</rightbumper>
+ </joystick>
+ </MyFiles>
+ <MyMusicPlaylist>
+ <joystick>
+ <leftbumper>Delete</leftbumper>
+ </joystick>
+ </MyMusicPlaylist>
+ <MyMusicFiles>
+ </MyMusicFiles>
+ <MyMusicLibrary>
+ </MyMusicLibrary>
+ <FullscreenVideo>
+ <joystick>
+ <a>Pause</a>
+ <b>Stop</b>
+ <x>OSD</x>
+ <y>FullScreen</y>
+ <start>Info</start>
+ <back>Seek(-7)</back>
+ <guide>ActivateWindow(Home)</guide>
+ <up>ChapterOrBigStepForward</up>
+ <down>ChapterOrBigStepBack</down>
+ <right>StepForward</right>
+ <left>StepBack</left>
+ <leftthumb>ShowSubtitles</leftthumb>
+ <rightthumb>AspectRatio</rightthumb>
+ <lefttrigger>AnalogRewind</lefttrigger>
+ <righttrigger>AnalogFastForward</righttrigger>
+ <leftbumper>AnalogRewind</leftbumper>
+ <rightbumper>AnalogFastForward</rightbumper>
+ <leftstickleft>AnalogSeekBack</leftstickleft>
+ <leftstickright>AnalogSeekForward</leftstickright>
+ <leftstickup>AnalogSeekForward</leftstickup>
+ <leftstickdown>AnalogSeekBack</leftstickdown>
+ <rightstickleft>VolumeDown</rightstickleft>
+ <rightstickright>VolumeUp</rightstickright>
+ <rightstickup>VolumeUp</rightstickup>
+ <rightstickdown>VolumeDown</rightstickdown>
+ </joystick>
+ </FullscreenVideo>
+ <FullscreenLiveTV>
+ <joystick>
+ <up>ChannelUp</up>
+ <down>ChannelDown</down>
+ <left>StepBack</left>
+ <right>StepForward</right>
+ </joystick>
+ </FullscreenLiveTV>
+ <FullscreenRadio>
+ <joystick>
+ <up>ChannelUp</up>
+ <down>ChannelDown</down>
+ <left>StepBack</left>
+ <right>StepForward</right>
+ </joystick>
+ </FullscreenRadio>
+ <FullscreenInfo>
+ <joystick>
+ <b>Close</b>
+ <x>OSD</x>
+ <start>Close</start>
+ <lefttrigger>AnalogRewind</lefttrigger>
+ <righttrigger>AnalogFastForward</righttrigger>
+ <leftbumper>AnalogRewind</leftbumper>
+ <rightbumper>AnalogFastForward</rightbumper>
+ </joystick>
+ </FullscreenInfo>
+ <PlayerControls>
+ <joystick>
+ <x>Close</x>
+ <leftthumb>Close</leftthumb>
+ <rightthumb>Close</rightthumb>
+ </joystick>
+ </PlayerControls>
+ <Visualisation>
+ <joystick>
+ <a>Pause</a>
+ <b>Stop</b>
+ <x>ActivateWindow(VisualisationSettings)</x>
+ <y>ActivateWindow(VisualisationPresetList)</y>
+ <start>Info</start>
+ <rightthumb>ActivateWindow(MusicOSD)</rightthumb>
+ <up>SkipNext</up>
+ <down>SkipPrevious</down>
+ <left>StepBack</left>
+ <right>StepForward</right>
+ <lefttrigger>AnalogRewind</lefttrigger>
+ <righttrigger>AnalogFastForward</righttrigger>
+ <leftbumper>AnalogRewind</leftbumper>
+ <rightbumper>AnalogFastForward</rightbumper>
+ <leftstickleft>PreviousPreset</leftstickleft>
+ <leftstickright>NextPreset</leftstickright>
+ </joystick>
+ </Visualisation>
+ <MusicOSD>
+ <joystick>
+ <b>Close</b>
+ <start>Info</start>
+ </joystick>
+ </MusicOSD>
+ <VisualisationSettings>
+ <joystick>
+ <b>Close</b>
+ </joystick>
+ </VisualisationSettings>
+ <VisualisationPresetList>
+ <joystick>
+ <b>Close</b>
+ </joystick>
+ </VisualisationPresetList>
+ <SlideShow>
+ <joystick>
+ <a>Pause</a>
+ <b>Stop</b>
+ <y>ZoomNormal</y>
+ <leftbumper>Rotate</leftbumper>
+ <rightbumper>CodecInfo</rightbumper>
+ <up>ZoomIn</up>
+ <down>ZoomOut</down>
+ <left>PreviousPicture</left>
+ <right>NextPicture</right>
+ <leftstickleft>AnalogMoveX</leftstickleft>
+ <leftstickright>AnalogMoveX</leftstickright>
+ <leftstickup>AnalogMoveY</leftstickup>
+ <leftstickdown>AnalogMoveY</leftstickdown>
+ <lefttrigger>ZoomOut</lefttrigger>
+ <righttrigger>ZoomIn</righttrigger>
+ </joystick>
+ </SlideShow>
+ <ScreenCalibration>
+ <joystick>
+ <x>ResetCalibration</x>
+ <leftbumper>NextResolution</leftbumper>
+ <rightbumper>NextCalibration</rightbumper>
+ </joystick>
+ </ScreenCalibration>
+ <GUICalibration>
+ <joystick>
+ <x>ResetCalibration</x>
+ <leftbumper>NextResolution</leftbumper>
+ <rightbumper>NextCalibration</rightbumper>
+ </joystick>
+ </GUICalibration>
+ <VideoOSD>
+ <joystick>
+ <b>Close</b>
+ </joystick>
+ </VideoOSD>
+ <VideoMenu>
+ <joystick>
+ <b>Stop</b>
+ <x>OSD</x>
+ <leftbumper>AspectRatio</leftbumper>
+ <start>Info</start>
+ </joystick>
+ </VideoMenu>
+ <OSDVideoSettings>
+ <joystick>
+ <leftbumper>AspectRatio</leftbumper>
+ <x>Close</x>
+ </joystick>
+ </OSDVideoSettings>
+ <OSDAudioSettings>
+ <joystick>
+ <leftbumper>AspectRatio</leftbumper>
+ <x>Close</x>
+ </joystick>
+ </OSDAudioSettings>
+ <VideoBookmarks>
+ <joystick>
+ <leftbumper>Delete</leftbumper>
+ </joystick>
+ </VideoBookmarks>
+ <MyVideoLibrary>
+ </MyVideoLibrary>
+ <MyVideoFiles>
+ </MyVideoFiles>
+ <MyVideoPlaylist>
+ <joystick>
+ <leftbumper>Delete</leftbumper>
+ </joystick>
+ </MyVideoPlaylist>
+ <VirtualKeyboard>
+ <joystick>
+ <b>BackSpace</b>
+ <y>Symbols</y>
+ <leftbumper>Shift</leftbumper>
+ <leftthumb>Enter</leftthumb>
+ <lefttrigger>CursorLeft</lefttrigger>
+ <righttrigger>CursorRight</righttrigger>
+ </joystick>
+ </VirtualKeyboard>
+ <ContextMenu>
+ <joystick>
+ <b>Close</b>
+ </joystick>
+ </ContextMenu>
+ <Scripts>
+ <joystick>
+ <x>ContextMenu</x>
+ </joystick>
+ </Scripts>
+ <Settings>
+ <joystick>
+ <b>PreviousMenu</b>
+ </joystick>
+ </Settings>
+ <AddonInformation>
+ <joystick>
+ <b>Close</b>
+ </joystick>
+ </AddonInformation>
+ <AddonSettings>
+ <joystick>
+ <b>Close</b>
+ </joystick>
+ </AddonSettings>
+ <TextViewer>
+ <joystick>
+ <b>Close</b>
+ </joystick>
+ </TextViewer>
+ <shutdownmenu>
+ <joystick>
+ <b>PreviousMenu</b>
+ <leftthumb>PreviousMenu</leftthumb>
+ </joystick>
+ </shutdownmenu>
+ <submenu>
+ <joystick>
+ <b>PreviousMenu</b>
+ </joystick>
+ </submenu>
+ <MusicInformation>
+ <joystick>
+ <b>Close</b>
+ </joystick>
+ </MusicInformation>
+ <MovieInformation>
+ <joystick>
+ <b>Close</b>
+ </joystick>
+ </MovieInformation>
+ <NumericInput>
+ <joystick>
+ <b>BackSpace</b>
+ <leftthumb>Enter</leftthumb>
+ </joystick>
+ </NumericInput>
+ <GamepadInput>
+ <joystick>
+ <leftthumb>Stop</leftthumb>
+ </joystick>
+ </GamepadInput>
+ <LockSettings>
+ <joystick>
+ <b>PreviousMenu</b>
+ <leftthumb>Close</leftthumb>
+ </joystick>
+ </LockSettings>
+ <ProfileSettings>
+ <joystick>
+ <b>PreviousMenu</b>
+ <leftthumb>Close</leftthumb>
+ </joystick>
+ </ProfileSettings>
+</keymap>
diff --git a/xbmc/input/ButtonTranslator.cpp b/xbmc/input/ButtonTranslator.cpp
index 01bfc72c79..ca9c179d3a 100644
--- a/xbmc/input/ButtonTranslator.cpp
+++ b/xbmc/input/ButtonTranslator.cpp
@@ -976,7 +976,7 @@ void CButtonTranslator::MapWindowActions(TiXmlNode *pWindow, int windowID)
TiXmlNode* pDevice;
- const char* types[] = {"gamepad", "remote", "universalremote", "keyboard", "mouse", "appcommand", NULL};
+ const char* types[] = {"gamepad", "remote", "universalremote", "keyboard", "mouse", "appcommand", "joystick", NULL};
for (int i = 0; types[i]; ++i)
{
std::string type(types[i]);
@@ -1009,6 +1009,8 @@ void CButtonTranslator::MapWindowActions(TiXmlNode *pWindow, int windowID)
buttonCode = TranslateMouseCommand(pButton);
else if (type == "appcommand")
buttonCode = TranslateAppCommand(pButton->Value());
+ else if (type == "joystick")
+ buttonCode = TranslateJoystickString(pButton->Value());
if (buttonCode)
{
@@ -1493,3 +1495,41 @@ int CButtonTranslator::GetTouchActionCode(int window, int action, std::string &a
actionString = touchIt->second.strID;
return touchIt->second.id;
}
+
+uint32_t CButtonTranslator::TranslateJoystickString(const char *szButton)
+{
+ if (!szButton)
+ return 0;
+ uint32_t buttonCode = 0;
+ std::string strButton = szButton;
+ StringUtils::ToLower(strButton);
+
+ if (strButton == "a") buttonCode = KEY_JOYSTICK_BUTTON_A;
+ else if (strButton == "b") buttonCode = KEY_JOYSTICK_BUTTON_B;
+ else if (strButton == "x") buttonCode = KEY_JOYSTICK_BUTTON_X;
+ else if (strButton == "y") buttonCode = KEY_JOYSTICK_BUTTON_Y;
+ else if (strButton == "start") buttonCode = KEY_JOYSTICK_BUTTON_START;
+ else if (strButton == "back") buttonCode = KEY_JOYSTICK_BUTTON_BACK;
+ else if (strButton == "left") buttonCode = KEY_JOYSTICK_BUTTON_DPAD_LEFT;
+ else if (strButton == "right") buttonCode = KEY_JOYSTICK_BUTTON_DPAD_RIGHT;
+ else if (strButton == "up") buttonCode = KEY_JOYSTICK_BUTTON_DPAD_UP;
+ else if (strButton == "down") buttonCode = KEY_JOYSTICK_BUTTON_DPAD_DOWN;
+ else if (strButton == "leftthumb") buttonCode = KEY_JOYSTICK_BUTTON_LEFT_STICK_BUTTON;
+ else if (strButton == "rightthumb") buttonCode = KEY_JOYSTICK_BUTTON_RIGHT_STICK_BUTTON;
+ else if (strButton == "leftstickup") buttonCode = KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_UP;
+ else if (strButton == "leftstickdown") buttonCode = KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_DOWN;
+ else if (strButton == "leftstickleft") buttonCode = KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_LEFT;
+ else if (strButton == "leftstickright") buttonCode = KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_RIGHT;
+ else if (strButton == "rightstickup") buttonCode = KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_UP;
+ else if (strButton == "rightstickdown") buttonCode = KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_DOWN;
+ else if (strButton == "rightstickleft") buttonCode = KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_LEFT;
+ else if (strButton == "rightstickright") buttonCode = KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_RIGHT;
+ else if (strButton == "lefttrigger") buttonCode = KEY_JOYSTICK_BUTTON_LEFT_TRIGGER;
+ else if (strButton == "righttrigger") buttonCode = KEY_JOYSTICK_BUTTON_RIGHT_TRIGGER;
+ else if (strButton == "leftbumper") buttonCode = KEY_JOYSTICK_BUTTON_LEFT_SHOULDER;
+ else if (strButton == "rightbumper") buttonCode = KEY_JOYSTICK_BUTTON_RIGHT_SHOULDER;
+ else if (strButton == "guide") buttonCode = KEY_JOYSTICK_BUTTON_GUIDE;
+ else CLog::Log(LOGERROR, "Joystick Translator: Can't find button %s", strButton.c_str());
+
+ return buttonCode;
+}
diff --git a/xbmc/input/ButtonTranslator.h b/xbmc/input/ButtonTranslator.h
index d4f4178711..f1904a5ae2 100644
--- a/xbmc/input/ButtonTranslator.h
+++ b/xbmc/input/ButtonTranslator.h
@@ -130,6 +130,7 @@ private:
static uint32_t TranslateGamepadString(const char *szButton);
static uint32_t TranslateRemoteString(const char *szButton);
static uint32_t TranslateUniversalRemoteString(const char *szButton);
+ static uint32_t TranslateJoystickString(const char *szButton);
static uint32_t TranslateKeyboardString(const char *szButton);
static uint32_t TranslateKeyboardButton(TiXmlElement *pButton);
diff --git a/xbmc/input/InputManager.cpp b/xbmc/input/InputManager.cpp
index 69e6c31853..bc8b3a740d 100644
--- a/xbmc/input/InputManager.cpp
+++ b/xbmc/input/InputManager.cpp
@@ -260,6 +260,35 @@ bool CInputManager::ProcessEventServer(int windowId, float frameTime)
return false;
}
+void CInputManager::ProcessQueuedActions()
+{
+ std::vector<CAction> queuedActions;
+ {
+ CSingleLock lock(m_actionMutex);
+ queuedActions.swap(m_queuedActions);
+ }
+
+ for (const CAction& action : queuedActions)
+ g_application.OnAction(action);
+}
+
+void CInputManager::QueueAction(const CAction& action)
+{
+ CSingleLock lock(m_actionMutex);
+
+ // Avoid dispatching multiple analog actions per frame with the same ID
+ if (action.IsAnalog())
+ {
+ m_queuedActions.erase(std::remove_if(m_queuedActions.begin(), m_queuedActions.end(),
+ [&action](const CAction& queuedAction)
+ {
+ return action.GetID() == queuedAction.GetID();
+ }), m_queuedActions.end());
+ }
+
+ m_queuedActions.push_back(action);
+}
+
bool CInputManager::Process(int windowId, float frameTime)
{
#if defined(HAS_LIRC) || defined(HAS_IRSERVERSUITE)
@@ -271,6 +300,7 @@ bool CInputManager::Process(int windowId, float frameTime)
ProcessRemote(windowId);
ProcessEventServer(windowId, frameTime);
ProcessPeripherals(frameTime);
+ ProcessQueuedActions();
return true;
}
diff --git a/xbmc/input/InputManager.h b/xbmc/input/InputManager.h
index f801efce3c..9afe96b25a 100644
--- a/xbmc/input/InputManager.h
+++ b/xbmc/input/InputManager.h
@@ -34,6 +34,7 @@
#include "input/KeyboardStat.h"
#include "input/MouseStat.h"
#include "settings/lib/ISettingCallback.h"
+#include "threads/CriticalSection.h"
class CKey;
@@ -79,6 +80,14 @@ public:
*/
bool ProcessPeripherals(float frameTime);
+ /*! \brief Dispatch actions queued since the last call to Process()
+ */
+ void ProcessQueuedActions();
+
+ /*! \brief Queue an action to be processed on the next call to Process()
+ */
+ void QueueAction(const CAction& action);
+
/*! \brief Process all inputs
*
* \param windowId Currently active window
@@ -240,4 +249,7 @@ private:
#if defined(HAS_EVENT_SERVER)
std::map<std::string, std::map<int, float> > m_lastAxisMap;
#endif
+
+ std::vector<CAction> m_queuedActions;
+ CCriticalSection m_actionMutex;
};
diff --git a/xbmc/input/Key.h b/xbmc/input/Key.h
index 5e68505788..5af7415804 100644
--- a/xbmc/input/Key.h
+++ b/xbmc/input/Key.h
@@ -31,6 +31,9 @@
// XBIRRemote.h
// XINPUT_IR_REMOTE-*
+/*
+ * EventServer "gamepad" keys based on original Xbox controller
+ */
// Analogue - don't change order
#define KEY_BUTTON_A 256
#define KEY_BUTTON_B 257
@@ -69,6 +72,35 @@
#define KEY_BUTTON_LEFT_THUMB_STICK_LEFT 282
#define KEY_BUTTON_LEFT_THUMB_STICK_RIGHT 283
+/*
+ * joystick.xml keys based on Xbox 360 controller
+ */
+#define KEY_JOYSTICK_BUTTON_A 284
+#define KEY_JOYSTICK_BUTTON_B 285
+#define KEY_JOYSTICK_BUTTON_X 286
+#define KEY_JOYSTICK_BUTTON_Y 287
+#define KEY_JOYSTICK_BUTTON_LEFT_SHOULDER 288
+#define KEY_JOYSTICK_BUTTON_RIGHT_SHOULDER 289
+#define KEY_JOYSTICK_BUTTON_LEFT_TRIGGER 290
+#define KEY_JOYSTICK_BUTTON_RIGHT_TRIGGER 291
+#define KEY_JOYSTICK_BUTTON_LEFT_STICK_BUTTON 292
+#define KEY_JOYSTICK_BUTTON_RIGHT_STICK_BUTTON 293
+#define KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_UP 294
+#define KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_DOWN 295
+#define KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_LEFT 296
+#define KEY_JOYSTICK_BUTTON_RIGHT_THUMB_STICK_RIGHT 297
+#define KEY_JOYSTICK_BUTTON_DPAD_UP 298
+#define KEY_JOYSTICK_BUTTON_DPAD_DOWN 299
+#define KEY_JOYSTICK_BUTTON_DPAD_LEFT 300
+#define KEY_JOYSTICK_BUTTON_DPAD_RIGHT 301
+#define KEY_JOYSTICK_BUTTON_START 302
+#define KEY_JOYSTICK_BUTTON_BACK 303
+#define KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_UP 304
+#define KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_DOWN 305
+#define KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_LEFT 306
+#define KEY_JOYSTICK_BUTTON_LEFT_THUMB_STICK_RIGHT 307
+#define KEY_JOYSTICK_BUTTON_GUIDE 308
+
// 0xF000 -> 0xF200 is reserved for the keyboard; a keyboard press is either
#define KEY_VKEY 0xF000 // a virtual key/functional key e.g. cursor left
#define KEY_ASCII 0xF100 // a printable character in the range of TRUE ASCII (from 0 to 127) // FIXME make it clean and pure unicode! remove the need for KEY_ASCII
diff --git a/xbmc/input/joysticks/DriverPrimitive.cpp b/xbmc/input/joysticks/DriverPrimitive.cpp
new file mode 100644
index 0000000000..70bd2e0d9b
--- /dev/null
+++ b/xbmc/input/joysticks/DriverPrimitive.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "DriverPrimitive.h"
+
+using namespace JOYSTICK;
+
+CDriverPrimitive::CDriverPrimitive(void)
+ : m_type(),
+ m_driverIndex(0),
+ m_hatDirection(),
+ m_semiAxisDirection()
+{
+}
+
+CDriverPrimitive::CDriverPrimitive(unsigned int buttonIndex)
+ : m_type(BUTTON),
+ m_driverIndex(buttonIndex),
+ m_hatDirection(),
+ m_semiAxisDirection()
+{
+}
+
+CDriverPrimitive::CDriverPrimitive(unsigned int hatIndex, HAT_DIRECTION direction)
+ : m_type(HAT),
+ m_driverIndex(hatIndex),
+ m_hatDirection(direction),
+ m_semiAxisDirection()
+{
+}
+
+CDriverPrimitive::CDriverPrimitive(unsigned int axisIndex, SEMIAXIS_DIRECTION direction)
+ : m_type(SEMIAXIS),
+ m_driverIndex(axisIndex),
+ m_hatDirection(),
+ m_semiAxisDirection(direction)
+{
+}
+
+bool CDriverPrimitive::operator==(const CDriverPrimitive& rhs) const
+{
+ if (m_type == rhs.m_type)
+ {
+ switch (m_type)
+ {
+ case BUTTON:
+ return m_driverIndex == rhs.m_driverIndex;
+ case HAT:
+ return m_driverIndex == rhs.m_driverIndex && m_hatDirection == rhs.m_hatDirection;
+ case SEMIAXIS:
+ return m_driverIndex == rhs.m_driverIndex && m_semiAxisDirection == rhs.m_semiAxisDirection;
+ default:
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CDriverPrimitive::operator<(const CDriverPrimitive& rhs) const
+{
+ if (m_type < rhs.m_type) return true;
+ if (m_type > rhs.m_type) return false;
+
+ // Driver index is common to all valid primitives
+ if (m_type != UNKNOWN)
+ {
+ if (m_driverIndex < rhs.m_driverIndex) return true;
+ if (m_driverIndex > rhs.m_driverIndex) return false;
+ }
+
+ if (m_type == HAT)
+ {
+ if (m_hatDirection < rhs.m_hatDirection) return true;
+ if (m_hatDirection > rhs.m_hatDirection) return false;
+ }
+
+ if (m_type == SEMIAXIS)
+ {
+ if (m_semiAxisDirection < rhs.m_semiAxisDirection) return true;
+ if (m_semiAxisDirection > rhs.m_semiAxisDirection) return false;
+ }
+
+ return false;
+}
+
+bool CDriverPrimitive::IsValid(void) const
+{
+ if (m_type == BUTTON)
+ return true;
+
+ if (m_type == HAT)
+ {
+ return m_hatDirection == HAT_DIRECTION::UP ||
+ m_hatDirection == HAT_DIRECTION::DOWN ||
+ m_hatDirection == HAT_DIRECTION::RIGHT ||
+ m_hatDirection == HAT_DIRECTION::LEFT;
+ }
+
+ if (m_type == SEMIAXIS)
+ {
+ return m_semiAxisDirection == SEMIAXIS_DIRECTION::POSITIVE ||
+ m_semiAxisDirection == SEMIAXIS_DIRECTION::NEGATIVE;
+ }
+
+ return false;
+}
diff --git a/xbmc/input/joysticks/DriverPrimitive.h b/xbmc/input/joysticks/DriverPrimitive.h
new file mode 100644
index 0000000000..626a368bf5
--- /dev/null
+++ b/xbmc/input/joysticks/DriverPrimitive.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "JoystickTypes.h"
+
+#include <stdint.h>
+
+namespace JOYSTICK
+{
+ /*!
+ * \brief Basic driver element associated with input events
+ *
+ * Driver input (bools, floats and enums) is split into primitives that better
+ * map to the physical features on a joystick.
+ *
+ * A bool obviously only maps to a single feature, so it is a driver
+ * primitive. Here, these are called "buttons".
+ *
+ * A hat enum encodes the state of the four hat directions. Each direction
+ * can map to a different feature, so a hat enum consists of four driver
+ * primitives called "hat directions".
+ *
+ * A float is a little trickier. Trivially, it can map to an analog stick or
+ * trigger. However, DirectInput combines two triggers onto a single axis.
+ * Therefore, the axis is split into two primitives called "semiaxes".
+ *
+ * The type determines the fields in use:
+ *
+ * Button:
+ * - driver index
+ *
+ * Hat direction:
+ * - driver index
+ * - hat direction (up/right/down/left)
+ *
+ * Semiaxis:
+ * - driver index
+ * - semiaxis direction (positive/negative)
+ *
+ * For more info, see "Chapter 2. Joystick drivers" in the documentation
+ * thread: http://forum.kodi.tv/showthread.php?tid=257764
+ */
+ class CDriverPrimitive
+ {
+ public:
+ /*!
+ * \brief Type of driver primitive
+ */
+ enum PrimitiveType
+ {
+ UNKNOWN = 0, // primitive has no type (invalid)
+ BUTTON, // a digital button
+ HAT, // one of the four direction arrows on a D-pad
+ SEMIAXIS, // the positive or negative half of an axis
+ };
+
+ /*!
+ * \brief Construct an invalid driver primitive
+ */
+ CDriverPrimitive(void);
+
+ /*!
+ * \brief Construct a driver primitive representing a button
+ */
+ CDriverPrimitive(unsigned int buttonIndex);
+
+ /*!
+ * \brief Construct a driver primitive representing one of the four
+ * direction arrows on a dpad
+ */
+ CDriverPrimitive(unsigned int hatIndex, HAT_DIRECTION direction);
+
+ /*!
+ * \brief Construct a driver primitive representing the positive or negative
+ * half of an axis
+ */
+ CDriverPrimitive(unsigned int axisIndex, SEMIAXIS_DIRECTION direction);
+
+ bool operator==(const CDriverPrimitive& rhs) const;
+ bool operator<(const CDriverPrimitive& rhs) const;
+
+ bool operator!=(const CDriverPrimitive& rhs) const { return !operator==(rhs); }
+ bool operator>(const CDriverPrimitive& rhs) const { return !(operator<(rhs) || operator==(rhs)); }
+ bool operator<=(const CDriverPrimitive& rhs) const { return operator<(rhs) || operator==(rhs); }
+ bool operator>=(const CDriverPrimitive& rhs) const { return !operator<(rhs); }
+
+ /*!
+ * \brief The type of driver primitive
+ */
+ PrimitiveType Type(void) const { return m_type; }
+
+ /*!
+ * \brief The index used by the driver (valid for all types)
+ */
+ unsigned int Index(void) const { return m_driverIndex; }
+
+ /*!
+ * \brief The direction arrow (valid for hat directions)
+ */
+ HAT_DIRECTION HatDirection(void) const { return m_hatDirection; }
+
+ /*!
+ * \brief The semiaxis direction (valid for semiaxes)
+ */
+ SEMIAXIS_DIRECTION SemiAxisDirection(void) const { return m_semiAxisDirection; }
+
+ /*!
+ * \brief Test if an driver primitive is valid
+ *
+ * A driver primitive is valid if it has a known type and:
+ *
+ * 1) for hats, it is a cardinal direction
+ * 2) for semi-axes, it is a positive or negative direction
+ */
+ bool IsValid(void) const;
+
+ private:
+ PrimitiveType m_type;
+ unsigned int m_driverIndex;
+ HAT_DIRECTION m_hatDirection;
+ SEMIAXIS_DIRECTION m_semiAxisDirection;
+ };
+}
diff --git a/xbmc/input/joysticks/IJoystickButtonMap.h b/xbmc/input/joysticks/IJoystickButtonMap.h
new file mode 100644
index 0000000000..744cc9edf9
--- /dev/null
+++ b/xbmc/input/joysticks/IJoystickButtonMap.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "DriverPrimitive.h"
+#include "JoystickTypes.h"
+
+#include <string>
+
+namespace JOYSTICK
+{
+ /*!
+ * \brief Button map interface to translate between the driver's raw
+ * button/hat/axis elements and physical joystick features.
+ *
+ * \sa IJoystickButtonMapper
+ */
+ class IJoystickButtonMap
+ {
+ public:
+ virtual ~IJoystickButtonMap(void) { }
+
+ /*!
+ * \brief The add-on ID of the game controller associated with this button map
+ *
+ * The controller ID provided by the implementation serves as the context
+ * for the feature names below.
+ *
+ * \return The ID of this button map's game controller add-on
+ */
+ virtual std::string ControllerID(void) const = 0;
+
+ /*!
+ * \brief Load the button map into memory
+ *
+ * \return True if button map is ready to start translating buttons, false otherwise
+ */
+ virtual bool Load(void) = 0;
+
+ /*!
+ * \brief Reset the button map to its defaults, or clear button map if no defaults
+ */
+ virtual void Reset(void) = 0;
+
+ /*!
+ * \brief Get the feature associated with a driver primitive
+ *
+ * Multiple primitives can be mapped to the same feature. For example,
+ * analog sticks use one primitive for each direction.
+ *
+ * \param primitive The driver primitive (a button, hat direction or semi-axis)
+ * \param feature The name of the resolved joystick feature, or
+ * invalid if false is returned
+ *
+ * \return True if the driver primitive is associated with a feature, false otherwise
+ */
+ virtual bool GetFeature(
+ const CDriverPrimitive& primitive,
+ FeatureName& feature
+ ) = 0;
+
+ /*!
+ * \brief Get the type of the feature for the given name
+ *
+ * \param feature The feature to look up
+ *
+ * \return The feature's type
+ */
+ virtual FEATURE_TYPE GetFeatureType(const FeatureName& feature) = 0;
+
+ /*!
+ * \brief Get the driver primitive for a scalar feature
+ *
+ * When a feature can be represented by a single driver primitive, it is
+ * called a scalar feature.
+ *
+ * - This includes buttons and triggers, because they can be mapped to a
+ * single button/hat/semiaxis
+ *
+ * - This does not include analog sticks, because they require two axes
+ * and four driver primitives (one for each semiaxis)
+ *
+ * \param feature Must be a scalar feature (a feature that only
+ * requires a single driver primitive)
+ * \param primitive The resolved driver primitive
+ *
+ * \return True if the feature resolved to a driver primitive, false if the
+ * feature didn't resolve or isn't a scalar feature
+ */
+ virtual bool GetScalar(
+ const FeatureName& feature,
+ CDriverPrimitive& primitive
+ ) = 0;
+
+ /*!
+ * \brief Add or update a scalar feature
+ *
+ * \param feature Must be a scalar feature
+ * \param primitive The feature's driver primitive
+ *
+ * \return True if the feature was updated, false if the feature is
+ * unchanged or failure occurs
+ */
+ virtual bool AddScalar(
+ const FeatureName& feature,
+ const CDriverPrimitive& primitive
+ ) = 0;
+
+ /*!
+ * \brief Get an analog stick from the button map
+ *
+ * \param feature Must be an analog stick or this will return false
+ * \param up The primitive mapped to the up direction (possibly unknown)
+ * \param down The primitive mapped to the down direction (possibly unknown)
+ * \param right The primitive mapped to the right direction (possibly unknown)
+ * \param left The primitive mapped to the left direction (possibly unknown)
+ *
+ * \return True if the feature resolved to an analog stick with at least 1 known direction
+ */
+ virtual bool GetAnalogStick(
+ const FeatureName& feature,
+ CDriverPrimitive& up,
+ CDriverPrimitive& down,
+ CDriverPrimitive& right,
+ CDriverPrimitive& left
+ ) = 0;
+
+ /*!
+ * \brief Add or update an analog stick
+ *
+ * \param feature Must be an analog stick or this will return false
+ * \param up The driver primitive for the up direction
+ * \param down The driver primitive for the down direction
+ * \param right The driver primitive for the right direction
+ * \param left The driver primitive for the left direction
+ *
+ * It is not required that these primitives be axes. If a primitive is a
+ * semiaxis, its opposite should point to the same axis index but with
+ * opposite direction.
+ *
+ * \return True if the analog stick was updated, false otherwise
+ */
+ virtual bool AddAnalogStick(
+ const FeatureName& feature,
+ const CDriverPrimitive& up,
+ const CDriverPrimitive& down,
+ const CDriverPrimitive& right,
+ const CDriverPrimitive& left
+ ) = 0;
+
+ /*!
+ * \brief Get an accelerometer from the button map
+ *
+ * \param feature Must be an accelerometer or this will return false
+ * \param positiveX The semiaxis mapped to the positive X direction (possibly unknown)
+ * \param positiveY The semiaxis mapped to the positive Y direction (possibly unknown)
+ * \param positiveZ The semiaxis mapped to the positive Z direction (possibly unknown)
+ *
+ * \return True if the feature resolved to an accelerometer with at least 1 known axis
+ */
+ virtual bool GetAccelerometer(
+ const FeatureName& feature,
+ CDriverPrimitive& positiveX,
+ CDriverPrimitive& positiveY,
+ CDriverPrimitive& positiveZ
+ ) = 0;
+
+ /*!
+ * \brief Get or update an accelerometer
+ *
+ * \param feature Must be an accelerometer or this will return false
+ * \param positiveX The semiaxis corresponding to the positive X direction
+ * \param positiveY The semiaxis corresponding to the positive Y direction
+ * \param positiveZ The semiaxis corresponding to the positive Z direction
+ *
+ * The driver primitives must be mapped to a semiaxis or this function will fail.
+ *
+ * \return True if the accelerometer was updated, false if unchanged or failure occurred
+ */
+ virtual bool AddAccelerometer(
+ const FeatureName& feature,
+ const CDriverPrimitive& positiveX,
+ const CDriverPrimitive& positiveY,
+ const CDriverPrimitive& positiveZ
+ ) = 0;
+ };
+}
diff --git a/xbmc/input/joysticks/IJoystickButtonMapper.h b/xbmc/input/joysticks/IJoystickButtonMapper.h
new file mode 100644
index 0000000000..2f73059421
--- /dev/null
+++ b/xbmc/input/joysticks/IJoystickButtonMapper.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <string>
+
+namespace JOYSTICK
+{
+ class CDriverPrimitive;
+ class IJoystickButtonMap;
+
+ /*!
+ * \ingroup joysticks
+ *
+ * \brief Button mapper interface to assign the driver's raw button/hat/axis
+ * elements to physical joystick features using a provided button map.
+ *
+ * \sa IJoystickButtonMap
+ */
+ class IJoystickButtonMapper
+ {
+ public:
+ virtual ~IJoystickButtonMapper(void) { }
+
+ /*!
+ * \brief The add-on ID of the game controller associated with this button mapper
+ *
+ * \return The ID of the add-on extending kodi.game.controller
+ */
+ virtual std::string ControllerID(void) const = 0;
+
+ /*!
+ * \brief Handle button/hat press or axis threshold
+ *
+ * \param buttonMap The button map being manipulated
+ * \param primitive The source of the action
+ *
+ * \return True if action was mapped to a feature
+ */
+ virtual bool MapPrimitive(IJoystickButtonMap* buttonMap, const CDriverPrimitive& primitive) = 0;
+ };
+}
diff --git a/xbmc/input/joysticks/IJoystickDriverHandler.h b/xbmc/input/joysticks/IJoystickDriverHandler.h
new file mode 100644
index 0000000000..d60faecced
--- /dev/null
+++ b/xbmc/input/joysticks/IJoystickDriverHandler.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "JoystickTypes.h"
+
+namespace JOYSTICK
+{
+ /*!
+ * \brief Interface defining methods to handle joystick events for raw driver
+ * elements (buttons, hats, axes)
+ */
+ class IJoystickDriverHandler
+ {
+ public:
+ virtual ~IJoystickDriverHandler(void) { }
+
+ /*!
+ * \brief Handle button motion
+ *
+ * \param buttonIndex The index of the button as reported by the driver
+ * \param bPressed true for press motion, false for release motion
+ *
+ * \return True if a press was handled, false otherwise
+ */
+ virtual bool OnButtonMotion(unsigned int buttonIndex, bool bPressed) = 0;
+
+ /*!
+ * \brief Handle hat motion
+ *
+ * \param hatIndex The index of the hat as reported by the driver
+ * \param state The direction the hat is now being pressed
+ *
+ * \return True if the new direction was handled, false otherwise
+ */
+ virtual bool OnHatMotion(unsigned int hatIndex, HAT_STATE state) = 0;
+
+ /*!
+ * \brief Handle axis motion
+ *
+ * If a joystick feature requires multiple axes (analog sticks, accelerometers),
+ * they can be buffered for later processing.
+ *
+ * \param axisIndex The index of the axis as reported by the driver
+ * \param position The position of the axis in the closed interval [-1.0, 1.0]
+ *
+ * \return True if the motion was handled, false otherwise
+ */
+ virtual bool OnAxisMotion(unsigned int axisIndex, float position) = 0;
+
+ /*!
+ * \brief Handle buffered axis positions for features that require multiple axes
+ *
+ * ProcessAxisMotions() is called at the end of the frame when all axis motions
+ * have been reported. This has several uses, including:
+ *
+ * - Combining multiple axes into a single analog stick or accelerometer event
+ * - Imitating an analog feature with a digital button so that events can be
+ * dispatched every frame.
+ */
+ virtual void ProcessAxisMotions(void) = 0;
+ };
+}
diff --git a/xbmc/input/joysticks/IJoystickInputHandler.h b/xbmc/input/joysticks/IJoystickInputHandler.h
new file mode 100644
index 0000000000..a3d8e9cf70
--- /dev/null
+++ b/xbmc/input/joysticks/IJoystickInputHandler.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "JoystickTypes.h"
+
+#include <string>
+
+namespace JOYSTICK
+{
+ /*!
+ * \brief Interface for handling input events for game controllers
+ */
+ class IJoystickInputHandler
+ {
+ public:
+ virtual ~IJoystickInputHandler(void) { }
+
+ /*!
+ * \brief The add-on ID of the game controller associated with this input handler
+ *
+ * \return The ID of the add-on extending kodi.game.controller
+ */
+ virtual std::string ControllerID(void) const = 0;
+
+ virtual bool HasFeature(const FeatureName& feature) const = 0;
+
+ /*!
+ * \brief Get the type of input handled by the specified feature
+ *
+ * \return INPUT_TYPE::DIGITAL for digital buttons, INPUT::ANALOG for analog
+ * buttons, or INPUT::UNKNOWN otherwise
+ */
+ virtual INPUT_TYPE GetInputType(const FeatureName& feature) const = 0;
+
+ /*!
+ * \brief A digital button has been pressed or released
+ *
+ * \param feature The feature being pressed
+ * \param bPressed True if pressed, false if released
+ *
+ * \return True if the event was handled otherwise false
+ */
+ virtual bool OnButtonPress(const FeatureName& feature, bool bPressed) = 0;
+
+ /*!
+ * \brief An analog button (trigger or a pressure-sensitive button) has changed state
+ *
+ * \param feature The feature changing state
+ * \param magnitude The button pressure or trigger travel distance in the
+ * closed interval [0, 1]
+ *
+ * \return True if the event was handled otherwise false
+ */
+ virtual bool OnButtonMotion(const FeatureName& feature, float magnitude) = 0;
+
+ /*!
+ * \brief An analog stick has moved
+ *
+ * \param feature The analog stick being moved
+ * \param x The x coordinate in the closed interval [-1, 1]
+ * \param y The y coordinate in the closed interval [-1, 1]
+ *
+ * \return True if the event was handled otherwise false
+ */
+ virtual bool OnAnalogStickMotion(const FeatureName& feature, float x, float y) = 0;
+
+ /*!
+ * \brief An accelerometer's state has changed
+ *
+ * \param feature The accelerometer being accelerated
+ * \param x The x coordinate in the closed interval [-1, 1]
+ * \param y The y coordinate in the closed interval [-1, 1]
+ * \param z The z coordinate in the closed interval [-1, 1]
+ *
+ * \return True if the event was handled otherwise false
+ */
+ virtual bool OnAccelerometerMotion(const FeatureName& feature, float x, float y, float z) { return false; }
+ };
+}
diff --git a/xbmc/input/joysticks/IKeymapHandler.h b/xbmc/input/joysticks/IKeymapHandler.h
new file mode 100644
index 0000000000..75de4f51e7
--- /dev/null
+++ b/xbmc/input/joysticks/IKeymapHandler.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "JoystickTypes.h"
+
+namespace JOYSTICK
+{
+ /*!
+ * \brief Interface for handling keymap keys
+ *
+ * Keys can be mapped to analog actions (e.g. "AnalogSeekForward") or digital
+ * actions (e.g. "Up").
+ */
+ class IKeymapHandler
+ {
+ public:
+ virtual ~IKeymapHandler(void) { }
+
+ /*!
+ * \brief Get the type of action mapped to the specified key ID
+ *
+ * \param keyId The key ID from Key.h
+ *
+ * \return The type of action mapped to keyId, or INPUT_TYPE::UNKNOWN if
+ * no action is mapped to the specified key
+ */
+ virtual INPUT_TYPE GetInputType(unsigned int keyId) const = 0;
+
+ /*!
+ * \brief A key mapped to a digital action has been pressed or released
+ *
+ * \param keyId The key ID from Key.h
+ * \param bPressed true if the key's button/axis is activated, false if deactivated
+ */
+ virtual void OnDigitalKey(unsigned int keyId, bool bPressed) = 0;
+
+ /*!
+ * \brief Callback for keys mapped to analog actions
+ *
+ * \param keyId The button key ID from Key.h
+ * \param magnitude The amount of the analog action
+ *
+ * If keyId is not mapped to an analog action, no action need be taken
+ */
+ virtual void OnAnalogKey(unsigned int buttonKeyId, float magnitude) = 0;
+ };
+}
diff --git a/xbmc/input/joysticks/JoystickMonitor.cpp b/xbmc/input/joysticks/JoystickMonitor.cpp
new file mode 100644
index 0000000000..6de84abf43
--- /dev/null
+++ b/xbmc/input/joysticks/JoystickMonitor.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "JoystickMonitor.h"
+#include "Application.h"
+#include "input/InputManager.h"
+
+using namespace JOYSTICK;
+
+bool CJoystickMonitor::OnButtonMotion(unsigned int buttonIndex, bool bPressed)
+{
+ if (bPressed)
+ {
+ CInputManager::GetInstance().SetMouseActive(false);
+ return ResetTimers();
+ }
+
+ return false;
+}
+
+bool CJoystickMonitor::OnHatMotion(unsigned int hatIndex, HAT_STATE state)
+{
+ if (state != HAT_STATE::UNPRESSED)
+ {
+ CInputManager::GetInstance().SetMouseActive(false);
+ return ResetTimers();
+ }
+
+ return false;
+}
+
+bool CJoystickMonitor::OnAxisMotion(unsigned int axisIndex, float position)
+{
+ if (position)
+ {
+ CInputManager::GetInstance().SetMouseActive(false);
+ return ResetTimers();
+ }
+
+ return false;
+}
+
+bool CJoystickMonitor::ResetTimers(void)
+{
+ g_application.ResetSystemIdleTimer();
+ g_application.ResetScreenSaver();
+ return g_application.WakeUpScreenSaverAndDPMS();
+}
diff --git a/xbmc/input/joysticks/JoystickMonitor.h b/xbmc/input/joysticks/JoystickMonitor.h
new file mode 100644
index 0000000000..6bfca8b069
--- /dev/null
+++ b/xbmc/input/joysticks/JoystickMonitor.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "IJoystickDriverHandler.h"
+
+namespace JOYSTICK
+{
+ /*!
+ * \brief Monitors joystick input and resets screensaver/shutdown timers
+ * whenever motion occurs.
+ */
+ class CJoystickMonitor : public IJoystickDriverHandler
+ {
+ public:
+ // implementation of IJoystickDriverHandler
+ virtual bool OnButtonMotion(unsigned int buttonIndex, bool bPressed) override;
+ virtual bool OnHatMotion(unsigned int hatIndex, HAT_STATE state) override;
+ virtual bool OnAxisMotion(unsigned int axisIndex, float position) override;
+ virtual void ProcessAxisMotions(void) override { }
+
+ private:
+ /*!
+ * \brief Reset screensaver and shutdown timers
+ * \return True if the application was woken from screensaver
+ */
+ bool ResetTimers(void);
+ };
+}
diff --git a/xbmc/input/joysticks/JoystickTranslator.cpp b/xbmc/input/joysticks/JoystickTranslator.cpp
new file mode 100644
index 0000000000..b0faee3c54
--- /dev/null
+++ b/xbmc/input/joysticks/JoystickTranslator.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "JoystickTranslator.h"
+
+using namespace JOYSTICK;
+
+const char* CJoystickTranslator::HatStateToString(HAT_STATE state)
+{
+ switch (state)
+ {
+ case HAT_STATE::UP: return "UP";
+ case HAT_STATE::DOWN: return "DOWN";
+ case HAT_STATE::RIGHT: return "RIGHT";
+ case HAT_STATE::LEFT: return "LEFT";
+ case HAT_STATE::RIGHTUP: return "UP RIGHT";
+ case HAT_STATE::RIGHTDOWN: return "DOWN RIGHT";
+ case HAT_STATE::LEFTUP: return "UP LEFT";
+ case HAT_STATE::LEFTDOWN: return "DOWN LEFT";
+ case HAT_STATE::UNPRESSED:
+ default:
+ break;
+ }
+
+ return "RELEASED";
+}
+
+SEMIAXIS_DIRECTION CJoystickTranslator::PositionToSemiAxisDirection(float position)
+{
+ if (position > 0) return SEMIAXIS_DIRECTION::POSITIVE;
+ else if (position < 0) return SEMIAXIS_DIRECTION::NEGATIVE;
+
+ return SEMIAXIS_DIRECTION::ZERO;
+}
+
+CARDINAL_DIRECTION CJoystickTranslator::VectorToCardinalDirection(float x, float y)
+{
+ if (y >= x && y > -x) return CARDINAL_DIRECTION::UP;
+ else if (y < x && y >= -x) return CARDINAL_DIRECTION::RIGHT;
+ else if (y <= x && y < -x) return CARDINAL_DIRECTION::DOWN;
+ else if (y > x && y <= -x) return CARDINAL_DIRECTION::LEFT;
+
+ return CARDINAL_DIRECTION::UNKNOWN;
+}
diff --git a/xbmc/input/joysticks/JoystickTranslator.h b/xbmc/input/joysticks/JoystickTranslator.h
new file mode 100644
index 0000000000..659deb31dd
--- /dev/null
+++ b/xbmc/input/joysticks/JoystickTranslator.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "JoystickTypes.h"
+
+namespace JOYSTICK
+{
+ class CJoystickTranslator
+ {
+ public:
+ /*!
+ * \brief Translate a hat state to a string representation
+ *
+ * \param state The hat state
+ *
+ * \return A capitalized string representation, or "RELEASED" if the hat is centered.
+ */
+ static const char* HatStateToString(HAT_STATE state);
+
+ /*!
+ * \brief Get the semi-axis direction containing the specified position
+ *
+ * \param position The position of the axis
+ *
+ * \return POSITIVE, NEGATIVE, or UNKNOWN if position is 0
+ */
+ static SEMIAXIS_DIRECTION PositionToSemiAxisDirection(float position);
+
+ /*!
+ * \brief Get the closest cardinal direction to the given vector
+ *
+ * Ties are resolved in the clockwise direction: (0.5, 0.5) will resolve to
+ * RIGHT.
+ *
+ * \param x The x component of the vector
+ * \param y The y component of the vector
+ *
+ * \return The closest cardinal directon (up, down, right or left), or unknown
+ * if x and y are both 0.
+ */
+ static CARDINAL_DIRECTION VectorToCardinalDirection(float x, float y);
+ };
+}
diff --git a/xbmc/input/joysticks/JoystickTypes.h b/xbmc/input/joysticks/JoystickTypes.h
new file mode 100644
index 0000000000..fee25bdb44
--- /dev/null
+++ b/xbmc/input/joysticks/JoystickTypes.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <string>
+
+namespace JOYSTICK
+{
+ /*!
+ * \brief Name of a physical feature belonging to the joystick
+ */
+ typedef std::string FeatureName;
+
+ /*!
+ * \brief Types of features used in the joystick library
+ *
+ * Available types:
+ *
+ * 1) scalar[1]
+ * 2) analog stick
+ * 3) accelerometer
+ *
+ * [1] All three driver primitives (buttons, hats and axes) have a state that
+ * can be represented using a single scalar value. For this reason,
+ * features that map to a single primitive are called "scalar features".
+ */
+ enum class FEATURE_TYPE
+ {
+ UNKNOWN,
+ SCALAR,
+ ANALOG_STICK,
+ ACCELEROMETER,
+ };
+
+ /*!
+ * \brief Direction arrows on the hat (directional pad)
+ */
+ enum class HAT_DIRECTION
+ {
+ UNKNOWN = 0x0,
+ UP = 0x1,
+ DOWN = 0x2,
+ RIGHT = 0x4,
+ LEFT = 0x8,
+ };
+
+ /*!
+ * \brief Generic typedef for cardinal directions
+ */
+ typedef HAT_DIRECTION CARDINAL_DIRECTION;
+
+ /*!
+ * \brief States in which a hat can be
+ */
+ enum class HAT_STATE
+ {
+ UNPRESSED = 0x0, /*!< @brief no directions are pressed */
+ UP = 0x1, /*!< @brief only up is pressed */
+ DOWN = 0x2, /*!< @brief only down is pressed */
+ RIGHT = 0x4, /*!< @brief only right is pressed */
+ LEFT = 0x8, /*!< @brief only left is pressed */
+ RIGHTUP = RIGHT | UP,
+ RIGHTDOWN = RIGHT | DOWN,
+ LEFTUP = LEFT | UP,
+ LEFTDOWN = LEFT | DOWN,
+ };
+
+ /*!
+ * \brief Generic typedef for intercardinal directions
+ */
+ typedef HAT_STATE INTERCARDINAL_DIRECTION;
+
+ /*!
+ * \brief Directions in which a semiaxis can point
+ */
+ enum class SEMIAXIS_DIRECTION
+ {
+ NEGATIVE = -1, // semiaxis lies in the interval [-1.0, 0.0]
+ ZERO = 0, // semiaxis is unknown or invalid
+ POSITIVE = 1, // semiaxis lies in the interval [0.0, 1.0]
+ };
+
+ /*!
+ * \brief Types of input available for scalar features
+ */
+ enum class INPUT_TYPE
+ {
+ UNKNOWN,
+ DIGITAL,
+ ANALOG,
+ };
+}
diff --git a/xbmc/input/joysticks/JoystickUtils.h b/xbmc/input/joysticks/JoystickUtils.h
new file mode 100644
index 0000000000..8d2c0b0bbf
--- /dev/null
+++ b/xbmc/input/joysticks/JoystickUtils.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "JoystickTypes.h"
+
+inline JOYSTICK::HAT_DIRECTION& operator|=(JOYSTICK::HAT_DIRECTION& lhs, JOYSTICK::HAT_DIRECTION rhs)
+{
+ return lhs = static_cast<JOYSTICK::HAT_DIRECTION>(static_cast<int>(lhs) | static_cast<int>(rhs));
+}
+
+inline JOYSTICK::HAT_STATE& operator|=(JOYSTICK::HAT_STATE& lhs, JOYSTICK::HAT_STATE rhs)
+{
+ return lhs = static_cast<JOYSTICK::HAT_STATE>(static_cast<int>(lhs) | static_cast<int>(rhs));
+}
+
+inline bool operator&(JOYSTICK::HAT_STATE lhs, JOYSTICK::HAT_DIRECTION rhs)
+{
+ return (static_cast<int>(lhs) & static_cast<int>(rhs)) ? true : false;
+}
+
+inline JOYSTICK::SEMIAXIS_DIRECTION operator*(JOYSTICK::SEMIAXIS_DIRECTION lhs, int rhs)
+{
+ return static_cast<JOYSTICK::SEMIAXIS_DIRECTION>(static_cast<int>(lhs) * rhs);
+}
+
+inline float operator*(float lhs, JOYSTICK::SEMIAXIS_DIRECTION rhs)
+{
+ return lhs * static_cast<int>(rhs);
+}
diff --git a/xbmc/input/joysticks/KeymapHandler.cpp b/xbmc/input/joysticks/KeymapHandler.cpp
new file mode 100644
index 0000000000..3574de45e4
--- /dev/null
+++ b/xbmc/input/joysticks/KeymapHandler.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2015-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "KeymapHandler.h"
+#include "guilib/GUIWindowManager.h"
+#include "input/ButtonTranslator.h"
+#include "input/InputManager.h"
+#include "input/Key.h"
+
+#include <algorithm>
+
+using namespace KODI;
+using namespace MESSAGING;
+
+#define HOLD_TIMEOUT_MS 500
+#define REPEAT_TIMEOUT_MS 50
+
+using namespace JOYSTICK;
+
+CKeymapHandler::CKeymapHandler(void)
+ : CThread("KeymapHandler"),
+ m_state(STATE_UNPRESSED),
+ m_lastButtonPress(0)
+{
+ Create(false);
+}
+
+CKeymapHandler::~CKeymapHandler(void)
+{
+ StopThread(true);
+}
+
+INPUT_TYPE CKeymapHandler::GetInputType(unsigned int keyId) const
+{
+ if (keyId != 0)
+ {
+ CAction action(CButtonTranslator::GetInstance().GetAction(g_windowManager.GetActiveWindowID(), CKey(keyId)));
+ if (action.GetID() > 0)
+ {
+ if (action.IsAnalog())
+ return INPUT_TYPE::ANALOG;
+ else
+ return INPUT_TYPE::DIGITAL;
+ }
+ }
+
+ return INPUT_TYPE::UNKNOWN;
+}
+
+void CKeymapHandler::OnDigitalKey(unsigned int keyId, bool bPressed)
+{
+ if (keyId != 0)
+ {
+ CSingleLock lock(m_digitalMutex);
+
+ if (bPressed && !IsPressed(keyId))
+ ProcessButtonPress(keyId);
+ else if (!bPressed && IsPressed(keyId))
+ ProcessButtonRelease(keyId);
+ }
+}
+
+void CKeymapHandler::OnAnalogKey(unsigned int keyId, float magnitude)
+{
+ if (keyId != 0)
+ SendAnalogAction(keyId, magnitude);
+}
+
+void CKeymapHandler::Process()
+{
+ unsigned int holdStartTime = 0;
+ unsigned int pressedButton = 0;
+
+ while (!m_bStop)
+ {
+ switch (m_state)
+ {
+ case STATE_UNPRESSED:
+ {
+ // Wait for button press
+ WaitResponse waitResponse = AbortableWait(m_pressEvent);
+
+ CSingleLock lock(m_digitalMutex);
+
+ if (waitResponse == WAIT_SIGNALED && m_lastButtonPress != 0)
+ {
+ pressedButton = m_lastButtonPress;
+ m_state = STATE_BUTTON_PRESSED;
+ }
+ break;
+ }
+
+ case STATE_BUTTON_PRESSED:
+ {
+ holdStartTime = XbmcThreads::SystemClockMillis();
+
+ // Wait for hold time to elapse
+ WaitResponse waitResponse = AbortableWait(m_pressEvent, HOLD_TIMEOUT_MS);
+
+ CSingleLock lock(m_digitalMutex);
+
+ if (m_lastButtonPress == 0)
+ {
+ m_state = STATE_UNPRESSED;
+ }
+ else if (waitResponse == WAIT_SIGNALED || m_lastButtonPress != pressedButton)
+ {
+ pressedButton = m_lastButtonPress;
+ // m_state is unchanged
+ }
+ else if (waitResponse == WAIT_TIMEDOUT)
+ {
+ m_state = STATE_BUTTON_HELD;
+ }
+ break;
+ }
+
+ case STATE_BUTTON_HELD:
+ {
+ const unsigned int holdTimeMs = XbmcThreads::SystemClockMillis() - holdStartTime;
+ SendDigitalAction(pressedButton, holdTimeMs);
+
+ // Wait for repeat time to elapse
+ WaitResponse waitResponse = AbortableWait(m_pressEvent, REPEAT_TIMEOUT_MS);
+
+ CSingleLock lock(m_digitalMutex);
+
+ if (m_lastButtonPress == 0)
+ {
+ m_state = STATE_UNPRESSED;
+ }
+ else if (waitResponse == WAIT_SIGNALED || m_lastButtonPress != pressedButton)
+ {
+ pressedButton = m_lastButtonPress;
+ m_state = STATE_BUTTON_PRESSED;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+}
+
+bool CKeymapHandler::ProcessButtonPress(unsigned int keyId)
+{
+ m_pressedButtons.push_back(keyId);
+
+ if (SendDigitalAction(keyId))
+ {
+ m_lastButtonPress = keyId;
+ m_pressEvent.Set();
+ return true;
+ }
+
+ return false;
+}
+
+void CKeymapHandler::ProcessButtonRelease(unsigned int keyId)
+{
+ m_pressedButtons.erase(std::remove(m_pressedButtons.begin(), m_pressedButtons.end(), keyId), m_pressedButtons.end());
+
+ if (keyId == m_lastButtonPress || m_pressedButtons.empty())
+ {
+ m_lastButtonPress = 0;
+ m_pressEvent.Set();
+ }
+}
+
+bool CKeymapHandler::IsPressed(unsigned int keyId) const
+{
+ return std::find(m_pressedButtons.begin(), m_pressedButtons.end(), keyId) != m_pressedButtons.end();
+}
+
+bool CKeymapHandler::SendDigitalAction(unsigned int keyId, unsigned int holdTimeMs /* = 0 */)
+{
+ CAction action(CButtonTranslator::GetInstance().GetAction(g_windowManager.GetActiveWindowID(), CKey(keyId, holdTimeMs)));
+ if (action.GetID() > 0)
+ {
+ CInputManager::GetInstance().QueueAction(action);
+ return true;
+ }
+
+ return false;
+}
+
+bool CKeymapHandler::SendAnalogAction(unsigned int keyId, float magnitude)
+{
+ CAction action(CButtonTranslator::GetInstance().GetAction(g_windowManager.GetActiveWindowID(), CKey(keyId)));
+ if (action.GetID() > 0)
+ {
+ CAction actionWithAmount(action.GetID(), magnitude, 0.0f, action.GetName());
+ CInputManager::GetInstance().QueueAction(actionWithAmount);
+ return true;
+ }
+
+ return false;
+}
diff --git a/xbmc/input/joysticks/KeymapHandler.h b/xbmc/input/joysticks/KeymapHandler.h
new file mode 100644
index 0000000000..4d718c1627
--- /dev/null
+++ b/xbmc/input/joysticks/KeymapHandler.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "input/joysticks/IKeymapHandler.h"
+#include "threads/CriticalSection.h"
+#include "threads/Event.h"
+#include "threads/Thread.h"
+
+#include <vector>
+
+namespace JOYSTICK
+{
+ class CKeymapHandler : public IKeymapHandler,
+ protected CThread
+ {
+ public:
+ CKeymapHandler(void);
+
+ virtual ~CKeymapHandler(void);
+
+ // implementation of IKeymapHandler
+ virtual INPUT_TYPE GetInputType(unsigned int keyId) const override;
+ virtual void OnDigitalKey(unsigned int keyId, bool bPressed) override;
+ virtual void OnAnalogKey(unsigned int keyId, float magnitude) override;
+
+ protected:
+ // implementation of CThread
+ virtual void Process(void) override;
+
+ private:
+ enum BUTTON_STATE
+ {
+ STATE_UNPRESSED,
+ STATE_BUTTON_PRESSED,
+ STATE_BUTTON_HELD,
+ };
+
+ bool ProcessButtonPress(unsigned int keyId);
+ void ProcessButtonRelease(unsigned int keyId);
+ bool IsPressed(unsigned int keyId) const;
+
+ static bool SendDigitalAction(unsigned int keyId, unsigned int holdTimeMs = 0);
+ static bool SendAnalogAction(unsigned int keyId, float magnitude);
+
+ BUTTON_STATE m_state;
+ unsigned int m_lastButtonPress;
+ std::vector<unsigned int> m_pressedButtons;
+ CEvent m_pressEvent;
+ CCriticalSection m_digitalMutex;
+ };
+}
diff --git a/xbmc/input/joysticks/Makefile b/xbmc/input/joysticks/Makefile
new file mode 100644
index 0000000000..03b4fca88d
--- /dev/null
+++ b/xbmc/input/joysticks/Makefile
@@ -0,0 +1,9 @@
+SRCS=DriverPrimitive.cpp \
+ JoystickMonitor.cpp \
+ JoystickTranslator.cpp \
+ KeymapHandler.cpp \
+
+LIB=input_joysticks.a
+
+include ../../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/input/joysticks/generic/GenericJoystickButtonMapping.cpp b/xbmc/input/joysticks/generic/GenericJoystickButtonMapping.cpp
new file mode 100644
index 0000000000..8432066598
--- /dev/null
+++ b/xbmc/input/joysticks/generic/GenericJoystickButtonMapping.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "GenericJoystickButtonMapping.h"
+#include "input/joysticks/DriverPrimitive.h"
+#include "input/joysticks/IJoystickButtonMapper.h"
+#include "input/joysticks/JoystickTranslator.h"
+#include "input/joysticks/JoystickUtils.h"
+#include "threads/SystemClock.h"
+#include "utils/log.h"
+
+#include <algorithm>
+#include <assert.h>
+#include <cmath>
+
+using namespace JOYSTICK;
+using namespace XbmcThreads;
+
+#define MAPPING_COOLDOWN_MS 50 // Guard against repeated input
+#define AXIS_THRESHOLD 0.75f // Axis must exceed this value to be mapped
+
+CGenericJoystickButtonMapping::CGenericJoystickButtonMapping(IJoystickButtonMapper* buttonMapper, IJoystickButtonMap* buttonMap)
+ : m_buttonMapper(buttonMapper),
+ m_buttonMap(buttonMap),
+ m_lastAction(0)
+{
+ assert(m_buttonMapper != NULL);
+ assert(m_buttonMap != NULL);
+}
+
+bool CGenericJoystickButtonMapping::OnButtonMotion(unsigned int buttonIndex, bool bPressed)
+{
+ if (bPressed)
+ {
+ CDriverPrimitive buttonPrimitive(buttonIndex);
+ if (buttonPrimitive.IsValid())
+ {
+ MapPrimitive(buttonPrimitive);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CGenericJoystickButtonMapping::OnHatMotion(unsigned int hatIndex, HAT_STATE state)
+{
+ CDriverPrimitive hatPrimitive(hatIndex, static_cast<HAT_DIRECTION>(state));
+ if (hatPrimitive.IsValid())
+ {
+ MapPrimitive(hatPrimitive);
+ return true;
+ }
+
+ return false;
+}
+
+bool CGenericJoystickButtonMapping::OnAxisMotion(unsigned int axisIndex, float position)
+{
+ SEMIAXIS_DIRECTION dir = CJoystickTranslator::PositionToSemiAxisDirection(position);
+
+ CDriverPrimitive axis(axisIndex, dir);
+ CDriverPrimitive oppositeAxis(axisIndex, dir * -1);
+
+ if (position == 0.0f)
+ {
+ Deactivate(axis);
+ Deactivate(oppositeAxis);
+ }
+ else
+ {
+ Deactivate(oppositeAxis);
+
+ if (std::abs(position) >= AXIS_THRESHOLD)
+ Activate(axis);
+ else
+ Deactivate(axis);
+ }
+
+ return true;
+}
+
+void CGenericJoystickButtonMapping::ProcessAxisMotions(void)
+{
+ for (std::vector<ActivatedAxis>::iterator it = m_activatedAxes.begin(); it != m_activatedAxes.end(); ++it)
+ {
+ ActivatedAxis& semiaxis = *it;
+
+ // Only emit once
+ if (!semiaxis.bEmitted)
+ {
+ semiaxis.bEmitted = true;
+ MapPrimitive(semiaxis.driverPrimitive);
+ }
+ }
+}
+
+void CGenericJoystickButtonMapping::MapPrimitive(const CDriverPrimitive& primitive)
+{
+ const unsigned int now = SystemClockMillis();
+
+ bool bTimeoutElapsed = (now >= m_lastAction + MAPPING_COOLDOWN_MS);
+ if (bTimeoutElapsed)
+ {
+ m_lastAction = SystemClockMillis();
+ m_buttonMapper->MapPrimitive(m_buttonMap, primitive);
+ }
+ else
+ {
+ const unsigned int elapsed = now - m_lastAction;
+ CLog::Log(LOGDEBUG, "Button mapping: rapid input after %ums dropped for profile \"%s\"",
+ elapsed, m_buttonMapper->ControllerID().c_str());
+ }
+}
+
+void CGenericJoystickButtonMapping::Activate(const CDriverPrimitive& semiaxis)
+{
+ if (!IsActive(semiaxis))
+ m_activatedAxes.push_back(ActivatedAxis{semiaxis});
+}
+
+void CGenericJoystickButtonMapping::Deactivate(const CDriverPrimitive& semiaxis)
+{
+ m_activatedAxes.erase(std::remove_if(m_activatedAxes.begin(), m_activatedAxes.end(),
+ [&semiaxis](const ActivatedAxis& axis)
+ {
+ return semiaxis == axis.driverPrimitive;
+ }), m_activatedAxes.end());
+}
+
+bool CGenericJoystickButtonMapping::IsActive(const CDriverPrimitive& semiaxis)
+{
+ return std::find_if(m_activatedAxes.begin(), m_activatedAxes.end(),
+ [&semiaxis](const ActivatedAxis& axis)
+ {
+ return semiaxis == axis.driverPrimitive;
+ }) != m_activatedAxes.end();
+}
diff --git a/xbmc/input/joysticks/generic/GenericJoystickButtonMapping.h b/xbmc/input/joysticks/generic/GenericJoystickButtonMapping.h
new file mode 100644
index 0000000000..4bbb4c4847
--- /dev/null
+++ b/xbmc/input/joysticks/generic/GenericJoystickButtonMapping.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "input/joysticks/DriverPrimitive.h"
+#include "input/joysticks/IJoystickDriverHandler.h"
+
+#include <vector>
+
+namespace JOYSTICK
+{
+ class IJoystickButtonMap;
+ class IJoystickButtonMapper;
+
+ /*
+ * \brief Generic implementation of a class that provides button mapping by
+ * translating driver events to button mapping commands
+ *
+ * Button mapping commands are invoked instantly for buttons and hats.
+ *
+ * Button mapping commands are deferred for a short while after an axis is
+ * activated, and only one command will be invoked per activation.
+ */
+ class CGenericJoystickButtonMapping : public IJoystickDriverHandler
+ {
+ public:
+ /*
+ * \brief Constructor for CGenericJoystickButtonMapping
+ *
+ * \param buttonMapper Carries out button-mapping commands using <buttonMap>
+ * \param buttonMap The button map given to <buttonMapper> on each command
+ */
+ CGenericJoystickButtonMapping(IJoystickButtonMapper* buttonMapper, IJoystickButtonMap* buttonMap);
+
+ virtual ~CGenericJoystickButtonMapping(void) { }
+
+ // implementation of IJoystickDriverHandler
+ virtual bool OnButtonMotion(unsigned int buttonIndex, bool bPressed) override;
+ virtual bool OnHatMotion(unsigned int hatIndex, HAT_STATE state) override;
+ virtual bool OnAxisMotion(unsigned int axisIndex, float position) override;
+ virtual void ProcessAxisMotions(void) override;
+
+ private:
+ void MapPrimitive(const CDriverPrimitive& primitive);
+
+ void Activate(const CDriverPrimitive& semiAxis);
+ void Deactivate(const CDriverPrimitive& semiAxis);
+ bool IsActive(const CDriverPrimitive& semiAxis);
+
+ IJoystickButtonMapper* const m_buttonMapper;
+ IJoystickButtonMap* const m_buttonMap;
+
+ struct ActivatedAxis
+ {
+ CDriverPrimitive driverPrimitive;
+ bool bEmitted; // true if this axis has emited a button-mapping command
+ };
+
+ std::vector<ActivatedAxis> m_activatedAxes;
+ unsigned int m_lastAction;
+ };
+}
diff --git a/xbmc/input/joysticks/generic/GenericJoystickFeatureHandling.cpp b/xbmc/input/joysticks/generic/GenericJoystickFeatureHandling.cpp
new file mode 100644
index 0000000000..d82ac7ca53
--- /dev/null
+++ b/xbmc/input/joysticks/generic/GenericJoystickFeatureHandling.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "GenericJoystickFeatureHandling.h"
+#include "input/joysticks/DriverPrimitive.h"
+#include "input/joysticks/IJoystickButtonMap.h"
+#include "input/joysticks/IJoystickInputHandler.h"
+#include "utils/log.h"
+
+using namespace JOYSTICK;
+
+#define ANALOG_DIGITAL_THRESHOLD 0.5f
+
+// --- CJoystickFeature --------------------------------------------------------
+
+CJoystickFeature::CJoystickFeature(const FeatureName& name, IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap) :
+ m_name(name),
+ m_handler(handler),
+ m_buttonMap(buttonMap)
+{
+}
+
+// --- CScalarFeature ----------------------------------------------------------
+
+CScalarFeature::CScalarFeature(const FeatureName& name, IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap) :
+ CJoystickFeature(name, handler, buttonMap),
+ m_inputType(handler->GetInputType(name)),
+ m_bDigitalState(false),
+ m_analogState(0.0f)
+{
+}
+
+bool CScalarFeature::OnDigitalMotion(const CDriverPrimitive& source, bool bPressed)
+{
+ bool bHandled = false;
+
+ if (m_inputType == INPUT_TYPE::DIGITAL)
+ {
+ if (m_bDigitalState != bPressed)
+ {
+ m_bDigitalState = bPressed;
+ bHandled = OnDigitalMotion(bPressed);
+ }
+ }
+ else if (m_inputType == INPUT_TYPE::ANALOG)
+ {
+ bHandled = OnAnalogMotion(source, bPressed ? 1.0f : 0.0f);
+ }
+
+ return bHandled;
+}
+
+bool CScalarFeature::OnAnalogMotion(const CDriverPrimitive& source, float magnitude)
+{
+ bool bHandled = false;
+
+ if (m_inputType == INPUT_TYPE::DIGITAL)
+ {
+ bHandled = OnDigitalMotion(source, magnitude >= ANALOG_DIGITAL_THRESHOLD);
+ }
+ else if (m_inputType == INPUT_TYPE::ANALOG)
+ {
+ if (m_analogState != 0.0f || magnitude != 0.0f)
+ {
+ m_analogState = magnitude;
+ bHandled = OnAnalogMotion(magnitude);
+ }
+ }
+
+ return bHandled;
+}
+
+bool CScalarFeature::OnDigitalMotion(bool bPressed)
+{
+ CLog::Log(LOGDEBUG, "Feature [ %s ] on %s %s",
+ m_name.c_str(), m_handler->ControllerID().c_str(), bPressed ? "pressed" : "released");
+
+ return m_handler->OnButtonPress(m_name, bPressed);
+}
+
+bool CScalarFeature::OnAnalogMotion(float magnitude)
+{
+ const bool bActivated = (magnitude != 0.0f);
+
+ if (m_bDigitalState != bActivated)
+ {
+ m_bDigitalState = bActivated;
+
+ CLog::Log(LOGDEBUG, "Feature [ %s ] on %s %s",
+ m_name.c_str(), m_handler->ControllerID().c_str(), bActivated ? "activated" : "deactivated");
+ }
+
+ return m_handler->OnButtonMotion(m_name, magnitude);
+}
+
+// --- CAnalogStick ------------------------------------------------------------
+
+CAnalogStick::CAnalogStick(const FeatureName& name, IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap) :
+ CJoystickFeature(name, handler, buttonMap),
+ m_vertState(0.0f),
+ m_horizState(0.0f)
+{
+}
+
+bool CAnalogStick::OnDigitalMotion(const CDriverPrimitive& source, bool bPressed)
+{
+ return OnAnalogMotion(source, bPressed ? 1.0f : 0.0f);
+}
+
+bool CAnalogStick::OnAnalogMotion(const CDriverPrimitive& source, float magnitude)
+{
+ CDriverPrimitive up;
+ CDriverPrimitive down;
+ CDriverPrimitive right;
+ CDriverPrimitive left;
+
+ m_buttonMap->GetAnalogStick(m_name, up, down, right, left);
+
+ if (source == up)
+ m_vertAxis.SetPositiveDistance(magnitude);
+ else if (source == down)
+ m_vertAxis.SetNegativeDistance(magnitude);
+ else if (source == right)
+ m_horizAxis.SetPositiveDistance(magnitude);
+ else if (source == left)
+ m_horizAxis.SetNegativeDistance(magnitude);
+ else
+ {
+ // Just in case, avoid sticking
+ m_vertAxis.Reset();
+ m_horizAxis.Reset();
+ }
+
+ return true;
+}
+
+void CAnalogStick::ProcessMotions(void)
+{
+ const float newVertState = m_vertAxis.GetPosition();
+ const float newHorizState = m_horizAxis.GetPosition();
+
+ if (m_vertState != 0 || m_horizState != 0 ||
+ newVertState != 0 || newHorizState != 0)
+ {
+ m_vertState = newVertState;
+ m_horizState = newHorizState;
+ m_handler->OnAnalogStickMotion(m_name, newHorizState, newVertState);
+ }
+}
+
+// --- CAccelerometer ----------------------------------------------------------
+
+CAccelerometer::CAccelerometer(const FeatureName& name, IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap) :
+ CJoystickFeature(name, handler, buttonMap),
+ m_xAxisState(0.0f),
+ m_yAxisState(0.0f),
+ m_zAxisState(0.0f)
+{
+}
+
+bool CAccelerometer::OnDigitalMotion(const CDriverPrimitive& source, bool bPressed)
+{
+ return OnAnalogMotion(source, bPressed ? 1.0f : 0.0f);
+}
+
+bool CAccelerometer::OnAnalogMotion(const CDriverPrimitive& source, float magnitude)
+{
+ CDriverPrimitive positiveX;
+ CDriverPrimitive positiveY;
+ CDriverPrimitive positiveZ;
+
+ m_buttonMap->GetAccelerometer(m_name, positiveX, positiveY, positiveZ);
+
+ if (source == positiveX)
+ m_xAxis.SetPositiveDistance(magnitude);
+ else if (source == positiveY)
+ m_yAxis.SetPositiveDistance(magnitude);
+ else if (source == positiveZ)
+ m_zAxis.SetPositiveDistance(magnitude);
+ else
+ {
+ // Just in case, avoid sticking
+ m_xAxis.Reset();
+ m_xAxis.Reset();
+ m_yAxis.Reset();
+ }
+
+ return true;
+}
+
+void CAccelerometer::ProcessMotions(void)
+{
+ const float newXAxis = m_xAxis.GetPosition();
+ const float newYAxis = m_yAxis.GetPosition();
+ const float newZAxis = m_zAxis.GetPosition();
+
+ if (m_xAxisState != 0 || m_yAxisState != 0 || m_zAxisState != 0 ||
+ newXAxis != 0 || newYAxis != 0 || newZAxis)
+ {
+ m_xAxisState = newXAxis;
+ m_yAxisState = newYAxis;
+ m_zAxisState = newZAxis;
+ m_handler->OnAccelerometerMotion(m_name, newXAxis, newYAxis, newZAxis);
+ }
+}
diff --git a/xbmc/input/joysticks/generic/GenericJoystickFeatureHandling.h b/xbmc/input/joysticks/generic/GenericJoystickFeatureHandling.h
new file mode 100644
index 0000000000..077f0f02da
--- /dev/null
+++ b/xbmc/input/joysticks/generic/GenericJoystickFeatureHandling.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "input/joysticks/JoystickTypes.h"
+
+#include <memory>
+
+namespace JOYSTICK
+{
+ class CDriverPrimitive;
+ class IJoystickInputHandler;
+ class IJoystickButtonMap;
+
+ class CJoystickFeature;
+ typedef std::shared_ptr<CJoystickFeature> FeaturePtr;
+
+ /*!
+ * \brief Base class for joystick features
+ *
+ * See list of feature types in JoystickTypes.h.
+ */
+ class CJoystickFeature
+ {
+ public:
+ CJoystickFeature(const FeatureName& name, IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap);
+ virtual ~CJoystickFeature(void) { }
+
+ /*!
+ * \brief A digital motion has occured
+ *
+ * \param source The source of the motion. Must be digital (button or hat)
+ * \param bPressed True for press motion, false for release motion
+ *
+ * \return true if the motion was handled, false otherwise
+ */
+ virtual bool OnDigitalMotion(const CDriverPrimitive& source, bool bPressed) = 0;
+
+ /*!
+ * \brief An analog motion has occured
+ *
+ * \param source The source of the motion. Must be a semiaxis
+ * \param magnitude The magnitude of the press or motion in the interval [0.0, 1.0]
+ *
+ * For semiaxes, the magnitude is the force or travel distance in the
+ * direction of the semiaxis. If the value is in the opposite direction,
+ * the magnitude is 0.0.
+ *
+ * For example, if the analog stick goes left, the negative semiaxis will
+ * have a value of 1.0 and the positive semiaxis will have a value of 0.0.
+ */
+ virtual bool OnAnalogMotion(const CDriverPrimitive& source, float magnitude) = 0;
+
+ /*!
+ * \brief Process the motions that have occured since the last invocation
+ *
+ * This allows features with motion on multiple driver primitives to call
+ * their handler once all driver primitives are accounted for.
+ */
+ virtual void ProcessMotions(void) = 0;
+
+ protected:
+ const FeatureName m_name;
+ IJoystickInputHandler* const m_handler;
+ IJoystickButtonMap* const m_buttonMap;
+ };
+
+ class CScalarFeature : public CJoystickFeature
+ {
+ public:
+ CScalarFeature(const FeatureName& name, IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap);
+ virtual ~CScalarFeature(void) { }
+
+ // implementation of CJoystickFeature
+ virtual bool OnDigitalMotion(const CDriverPrimitive& source, bool bPressed) override;
+ virtual bool OnAnalogMotion(const CDriverPrimitive& source, float magnitude) override;
+ virtual void ProcessMotions(void) override { } // Actions are dispatched immediately
+
+ private:
+ bool OnDigitalMotion(bool bPressed);
+ bool OnAnalogMotion(float magnitude);
+
+ const INPUT_TYPE m_inputType;
+ bool m_bDigitalState;
+ float m_analogState;
+ };
+
+ /*!
+ * \brief Axis of a feature (analog stick, accelerometer, etc)
+ *
+ * Axes are composed of two driver primitives, one for the positive semiaxis
+ * and one for the negative semiaxis.
+ *
+ * This effectively means that an axis is two-dimensional, with each dimension
+ * either:
+ *
+ * - a digital value (0.0 or 1.0)
+ * - an analog value (continuous in the interval [0.0, 1.0])
+ */
+ class CFeatureAxis
+ {
+ public:
+ CFeatureAxis(void) { Reset(); }
+
+ /*!
+ * \brief Set value of positive axis
+ */
+ void SetPositiveDistance(float distance) { m_positiveDistance = distance; }
+
+ /*!
+ * \brief Set value of negative axis
+ */
+ void SetNegativeDistance(float distance) { m_negativeDistance = distance; }
+
+ /*!
+ * \brief Get the final value of this axis.
+ *
+ * This axis is two-dimensional, so we need to compress these into a single
+ * dimension. This is done by subtracting the negative from the positive.
+ * Some examples:
+ *
+ * Positive axis: 1.0 (User presses right or analog stick moves right)
+ * Negative axis: 0.0
+ * -------------------
+ * Pos - Neg: 1.0 (Emulated analog stick moves right)
+ *
+ *
+ * Positive axis: 0.0
+ * Negative axis: 1.0 (User presses left or analog stick moves left)
+ * -------------------
+ * Pos - Neg: -1.0 (Emulated analog stick moves left)
+ *
+ *
+ * Positive axis: 1.0 (User presses both buttons)
+ * Negative axis: 1.0
+ * -------------------
+ * Pos - Neg: 0.0 (Emulated analog stick is centered)
+ *
+ */
+ float GetPosition(void) const { return m_positiveDistance - m_negativeDistance; }
+
+ /*!
+ * \brief Reset both positive and negative values to zero
+ */
+ void Reset(void) { m_positiveDistance = m_negativeDistance = 0.0f; }
+
+ protected:
+ float m_positiveDistance;
+ float m_negativeDistance;
+ };
+
+ class CAnalogStick : public CJoystickFeature
+ {
+ public:
+ CAnalogStick(const FeatureName& name, IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap);
+ virtual ~CAnalogStick(void) { }
+
+ // implementation of CJoystickFeature
+ virtual bool OnDigitalMotion(const CDriverPrimitive& source, bool bPressed) override;
+ virtual bool OnAnalogMotion(const CDriverPrimitive& source, float magnitude) override;
+ virtual void ProcessMotions(void) override;
+
+ protected:
+ CFeatureAxis m_vertAxis;
+ CFeatureAxis m_horizAxis;
+
+ float m_vertState;
+ float m_horizState;
+ };
+
+ class CAccelerometer : public CJoystickFeature
+ {
+ public:
+ CAccelerometer(const FeatureName& name, IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap);
+ virtual ~CAccelerometer(void) { }
+
+ // implementation of CJoystickFeature
+ virtual bool OnDigitalMotion(const CDriverPrimitive& source, bool bPressed) override;
+ virtual bool OnAnalogMotion(const CDriverPrimitive& source, float magnitude) override;
+ virtual void ProcessMotions(void) override;
+
+ protected:
+ CFeatureAxis m_xAxis;
+ CFeatureAxis m_yAxis;
+ CFeatureAxis m_zAxis;
+
+ float m_xAxisState;
+ float m_yAxisState;
+ float m_zAxisState;
+ };
+}
diff --git a/xbmc/input/joysticks/generic/GenericJoystickInputHandling.cpp b/xbmc/input/joysticks/generic/GenericJoystickInputHandling.cpp
new file mode 100644
index 0000000000..f25767b74d
--- /dev/null
+++ b/xbmc/input/joysticks/generic/GenericJoystickInputHandling.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "GenericJoystickInputHandling.h"
+#include "input/joysticks/DriverPrimitive.h"
+#include "input/joysticks/IJoystickButtonMap.h"
+#include "input/joysticks/IJoystickInputHandler.h"
+#include "input/joysticks/JoystickUtils.h"
+
+using namespace JOYSTICK;
+
+CGenericJoystickInputHandling::CGenericJoystickInputHandling(IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap)
+ : m_handler(handler),
+ m_buttonMap(buttonMap)
+{
+}
+
+CGenericJoystickInputHandling::~CGenericJoystickInputHandling(void)
+{
+}
+
+bool CGenericJoystickInputHandling::OnButtonMotion(unsigned int buttonIndex, bool bPressed)
+{
+ return OnDigitalMotion(CDriverPrimitive(buttonIndex), bPressed);
+}
+
+bool CGenericJoystickInputHandling::OnHatMotion(unsigned int hatIndex, HAT_STATE state)
+{
+ bool bHandled = false;
+
+ bHandled |= OnDigitalMotion(CDriverPrimitive(hatIndex, HAT_DIRECTION::UP), state & HAT_DIRECTION::UP);
+ bHandled |= OnDigitalMotion(CDriverPrimitive(hatIndex, HAT_DIRECTION::RIGHT), state & HAT_DIRECTION::RIGHT);
+ bHandled |= OnDigitalMotion(CDriverPrimitive(hatIndex, HAT_DIRECTION::DOWN), state & HAT_DIRECTION::DOWN);
+ bHandled |= OnDigitalMotion(CDriverPrimitive(hatIndex, HAT_DIRECTION::LEFT), state & HAT_DIRECTION::LEFT);
+
+ return bHandled;
+}
+
+bool CGenericJoystickInputHandling::OnAxisMotion(unsigned int axisIndex, float position)
+{
+ bool bHandled = false;
+
+ CDriverPrimitive positiveSemiaxis(axisIndex, SEMIAXIS_DIRECTION::POSITIVE);
+ CDriverPrimitive negativeSemiaxis(axisIndex, SEMIAXIS_DIRECTION::NEGATIVE);
+
+ bHandled |= OnAnalogMotion(positiveSemiaxis, position > 0.0f ? position : 0.0f);
+ bHandled |= OnAnalogMotion(negativeSemiaxis, position < 0.0f ? -position : 0.0f);
+
+ return bHandled;
+}
+
+void CGenericJoystickInputHandling::ProcessAxisMotions(void)
+{
+ for (std::map<FeatureName, FeaturePtr>::iterator it = m_features.begin(); it != m_features.end(); ++it)
+ it->second->ProcessMotions();
+}
+
+bool CGenericJoystickInputHandling::OnDigitalMotion(const CDriverPrimitive& source, bool bPressed)
+{
+ bool bHandled = false;
+
+ FeatureName featureName;
+ if (m_buttonMap->GetFeature(source, featureName))
+ {
+ FeaturePtr& feature = m_features[featureName];
+
+ if (!feature)
+ feature = FeaturePtr(CreateFeature(featureName));
+
+ if (feature)
+ bHandled = feature->OnDigitalMotion(source, bPressed);
+ }
+
+ return bHandled;
+}
+
+bool CGenericJoystickInputHandling::OnAnalogMotion(const CDriverPrimitive& source, float magnitude)
+{
+ bool bHandled = false;
+
+ FeatureName featureName;
+ if (m_buttonMap->GetFeature(source, featureName))
+ {
+ FeaturePtr& feature = m_features[featureName];
+
+ if (!feature)
+ feature = FeaturePtr(CreateFeature(featureName));
+
+ if (feature)
+ bHandled = feature->OnAnalogMotion(source, magnitude);
+ }
+
+ return bHandled;
+}
+
+CJoystickFeature* CGenericJoystickInputHandling::CreateFeature(const FeatureName& featureName)
+{
+ CJoystickFeature* feature = nullptr;
+
+ switch (m_buttonMap->GetFeatureType(featureName))
+ {
+ case FEATURE_TYPE::SCALAR:
+ {
+ feature = new CScalarFeature(featureName, m_handler, m_buttonMap);
+ break;
+ }
+ case FEATURE_TYPE::ANALOG_STICK:
+ {
+ feature = new CAnalogStick(featureName, m_handler, m_buttonMap);
+ break;
+ }
+ case FEATURE_TYPE::ACCELEROMETER:
+ {
+ feature = new CAccelerometer(featureName, m_handler, m_buttonMap);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return feature;
+}
diff --git a/xbmc/input/joysticks/generic/GenericJoystickInputHandling.h b/xbmc/input/joysticks/generic/GenericJoystickInputHandling.h
new file mode 100644
index 0000000000..da0a338865
--- /dev/null
+++ b/xbmc/input/joysticks/generic/GenericJoystickInputHandling.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014-2016 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "GenericJoystickFeatureHandling.h"
+#include "input/joysticks/IJoystickDriverHandler.h"
+#include "input/joysticks/JoystickTypes.h"
+
+#include <map>
+
+namespace JOYSTICK
+{
+ class CDriverPrimitive;
+ class IJoystickInputHandler;
+ class IJoystickButtonMap;
+
+ /*!
+ * \brief Class to translate input from the driver into higher-level features
+ *
+ * Raw driver input arrives for three elements: buttons, hats and axes. When
+ * driver input is handled by this class, it translates the raw driver
+ * elements into physical joystick features, such as buttons, analog sticks,
+ * etc.
+ *
+ * A button map is used to translate driver primitives to controller features.
+ * The button map has been abstracted away behind the IJoystickButtonMap
+ * interface so that it can be provided by an add-on.
+ */
+ class CGenericJoystickInputHandling : public IJoystickDriverHandler
+ {
+ public:
+ CGenericJoystickInputHandling(IJoystickInputHandler* handler, IJoystickButtonMap* buttonMap);
+
+ virtual ~CGenericJoystickInputHandling(void);
+
+ // implementation of IJoystickDriverHandler
+ virtual bool OnButtonMotion(unsigned int buttonIndex, bool bPressed) override;
+ virtual bool OnHatMotion(unsigned int hatIndex, HAT_STATE state) override;
+ virtual bool OnAxisMotion(unsigned int axisIndex, float position) override;
+ virtual void ProcessAxisMotions(void) override;
+
+ private:
+ bool OnDigitalMotion(const CDriverPrimitive& source, bool bPressed);
+ bool OnAnalogMotion(const CDriverPrimitive& source, float magnitude);
+
+ CJoystickFeature* CreateFeature(const FeatureName& featureName);
+
+ IJoystickInputHandler* const m_handler;
+ IJoystickButtonMap* const m_buttonMap;
+
+ std::map<FeatureName, FeaturePtr> m_features;
+ };
+}
diff --git a/xbmc/input/joysticks/generic/Makefile b/xbmc/input/joysticks/generic/Makefile
new file mode 100644
index 0000000000..f7f64fa112
--- /dev/null
+++ b/xbmc/input/joysticks/generic/Makefile
@@ -0,0 +1,8 @@
+SRCS=GenericJoystickButtonMapping.cpp \
+ GenericJoystickFeatureHandling.cpp \
+ GenericJoystickInputHandling.cpp \
+
+LIB=input_joysticks_generic.a
+
+include ../../../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))