2 * Copyright (C) 2014-2024 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "PeripheralAddon.h"
12 #include "FileItemList.h"
13 #include "PeripheralAddonTranslator.h"
14 #include "addons/addoninfo/AddonInfo.h"
15 #include "addons/addoninfo/AddonType.h"
16 #include "filesystem/Directory.h"
17 #include "filesystem/SpecialProtocol.h"
18 #include "games/controllers/Controller.h"
19 #include "games/controllers/ControllerManager.h"
20 #include "input/joysticks/DriverPrimitive.h"
21 #include "input/joysticks/interfaces/IButtonMap.h"
22 #include "peripherals/Peripherals.h"
23 #include "peripherals/bus/virtual/PeripheralBusAddon.h"
24 #include "peripherals/devices/PeripheralJoystick.h"
25 #include "utils/StringUtils.h"
26 #include "utils/log.h"
30 #include <shared_mutex>
35 using namespace JOYSTICK
;
36 using namespace PERIPHERALS
;
37 using namespace XFILE
;
39 #define KEYBOARD_BUTTON_MAP_NAME "Keyboard"
40 #define KEYBOARD_PROVIDER "application"
42 #define MOUSE_BUTTON_MAP_NAME "Mouse"
43 #define MOUSE_PROVIDER "application"
46 #define SAFE_DELETE(p) \
54 CPeripheralAddon::CPeripheralAddon(const ADDON::AddonInfoPtr
& addonInfo
, CPeripherals
& manager
)
55 : IAddonInstanceHandler(ADDON_INSTANCE_PERIPHERAL
, addonInfo
), m_manager(manager
)
57 m_bProvidesJoysticks
=
58 addonInfo
->Type(ADDON::AddonType::PERIPHERALDLL
)->GetValue("@provides_joysticks").asBoolean();
59 m_bProvidesButtonMaps
= addonInfo
->Type(ADDON::AddonType::PERIPHERALDLL
)
60 ->GetValue("@provides_buttonmaps")
63 // Create "C" interface structures, used as own parts to prevent API problems on update
64 m_ifc
.peripheral
= new AddonInstance_Peripheral
;
65 m_ifc
.peripheral
->props
= new AddonProps_Peripheral();
66 m_ifc
.peripheral
->toAddon
= new KodiToAddonFuncTable_Peripheral();
67 m_ifc
.peripheral
->toKodi
= new AddonToKodiFuncTable_Peripheral();
72 CPeripheralAddon::~CPeripheralAddon(void)
78 delete m_ifc
.peripheral
->toAddon
;
79 delete m_ifc
.peripheral
->toKodi
;
80 delete m_ifc
.peripheral
->props
;
82 delete m_ifc
.peripheral
;
85 void CPeripheralAddon::ResetProperties(void)
88 m_strUserPath
= CSpecialProtocol::TranslatePath(Profile());
89 m_strClientPath
= CSpecialProtocol::TranslatePath(Path());
91 m_ifc
.peripheral
->props
->user_path
= m_strUserPath
.c_str();
92 m_ifc
.peripheral
->props
->addon_path
= m_strClientPath
.c_str();
94 m_ifc
.peripheral
->toKodi
->kodiInstance
= this;
95 m_ifc
.peripheral
->toKodi
->feature_count
= cb_feature_count
;
96 m_ifc
.peripheral
->toKodi
->feature_type
= cb_feature_type
;
97 m_ifc
.peripheral
->toKodi
->refresh_button_maps
= cb_refresh_button_maps
;
98 m_ifc
.peripheral
->toKodi
->trigger_scan
= cb_trigger_scan
;
100 memset(m_ifc
.peripheral
->toAddon
, 0, sizeof(KodiToAddonFuncTable_Peripheral
));
103 bool CPeripheralAddon::CreateAddon(void)
105 std::unique_lock
<CSharedSection
> lock(m_dllSection
);
107 // Reset all properties to defaults
110 // Create directory for user data
111 if (!CDirectory::Exists(m_strUserPath
))
112 CDirectory::Create(m_strUserPath
);
114 // Initialise the add-on
115 CLog::Log(LOGDEBUG
, "PERIPHERAL - {} - creating peripheral add-on instance '{}'", __FUNCTION__
,
118 if (CreateInstance() != ADDON_STATUS_OK
)
121 if (!GetAddonProperties())
130 void CPeripheralAddon::DestroyAddon()
133 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
134 m_peripherals
.clear();
138 std::unique_lock
<CCriticalSection
> lock(m_buttonMapMutex
);
139 // only clear buttonMaps but don't delete them as they are owned by a
140 // CAddonJoystickInputHandling instance
141 m_buttonMaps
.clear();
145 std::unique_lock
<CSharedSection
> lock(m_dllSection
);
150 bool CPeripheralAddon::GetAddonProperties(void)
152 PERIPHERAL_CAPABILITIES addonCapabilities
= {};
154 // Get the capabilities
155 m_ifc
.peripheral
->toAddon
->get_capabilities(m_ifc
.peripheral
, &addonCapabilities
);
157 // Verify capabilities against addon.xml
158 if (m_bProvidesJoysticks
!= addonCapabilities
.provides_joysticks
)
162 "PERIPHERAL - Add-on '{}': provides_joysticks'({}) in add-on DLL doesn't match "
163 "'provides_joysticks'({}) in addon.xml. Please contact the developer of this add-on: {}",
164 Name(), addonCapabilities
.provides_joysticks
? "true" : "false",
165 m_bProvidesJoysticks
? "true" : "false", Author());
168 if (m_bProvidesButtonMaps
!= addonCapabilities
.provides_buttonmaps
)
172 "PERIPHERAL - Add-on '{}': provides_buttonmaps' ({}) in add-on DLL doesn't match "
173 "'provides_buttonmaps' ({}) in addon.xml. Please contact the developer of this add-on: {}",
174 Name(), addonCapabilities
.provides_buttonmaps
? "true" : "false",
175 m_bProvidesButtonMaps
? "true" : "false", Author());
179 // Read properties that depend on underlying driver
180 m_bSupportsJoystickRumble
= addonCapabilities
.provides_joystick_rumble
;
181 m_bSupportsJoystickPowerOff
= addonCapabilities
.provides_joystick_power_off
;
186 bool CPeripheralAddon::Register(unsigned int peripheralIndex
, const PeripheralPtr
& peripheral
)
191 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
192 if (m_peripherals
.find(peripheralIndex
) == m_peripherals
.end())
194 if (peripheral
->Type() == PERIPHERAL_JOYSTICK
)
196 m_peripherals
[peripheralIndex
] = std::static_pointer_cast
<CPeripheralJoystick
>(peripheral
);
198 CLog::Log(LOGINFO
, "{} - new {} device registered on {}->{}: {}", __FUNCTION__
,
199 PeripheralTypeTranslator::TypeToString(peripheral
->Type()),
200 PeripheralTypeTranslator::BusTypeToString(PERIPHERAL_BUS_ADDON
),
201 peripheral
->Location(), peripheral
->DeviceName());
209 void CPeripheralAddon::UnregisterRemovedDevices(const PeripheralScanResults
& results
,
210 PeripheralVector
& removedPeripherals
)
212 std::vector
<unsigned int> removedIndexes
;
215 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
216 for (auto& it
: m_peripherals
)
218 const PeripheralPtr
& peripheral
= it
.second
;
219 PeripheralScanResult
updatedDevice(PERIPHERAL_BUS_ADDON
);
220 if (!results
.GetDeviceOnLocation(peripheral
->Location(), &updatedDevice
) ||
221 *peripheral
!= updatedDevice
)
224 removedIndexes
.push_back(it
.first
);
229 for (auto index
: removedIndexes
)
231 auto it
= m_peripherals
.find(index
);
232 const PeripheralPtr
& peripheral
= it
->second
;
233 CLog::Log(LOGINFO
, "{} - device removed from {}/{}: {} ({}:{})", __FUNCTION__
,
234 PeripheralTypeTranslator::TypeToString(peripheral
->Type()), peripheral
->Location(),
235 peripheral
->DeviceName(), peripheral
->VendorIdAsString(),
236 peripheral
->ProductIdAsString());
237 UnregisterButtonMap(peripheral
.get());
238 peripheral
->OnDeviceRemoved();
239 removedPeripherals
.push_back(peripheral
);
240 m_peripherals
.erase(it
);
244 bool CPeripheralAddon::HasFeature(const PeripheralFeature feature
) const
246 if (feature
== FEATURE_JOYSTICK
)
247 return m_bProvidesJoysticks
;
252 void CPeripheralAddon::GetFeatures(std::vector
<PeripheralFeature
>& features
) const
254 if (m_bProvidesJoysticks
&&
255 std::find(features
.begin(), features
.end(), FEATURE_JOYSTICK
) == features
.end())
256 features
.push_back(FEATURE_JOYSTICK
);
259 PeripheralPtr
CPeripheralAddon::GetPeripheral(unsigned int index
) const
261 PeripheralPtr peripheral
;
262 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
263 auto it
= m_peripherals
.find(index
);
264 if (it
!= m_peripherals
.end())
265 peripheral
= it
->second
;
269 PeripheralPtr
CPeripheralAddon::GetByPath(const std::string
& strPath
) const
271 PeripheralPtr result
;
273 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
274 for (const auto& it
: m_peripherals
)
276 if (StringUtils::EqualsNoCase(strPath
, it
.second
->FileLocation()))
286 bool CPeripheralAddon::SupportsFeature(PeripheralFeature feature
) const
291 return m_bSupportsJoystickRumble
;
292 case FEATURE_POWER_OFF
:
293 return m_bSupportsJoystickPowerOff
;
301 unsigned int CPeripheralAddon::GetPeripheralsWithFeature(PeripheralVector
& results
,
302 const PeripheralFeature feature
) const
304 unsigned int iReturn
= 0;
305 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
306 for (const auto& it
: m_peripherals
)
308 if (it
.second
->HasFeature(feature
))
310 results
.push_back(it
.second
);
317 unsigned int CPeripheralAddon::GetNumberOfPeripherals(void) const
319 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
320 return static_cast<unsigned int>(m_peripherals
.size());
323 unsigned int CPeripheralAddon::GetNumberOfPeripheralsWithId(const int iVendorId
,
324 const int iProductId
) const
326 unsigned int iReturn
= 0;
327 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
328 for (const auto& it
: m_peripherals
)
330 if (it
.second
->VendorId() == iVendorId
&& it
.second
->ProductId() == iProductId
)
337 void CPeripheralAddon::GetDirectory(const std::string
& strPath
, CFileItemList
& items
) const
339 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
340 for (const auto& it
: m_peripherals
)
342 const PeripheralPtr
& peripheral
= it
.second
;
343 if (peripheral
->IsHidden())
346 CFileItemPtr
peripheralFile(new CFileItem(peripheral
->DeviceName()));
347 peripheralFile
->SetPath(peripheral
->FileLocation());
348 peripheralFile
->SetProperty("vendor", peripheral
->VendorIdAsString());
349 peripheralFile
->SetProperty("product", peripheral
->ProductIdAsString());
350 peripheralFile
->SetProperty(
351 "bus", PeripheralTypeTranslator::BusTypeToString(peripheral
->GetBusType()));
352 peripheralFile
->SetProperty("location", peripheral
->Location());
353 peripheralFile
->SetProperty("class",
354 PeripheralTypeTranslator::TypeToString(peripheral
->Type()));
355 peripheralFile
->SetProperty("version", peripheral
->GetVersionInfo());
356 peripheralFile
->SetArt("icon", peripheral
->GetIcon());
357 items
.Add(peripheralFile
);
361 bool CPeripheralAddon::PerformDeviceScan(PeripheralScanResults
& results
)
363 unsigned int peripheralCount
;
364 PERIPHERAL_INFO
* pScanResults
;
365 PERIPHERAL_ERROR retVal
;
367 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
369 if (!m_ifc
.peripheral
->toAddon
->perform_device_scan
)
372 LogError(retVal
= m_ifc
.peripheral
->toAddon
->perform_device_scan(m_ifc
.peripheral
,
373 &peripheralCount
, &pScanResults
),
374 "PerformDeviceScan()");
376 if (retVal
== PERIPHERAL_NO_ERROR
)
378 for (unsigned int i
= 0; i
< peripheralCount
; i
++)
380 kodi::addon::Peripheral
peripheral(pScanResults
[i
]);
381 PeripheralScanResult
result(PERIPHERAL_BUS_ADDON
);
382 switch (peripheral
.Type())
384 case PERIPHERAL_TYPE_JOYSTICK
:
385 result
.m_type
= PERIPHERAL_JOYSTICK
;
391 result
.m_strDeviceName
= peripheral
.Name();
392 result
.m_strLocation
= StringUtils::Format("{}/{}", ID(), peripheral
.Index());
393 result
.m_iVendorId
= peripheral
.VendorID();
394 result
.m_iProductId
= peripheral
.ProductID();
395 result
.m_mappedType
= PERIPHERAL_JOYSTICK
;
396 result
.m_mappedBusType
= PERIPHERAL_BUS_ADDON
;
397 result
.m_iSequence
= 0;
399 if (!results
.ContainsResult(result
))
400 results
.m_results
.push_back(result
);
403 m_ifc
.peripheral
->toAddon
->free_scan_results(m_ifc
.peripheral
, peripheralCount
, pScanResults
);
411 bool CPeripheralAddon::ProcessEvents(void)
413 if (!m_bProvidesJoysticks
)
416 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
418 if (!m_ifc
.peripheral
->toAddon
->get_events
)
421 PERIPHERAL_ERROR retVal
;
423 unsigned int eventCount
= 0;
424 PERIPHERAL_EVENT
* pEvents
= nullptr;
426 LogError(retVal
= m_ifc
.peripheral
->toAddon
->get_events(m_ifc
.peripheral
, &eventCount
, &pEvents
),
428 if (retVal
== PERIPHERAL_NO_ERROR
)
430 for (unsigned int i
= 0; i
< eventCount
; i
++)
432 kodi::addon::PeripheralEvent
event(pEvents
[i
]);
433 PeripheralPtr device
= GetPeripheral(event
.PeripheralIndex());
437 switch (device
->Type())
439 case PERIPHERAL_JOYSTICK
:
441 std::shared_ptr
<CPeripheralJoystick
> joystickDevice
=
442 std::static_pointer_cast
<CPeripheralJoystick
>(device
);
444 switch (event
.Type())
446 case PERIPHERAL_EVENT_TYPE_DRIVER_BUTTON
:
448 const bool bPressed
= (event
.ButtonState() == JOYSTICK_STATE_BUTTON_PRESSED
);
449 joystickDevice
->OnButtonMotion(event
.DriverIndex(), bPressed
);
452 case PERIPHERAL_EVENT_TYPE_DRIVER_HAT
:
454 const HAT_STATE state
=
455 CPeripheralAddonTranslator::TranslateHatState(event
.HatState());
456 joystickDevice
->OnHatMotion(event
.DriverIndex(), state
);
459 case PERIPHERAL_EVENT_TYPE_DRIVER_AXIS
:
461 joystickDevice
->OnAxisMotion(event
.DriverIndex(), event
.AxisState());
474 for (const auto& it
: m_peripherals
)
476 if (it
.second
->Type() == PERIPHERAL_JOYSTICK
)
477 std::static_pointer_cast
<CPeripheralJoystick
>(it
.second
)->OnInputFrame();
480 m_ifc
.peripheral
->toAddon
->free_events(m_ifc
.peripheral
, eventCount
, pEvents
);
488 bool CPeripheralAddon::SendRumbleEvent(unsigned int peripheralIndex
,
489 unsigned int driverIndex
,
492 if (!m_bProvidesJoysticks
)
495 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
497 if (!m_ifc
.peripheral
->toAddon
->send_event
)
500 PERIPHERAL_EVENT eventStruct
= {};
502 eventStruct
.peripheral_index
= peripheralIndex
;
503 eventStruct
.type
= PERIPHERAL_EVENT_TYPE_SET_MOTOR
;
504 eventStruct
.driver_index
= driverIndex
;
505 eventStruct
.motor_state
= magnitude
;
507 return m_ifc
.peripheral
->toAddon
->send_event(m_ifc
.peripheral
, &eventStruct
);
510 bool CPeripheralAddon::GetJoystickProperties(unsigned int index
, CPeripheralJoystick
& joystick
)
512 if (!m_bProvidesJoysticks
)
515 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
517 if (!m_ifc
.peripheral
->toAddon
->get_joystick_info
)
520 PERIPHERAL_ERROR retVal
;
522 JOYSTICK_INFO joystickStruct
;
524 LogError(retVal
= m_ifc
.peripheral
->toAddon
->get_joystick_info(m_ifc
.peripheral
, index
,
526 "GetJoystickInfo()");
527 if (retVal
== PERIPHERAL_NO_ERROR
)
529 kodi::addon::Joystick
addonJoystick(joystickStruct
);
530 SetJoystickInfo(joystick
, addonJoystick
);
532 m_ifc
.peripheral
->toAddon
->free_joystick_info(m_ifc
.peripheral
, &joystickStruct
);
540 bool CPeripheralAddon::GetAppearance(const CPeripheral
* device
, std::string
& controllerId
)
542 if (!m_bProvidesButtonMaps
)
545 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
547 if (!m_ifc
.peripheral
->toAddon
->get_appearance
)
550 PERIPHERAL_ERROR retVal
;
552 kodi::addon::Joystick joystickInfo
;
553 GetJoystickInfo(device
, joystickInfo
);
555 JOYSTICK_INFO joystickStruct
;
556 joystickInfo
.ToStruct(joystickStruct
);
558 char strControllerId
[1024]{};
560 LogError(retVal
= m_ifc
.peripheral
->toAddon
->get_appearance(
561 m_ifc
.peripheral
, &joystickStruct
, strControllerId
, sizeof(strControllerId
)),
564 kodi::addon::Joystick::FreeStruct(joystickStruct
);
566 if (retVal
== PERIPHERAL_NO_ERROR
)
568 controllerId
= strControllerId
;
575 bool CPeripheralAddon::SetAppearance(const CPeripheral
* device
, const std::string
& controllerId
)
577 if (!m_bProvidesButtonMaps
)
580 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
582 if (!m_ifc
.peripheral
->toAddon
->set_appearance
)
585 PERIPHERAL_ERROR retVal
;
587 kodi::addon::Joystick joystickInfo
;
588 GetJoystickInfo(device
, joystickInfo
);
590 JOYSTICK_INFO joystickStruct
;
591 joystickInfo
.ToStruct(joystickStruct
);
593 LogError(retVal
= m_ifc
.peripheral
->toAddon
->set_appearance(m_ifc
.peripheral
, &joystickStruct
,
594 controllerId
.c_str()),
597 kodi::addon::Joystick::FreeStruct(joystickStruct
);
599 return retVal
== PERIPHERAL_NO_ERROR
;
602 bool CPeripheralAddon::GetFeatures(const CPeripheral
* device
,
603 const std::string
& strControllerId
,
604 FeatureMap
& features
)
606 if (!m_bProvidesButtonMaps
)
609 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
611 if (!m_ifc
.peripheral
->toAddon
->get_features
)
614 PERIPHERAL_ERROR retVal
;
616 kodi::addon::Joystick joystickInfo
;
617 GetJoystickInfo(device
, joystickInfo
);
619 JOYSTICK_INFO joystickStruct
;
620 joystickInfo
.ToStruct(joystickStruct
);
622 unsigned int featureCount
= 0;
623 JOYSTICK_FEATURE
* pFeatures
= nullptr;
625 LogError(retVal
= m_ifc
.peripheral
->toAddon
->get_features(m_ifc
.peripheral
, &joystickStruct
,
626 strControllerId
.c_str(), &featureCount
,
630 kodi::addon::Joystick::FreeStruct(joystickStruct
);
632 if (retVal
== PERIPHERAL_NO_ERROR
)
634 for (unsigned int i
= 0; i
< featureCount
; i
++)
636 kodi::addon::JoystickFeature
feature(pFeatures
[i
]);
637 if (feature
.Type() != JOYSTICK_FEATURE_TYPE_UNKNOWN
)
638 features
[feature
.Name()] = feature
;
641 m_ifc
.peripheral
->toAddon
->free_features(m_ifc
.peripheral
, featureCount
, pFeatures
);
649 bool CPeripheralAddon::MapFeature(const CPeripheral
* device
,
650 const std::string
& strControllerId
,
651 const kodi::addon::JoystickFeature
& feature
)
653 if (!m_bProvidesButtonMaps
)
656 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
658 if (!m_ifc
.peripheral
->toAddon
->map_features
)
661 PERIPHERAL_ERROR retVal
;
663 kodi::addon::Joystick joystickInfo
;
664 GetJoystickInfo(device
, joystickInfo
);
666 JOYSTICK_INFO joystickStruct
;
667 joystickInfo
.ToStruct(joystickStruct
);
669 JOYSTICK_FEATURE addonFeature
;
670 feature
.ToStruct(addonFeature
);
672 LogError(retVal
= m_ifc
.peripheral
->toAddon
->map_features(
673 m_ifc
.peripheral
, &joystickStruct
, strControllerId
.c_str(), 1, &addonFeature
),
676 kodi::addon::Joystick::FreeStruct(joystickStruct
);
677 kodi::addon::JoystickFeature::FreeStruct(addonFeature
);
679 return retVal
== PERIPHERAL_NO_ERROR
;
682 bool CPeripheralAddon::GetIgnoredPrimitives(const CPeripheral
* device
, PrimitiveVector
& primitives
)
684 if (!m_bProvidesButtonMaps
)
687 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
689 if (!m_ifc
.peripheral
->toAddon
->get_ignored_primitives
)
692 PERIPHERAL_ERROR retVal
;
694 kodi::addon::Joystick joystickInfo
;
695 GetJoystickInfo(device
, joystickInfo
);
697 JOYSTICK_INFO joystickStruct
;
698 joystickInfo
.ToStruct(joystickStruct
);
700 unsigned int primitiveCount
= 0;
701 JOYSTICK_DRIVER_PRIMITIVE
* pPrimitives
= nullptr;
703 LogError(retVal
= m_ifc
.peripheral
->toAddon
->get_ignored_primitives(
704 m_ifc
.peripheral
, &joystickStruct
, &primitiveCount
, &pPrimitives
),
705 "GetIgnoredPrimitives()");
707 kodi::addon::Joystick::FreeStruct(joystickStruct
);
709 if (retVal
== PERIPHERAL_NO_ERROR
)
711 for (unsigned int i
= 0; i
< primitiveCount
; i
++)
712 primitives
.emplace_back(pPrimitives
[i
]);
714 m_ifc
.peripheral
->toAddon
->free_primitives(m_ifc
.peripheral
, primitiveCount
, pPrimitives
);
722 bool CPeripheralAddon::SetIgnoredPrimitives(const CPeripheral
* device
,
723 const PrimitiveVector
& primitives
)
725 if (!m_bProvidesButtonMaps
)
728 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
730 if (!m_ifc
.peripheral
->toAddon
->set_ignored_primitives
)
733 PERIPHERAL_ERROR retVal
;
735 kodi::addon::Joystick joystickInfo
;
736 GetJoystickInfo(device
, joystickInfo
);
738 JOYSTICK_INFO joystickStruct
;
739 joystickInfo
.ToStruct(joystickStruct
);
741 JOYSTICK_DRIVER_PRIMITIVE
* addonPrimitives
= nullptr;
742 kodi::addon::DriverPrimitives::ToStructs(primitives
, &addonPrimitives
);
743 const unsigned int primitiveCount
= static_cast<unsigned int>(primitives
.size());
745 LogError(retVal
= m_ifc
.peripheral
->toAddon
->set_ignored_primitives(
746 m_ifc
.peripheral
, &joystickStruct
, primitiveCount
, addonPrimitives
),
747 "SetIgnoredPrimitives()");
749 kodi::addon::Joystick::FreeStruct(joystickStruct
);
750 kodi::addon::DriverPrimitives::FreeStructs(primitiveCount
, addonPrimitives
);
752 return retVal
== PERIPHERAL_NO_ERROR
;
755 void CPeripheralAddon::SaveButtonMap(const CPeripheral
* device
)
757 if (!m_bProvidesButtonMaps
)
760 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
762 if (!m_ifc
.peripheral
->toAddon
->save_button_map
)
765 kodi::addon::Joystick joystickInfo
;
766 GetJoystickInfo(device
, joystickInfo
);
768 JOYSTICK_INFO joystickStruct
;
769 joystickInfo
.ToStruct(joystickStruct
);
771 m_ifc
.peripheral
->toAddon
->save_button_map(m_ifc
.peripheral
, &joystickStruct
);
773 kodi::addon::Joystick::FreeStruct(joystickStruct
);
775 // Notify observing button maps
776 RefreshButtonMaps(device
->DeviceName());
779 void CPeripheralAddon::RevertButtonMap(const CPeripheral
* device
)
781 if (!m_bProvidesButtonMaps
)
784 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
786 if (!m_ifc
.peripheral
->toAddon
->revert_button_map
)
789 kodi::addon::Joystick joystickInfo
;
790 GetJoystickInfo(device
, joystickInfo
);
792 JOYSTICK_INFO joystickStruct
;
793 joystickInfo
.ToStruct(joystickStruct
);
795 m_ifc
.peripheral
->toAddon
->revert_button_map(m_ifc
.peripheral
, &joystickStruct
);
797 kodi::addon::Joystick::FreeStruct(joystickStruct
);
800 void CPeripheralAddon::ResetButtonMap(const CPeripheral
* device
, const std::string
& strControllerId
)
802 if (!m_bProvidesButtonMaps
)
805 kodi::addon::Joystick joystickInfo
;
806 GetJoystickInfo(device
, joystickInfo
);
808 JOYSTICK_INFO joystickStruct
;
809 joystickInfo
.ToStruct(joystickStruct
);
811 m_ifc
.peripheral
->toAddon
->reset_button_map(m_ifc
.peripheral
, &joystickStruct
,
812 strControllerId
.c_str());
814 kodi::addon::Joystick::FreeStruct(joystickStruct
);
816 // Notify observing button maps
817 RefreshButtonMaps(device
->DeviceName());
820 void CPeripheralAddon::PowerOffJoystick(unsigned int index
)
822 if (!HasFeature(FEATURE_JOYSTICK
))
825 if (!SupportsFeature(FEATURE_POWER_OFF
))
828 std::shared_lock
<CSharedSection
> lock(m_dllSection
);
830 if (!m_ifc
.peripheral
->toAddon
->power_off_joystick
)
833 m_ifc
.peripheral
->toAddon
->power_off_joystick(m_ifc
.peripheral
, index
);
836 void CPeripheralAddon::RegisterButtonMap(CPeripheral
* device
, IButtonMap
* buttonMap
)
838 std::unique_lock
<CCriticalSection
> lock(m_buttonMapMutex
);
840 UnregisterButtonMap(buttonMap
);
841 m_buttonMaps
.emplace_back(device
, buttonMap
);
844 void CPeripheralAddon::UnregisterButtonMap(IButtonMap
* buttonMap
)
846 std::unique_lock
<CCriticalSection
> lock(m_buttonMapMutex
);
848 for (auto it
= m_buttonMaps
.begin(); it
!= m_buttonMaps
.end(); ++it
)
850 if (it
->second
== buttonMap
)
852 m_buttonMaps
.erase(it
);
858 void CPeripheralAddon::UnregisterButtonMap(CPeripheral
* device
)
860 std::unique_lock
<CCriticalSection
> lock(m_buttonMapMutex
);
863 std::remove_if(m_buttonMaps
.begin(), m_buttonMaps
.end(),
864 [device
](const std::pair
<CPeripheral
*, JOYSTICK::IButtonMap
*>& buttonMap
)
865 { return buttonMap
.first
== device
; }),
869 void CPeripheralAddon::RefreshButtonMaps(const std::string
& strDeviceName
/* = "" */)
871 std::unique_lock
<CCriticalSection
> lock(m_buttonMapMutex
);
873 for (auto it
= m_buttonMaps
.begin(); it
!= m_buttonMaps
.end(); ++it
)
875 if (strDeviceName
.empty() || strDeviceName
== it
->first
->DeviceName())
880 bool CPeripheralAddon::ProvidesJoysticks(const ADDON::AddonInfoPtr
& addonInfo
)
882 return addonInfo
->Type(ADDON::AddonType::PERIPHERALDLL
)
883 ->GetValue("@provides_joysticks")
887 bool CPeripheralAddon::ProvidesButtonMaps(const ADDON::AddonInfoPtr
& addonInfo
)
889 return addonInfo
->Type(ADDON::AddonType::PERIPHERALDLL
)
890 ->GetValue("@provides_buttonmaps")
894 void CPeripheralAddon::TriggerDeviceScan()
896 m_manager
.TriggerDeviceScan(PERIPHERAL_BUS_ADDON
);
899 unsigned int CPeripheralAddon::FeatureCount(const std::string
& controllerId
,
900 JOYSTICK_FEATURE_TYPE type
) const
902 using namespace GAME
;
904 unsigned int count
= 0;
906 CControllerManager
& controllerProfiles
= m_manager
.GetControllerProfiles();
907 ControllerPtr controller
= controllerProfiles
.GetController(controllerId
);
909 count
= controller
->FeatureCount(CPeripheralAddonTranslator::TranslateFeatureType(type
));
914 JOYSTICK_FEATURE_TYPE
CPeripheralAddon::FeatureType(const std::string
& controllerId
,
915 const std::string
& featureName
) const
917 using namespace GAME
;
919 JOYSTICK_FEATURE_TYPE type
= JOYSTICK_FEATURE_TYPE_UNKNOWN
;
921 CControllerManager
& controllerProfiles
= m_manager
.GetControllerProfiles();
922 ControllerPtr controller
= controllerProfiles
.GetController(controllerId
);
924 type
= CPeripheralAddonTranslator::TranslateFeatureType(controller
->FeatureType(featureName
));
929 void CPeripheralAddon::GetPeripheralInfo(const CPeripheral
* device
,
930 kodi::addon::Peripheral
& peripheralInfo
)
932 peripheralInfo
.SetType(CPeripheralAddonTranslator::TranslateType(device
->Type()));
933 peripheralInfo
.SetName(device
->DeviceName());
934 peripheralInfo
.SetVendorID(device
->VendorId());
935 peripheralInfo
.SetProductID(device
->ProductId());
938 void CPeripheralAddon::GetJoystickInfo(const CPeripheral
* device
,
939 kodi::addon::Joystick
& joystickInfo
)
941 GetPeripheralInfo(device
, joystickInfo
);
943 if (device
->Type() == PERIPHERAL_JOYSTICK
)
945 const CPeripheralJoystick
* joystick
= static_cast<const CPeripheralJoystick
*>(device
);
946 joystickInfo
.SetProvider(joystick
->Provider());
947 joystickInfo
.SetButtonCount(joystick
->ButtonCount());
948 joystickInfo
.SetHatCount(joystick
->HatCount());
949 joystickInfo
.SetAxisCount(joystick
->AxisCount());
950 joystickInfo
.SetMotorCount(joystick
->MotorCount());
951 joystickInfo
.SetSupportsPowerOff(joystick
->SupportsPowerOff());
953 else if (device
->Type() == PERIPHERAL_KEYBOARD
|| device
->Type() == PERIPHERAL_MOUSE
)
955 joystickInfo
.SetName(GetDeviceName(device
->Type())); // Override name with non-localized version
956 joystickInfo
.SetProvider(GetProvider(device
->Type()));
960 void CPeripheralAddon::SetJoystickInfo(CPeripheralJoystick
& joystick
,
961 const kodi::addon::Joystick
& joystickInfo
)
963 joystick
.SetProvider(joystickInfo
.Provider());
964 joystick
.SetRequestedPort(joystickInfo
.RequestedPort());
965 joystick
.SetButtonCount(joystickInfo
.ButtonCount());
966 joystick
.SetHatCount(joystickInfo
.HatCount());
967 joystick
.SetAxisCount(joystickInfo
.AxisCount());
968 joystick
.SetMotorCount(joystickInfo
.MotorCount());
969 joystick
.SetSupportsPowerOff(joystickInfo
.SupportsPowerOff());
972 bool CPeripheralAddon::LogError(const PERIPHERAL_ERROR error
, const char* strMethod
) const
974 if (error
!= PERIPHERAL_NO_ERROR
)
976 CLog::Log(LOGERROR
, "PERIPHERAL - {} - addon '{}' returned an error: {}", strMethod
, Name(),
977 CPeripheralAddonTranslator::TranslateError(error
));
983 std::string
CPeripheralAddon::GetDeviceName(PeripheralType type
)
987 case PERIPHERAL_KEYBOARD
:
988 return KEYBOARD_BUTTON_MAP_NAME
;
989 case PERIPHERAL_MOUSE
:
990 return MOUSE_BUTTON_MAP_NAME
;
998 std::string
CPeripheralAddon::GetProvider(PeripheralType type
)
1002 case PERIPHERAL_KEYBOARD
:
1003 return KEYBOARD_PROVIDER
;
1004 case PERIPHERAL_MOUSE
:
1005 return MOUSE_PROVIDER
;
1013 void CPeripheralAddon::cb_trigger_scan(void* kodiInstance
)
1015 if (kodiInstance
== nullptr)
1018 static_cast<CPeripheralAddon
*>(kodiInstance
)->TriggerDeviceScan();
1021 void CPeripheralAddon::cb_refresh_button_maps(void* kodiInstance
,
1022 const char* deviceName
,
1023 const char* controllerId
)
1028 static_cast<CPeripheralAddon
*>(kodiInstance
)->RefreshButtonMaps(deviceName
? deviceName
: "");
1031 unsigned int CPeripheralAddon::cb_feature_count(void* kodiInstance
,
1032 const char* controllerId
,
1033 JOYSTICK_FEATURE_TYPE type
)
1035 if (kodiInstance
== nullptr || controllerId
== nullptr)
1038 return static_cast<CPeripheralAddon
*>(kodiInstance
)->FeatureCount(controllerId
, type
);
1041 JOYSTICK_FEATURE_TYPE
CPeripheralAddon::cb_feature_type(void* kodiInstance
,
1042 const char* controllerId
,
1043 const char* featureName
)
1045 if (kodiInstance
== nullptr || controllerId
== nullptr || featureName
== nullptr)
1046 return JOYSTICK_FEATURE_TYPE_UNKNOWN
;
1048 return static_cast<CPeripheralAddon
*>(kodiInstance
)->FeatureType(controllerId
, featureName
);