aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjenkins4kodi <jenkins4kodi@users.noreply.github.com>2016-11-13 02:59:14 +0100
committerGitHub <noreply@github.com>2016-11-13 02:59:14 +0100
commit24990b5b9f334a128be75710998c4edc343fd8de (patch)
treebf93c9ff6533b1960cc27bef9df903af3c82d9f9
parentae37dd618d91912749b3de5e749cac5b3bc05eb2 (diff)
parent921862eb77687291739e90f3850f33d7e35e62be (diff)
Merge pull request #10910 from garbear/fix-skipping
-rw-r--r--Kodi.xcodeproj/project.pbxproj27
-rw-r--r--Makefile.in1
-rw-r--r--addons/kodi.peripheral/addon.xml4
-rw-r--r--addons/resource.language.en_gb/resources/strings.po26
-rw-r--r--addons/skin.estuary/1080i/DialogGameControllers.xml5
-rw-r--r--project/cmake/treedata/common/games.txt1
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_dll.h47
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_types.h10
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_utils.hpp7
-rw-r--r--xbmc/dialogs/GUIDialogOK.cpp10
-rw-r--r--xbmc/dialogs/GUIDialogOK.h4
-rw-r--r--xbmc/games/controllers/dialogs/CMakeLists.txt5
-rw-r--r--xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp240
-rw-r--r--xbmc/games/controllers/dialogs/GUIDialogButtonCapture.h73
-rw-r--r--xbmc/games/controllers/dialogs/Makefile6
-rw-r--r--xbmc/games/controllers/windows/GUIConfigurationWizard.cpp33
-rw-r--r--xbmc/games/controllers/windows/GUIConfigurationWizard.h9
-rw-r--r--xbmc/games/controllers/windows/GUIControllerDefines.h1
-rw-r--r--xbmc/games/controllers/windows/GUIControllerList.cpp12
-rw-r--r--xbmc/games/controllers/windows/GUIControllerList.h1
-rw-r--r--xbmc/games/controllers/windows/GUIControllerWindow.cpp10
-rw-r--r--xbmc/games/controllers/windows/GUIControllerWindow.h1
-rw-r--r--xbmc/games/controllers/windows/GUIFeatureList.cpp9
-rw-r--r--xbmc/games/controllers/windows/GUIFeatureList.h6
-rw-r--r--xbmc/games/controllers/windows/IConfigurationWindow.h21
-rw-r--r--xbmc/input/joysticks/CMakeLists.txt1
-rw-r--r--xbmc/input/joysticks/DefaultJoystick.cpp10
-rw-r--r--xbmc/input/joysticks/DefaultJoystick.h7
-rw-r--r--xbmc/input/joysticks/IActionMap.h47
-rw-r--r--xbmc/input/joysticks/IButtonMap.h34
-rw-r--r--xbmc/input/joysticks/IButtonMapCallback.h62
-rw-r--r--xbmc/input/joysticks/IButtonMapper.h17
-rw-r--r--xbmc/input/joysticks/IDriverReceiver.h54
-rw-r--r--xbmc/input/joysticks/IInputHandler.h16
-rw-r--r--xbmc/input/joysticks/IKeymapHandler.h10
-rw-r--r--xbmc/input/joysticks/KeymapHandler.cpp10
-rw-r--r--xbmc/input/joysticks/KeymapHandler.h1
-rw-r--r--xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.cpp2
-rw-r--r--xbmc/input/joysticks/generic/ButtonMapping.cpp40
-rw-r--r--xbmc/input/joysticks/generic/ButtonMapping.h8
-rw-r--r--xbmc/peripherals/addons/AddonButtonMap.cpp32
-rw-r--r--xbmc/peripherals/addons/AddonButtonMap.h10
-rw-r--r--xbmc/peripherals/addons/AddonButtonMapping.cpp36
-rw-r--r--xbmc/peripherals/addons/AddonButtonMapping.h5
-rw-r--r--xbmc/peripherals/addons/PeripheralAddon.cpp95
-rw-r--r--xbmc/peripherals/addons/PeripheralAddon.h4
-rw-r--r--xbmc/peripherals/addons/PeripheralAddonTranslator.cpp25
-rw-r--r--xbmc/peripherals/addons/PeripheralAddonTranslator.h5
-rw-r--r--xbmc/peripherals/devices/Peripheral.h3
-rw-r--r--xbmc/peripherals/devices/PeripheralJoystick.h1
50 files changed, 994 insertions, 110 deletions
diff --git a/Kodi.xcodeproj/project.pbxproj b/Kodi.xcodeproj/project.pbxproj
index 0a3b71c7d1..7ce0ad3682 100644
--- a/Kodi.xcodeproj/project.pbxproj
+++ b/Kodi.xcodeproj/project.pbxproj
@@ -253,6 +253,8 @@
5EB3113C1A978B9B00551907 /* CueInfoLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EB3113A1A978B9B00551907 /* CueInfoLoader.cpp */; };
5EE4F9181A9FF36F002E20F8 /* CueInfoLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EB3113A1A978B9B00551907 /* CueInfoLoader.cpp */; };
5EF801001A97892A0035AA4D /* ReplayGain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EF800FE1A97892A0035AA4D /* ReplayGain.cpp */; };
+ 680E23B31DD3D65200D2B766 /* GUIDialogButtonCapture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 680E23B11DD3D65200D2B766 /* GUIDialogButtonCapture.cpp */; };
+ 680E23B41DD3D65200D2B766 /* GUIDialogButtonCapture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 680E23B11DD3D65200D2B766 /* GUIDialogButtonCapture.cpp */; };
6815C1411CC7BADB000DB91A /* RumbleGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6815C13F1CC7BADB000DB91A /* RumbleGenerator.cpp */; };
6815C1421CC7BADB000DB91A /* RumbleGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6815C13F1CC7BADB000DB91A /* RumbleGenerator.cpp */; };
6838CF811D6665510057F17B /* DeadzoneFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6838CF7F1D6665510057F17B /* DeadzoneFilter.cpp */; };
@@ -2762,6 +2764,9 @@
5EB3113B1A978B9B00551907 /* CueInfoLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CueInfoLoader.h; sourceTree = "<group>"; };
5EF800FE1A97892A0035AA4D /* ReplayGain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplayGain.cpp; sourceTree = "<group>"; };
5EF800FF1A97892A0035AA4D /* ReplayGain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayGain.h; sourceTree = "<group>"; };
+ 680E23B11DD3D65200D2B766 /* GUIDialogButtonCapture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GUIDialogButtonCapture.cpp; path = games/controllers/dialogs/GUIDialogButtonCapture.cpp; sourceTree = "<group>"; };
+ 680E23B21DD3D65200D2B766 /* GUIDialogButtonCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GUIDialogButtonCapture.h; path = games/controllers/dialogs/GUIDialogButtonCapture.h; sourceTree = "<group>"; };
+ 680E23B51DD42BF700D2B766 /* IActionMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IActionMap.h; path = joysticks/IActionMap.h; sourceTree = "<group>"; };
6815C13F1CC7BADB000DB91A /* RumbleGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RumbleGenerator.cpp; path = joysticks/RumbleGenerator.cpp; sourceTree = "<group>"; };
6815C1401CC7BADB000DB91A /* RumbleGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RumbleGenerator.h; path = joysticks/RumbleGenerator.h; sourceTree = "<group>"; };
6819C8B61D76492500A60E30 /* IButtonMapCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IButtonMapCallback.h; path = joysticks/IButtonMapCallback.h; sourceTree = "<group>"; };
@@ -6149,6 +6154,24 @@
path = osx;
sourceTree = "<group>";
};
+ 680E23B01DD3D63600D2B766 /* dialogs */ = {
+ isa = PBXGroup;
+ children = (
+ 680E23B11DD3D65200D2B766 /* GUIDialogButtonCapture.cpp */,
+ 680E23B21DD3D65200D2B766 /* GUIDialogButtonCapture.h */,
+ );
+ name = dialogs;
+ sourceTree = "<group>";
+ };
+ 6827D71B1DD03E5300BE9114 /* dialogs */ = {
+ isa = PBXGroup;
+ children = (
+ 6827D71C1DD03E5F00BE9114 /* GUIDialogNewJoystick.cpp */,
+ 6827D71D1DD03E5F00BE9114 /* GUIDialogNewJoystick.h */,
+ );
+ name = dialogs;
+ sourceTree = "<group>";
+ };
68AE5BA21C92410300C4D527 /* Peripheral */ = {
isa = PBXGroup;
children = (
@@ -6169,6 +6192,7 @@
68AE5BAD1C9241DF00C4D527 /* DefaultJoystick.h */,
68AE5BAE1C9241DF00C4D527 /* DriverPrimitive.cpp */,
68AE5BAF1C9241DF00C4D527 /* DriverPrimitive.h */,
+ 680E23B51DD42BF700D2B766 /* IActionMap.h */,
68AE5BB01C9241DF00C4D527 /* IButtonMap.h */,
6819C8B61D76492500A60E30 /* IButtonMapCallback.h */,
68AE5BB11C9241DF00C4D527 /* IButtonMapper.h */,
@@ -6234,6 +6258,7 @@
68AE5BFA1C92433900C4D527 /* controllers */ = {
isa = PBXGroup;
children = (
+ 680E23B01DD3D63600D2B766 /* dialogs */,
68AE5BFB1C92435200C4D527 /* guicontrols */,
68AE5BFC1C92436500C4D527 /* windows */,
68AE5C231C9243A000C4D527 /* Controller.cpp */,
@@ -9831,6 +9856,7 @@
E38E1FAE0D25F9FD00618676 /* DVDSubtitleParserSubrip.cpp in Sources */,
E38E1FAF0D25F9FD00618676 /* DVDSubtitleStream.cpp in Sources */,
E38E1FC50D25F9FD00618676 /* AudioDecoder.cpp in Sources */,
+ 680E23B31DD3D65200D2B766 /* GUIDialogButtonCapture.cpp in Sources */,
E38E1FC70D25F9FD00618676 /* CodecFactory.cpp in Sources */,
E38E1FE90D25F9FD00618676 /* LinuxRendererGL.cpp in Sources */,
E38E1FEC0D25F9FD00618676 /* RenderManager.cpp in Sources */,
@@ -10973,6 +10999,7 @@
E4991198174E5CF600741B6D /* AEEncoderFFmpeg.cpp in Sources */,
E49911A6174E5CFE00741B6D /* AEBitstreamPacker.cpp in Sources */,
E49911A8174E5CFE00741B6D /* AEChannelInfo.cpp in Sources */,
+ 680E23B41DD3D65200D2B766 /* GUIDialogButtonCapture.cpp in Sources */,
E49911AA174E5CFE00741B6D /* AEDeviceInfo.cpp in Sources */,
E49911AB174E5CFE00741B6D /* AELimiter.cpp in Sources */,
E49911AC174E5CFE00741B6D /* AEPackIEC61937.cpp in Sources */,
diff --git a/Makefile.in b/Makefile.in
index f500e9de49..0d70e9b122 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -54,6 +54,7 @@ DIRECTORY_ARCHIVES=$(VideoPlayer_ARCHIVES) \
xbmc/filesystem/VideoDatabaseDirectory/videodatabasedirectory.a \
xbmc/filesystem/filesystem.a \
xbmc/games/controllers/controllers.a \
+ xbmc/games/controllers/dialogs/controllerdialogs.a \
xbmc/games/controllers/guicontrols/controllerguicontrols.a \
xbmc/games/controllers/windows/controllerwindows.a \
xbmc/guilib/guilib.a \
diff --git a/addons/kodi.peripheral/addon.xml b/addons/kodi.peripheral/addon.xml
index 47ae0b84ef..7dbd763262 100644
--- a/addons/kodi.peripheral/addon.xml
+++ b/addons/kodi.peripheral/addon.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<addon id="kodi.peripheral" version="1.1.0" provider-name="Team-Kodi">
- <backwards-compatibility abi="1.1.0"/>
+<addon id="kodi.peripheral" version="1.2.0" provider-name="Team-Kodi">
+ <backwards-compatibility abi="1.2.0"/>
<requires>
<import addon="xbmc.core" version="0.1.0"/>
</requires>
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 7b6da409dd..fd225ac110 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -16032,7 +16032,31 @@ msgctxt "#35012"
msgid "A new controller has been detected. Configuration can be done at any time in \"Settings -> System Settings -> Input\". Would you like to configure it now?"
msgstr ""
-#empty strings from id 35013 to 35048
+#. Label of the button to fix the bug where buttons are skipped in the controller dialog
+#: addons/skin.estuary/1080i/DialogGameControllers.xml
+msgctxt "#35013"
+msgid "Fix skipping"
+msgstr ""
+
+#. Help text of the button to fix the bug where buttons are skipped in the controller dialog. %s - list of disabled buttons and axes
+#:
+msgctxt "#35014"
+msgid "Some controllers have buttons and axes that interfere with mapping. Press these now to disable them:[CR]%s"
+msgstr ""
+
+#. Name of a controller button, e.g. Button 1. %d - button index
+#:
+msgctxt "#35015"
+msgid "Button %d"
+msgstr ""
+
+#. Name of a controller axis, e.g. Axis 2. %d - axis index
+#:
+msgctxt "#35016"
+msgid "Axis %d"
+msgstr ""
+
+#empty strings from id 35017 to 35048
#. Name of game add-ons category
#: xbmc/filesystem/AddonsDirectory.cpp
diff --git a/addons/skin.estuary/1080i/DialogGameControllers.xml b/addons/skin.estuary/1080i/DialogGameControllers.xml
index db3c0f1535..37e6c13392 100644
--- a/addons/skin.estuary/1080i/DialogGameControllers.xml
+++ b/addons/skin.estuary/1080i/DialogGameControllers.xml
@@ -152,6 +152,11 @@
<param name="id" value="17" />
<param name="label" value="$LOCALIZE[10043]" />
</include>
+ <include content="DefaultDialogButton">
+ <param name="width" value="350" />
+ <param name="id" value="21" />
+ <param name="label" value="$LOCALIZE[35013]" />
+ </include>
</control>
</control>
</controls>
diff --git a/project/cmake/treedata/common/games.txt b/project/cmake/treedata/common/games.txt
index e4e8b890c6..b622f5a56b 100644
--- a/project/cmake/treedata/common/games.txt
+++ b/project/cmake/treedata/common/games.txt
@@ -1,3 +1,4 @@
xbmc/games/controllers games/controllers
+xbmc/games/controllers/dialogs games/controllers/dialogs
xbmc/games/controllers/guicontrols games/controllers/guicontrols
xbmc/games/controllers/windows games/controllers/windows
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_dll.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_dll.h
index 772269a640..f9d7482b1a 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_dll.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_dll.h
@@ -158,12 +158,45 @@ extern "C"
* @brief Add or update joystick features
* @param joystick The device's joystick properties; unknown values may be left at their default
* @param controller_id The game controller profile being updated
- * @param feature_count The number of features int the features array
+ * @param feature_count The number of features in the features array
* @param features The array of features
* @return PERIPHERAL_NO_ERROR if successful
*/
PERIPHERAL_ERROR MapFeatures(const JOYSTICK_INFO* joystick, const char* controller_id,
- unsigned int feature_count, JOYSTICK_FEATURE* features);
+ unsigned int feature_count, const JOYSTICK_FEATURE* features);
+
+ /*!
+ * @brief Get the driver primitives that should be ignored while mapping the device
+ * @param joystick The device's joystick properties; unknown values may be left at their default
+ * @param primitive_count The number of features allocated for the primitives array
+ * @param primitives The array of allocated driver primitives to be ignored
+ * @return PERIPHERAL_NO_ERROR if successful; array must be freed using
+ * FreePrimitives() in this case
+ */
+ PERIPHERAL_ERROR GetIgnoredPrimitives(const JOYSTICK_INFO* joystick,
+ unsigned int* primitive_count,
+ JOYSTICK_DRIVER_PRIMITIVE** primitives);
+
+ /*!
+ * @brief Free the memory allocated in GetIgnoredPrimitives()
+ *
+ * Must be called if GetIgnoredPrimitives() returns PERIPHERAL_NO_ERROR.
+ *
+ * @param primitive_count The number of driver primitives allocated for the primitives array
+ * @param primitives The array of allocated driver primitives
+ */
+ void FreePrimitives(unsigned int primitive_count, JOYSTICK_DRIVER_PRIMITIVE* primitives);
+
+ /*!
+ * @brief Set the list of driver primitives that are ignored for the device
+ * @param joystick The device's joystick properties; unknown values may be left at their default
+ * @param primitive_count The number of driver features in the primitives array
+ * @param primitives The array of driver primitives to ignore
+ * @return PERIPHERAL_NO_ERROR if successful
+ */
+ PERIPHERAL_ERROR SetIgnoredPrimitives(const JOYSTICK_INFO* joystick,
+ unsigned int primitive_count,
+ const JOYSTICK_DRIVER_PRIMITIVE* primitives);
/*!
* @brief Save the button map for the given joystick
@@ -172,6 +205,12 @@ extern "C"
void SaveButtonMap(const JOYSTICK_INFO* joystick);
/*!
+ * @brief Revert the button map to the last time it was loaded or committed to disk
+ * @param joystick The device's joystick properties
+ */
+ void RevertButtonMap(const JOYSTICK_INFO* joystick);
+
+ /*!
* @brief Reset the button map for the given joystick and controller profile ID
* @param joystick The device's joystick properties
* @param controller_id The game controller profile being reset
@@ -208,7 +247,11 @@ extern "C"
pClient->GetFeatures = GetFeatures;
pClient->FreeFeatures = FreeFeatures;
pClient->MapFeatures = MapFeatures;
+ pClient->GetIgnoredPrimitives = GetIgnoredPrimitives;
+ pClient->FreePrimitives = FreePrimitives;
+ pClient->SetIgnoredPrimitives = SetIgnoredPrimitives;
pClient->SaveButtonMap = SaveButtonMap;
+ pClient->RevertButtonMap = RevertButtonMap;
pClient->ResetButtonMap = ResetButtonMap;
pClient->PowerOffJoystick = PowerOffJoystick;
#endif
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_types.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_types.h
index 47e4fa9472..2df5622a14 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_types.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_types.h
@@ -51,10 +51,10 @@
#endif
/* current Peripheral API version */
-#define PERIPHERAL_API_VERSION "1.1.0"
+#define PERIPHERAL_API_VERSION "1.2.0"
/* min. Peripheral API version */
-#define PERIPHERAL_MIN_API_VERSION "1.1.0"
+#define PERIPHERAL_MIN_API_VERSION "1.2.0"
/* indicates a joystick has no preference for port number */
#define NO_PORT_REQUESTED (-1)
@@ -304,8 +304,12 @@ extern "C"
void (__cdecl* FreeJoystickInfo)(JOYSTICK_INFO*);
PERIPHERAL_ERROR (__cdecl* GetFeatures)(const JOYSTICK_INFO*, const char*, unsigned int*, JOYSTICK_FEATURE**);
void (__cdecl* FreeFeatures)(unsigned int, JOYSTICK_FEATURE*);
- PERIPHERAL_ERROR (__cdecl* MapFeatures)(const JOYSTICK_INFO*, const char*, unsigned int, JOYSTICK_FEATURE*);
+ PERIPHERAL_ERROR (__cdecl* MapFeatures)(const JOYSTICK_INFO*, const char*, unsigned int, const JOYSTICK_FEATURE*);
+ PERIPHERAL_ERROR (__cdecl* GetIgnoredPrimitives)(const JOYSTICK_INFO*, unsigned int*, JOYSTICK_DRIVER_PRIMITIVE**);
+ void (__cdecl* FreePrimitives)(unsigned int, JOYSTICK_DRIVER_PRIMITIVE*);
+ PERIPHERAL_ERROR (__cdecl* SetIgnoredPrimitives)(const JOYSTICK_INFO*, unsigned int, const JOYSTICK_DRIVER_PRIMITIVE*);
void (__cdecl* SaveButtonMap)(const JOYSTICK_INFO*);
+ void (__cdecl* RevertButtonMap)(const JOYSTICK_INFO*);
void (__cdecl* ResetButtonMap)(const JOYSTICK_INFO*, const char*);
void (__cdecl* PowerOffJoystick)(unsigned int);
///}
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_utils.hpp b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_utils.hpp
index 79df0c5232..f01180b1dc 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_utils.hpp
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/kodi_peripheral_utils.hpp
@@ -533,6 +533,11 @@ namespace ADDON
}
}
+ static void FreeStruct(JOYSTICK_DRIVER_PRIMITIVE& primitive)
+ {
+ (void)primitive;
+ }
+
private:
JOYSTICK_DRIVER_PRIMITIVE_TYPE m_type;
unsigned int m_driverIndex;
@@ -540,6 +545,8 @@ namespace ADDON
JOYSTICK_DRIVER_SEMIAXIS_DIRECTION m_semiAxisDirection;
};
+ typedef PeripheralVector<DriverPrimitive, JOYSTICK_DRIVER_PRIMITIVE> DriverPrimitives;
+
/*!
* ADDON::JoystickFeature
*
diff --git a/xbmc/dialogs/GUIDialogOK.cpp b/xbmc/dialogs/GUIDialogOK.cpp
index 91fc8fe385..f920cd4c33 100644
--- a/xbmc/dialogs/GUIDialogOK.cpp
+++ b/xbmc/dialogs/GUIDialogOK.cpp
@@ -47,27 +47,29 @@ bool CGUIDialogOK::OnMessage(CGUIMessage& message)
}
// \brief Show CGUIDialogOK dialog, then wait for user to dismiss it.
-void CGUIDialogOK::ShowAndGetInput(CVariant heading, CVariant text)
+bool CGUIDialogOK::ShowAndGetInput(CVariant heading, CVariant text)
{
CGUIDialogOK *dialog = (CGUIDialogOK *)g_windowManager.GetWindow(WINDOW_DIALOG_OK);
if (!dialog)
- return;
+ return false;
dialog->SetHeading(heading);
dialog->SetText(text);
dialog->Open();
+ return dialog->IsConfirmed();
}
// \brief Show CGUIDialogOK dialog, then wait for user to dismiss it.
-void CGUIDialogOK::ShowAndGetInput(CVariant heading, CVariant line0, CVariant line1, CVariant line2)
+bool CGUIDialogOK::ShowAndGetInput(CVariant heading, CVariant line0, CVariant line1, CVariant line2)
{
CGUIDialogOK *dialog = (CGUIDialogOK *)g_windowManager.GetWindow(WINDOW_DIALOG_OK);
if (!dialog)
- return;
+ return false;
dialog->SetHeading(heading);
dialog->SetLine(0, line0);
dialog->SetLine(1, line1);
dialog->SetLine(2, line2);
dialog->Open();
+ return dialog->IsConfirmed();
}
void CGUIDialogOK::OnInitWindow()
diff --git a/xbmc/dialogs/GUIDialogOK.h b/xbmc/dialogs/GUIDialogOK.h
index 3ee5c58327..85e2959b19 100644
--- a/xbmc/dialogs/GUIDialogOK.h
+++ b/xbmc/dialogs/GUIDialogOK.h
@@ -32,8 +32,8 @@ public:
CGUIDialogOK(void);
virtual ~CGUIDialogOK(void);
virtual bool OnMessage(CGUIMessage& message);
- static void ShowAndGetInput(CVariant heading, CVariant text);
- static void ShowAndGetInput(CVariant heading, CVariant line0, CVariant line1, CVariant line2);
+ static bool ShowAndGetInput(CVariant heading, CVariant text);
+ static bool ShowAndGetInput(CVariant heading, CVariant line0, CVariant line1, CVariant line2);
protected:
virtual void OnInitWindow();
virtual int GetDefaultLabelID(int controlId) const;
diff --git a/xbmc/games/controllers/dialogs/CMakeLists.txt b/xbmc/games/controllers/dialogs/CMakeLists.txt
new file mode 100644
index 0000000000..436712ca8c
--- /dev/null
+++ b/xbmc/games/controllers/dialogs/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(SOURCES GUIDialogButtonCapture.cpp)
+
+set(HEADERS GUIDialogButtonCapture.h)
+
+core_add_library(games_controller_dialogs)
diff --git a/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp b/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp
new file mode 100644
index 0000000000..3d3d817c4c
--- /dev/null
+++ b/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 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 "GUIDialogButtonCapture.h"
+#include "dialogs/GUIDialogOK.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/WindowIDs.h"
+#include "input/joysticks/IActionMap.h"
+#include "input/joysticks/IButtonMap.h"
+#include "input/joysticks/IButtonMapCallback.h"
+#include "input/joysticks/JoystickUtils.h"
+#include "input/Key.h"
+#include "utils/log.h"
+#include "peripherals/Peripherals.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+
+#include <algorithm>
+#include <iterator>
+
+using namespace GAME;
+
+CGUIDialogButtonCapture::CGUIDialogButtonCapture(const std::string& controllerId) :
+ CThread("ButtonCaptureDlg"),
+ m_controllerId(controllerId)
+{
+}
+
+void CGUIDialogButtonCapture::Show()
+{
+ using namespace KODI::MESSAGING;
+
+ if (!IsRunning())
+ {
+ InstallHooks();
+
+ Create();
+
+ bool bAccepted = CGUIDialogOK::ShowAndGetInput(CVariant{ 35013 }, CVariant{ GetDialogText() }); // "Fix skipping"
+
+ StopThread(false);
+
+ m_captureEvent.Set();
+
+ if (ButtonMapCallback())
+ {
+ if (bAccepted)
+ {
+ // See documentation of IButtonMapCallback::ResetIgnoredPrimitives()
+ // for why this call is needed
+ if (m_capturedPrimitives.empty())
+ ButtonMapCallback()->ResetIgnoredPrimitives();
+
+ ButtonMapCallback()->SaveButtonMap();
+ }
+ else
+ ButtonMapCallback()->RevertButtonMap();
+ }
+
+ RemoveHooks();
+ }
+}
+
+void CGUIDialogButtonCapture::Process()
+{
+ while (!m_bStop)
+ {
+ m_captureEvent.Wait();
+
+ if (m_bStop)
+ break;
+
+ //! @todo Move to rendering thread when there is a rendering thread
+ auto dialog = dynamic_cast<CGUIDialogOK*>(g_windowManager.GetWindow(WINDOW_DIALOG_OK));
+ if (dialog)
+ dialog->SetText(GetDialogText());
+ }
+}
+
+bool CGUIDialogButtonCapture::MapPrimitive(JOYSTICK::IButtonMap* buttonMap,
+ JOYSTICK::IActionMap* actionMap,
+ const JOYSTICK::CDriverPrimitive& primitive)
+{
+ if (m_bStop)
+ return false;
+
+ // First check to see if driver primitive closes the dialog
+ if (actionMap)
+ {
+ std::string feature;
+ if (buttonMap->GetFeature(primitive, feature))
+ {
+ switch (actionMap->GetActionID(feature))
+ {
+ case ACTION_SELECT_ITEM:
+ case ACTION_NAV_BACK:
+ case ACTION_PREVIOUS_MENU:
+ return false;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Check if we have already started capturing primitives for a device
+ const bool bHasDevice = !m_deviceName.empty();
+
+ // If a primitive comes from a different device, ignore it
+ if (bHasDevice && m_deviceName != buttonMap->DeviceName())
+ {
+ CLog::Log(LOGDEBUG, "%s: ignoring input from device %s", m_controllerId.c_str(), buttonMap->DeviceName().c_str());
+ return false;
+ }
+
+ if (!bHasDevice)
+ {
+ CLog::Log(LOGDEBUG, "%s: capturing input for device %s", m_controllerId.c_str(), buttonMap->DeviceName().c_str());
+ m_deviceName = buttonMap->DeviceName();
+ }
+
+ if (AddPrimitive(primitive))
+ {
+ buttonMap->SetIgnoredPrimitives(m_capturedPrimitives);
+ m_captureEvent.Set();
+ }
+
+ return true;
+}
+
+bool CGUIDialogButtonCapture::AddPrimitive(const JOYSTICK::CDriverPrimitive& primitive)
+{
+ bool bValid = false;
+
+ if (primitive.Type() == JOYSTICK::PRIMITIVE_TYPE::BUTTON)
+ {
+ bValid = std::find(m_capturedPrimitives.begin(), m_capturedPrimitives.end(), primitive) == m_capturedPrimitives.end();
+ }
+ else if (primitive.Type() == JOYSTICK::PRIMITIVE_TYPE::SEMIAXIS)
+ {
+ // Don't need to do anything if opposite semiaxis is already captured
+ JOYSTICK::CDriverPrimitive opposite(primitive.Index(), primitive.SemiAxisDirection() * -1);
+
+ bValid = std::find(m_capturedPrimitives.begin(), m_capturedPrimitives.end(), primitive) == m_capturedPrimitives.end() &&
+ std::find(m_capturedPrimitives.begin(), m_capturedPrimitives.end(), opposite) == m_capturedPrimitives.end();
+ }
+
+ if (bValid)
+ {
+ m_capturedPrimitives.emplace_back(primitive);
+ return true;
+ }
+
+ return false;
+}
+
+std::string CGUIDialogButtonCapture::GetDialogText()
+{
+ // "Some controllers have buttons and axes that interfere with mapping. Press
+ // these now to disable them:[CR][CR]%s"
+ std::string dialogText = g_localizeStrings.Get(35014);
+
+ std::vector<std::string> primitives;
+
+ std::transform(m_capturedPrimitives.begin(), m_capturedPrimitives.end(), std::back_inserter(primitives),
+ [](const JOYSTICK::CDriverPrimitive& primitive)
+ {
+ return GetPrimitiveName(primitive);
+ });
+
+ return StringUtils::Format(dialogText.c_str(), StringUtils::Join(primitives, " | ").c_str());
+}
+
+void CGUIDialogButtonCapture::InstallHooks(void)
+{
+ using namespace PERIPHERALS;
+
+ g_peripherals.RegisterJoystickButtonMapper(this);
+ g_peripherals.RegisterObserver(this);
+}
+
+void CGUIDialogButtonCapture::RemoveHooks(void)
+{
+ using namespace PERIPHERALS;
+
+ g_peripherals.UnregisterObserver(this);
+ g_peripherals.UnregisterJoystickButtonMapper(this);
+}
+
+void CGUIDialogButtonCapture::Notify(const Observable& obs, const ObservableMessage msg)
+{
+ using namespace PERIPHERALS;
+
+ switch (msg)
+ {
+ case ObservableMessagePeripheralsChanged:
+ {
+ g_peripherals.UnregisterJoystickButtonMapper(this);
+ g_peripherals.RegisterJoystickButtonMapper(this);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+std::string CGUIDialogButtonCapture::GetPrimitiveName(const JOYSTICK::CDriverPrimitive& primitive)
+{
+ std::string primitiveTemplate;
+
+ switch (primitive.Type())
+ {
+ case JOYSTICK::PRIMITIVE_TYPE::BUTTON:
+ primitiveTemplate = g_localizeStrings.Get(35015); // "Button %d"
+ break;
+ case JOYSTICK::PRIMITIVE_TYPE::SEMIAXIS:
+ primitiveTemplate = g_localizeStrings.Get(35016); // "Axis %d"
+ break;
+ default: break;
+ }
+
+ return StringUtils::Format(primitiveTemplate.c_str(), primitive.Index());
+}
diff --git a/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.h b/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.h
new file mode 100644
index 0000000000..3cf6503218
--- /dev/null
+++ b/xbmc/games/controllers/dialogs/GUIDialogButtonCapture.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 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/IButtonMapper.h"
+#include "threads/Event.h"
+#include "threads/Thread.h"
+#include "utils/Observer.h"
+
+#include <vector>
+
+namespace GAME
+{
+ class CGUIDialogButtonCapture : public JOYSTICK::IButtonMapper,
+ public Observer,
+ protected CThread
+ {
+ public:
+ CGUIDialogButtonCapture(const std::string& controllerId);
+
+ // implementation of IButtonMapper
+ virtual std::string ControllerID(void) const override { return m_controllerId; }
+ virtual bool NeedsCooldown(void) const override { return false; }
+ virtual bool MapPrimitive(JOYSTICK::IButtonMap* buttonMap,
+ JOYSTICK::IActionMap* actionMap,
+ const JOYSTICK::CDriverPrimitive& primitive) override;
+
+ // implementation of Observer
+ virtual void Notify(const Observable &obs, const ObservableMessage msg) override;
+
+ void Show();
+
+ protected:
+ // implementation of CThread
+ virtual void Process() override;
+
+ private:
+ bool AddPrimitive(const JOYSTICK::CDriverPrimitive& primitive);
+
+ std::string GetDialogText();
+
+ void InstallHooks();
+ void RemoveHooks();
+
+ static std::string GetPrimitiveName(const JOYSTICK::CDriverPrimitive& primitive);
+
+ // Construction parameters
+ const std::string m_controllerId;
+
+ // Button capture parameters
+ std::string m_deviceName;
+ std::vector<JOYSTICK::CDriverPrimitive> m_capturedPrimitives;
+ CEvent m_captureEvent;
+ };
+}
diff --git a/xbmc/games/controllers/dialogs/Makefile b/xbmc/games/controllers/dialogs/Makefile
new file mode 100644
index 0000000000..18739a2d5b
--- /dev/null
+++ b/xbmc/games/controllers/dialogs/Makefile
@@ -0,0 +1,6 @@
+SRCS=GUIDialogButtonCapture.cpp \
+
+LIB=controllerdialogs.a
+
+include ../../../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp b/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp
index 372a335b0f..85d49d1859 100644
--- a/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp
+++ b/xbmc/games/controllers/windows/GUIConfigurationWizard.cpp
@@ -32,6 +32,7 @@
using namespace GAME;
#define ESC_KEY_CODE 27
+#define SKIPPING_DETECTION_MS 200
CGUIConfigurationWizard::CGUIConfigurationWizard() :
CThread("GUIConfigurationWizard")
@@ -44,9 +45,10 @@ void CGUIConfigurationWizard::InitializeState(void)
m_currentButton = nullptr;
m_currentDirection = JOYSTICK::ANALOG_STICK_DIRECTION::UNKNOWN;
m_history.clear();
+ m_lastMappingActionMs = 0;
}
-void CGUIConfigurationWizard::Run(const std::string& strControllerId, const std::vector<IFeatureButton*>& buttons)
+void CGUIConfigurationWizard::Run(const std::string& strControllerId, const std::vector<IFeatureButton*>& buttons, IConfigurationWizardCallback* callback)
{
Abort();
@@ -56,6 +58,7 @@ void CGUIConfigurationWizard::Run(const std::string& strControllerId, const std:
// Set Run() parameters
m_strControllerId = strControllerId;
m_buttons = buttons;
+ m_callback = callback;
// Initialize state variables
InitializeState();
@@ -92,6 +95,8 @@ void CGUIConfigurationWizard::Process(void)
{
CLog::Log(LOGDEBUG, "Starting configuration wizard");
+ m_lastMappingActionMs = XbmcThreads::SystemClockMillis();
+
InstallHooks();
{
@@ -123,7 +128,8 @@ void CGUIConfigurationWizard::Process(void)
break;
}
- m_currentButton = nullptr;
+ // Finished mapping
+ InitializeState();
}
if (ButtonMapCallback())
@@ -134,7 +140,9 @@ void CGUIConfigurationWizard::Process(void)
CLog::Log(LOGDEBUG, "Configuration wizard ended");
}
-bool CGUIConfigurationWizard::MapPrimitive(JOYSTICK::IButtonMap* buttonMap, const JOYSTICK::CDriverPrimitive& primitive)
+bool CGUIConfigurationWizard::MapPrimitive(JOYSTICK::IButtonMap* buttonMap,
+ JOYSTICK::IActionMap* actionMap,
+ const JOYSTICK::CDriverPrimitive& primitive)
{
using namespace JOYSTICK;
@@ -151,6 +159,10 @@ bool CGUIConfigurationWizard::MapPrimitive(JOYSTICK::IButtonMap* buttonMap, cons
// Primitive has already been mapped this round, ignore it
bHandled = true;
}
+ else if (buttonMap->IsIgnored(primitive))
+ {
+ bHandled = true;
+ }
else
{
// Get the current state of the thread
@@ -165,6 +177,10 @@ bool CGUIConfigurationWizard::MapPrimitive(JOYSTICK::IButtonMap* buttonMap, cons
if (currentButton)
{
const CControllerFeature& feature = currentButton->Feature();
+
+ CLog::Log(LOGDEBUG, "%s: mapping feature \"%s\" for device %s",
+ m_strControllerId.c_str(), feature.Name().c_str(), buttonMap->DeviceName().c_str());
+
switch (feature.Type())
{
case FEATURE_TYPE::SCALAR:
@@ -186,6 +202,17 @@ bool CGUIConfigurationWizard::MapPrimitive(JOYSTICK::IButtonMap* buttonMap, cons
if (bHandled)
{
m_history.insert(primitive);
+
+ // Detect button skipping
+ unsigned int elapsed = XbmcThreads::SystemClockMillis() - m_lastMappingActionMs;
+ if (elapsed <= SKIPPING_DETECTION_MS)
+ {
+ CLog::Log(LOGDEBUG, "%s: Possible skip detected after %ums", m_strControllerId.c_str(), elapsed);
+ if (m_callback)
+ m_callback->OnSkipDetected();
+ }
+ m_lastMappingActionMs = XbmcThreads::SystemClockMillis();
+
m_inputEvent.Set();
}
}
diff --git a/xbmc/games/controllers/windows/GUIConfigurationWizard.h b/xbmc/games/controllers/windows/GUIConfigurationWizard.h
index b615ce190f..bc463762a2 100644
--- a/xbmc/games/controllers/windows/GUIConfigurationWizard.h
+++ b/xbmc/games/controllers/windows/GUIConfigurationWizard.h
@@ -46,13 +46,16 @@ namespace GAME
virtual ~CGUIConfigurationWizard(void) { }
// implementation of IConfigurationWizard
- virtual void Run(const std::string& strControllerId, const std::vector<IFeatureButton*>& buttons) override;
+ virtual void Run(const std::string& strControllerId, const std::vector<IFeatureButton*>& buttons, IConfigurationWizardCallback* callback) override;
virtual void OnUnfocus(IFeatureButton* button) override;
virtual bool Abort(bool bWait = true) override;
// implementation of IButtonMapper
virtual std::string ControllerID(void) const override { return m_strControllerId; }
- virtual bool MapPrimitive(JOYSTICK::IButtonMap* buttonMap, const JOYSTICK::CDriverPrimitive& primitive) override;
+ virtual bool NeedsCooldown(void) const override { return true; }
+ virtual bool MapPrimitive(JOYSTICK::IButtonMap* buttonMap,
+ JOYSTICK::IActionMap* actionMap,
+ const JOYSTICK::CDriverPrimitive& primitive) override;
// implementation of IKeyboardHandler
virtual bool OnKeyPress(const CKey& key) override;
@@ -74,11 +77,13 @@ namespace GAME
// Run() parameters
std::string m_strControllerId;
std::vector<IFeatureButton*> m_buttons;
+ IConfigurationWizardCallback* m_callback;
// State variables and mutex
IFeatureButton* m_currentButton;
JOYSTICK::ANALOG_STICK_DIRECTION m_currentDirection;
std::set<JOYSTICK::CDriverPrimitive> m_history; // History to avoid repeated features
+ unsigned int m_lastMappingActionMs; // The last mapping action, or 0 if not currently mapping
CCriticalSection m_stateMutex;
// Synchronization event
diff --git a/xbmc/games/controllers/windows/GUIControllerDefines.h b/xbmc/games/controllers/windows/GUIControllerDefines.h
index 54e1e28ac6..232dd91f16 100644
--- a/xbmc/games/controllers/windows/GUIControllerDefines.h
+++ b/xbmc/games/controllers/windows/GUIControllerDefines.h
@@ -36,6 +36,7 @@
#define CONTROL_CLOSE_BUTTON 18
#define CONTROL_RESET_BUTTON 19
#define CONTROL_GET_MORE 20
+#define CONTROL_FIX_SKIPPING 21
#define CONTROL_GAME_CONTROLLER 31
#define MAX_CONTROLLER_COUNT 100 // large enough
diff --git a/xbmc/games/controllers/windows/GUIControllerList.cpp b/xbmc/games/controllers/windows/GUIControllerList.cpp
index 655c3ebc74..650d004082 100644
--- a/xbmc/games/controllers/windows/GUIControllerList.cpp
+++ b/xbmc/games/controllers/windows/GUIControllerList.cpp
@@ -30,6 +30,7 @@
#include "addons/AddonManager.h"
#include "dialogs/GUIDialogYesNo.h"
#include "games/controllers/Controller.h"
+#include "games/controllers/dialogs/GUIDialogButtonCapture.h"
#include "games/controllers/guicontrols/GUIControllerButton.h"
#include "games/controllers/guicontrols/GUIGameController.h"
#include "guilib/GUIButtonControl.h"
@@ -142,6 +143,17 @@ void CGUIControllerList::ResetController(void)
}
}
+void CGUIControllerList::ShowButtonCaptureDialog(void)
+{
+ if (0 <= m_focusedController && m_focusedController < (int)m_controllers.size())
+ {
+ const std::string strControllerId = m_controllers[m_focusedController]->ID();
+
+ CGUIDialogButtonCapture dialog(strControllerId);
+ dialog.Show();
+ }
+}
+
void CGUIControllerList::OnEvent(const ADDON::AddonEvent& event)
{
if (typeid(event) == typeid(ADDON::AddonEvents::InstalledChanged))
diff --git a/xbmc/games/controllers/windows/GUIControllerList.h b/xbmc/games/controllers/windows/GUIControllerList.h
index fe31d44b1c..4059dccf4b 100644
--- a/xbmc/games/controllers/windows/GUIControllerList.h
+++ b/xbmc/games/controllers/windows/GUIControllerList.h
@@ -49,6 +49,7 @@ namespace GAME
virtual void OnSelect(unsigned int controllerIndex) override;
virtual int GetFocusedController() const override { return m_focusedController; }
virtual void ResetController(void) override;
+ virtual void ShowButtonCaptureDialog() override;
private:
bool RefreshControllers(void);
diff --git a/xbmc/games/controllers/windows/GUIControllerWindow.cpp b/xbmc/games/controllers/windows/GUIControllerWindow.cpp
index e5c0973f63..37c1717b6a 100644
--- a/xbmc/games/controllers/windows/GUIControllerWindow.cpp
+++ b/xbmc/games/controllers/windows/GUIControllerWindow.cpp
@@ -125,6 +125,10 @@ bool CGUIControllerWindow::OnMessage(CGUIMessage& message)
ShowHelp();
return true;
}
+ else if (controlId == CONTROL_FIX_SKIPPING)
+ {
+ ShowButtonCaptureDialog();
+ }
else if (CONTROL_CONTROLLER_BUTTONS_START <= controlId && controlId < CONTROL_CONTROLLER_BUTTONS_END)
{
OnControllerSelected(controlId - CONTROL_CONTROLLER_BUTTONS_START);
@@ -322,3 +326,9 @@ void CGUIControllerWindow::ShowHelp(void)
// <help text>
CGUIDialogOK::ShowAndGetInput(CVariant{10043}, CVariant{35055});
}
+
+void CGUIControllerWindow::ShowButtonCaptureDialog(void)
+{
+ if (m_controllerList)
+ m_controllerList->ShowButtonCaptureDialog();
+}
diff --git a/xbmc/games/controllers/windows/GUIControllerWindow.h b/xbmc/games/controllers/windows/GUIControllerWindow.h
index 00a1c1eca1..22efa0cbb2 100644
--- a/xbmc/games/controllers/windows/GUIControllerWindow.h
+++ b/xbmc/games/controllers/windows/GUIControllerWindow.h
@@ -55,6 +55,7 @@ namespace GAME
void GetMoreControllers(void);
void ResetController(void);
void ShowHelp(void);
+ void ShowButtonCaptureDialog(void);
IControllerList* m_controllerList;
IFeatureList* m_featureList;
diff --git a/xbmc/games/controllers/windows/GUIFeatureList.cpp b/xbmc/games/controllers/windows/GUIFeatureList.cpp
index 4aa114c870..0bcd937e3e 100644
--- a/xbmc/games/controllers/windows/GUIFeatureList.cpp
+++ b/xbmc/games/controllers/windows/GUIFeatureList.cpp
@@ -30,7 +30,9 @@
#include "guilib/GUIControlGroupList.h"
#include "guilib/GUIImage.h"
#include "guilib/GUILabelControl.h"
+#include "guilib/GUIMessage.h"
#include "guilib/GUIWindow.h"
+#include "messaging/ApplicationMessenger.h"
using namespace GAME;
@@ -145,7 +147,12 @@ void CGUIFeatureList::OnSelect(unsigned int index)
buttons.push_back(control);
}
- m_wizard->Run(m_controller->ID(), buttons);
+ m_wizard->Run(m_controller->ID(), buttons, this);
+}
+
+void CGUIFeatureList::OnSkipDetected()
+{
+ //! @todo
}
IFeatureButton* CGUIFeatureList::GetButtonControl(unsigned int featureIndex)
diff --git a/xbmc/games/controllers/windows/GUIFeatureList.h b/xbmc/games/controllers/windows/GUIFeatureList.h
index e5ed44d649..bfb618a943 100644
--- a/xbmc/games/controllers/windows/GUIFeatureList.h
+++ b/xbmc/games/controllers/windows/GUIFeatureList.h
@@ -31,7 +31,8 @@ class CGUIWindow;
namespace GAME
{
- class CGUIFeatureList : public IFeatureList
+ class CGUIFeatureList : public IFeatureList,
+ public IConfigurationWizardCallback
{
public:
CGUIFeatureList(CGUIWindow* window);
@@ -44,6 +45,9 @@ namespace GAME
virtual void OnFocus(unsigned int index) override { }
virtual void OnSelect(unsigned int index) override;
+ // implementation of IConfigurationWizardCallback
+ virtual void OnSkipDetected() override;
+
private:
IFeatureButton* GetButtonControl(unsigned int featureIndex);
diff --git a/xbmc/games/controllers/windows/IConfigurationWindow.h b/xbmc/games/controllers/windows/IConfigurationWindow.h
index 5f57a5bb8f..90fef58342 100644
--- a/xbmc/games/controllers/windows/IConfigurationWindow.h
+++ b/xbmc/games/controllers/windows/IConfigurationWindow.h
@@ -97,6 +97,11 @@ namespace GAME
* \brief Reset the focused controller
*/
virtual void ResetController(void) = 0;
+
+ /*!
+ * \brief Show a dialog for capturing input interfering with the button mapping process
+ */
+ virtual void ShowButtonCaptureDialog() = 0;
};
/*!
@@ -182,6 +187,20 @@ namespace GAME
};
/*!
+ * \brief Callback handler passed to the button mapping wizard
+ */
+ class IConfigurationWizardCallback
+ {
+ public:
+ virtual ~IConfigurationWizardCallback() = default;
+
+ /*!
+ * \brief Called when a "skip" is detected, defined as two mapping commands within a short duration
+ */
+ virtual void OnSkipDetected() = 0;
+ };
+
+ /*!
* \brief A wizard to direct user input
*/
class IConfigurationWizard
@@ -193,7 +212,7 @@ namespace GAME
* \brief Start the wizard at the specified feature
* \param featureIndex The index of the feature to start at
*/
- virtual void Run(const std::string& strControllerId, const std::vector<IFeatureButton*>& buttons) = 0;
+ virtual void Run(const std::string& strControllerId, const std::vector<IFeatureButton*>& buttons, IConfigurationWizardCallback* callback) = 0;
/*!
* \brief Callback for feature losing focus
diff --git a/xbmc/input/joysticks/CMakeLists.txt b/xbmc/input/joysticks/CMakeLists.txt
index 6a11726d7d..ac5450df91 100644
--- a/xbmc/input/joysticks/CMakeLists.txt
+++ b/xbmc/input/joysticks/CMakeLists.txt
@@ -9,6 +9,7 @@ set(SOURCES DeadzoneFilter.cpp
set(HEADERS DeadzoneFilter.h
DefaultJoystick.h
DriverPrimitive.h
+ IActionMap.h
IButtonMap.h
IButtonMapCallback.h
IButtonMapper.h
diff --git a/xbmc/input/joysticks/DefaultJoystick.cpp b/xbmc/input/joysticks/DefaultJoystick.cpp
index 56634190e5..cd2cfc19f8 100644
--- a/xbmc/input/joysticks/DefaultJoystick.cpp
+++ b/xbmc/input/joysticks/DefaultJoystick.cpp
@@ -129,6 +129,16 @@ bool CDefaultJoystick::OnAccelerometerMotion(const FeatureName& feature, float x
return false; //! @todo implement
}
+int CDefaultJoystick::GetActionID(const FeatureName& feature)
+{
+ const unsigned int keyId = GetKeyID(feature);
+
+ if (keyId > 0)
+ return m_handler->GetActionID(keyId);
+
+ return ACTION_NONE;
+}
+
bool CDefaultJoystick::ActivateDirection(const FeatureName& feature, float magnitude, ANALOG_STICK_DIRECTION dir, unsigned int motionTimeMs)
{
// Calculate the button key ID and input type for the analog stick's direction
diff --git a/xbmc/input/joysticks/DefaultJoystick.h b/xbmc/input/joysticks/DefaultJoystick.h
index 2a8a48ae37..b103e7ddbb 100644
--- a/xbmc/input/joysticks/DefaultJoystick.h
+++ b/xbmc/input/joysticks/DefaultJoystick.h
@@ -19,6 +19,7 @@
*/
#pragma once
+#include "IActionMap.h"
#include "IInputHandler.h"
#include "JoystickTypes.h"
#include "RumbleGenerator.h"
@@ -40,7 +41,8 @@ namespace JOYSTICK
*
* \sa IInputHandler
*/
- class CDefaultJoystick : public JOYSTICK::IInputHandler
+ class CDefaultJoystick : public JOYSTICK::IInputHandler,
+ public IActionMap
{
public:
CDefaultJoystick(void);
@@ -58,6 +60,9 @@ namespace JOYSTICK
virtual bool OnAnalogStickMotion(const FeatureName& feature, float x, float y, unsigned int motionTimeMs = 0) override;
virtual bool OnAccelerometerMotion(const FeatureName& feature, float x, float y, float z) override;
+ // implementation of IActionMap
+ virtual int GetActionID(const FeatureName& feature) override;
+
// Forward rumble commands to rumble generator
void NotifyUser(void) { m_rumbleGenerator.NotifyUser(InputReceiver()); }
bool TestRumble(void) { return m_rumbleGenerator.DoTest(InputReceiver()); }
diff --git a/xbmc/input/joysticks/IActionMap.h b/xbmc/input/joysticks/IActionMap.h
new file mode 100644
index 0000000000..c70ef219dc
--- /dev/null
+++ b/xbmc/input/joysticks/IActionMap.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 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 "input/Key.h"
+
+namespace JOYSTICK
+{
+ class CDriverPrimitive;
+
+ /*!
+ * \brief Interface for translating features to action IDs
+ */
+ class IActionMap
+ {
+ public:
+ virtual ~IActionMap() = default;
+
+ /*!
+ * \brief Get the action ID mapped to the specified feature
+ *
+ * \param feature The feature to look up
+ *
+ * \return The action ID from Key.h, or ACTION_NONE if no action is mapped
+ * to the specified key
+ */
+ virtual int GetActionID(const FeatureName& feature) = 0;
+ };
+}
diff --git a/xbmc/input/joysticks/IButtonMap.h b/xbmc/input/joysticks/IButtonMap.h
index 0d365b66ab..2da7705269 100644
--- a/xbmc/input/joysticks/IButtonMap.h
+++ b/xbmc/input/joysticks/IButtonMap.h
@@ -23,6 +23,7 @@
#include "JoystickTypes.h"
#include <string>
+#include <vector>
namespace JOYSTICK
{
@@ -48,6 +49,13 @@ namespace JOYSTICK
virtual std::string ControllerID(void) const = 0;
/*!
+ * \brief The name of the peripheral associated with this button map
+ *
+ * \return The peripheral's name
+ */
+ virtual std::string DeviceName(void) const = 0;
+
+ /*!
* \brief Load the button map into memory
*
* \return True if button map is ready to start translating buttons, false otherwise
@@ -197,8 +205,34 @@ namespace JOYSTICK
) = 0;
/*!
+ * \brief Set a list of driver primitives to be ignored
+ *
+ * This is necessary to prevent features from interfering with the button
+ * mapping process. This includes accelerometers, as well as PS4 triggers
+ * which send both a button press and an analog value.
+ *
+ * \param primitives The driver primitives to be ignored
+ */
+ virtual void SetIgnoredPrimitives(const std::vector<CDriverPrimitive>& primitives) = 0;
+
+ /*!
+ * \brief Check if a primitive is in the list of primitives to be ignored
+ *
+ * \param primitive The primitive to check
+ *
+ * \return True if the primitive should be ignored in the mapping process
+ */
+ virtual bool IsIgnored(const CDriverPrimitive& primitive) = 0;
+
+ /*!
* \brief Save the button map
*/
virtual void SaveButtonMap() = 0;
+
+ /*!
+ * \brief Revert changes to the button map since the last time it was loaded
+ * or commited to disk
+ */
+ virtual void RevertButtonMap() = 0;
};
}
diff --git a/xbmc/input/joysticks/IButtonMapCallback.h b/xbmc/input/joysticks/IButtonMapCallback.h
index 1ad2658605..4d22f91ba4 100644
--- a/xbmc/input/joysticks/IButtonMapCallback.h
+++ b/xbmc/input/joysticks/IButtonMapCallback.h
@@ -1,37 +1,55 @@
/*
-* Copyright (C) 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/>.
-*
-*/
+ * Copyright (C) 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
namespace JOYSTICK
{
/*!
- * \brief Interface for handling button maps
- */
+ * \brief Interface for handling button maps
+ */
class IButtonMapCallback
{
public:
virtual ~IButtonMapCallback() = default;
/*!
- * \brief Save the button map
- */
+ * \brief Save the button map
+ */
virtual void SaveButtonMap() = 0;
+
+ /*!
+ * \brief Clear the list of ignored driver primitives
+ *
+ * Called if the user begins capturing primitives to be ignored, and
+ * no primitives are captured before the dialog is accepted by the user.
+ *
+ * In this case, the button mapper won't have been given access to the
+ * button map, so a callback is needed to indicate that no primitives were
+ * captured and the user accepted this.
+ */
+ virtual void ResetIgnoredPrimitives() = 0;
+
+ /*!
+ * \brief Revert changes to the button map since the last time it was loaded
+ * or commited to disk
+ */
+ virtual void RevertButtonMap() = 0;
};
}
diff --git a/xbmc/input/joysticks/IButtonMapper.h b/xbmc/input/joysticks/IButtonMapper.h
index 43e89b6b81..0b7285be8a 100644
--- a/xbmc/input/joysticks/IButtonMapper.h
+++ b/xbmc/input/joysticks/IButtonMapper.h
@@ -24,6 +24,7 @@
namespace JOYSTICK
{
class CDriverPrimitive;
+ class IActionMap;
class IButtonMap;
class IButtonMapCallback;
@@ -50,14 +51,24 @@ namespace JOYSTICK
virtual std::string ControllerID(void) const = 0;
/*!
+ * \brief Return true if the button mapper wants a cooldown between button
+ * mapping commands
+ *
+ * \return True to only send button mapping commands that occur after a small
+ * timeout from the previous command.
+ */
+ virtual bool NeedsCooldown(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
+ * \param actionMap An interface capable of translating driver primitives to Kodi actions
+ * \param primitive The driver primitive
*
- * \return True if action was mapped to a feature
+ * \return True if driver primitive was mapped to a feature
*/
- virtual bool MapPrimitive(IButtonMap* buttonMap, const CDriverPrimitive& primitive) = 0;
+ virtual bool MapPrimitive(IButtonMap* buttonMap, IActionMap* actionMap, const CDriverPrimitive& primitive) = 0;
// Button map callback interface
void SetButtonMapCallback(IButtonMapCallback* callback) { m_callback = callback; }
diff --git a/xbmc/input/joysticks/IDriverReceiver.h b/xbmc/input/joysticks/IDriverReceiver.h
index c1a2a2083f..1a8cccb142 100644
--- a/xbmc/input/joysticks/IDriverReceiver.h
+++ b/xbmc/input/joysticks/IDriverReceiver.h
@@ -1,42 +1,42 @@
/*
-* Copyright (C) 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/>.
-*
-*/
+ * Copyright (C) 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
namespace JOYSTICK
{
/*!
- * \brief Interface for sending input events to joystick drivers
- */
+ * \brief Interface for sending input events to joystick drivers
+ */
class IDriverReceiver
{
public:
virtual ~IDriverReceiver(void) { }
/*!
- * \brief Set the value of a rumble motor
- *
- * \param motorIndex The driver index of the motor to rumble
- * \param magnitude The motor's new magnitude of vibration in the closed interval [0, 1]
- *
- * \return True if the event was handled otherwise false
- */
+ * \brief Set the value of a rumble motor
+ *
+ * \param motorIndex The driver index of the motor to rumble
+ * \param magnitude The motor's new magnitude of vibration in the closed interval [0, 1]
+ *
+ * \return True if the event was handled otherwise false
+ */
virtual bool SetMotorState(unsigned int motorIndex, float magnitude) = 0;
};
}
diff --git a/xbmc/input/joysticks/IInputHandler.h b/xbmc/input/joysticks/IInputHandler.h
index ae7f571422..6780609c54 100644
--- a/xbmc/input/joysticks/IInputHandler.h
+++ b/xbmc/input/joysticks/IInputHandler.h
@@ -77,14 +77,14 @@ namespace JOYSTICK
virtual bool OnButtonPress(const FeatureName& feature, bool bPressed) = 0;
/*!
- * \brief A digital button has been pressed for more than one event frame
- *
- * \param feature The feature being held
- * \param holdTimeMs The time elapsed since the initial press (ms)
- *
- * If OnButtonPress() returns true for the initial press, then this callback
- * is invoked on subsequent frames until the button is released.
- */
+ * \brief A digital button has been pressed for more than one event frame
+ *
+ * \param feature The feature being held
+ * \param holdTimeMs The time elapsed since the initial press (ms)
+ *
+ * If OnButtonPress() returns true for the initial press, then this callback
+ * is invoked on subsequent frames until the button is released.
+ */
virtual void OnButtonHold(const FeatureName& feature, unsigned int holdTimeMs) = 0;
/*!
diff --git a/xbmc/input/joysticks/IKeymapHandler.h b/xbmc/input/joysticks/IKeymapHandler.h
index 6f25b2ba56..562aa3d498 100644
--- a/xbmc/input/joysticks/IKeymapHandler.h
+++ b/xbmc/input/joysticks/IKeymapHandler.h
@@ -45,6 +45,16 @@ namespace JOYSTICK
virtual INPUT_TYPE GetInputType(unsigned int keyId) const = 0;
/*!
+ * \brief Get the action ID mapped to the specified key ID
+ *
+ * \param keyId The key ID from Key.h
+ *
+ * \return The action ID, or ACTION_NONE if no action is mapped to the
+ * specified key
+ */
+ virtual int GetActionID(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
diff --git a/xbmc/input/joysticks/KeymapHandler.cpp b/xbmc/input/joysticks/KeymapHandler.cpp
index c1bedbf01e..859bfcd467 100644
--- a/xbmc/input/joysticks/KeymapHandler.cpp
+++ b/xbmc/input/joysticks/KeymapHandler.cpp
@@ -63,6 +63,16 @@ INPUT_TYPE CKeymapHandler::GetInputType(unsigned int keyId) const
return INPUT_TYPE::UNKNOWN;
}
+int CKeymapHandler::GetActionID(unsigned int keyId) const
+{
+ CAction action(ACTION_NONE);
+
+ if (keyId != 0)
+ action = CButtonTranslator::GetInstance().GetAction(g_windowManager.GetActiveWindowID(), CKey(keyId));
+
+ return action.GetID();
+}
+
void CKeymapHandler::OnDigitalKey(unsigned int keyId, bool bPressed, unsigned int holdTimeMs /* = 0 */)
{
if (keyId != 0)
diff --git a/xbmc/input/joysticks/KeymapHandler.h b/xbmc/input/joysticks/KeymapHandler.h
index b5f2034ac1..ca27bccf96 100644
--- a/xbmc/input/joysticks/KeymapHandler.h
+++ b/xbmc/input/joysticks/KeymapHandler.h
@@ -34,6 +34,7 @@ namespace JOYSTICK
// implementation of IKeymapHandler
virtual INPUT_TYPE GetInputType(unsigned int keyId) const override;
+ virtual int GetActionID(unsigned int keyId) const override;
virtual void OnDigitalKey(unsigned int keyId, bool bPressed, unsigned int holdTimeMs = 0) override;
virtual void OnAnalogKey(unsigned int keyId, float magnitude) override;
diff --git a/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.cpp b/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.cpp
index 849b99fdae..1817d02917 100644
--- a/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.cpp
+++ b/xbmc/input/joysticks/dialogs/GUIDialogNewJoystick.cpp
@@ -39,7 +39,7 @@ void CGUIDialogNewJoystick::ShowAsync()
bShow = false;
else if (!CSettings::GetInstance().GetBool(CSettings::SETTING_INPUT_ASKNEWCONTROLLERS))
bShow = false;
- else if (g_windowManager.GetActiveWindow() == WINDOW_DIALOG_GAME_CONTROLLERS)
+ else if (g_windowManager.IsWindowActive(WINDOW_DIALOG_GAME_CONTROLLERS, false))
bShow = false;
if (bShow)
diff --git a/xbmc/input/joysticks/generic/ButtonMapping.cpp b/xbmc/input/joysticks/generic/ButtonMapping.cpp
index 99ed5a5c32..cd73dc61be 100644
--- a/xbmc/input/joysticks/generic/ButtonMapping.cpp
+++ b/xbmc/input/joysticks/generic/ButtonMapping.cpp
@@ -37,9 +37,10 @@ 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
-CButtonMapping::CButtonMapping(IButtonMapper* buttonMapper, IButtonMap* buttonMap)
+CButtonMapping::CButtonMapping(IButtonMapper* buttonMapper, IButtonMap* buttonMap, IActionMap* actionMap)
: m_buttonMapper(buttonMapper),
m_buttonMap(buttonMap),
+ m_actionMap(actionMap),
m_lastAction(0)
{
assert(m_buttonMapper != NULL);
@@ -53,8 +54,7 @@ bool CButtonMapping::OnButtonMotion(unsigned int buttonIndex, bool bPressed)
CDriverPrimitive buttonPrimitive(PRIMITIVE_TYPE::BUTTON, buttonIndex);
if (buttonPrimitive.IsValid())
{
- MapPrimitive(buttonPrimitive);
- return true;
+ return MapPrimitive(buttonPrimitive);
}
}
@@ -118,22 +118,48 @@ void CButtonMapping::SaveButtonMap()
m_buttonMap->SaveButtonMap();
}
-void CButtonMapping::MapPrimitive(const CDriverPrimitive& primitive)
+void CButtonMapping::ResetIgnoredPrimitives()
{
+ std::vector<CDriverPrimitive> empty;
+ m_buttonMap->SetIgnoredPrimitives(empty);
+}
+
+void CButtonMapping::RevertButtonMap()
+{
+ m_buttonMap->RevertButtonMap();
+}
+
+bool CButtonMapping::MapPrimitive(const CDriverPrimitive& primitive)
+{
+ bool bHandled = false;
+
const unsigned int now = SystemClockMillis();
- bool bTimeoutElapsed = (now >= m_lastAction + MAPPING_COOLDOWN_MS);
+ bool bTimeoutElapsed = true;
+
+ if (m_buttonMapper->NeedsCooldown())
+ bTimeoutElapsed = (now >= m_lastAction + MAPPING_COOLDOWN_MS);
+
if (bTimeoutElapsed)
{
- m_lastAction = SystemClockMillis();
- m_buttonMapper->MapPrimitive(m_buttonMap, primitive);
+ bHandled = m_buttonMapper->MapPrimitive(m_buttonMap, m_actionMap, primitive);
+
+ if (bHandled)
+ m_lastAction = SystemClockMillis();
+ }
+ else if (m_buttonMap->IsIgnored(primitive))
+ {
+ bHandled = true;
}
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());
+ bHandled = true;
}
+
+ return bHandled;
}
void CButtonMapping::Activate(const CDriverPrimitive& semiaxis)
diff --git a/xbmc/input/joysticks/generic/ButtonMapping.h b/xbmc/input/joysticks/generic/ButtonMapping.h
index 9d91abbe3a..d81cec7335 100644
--- a/xbmc/input/joysticks/generic/ButtonMapping.h
+++ b/xbmc/input/joysticks/generic/ButtonMapping.h
@@ -27,6 +27,7 @@
namespace JOYSTICK
{
+ class IActionMap;
class IButtonMap;
class IButtonMapper;
@@ -49,7 +50,7 @@ namespace JOYSTICK
* \param buttonMapper Carries out button-mapping commands using <buttonMap>
* \param buttonMap The button map given to <buttonMapper> on each command
*/
- CButtonMapping(IButtonMapper* buttonMapper, IButtonMap* buttonMap);
+ CButtonMapping(IButtonMapper* buttonMapper, IButtonMap* buttonMap, IActionMap* actionMap);
virtual ~CButtonMapping(void) { }
@@ -61,9 +62,11 @@ namespace JOYSTICK
// implementation of IButtonMapCallback
virtual void SaveButtonMap() override;
+ virtual void ResetIgnoredPrimitives() override;
+ virtual void RevertButtonMap() override;
private:
- void MapPrimitive(const CDriverPrimitive& primitive);
+ bool MapPrimitive(const CDriverPrimitive& primitive);
void Activate(const CDriverPrimitive& semiAxis);
void Deactivate(const CDriverPrimitive& semiAxis);
@@ -71,6 +74,7 @@ namespace JOYSTICK
IButtonMapper* const m_buttonMapper;
IButtonMap* const m_buttonMap;
+ IActionMap* const m_actionMap;
struct ActivatedAxis
{
diff --git a/xbmc/peripherals/addons/AddonButtonMap.cpp b/xbmc/peripherals/addons/AddonButtonMap.cpp
index 6fff54ce33..5ff375f4bc 100644
--- a/xbmc/peripherals/addons/AddonButtonMap.cpp
+++ b/xbmc/peripherals/addons/AddonButtonMap.cpp
@@ -24,6 +24,7 @@
#include "peripherals/devices/Peripheral.h"
#include "utils/log.h"
+#include <algorithm>
#include <assert.h>
#include <vector>
@@ -47,14 +48,23 @@ CAddonButtonMap::~CAddonButtonMap(void)
addon->UnregisterButtonMap(this);
}
+std::string CAddonButtonMap::DeviceName(void) const
+{
+ return m_device->DeviceName();
+}
+
bool CAddonButtonMap::Load(void)
{
FeatureMap features;
DriverMap driverMap;
+ PrimitiveVector ignoredPrimitives;
bool bSuccess = false;
if (auto addon = m_addon.lock())
- bSuccess = addon->GetFeatures(m_device, m_strControllerId, features);
+ {
+ bSuccess |= addon->GetFeatures(m_device, m_strControllerId, features);
+ bSuccess |= addon->GetIgnoredPrimitives(m_device, ignoredPrimitives);
+ }
// GetFeatures() was changed to always return false if no features were
// retrieved. Check here, just in case its contract is changed or violated in
@@ -71,6 +81,7 @@ bool CAddonButtonMap::Load(void)
CSingleLock lock(m_mutex);
m_features = std::move(features);
m_driverMap = std::move(driverMap);
+ m_ignoredPrimitives = std::move(CPeripheralAddonTranslator::TranslatePrimitives(ignoredPrimitives));
}
return true;
@@ -197,6 +208,8 @@ void CAddonButtonMap::AddAnalogStick(const FeatureName& feature,
if (auto addon = m_addon.lock())
addon->MapFeature(m_device, m_strControllerId, analogStick);
+ // Because each direction is mapped individually, we need to refresh the
+ // feature each time a new direction is mapped.
if (bModified)
Load();
}
@@ -242,8 +255,17 @@ void CAddonButtonMap::AddAccelerometer(const FeatureName& feature,
if (auto addon = m_addon.lock())
addon->MapFeature(m_device, m_strControllerId, accelerometer);
+}
- Load();
+void CAddonButtonMap::SetIgnoredPrimitives(const std::vector<JOYSTICK::CDriverPrimitive>& primitives)
+{
+ if (auto addon = m_addon.lock())
+ addon->SetIgnoredPrimitives(m_device, CPeripheralAddonTranslator::TranslatePrimitives(primitives));
+}
+
+bool CAddonButtonMap::IsIgnored(const JOYSTICK::CDriverPrimitive& primitive)
+{
+ return std::find(m_ignoredPrimitives.begin(), m_ignoredPrimitives.end(), primitive) != m_ignoredPrimitives.end();
}
void CAddonButtonMap::SaveButtonMap()
@@ -252,6 +274,12 @@ void CAddonButtonMap::SaveButtonMap()
addon->SaveButtonMap(m_device);
}
+void CAddonButtonMap::RevertButtonMap()
+{
+ if (auto addon = m_addon.lock())
+ addon->RevertButtonMap(m_device);
+}
+
CAddonButtonMap::DriverMap CAddonButtonMap::CreateLookupTable(const FeatureMap& features)
{
using namespace JOYSTICK;
diff --git a/xbmc/peripherals/addons/AddonButtonMap.h b/xbmc/peripherals/addons/AddonButtonMap.h
index 1f2965ab4e..b8bec15db7 100644
--- a/xbmc/peripherals/addons/AddonButtonMap.h
+++ b/xbmc/peripherals/addons/AddonButtonMap.h
@@ -41,6 +41,8 @@ namespace PERIPHERALS
// Implementation of IButtonMap
virtual std::string ControllerID(void) const override { return m_strControllerId; }
+ virtual std::string DeviceName(void) const override;
+
virtual bool Load(void) override;
virtual void Reset(void) override;
@@ -92,10 +94,17 @@ namespace PERIPHERALS
const JOYSTICK::CDriverPrimitive& positiveZ
) override;
+ virtual void SetIgnoredPrimitives(const std::vector<JOYSTICK::CDriverPrimitive>& primitives) override;
+
+ virtual bool IsIgnored(const JOYSTICK::CDriverPrimitive& primitive) override;
+
virtual void SaveButtonMap() override;
+ virtual void RevertButtonMap() override;
+
private:
typedef std::map<JOYSTICK::CDriverPrimitive, JOYSTICK::FeatureName> DriverMap;
+ typedef std::vector<JOYSTICK::CDriverPrimitive> JoystickPrimitiveVector;
// Utility functions
static DriverMap CreateLookupTable(const FeatureMap& features);
@@ -107,6 +116,7 @@ namespace PERIPHERALS
const std::string m_strControllerId;
FeatureMap m_features;
DriverMap m_driverMap;
+ JoystickPrimitiveVector m_ignoredPrimitives;
CCriticalSection m_mutex;
};
}
diff --git a/xbmc/peripherals/addons/AddonButtonMapping.cpp b/xbmc/peripherals/addons/AddonButtonMapping.cpp
index b5f25e167a..006572259b 100644
--- a/xbmc/peripherals/addons/AddonButtonMapping.cpp
+++ b/xbmc/peripherals/addons/AddonButtonMapping.cpp
@@ -40,7 +40,7 @@ CAddonButtonMapping::CAddonButtonMapping(CPeripheral* peripheral, IButtonMapper*
m_buttonMap.reset(new CAddonButtonMap(peripheral, addon, mapper->ControllerID()));
if (m_buttonMap->Load())
{
- m_driverHandler.reset(new CButtonMapping(mapper, m_buttonMap.get()));
+ m_buttonMapping.reset(new CButtonMapping(mapper, m_buttonMap.get(), peripheral->GetActionMap()));
// Allow the mapper to save our button map
mapper->SetButtonMapCallback(this);
@@ -52,42 +52,54 @@ CAddonButtonMapping::CAddonButtonMapping(CPeripheral* peripheral, IButtonMapper*
CAddonButtonMapping::~CAddonButtonMapping(void)
{
- m_driverHandler.reset();
+ m_buttonMapping.reset();
m_buttonMap.reset();
}
bool CAddonButtonMapping::OnButtonMotion(unsigned int buttonIndex, bool bPressed)
{
- if (m_driverHandler)
- return m_driverHandler->OnButtonMotion(buttonIndex, bPressed);
+ if (m_buttonMapping)
+ return m_buttonMapping->OnButtonMotion(buttonIndex, bPressed);
return false;
}
bool CAddonButtonMapping::OnHatMotion(unsigned int hatIndex, HAT_STATE state)
{
- if (m_driverHandler)
- return m_driverHandler->OnHatMotion(hatIndex, state);
+ if (m_buttonMapping)
+ return m_buttonMapping->OnHatMotion(hatIndex, state);
return false;
}
bool CAddonButtonMapping::OnAxisMotion(unsigned int axisIndex, float position)
{
- if (m_driverHandler)
- return m_driverHandler->OnAxisMotion(axisIndex, position);
+ if (m_buttonMapping)
+ return m_buttonMapping->OnAxisMotion(axisIndex, position);
return false;
}
void CAddonButtonMapping::ProcessAxisMotions(void)
{
- if (m_driverHandler)
- m_driverHandler->ProcessAxisMotions();
+ if (m_buttonMapping)
+ m_buttonMapping->ProcessAxisMotions();
}
void CAddonButtonMapping::SaveButtonMap()
{
- if (m_buttonMap)
- m_buttonMap->SaveButtonMap();
+ if (m_buttonMapping)
+ m_buttonMapping->SaveButtonMap();
+}
+
+void CAddonButtonMapping::ResetIgnoredPrimitives()
+{
+ if (m_buttonMapping)
+ m_buttonMapping->ResetIgnoredPrimitives();
+}
+
+void CAddonButtonMapping::RevertButtonMap()
+{
+ if (m_buttonMapping)
+ m_buttonMapping->RevertButtonMap();
}
diff --git a/xbmc/peripherals/addons/AddonButtonMapping.h b/xbmc/peripherals/addons/AddonButtonMapping.h
index 83f69cf02f..5b16e338e9 100644
--- a/xbmc/peripherals/addons/AddonButtonMapping.h
+++ b/xbmc/peripherals/addons/AddonButtonMapping.h
@@ -26,6 +26,7 @@
namespace JOYSTICK
{
+ class CButtonMapping;
class IButtonMap;
class IButtonMapper;
}
@@ -50,9 +51,11 @@ namespace PERIPHERALS
// implementation of IButtonMapCallback
virtual void SaveButtonMap() override;
+ virtual void ResetIgnoredPrimitives() override;
+ virtual void RevertButtonMap() override;
private:
- std::unique_ptr<JOYSTICK::IDriverHandler> m_driverHandler;
+ std::unique_ptr<JOYSTICK::CButtonMapping> m_buttonMapping;
std::unique_ptr<JOYSTICK::IButtonMap> m_buttonMap;
};
}
diff --git a/xbmc/peripherals/addons/PeripheralAddon.cpp b/xbmc/peripherals/addons/PeripheralAddon.cpp
index 1fce113e9b..5fe442a263 100644
--- a/xbmc/peripherals/addons/PeripheralAddon.cpp
+++ b/xbmc/peripherals/addons/PeripheralAddon.cpp
@@ -585,12 +585,85 @@ bool CPeripheralAddon::MapFeature(const CPeripheral* device,
1, &addonFeature), "MapFeatures()"); }
catch (std::exception &e) { LogException(e, "MapFeatures()"); return false; }
+ return retVal == PERIPHERAL_NO_ERROR;
+}
+
+bool CPeripheralAddon::GetIgnoredPrimitives(const CPeripheral* device, PrimitiveVector& primitives)
+{
+ if (!m_bProvidesButtonMaps)
+ return false;
+
+ PERIPHERAL_ERROR retVal;
+
+ ADDON::Joystick joystickInfo;
+ GetJoystickInfo(device, joystickInfo);
+
+ JOYSTICK_INFO joystickStruct;
+ joystickInfo.ToStruct(joystickStruct);
+
+ unsigned int primitiveCount = 0;
+ JOYSTICK_DRIVER_PRIMITIVE* pPrimitives = nullptr;
+
+ try
+ {
+ LogError(retVal = m_pStruct->GetIgnoredPrimitives(&joystickStruct, &primitiveCount,
+ &pPrimitives), "GetIgnoredPrimitives()");
+ }
+ catch (std::exception &e)
+ {
+ LogException(e, "GetIgnoredPrimitives()");
+ return false;
+ }
+
if (retVal == PERIPHERAL_NO_ERROR)
{
- // Notify observing button maps
- RefreshButtonMaps(device->DeviceName());
+ for (unsigned int i = 0; i < primitiveCount; i++)
+ primitives.emplace_back(pPrimitives[i]);
+
+ try
+ {
+ m_pStruct->FreePrimitives(primitiveCount, pPrimitives);
+ }
+ catch (std::exception &e)
+ {
+ LogException(e, "FreePrimitives()");
+ }
+
+ return true;
+ }
+
+ return false;
+
+}
+
+bool CPeripheralAddon::SetIgnoredPrimitives(const CPeripheral* device, const PrimitiveVector& primitives)
+{
+ if (!m_bProvidesButtonMaps)
+ return false;
+
+ PERIPHERAL_ERROR retVal;
+
+ ADDON::Joystick joystickInfo;
+ GetJoystickInfo(device, joystickInfo);
+
+ JOYSTICK_INFO joystickStruct;
+ joystickInfo.ToStruct(joystickStruct);
+
+ JOYSTICK_DRIVER_PRIMITIVE* addonPrimitives = nullptr;
+ ADDON::DriverPrimitives::ToStructs(primitives, &addonPrimitives);
+
+ try
+ {
+ LogError(retVal = m_pStruct->SetIgnoredPrimitives(&joystickStruct,
+ primitives.size(), addonPrimitives), "SetIgnoredPrimitives()");
+ }
+ catch (std::exception &e)
+ {
+ LogException(e, "SetIgnoredPrimitives()"); return false;
}
+ ADDON::DriverPrimitives::FreeStructs(primitives.size(), addonPrimitives);
+
return retVal == PERIPHERAL_NO_ERROR;
}
@@ -607,6 +680,24 @@ void CPeripheralAddon::SaveButtonMap(const CPeripheral* device)
try { m_pStruct->SaveButtonMap(&joystickStruct); }
catch (std::exception &e) { LogException(e, "SaveMap()"); return; }
+
+ // Notify observing button maps
+ RefreshButtonMaps(device->DeviceName());
+}
+
+void CPeripheralAddon::RevertButtonMap(const CPeripheral* device)
+{
+ if (!m_bProvidesButtonMaps)
+ return;
+
+ ADDON::Joystick joystickInfo;
+ GetJoystickInfo(device, joystickInfo);
+
+ JOYSTICK_INFO joystickStruct;
+ joystickInfo.ToStruct(joystickStruct);
+
+ try { m_pStruct->RevertButtonMap(&joystickStruct); }
+ catch (std::exception &e) { LogException(e, "RevertMap()"); return; }
}
void CPeripheralAddon::ResetButtonMap(const CPeripheral* device, const std::string& strControllerId)
diff --git a/xbmc/peripherals/addons/PeripheralAddon.h b/xbmc/peripherals/addons/PeripheralAddon.h
index 612b646ad6..3139402d0d 100644
--- a/xbmc/peripherals/addons/PeripheralAddon.h
+++ b/xbmc/peripherals/addons/PeripheralAddon.h
@@ -41,6 +41,7 @@ namespace PERIPHERALS
class CPeripheral;
class CPeripheralJoystick;
+ typedef std::vector<ADDON::DriverPrimitive> PrimitiveVector;
typedef std::map<JOYSTICK::FeatureName, ADDON::JoystickFeature> FeatureMap;
class CPeripheralAddon : public ADDON::CAddonDll<DllPeripheral, PeripheralAddon, PERIPHERAL_PROPERTIES>
@@ -84,7 +85,10 @@ namespace PERIPHERALS
bool HasButtonMaps(void) const { return m_bProvidesButtonMaps; }
bool GetFeatures(const CPeripheral* device, const std::string& strControllerId, FeatureMap& features);
bool MapFeature(const CPeripheral* device, const std::string& strControllerId, const ADDON::JoystickFeature& feature);
+ bool GetIgnoredPrimitives(const CPeripheral* device, PrimitiveVector& primitives);
+ bool SetIgnoredPrimitives(const CPeripheral* device, const PrimitiveVector& primitives);
void SaveButtonMap(const CPeripheral* device);
+ void RevertButtonMap(const CPeripheral* device);
void ResetButtonMap(const CPeripheral* device, const std::string& strControllerId);
void PowerOffJoystick(unsigned int index);
//@}
diff --git a/xbmc/peripherals/addons/PeripheralAddonTranslator.cpp b/xbmc/peripherals/addons/PeripheralAddonTranslator.cpp
index 2c00677f62..7d9b296bf6 100644
--- a/xbmc/peripherals/addons/PeripheralAddonTranslator.cpp
+++ b/xbmc/peripherals/addons/PeripheralAddonTranslator.cpp
@@ -21,6 +21,9 @@
#include "PeripheralAddonTranslator.h"
#include "input/joysticks/JoystickUtils.h"
+#include <algorithm>
+#include <iterator>
+
using namespace JOYSTICK;
using namespace PERIPHERALS;
@@ -121,6 +124,28 @@ ADDON::DriverPrimitive CPeripheralAddonTranslator::TranslatePrimitive(const CDri
return retVal;
}
+std::vector<JOYSTICK::CDriverPrimitive> CPeripheralAddonTranslator::TranslatePrimitives(const std::vector<ADDON::DriverPrimitive>& primitives)
+{
+ std::vector<JOYSTICK::CDriverPrimitive> ret;
+ std::transform(primitives.begin(), primitives.end(), std::back_inserter(ret),
+ [](const ADDON::DriverPrimitive& primitive)
+ {
+ return CPeripheralAddonTranslator::TranslatePrimitive(primitive);
+ });
+ return ret;
+}
+
+std::vector<ADDON::DriverPrimitive> CPeripheralAddonTranslator::TranslatePrimitives(const std::vector<JOYSTICK::CDriverPrimitive>& primitives)
+{
+ std::vector<ADDON::DriverPrimitive> ret;
+ std::transform(primitives.begin(), primitives.end(), std::back_inserter(ret),
+ [](const JOYSTICK::CDriverPrimitive& primitive)
+ {
+ return CPeripheralAddonTranslator::TranslatePrimitive(primitive);
+ });
+ return ret;
+}
+
HAT_DIRECTION CPeripheralAddonTranslator::TranslateHatDirection(JOYSTICK_DRIVER_HAT_DIRECTION dir)
{
switch (dir)
diff --git a/xbmc/peripherals/addons/PeripheralAddonTranslator.h b/xbmc/peripherals/addons/PeripheralAddonTranslator.h
index a2ccee82c3..1cdb339403 100644
--- a/xbmc/peripherals/addons/PeripheralAddonTranslator.h
+++ b/xbmc/peripherals/addons/PeripheralAddonTranslator.h
@@ -24,6 +24,8 @@
#include "input/joysticks/DriverPrimitive.h"
#include "input/joysticks/JoystickTypes.h"
+#include <vector>
+
namespace PERIPHERALS
{
class CPeripheralAddonTranslator
@@ -34,6 +36,9 @@ namespace PERIPHERALS
static JOYSTICK::CDriverPrimitive TranslatePrimitive(const ADDON::DriverPrimitive& primitive);
static ADDON::DriverPrimitive TranslatePrimitive(const JOYSTICK::CDriverPrimitive& primitive);
+ static std::vector<JOYSTICK::CDriverPrimitive> TranslatePrimitives(const std::vector<ADDON::DriverPrimitive>& primitives);
+ static std::vector<ADDON::DriverPrimitive> TranslatePrimitives(const std::vector<JOYSTICK::CDriverPrimitive>& primitives);
+
static JOYSTICK::HAT_DIRECTION TranslateHatDirection(JOYSTICK_DRIVER_HAT_DIRECTION dir);
static JOYSTICK_DRIVER_HAT_DIRECTION TranslateHatDirection(JOYSTICK::HAT_DIRECTION dir);
diff --git a/xbmc/peripherals/devices/Peripheral.h b/xbmc/peripherals/devices/Peripheral.h
index 4be500bb5f..f31edd56ec 100644
--- a/xbmc/peripherals/devices/Peripheral.h
+++ b/xbmc/peripherals/devices/Peripheral.h
@@ -30,6 +30,7 @@ class CSetting;
namespace JOYSTICK
{
+ class IActionMap;
class IButtonMapper;
class IDriverHandler;
class IDriverReceiver;
@@ -202,6 +203,8 @@ namespace PERIPHERALS
virtual JOYSTICK::IDriverReceiver* GetDriverReceiver() { return nullptr; }
+ virtual JOYSTICK::IActionMap* GetActionMap() { return nullptr; }
+
protected:
virtual void ClearSettings(void);
diff --git a/xbmc/peripherals/devices/PeripheralJoystick.h b/xbmc/peripherals/devices/PeripheralJoystick.h
index a6d24370ba..72e0bb2c65 100644
--- a/xbmc/peripherals/devices/PeripheralJoystick.h
+++ b/xbmc/peripherals/devices/PeripheralJoystick.h
@@ -57,6 +57,7 @@ namespace PERIPHERALS
virtual void RegisterJoystickDriverHandler(IDriverHandler* handler, bool bPromiscuous) override;
virtual void UnregisterJoystickDriverHandler(IDriverHandler* handler) override;
virtual JOYSTICK::IDriverReceiver* GetDriverReceiver() override { return this; }
+ virtual JOYSTICK::IActionMap* GetActionMap() override { return &m_defaultInputHandler; }
// implementation of IDriverHandler
virtual bool OnButtonMotion(unsigned int buttonIndex, bool bPressed) override;