1 /*
2  *  Copyright (C) 2014-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "GUIControllerWindow.h"
10 
11 #include "ControllerInstaller.h"
12 #include "GUIControllerDefines.h"
13 #include "GUIControllerList.h"
14 #include "GUIFeatureList.h"
15 #include "ServiceBroker.h"
16 #include "addons/AddonManager.h"
17 #include "addons/IAddon.h"
18 #include "addons/gui/GUIWindowAddonBrowser.h"
19 #include "cores/RetroPlayer/guibridge/GUIGameRenderManager.h"
20 #include "cores/RetroPlayer/guibridge/GUIGameSettingsHandle.h"
21 #include "games/addons/GameClient.h"
22 #include "games/controllers/dialogs/GUIDialogIgnoreInput.h"
23 #include "guilib/GUIButtonControl.h"
24 #include "guilib/GUIControl.h"
25 #include "guilib/GUIMessage.h"
26 #include "guilib/WindowIDs.h"
27 #include "messaging/helpers/DialogOKHelper.h"
28 
29 // To enable button mapping support
30 #include "peripherals/Peripherals.h"
31 
32 using namespace KODI;
33 using namespace GAME;
34 using namespace KODI::MESSAGING;
35 
CGUIControllerWindow(void)36 CGUIControllerWindow::CGUIControllerWindow(void)
37   : CGUIDialog(WINDOW_DIALOG_GAME_CONTROLLERS, "DialogGameControllers.xml"),
38     m_installer(new CControllerInstaller)
39 {
40   // initialize CGUIWindow
41   m_loadType = KEEP_IN_MEMORY;
42 }
43 
~CGUIControllerWindow(void)44 CGUIControllerWindow::~CGUIControllerWindow(void)
45 {
46   delete m_controllerList;
47   delete m_featureList;
48 }
49 
DoProcess(unsigned int currentTime,CDirtyRegionList & dirtyregions)50 void CGUIControllerWindow::DoProcess(unsigned int currentTime, CDirtyRegionList& dirtyregions)
51 {
52   /*
53    * Apply the faded focus texture to the current controller when unfocused
54    */
55 
56   CGUIControl* control = nullptr; // The controller button
57   bool bAlphaFaded = false; // True if the controller button has been focused and faded this frame
58 
59   if (m_controllerList && m_controllerList->GetFocusedController() >= 0)
60   {
61     control = GetFirstFocusableControl(CONTROL_CONTROLLER_BUTTONS_START +
62                                        m_controllerList->GetFocusedController());
63     if (control && !control->HasFocus())
64     {
65       if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
66       {
67         control->SetFocus(true);
68         static_cast<CGUIButtonControl*>(control)->SetAlpha(0x80);
69         bAlphaFaded = true;
70       }
71     }
72   }
73 
74   CGUIDialog::DoProcess(currentTime, dirtyregions);
75 
76   if (control && bAlphaFaded)
77   {
78     control->SetFocus(false);
79     if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
80       static_cast<CGUIButtonControl*>(control)->SetAlpha(0xFF);
81   }
82 }
83 
OnMessage(CGUIMessage & message)84 bool CGUIControllerWindow::OnMessage(CGUIMessage& message)
85 {
86   // Set to true to block the call to the super class
87   bool bHandled = false;
88 
89   switch (message.GetMessage())
90   {
91     case GUI_MSG_CLICKED:
92     {
93       int controlId = message.GetSenderId();
94 
95       if (controlId == CONTROL_CLOSE_BUTTON)
96       {
97         Close();
98         bHandled = true;
99       }
100       else if (controlId == CONTROL_GET_MORE)
101       {
102         GetMoreControllers();
103         bHandled = true;
104       }
105       else if (controlId == CONTROL_GET_ALL)
106       {
107         GetAllControllers();
108         bHandled = true;
109       }
110       else if (controlId == CONTROL_RESET_BUTTON)
111       {
112         ResetController();
113         bHandled = true;
114       }
115       else if (controlId == CONTROL_HELP_BUTTON)
116       {
117         ShowHelp();
118         bHandled = true;
119       }
120       else if (controlId == CONTROL_FIX_SKIPPING)
121       {
122         ShowButtonCaptureDialog();
123       }
124       else if (CONTROL_CONTROLLER_BUTTONS_START <= controlId &&
125                controlId < CONTROL_CONTROLLER_BUTTONS_END)
126       {
127         OnControllerSelected(controlId - CONTROL_CONTROLLER_BUTTONS_START);
128         bHandled = true;
129       }
130       else if (CONTROL_FEATURE_BUTTONS_START <= controlId &&
131                controlId < CONTROL_FEATURE_BUTTONS_END)
132       {
133         OnFeatureSelected(controlId - CONTROL_FEATURE_BUTTONS_START);
134         bHandled = true;
135       }
136       break;
137     }
138     case GUI_MSG_FOCUSED:
139     {
140       int controlId = message.GetControlId();
141 
142       if (CONTROL_CONTROLLER_BUTTONS_START <= controlId &&
143           controlId < CONTROL_CONTROLLER_BUTTONS_END)
144       {
145         OnControllerFocused(controlId - CONTROL_CONTROLLER_BUTTONS_START);
146       }
147       else if (CONTROL_FEATURE_BUTTONS_START <= controlId &&
148                controlId < CONTROL_FEATURE_BUTTONS_END)
149       {
150         OnFeatureFocused(controlId - CONTROL_FEATURE_BUTTONS_START);
151       }
152       break;
153     }
154     case GUI_MSG_SETFOCUS:
155     {
156       int controlId = message.GetControlId();
157 
158       if (CONTROL_CONTROLLER_BUTTONS_START <= controlId &&
159           controlId < CONTROL_CONTROLLER_BUTTONS_END)
160       {
161         OnControllerFocused(controlId - CONTROL_CONTROLLER_BUTTONS_START);
162       }
163       else if (CONTROL_FEATURE_BUTTONS_START <= controlId &&
164                controlId < CONTROL_FEATURE_BUTTONS_END)
165       {
166         OnFeatureFocused(controlId - CONTROL_FEATURE_BUTTONS_START);
167       }
168       break;
169     }
170     case GUI_MSG_REFRESH_LIST:
171     {
172       int controlId = message.GetControlId();
173 
174       if (controlId == CONTROL_CONTROLLER_LIST)
175       {
176         const std::string controllerId = message.GetStringParam();
177         if (m_controllerList && m_controllerList->Refresh(controllerId))
178         {
179           CGUIDialog::OnMessage(message);
180           bHandled = true;
181         }
182       }
183       break;
184     }
185     default:
186       break;
187   }
188 
189   if (!bHandled)
190     bHandled = CGUIDialog::OnMessage(message);
191 
192   return bHandled;
193 }
194 
OnEvent(const ADDON::CRepositoryUpdater::RepositoryUpdated & event)195 void CGUIControllerWindow::OnEvent(const ADDON::CRepositoryUpdater::RepositoryUpdated& event)
196 {
197   UpdateButtons();
198 }
199 
OnEvent(const ADDON::AddonEvent & event)200 void CGUIControllerWindow::OnEvent(const ADDON::AddonEvent& event)
201 {
202   using namespace ADDON;
203 
204   if (typeid(event) == typeid(AddonEvents::Enabled) || // also called on install,
205       typeid(event) == typeid(AddonEvents::Disabled) || // not called on uninstall
206       typeid(event) == typeid(AddonEvents::UnInstalled) ||
207       typeid(event) == typeid(AddonEvents::ReInstalled))
208   {
209     if (CServiceBroker::GetAddonMgr().HasType(event.id, ADDON_GAME_CONTROLLER))
210     {
211       UpdateButtons();
212     }
213   }
214 }
215 
OnInitWindow(void)216 void CGUIControllerWindow::OnInitWindow(void)
217 {
218   // Get active game add-on
219   GameClientPtr gameClient;
220   {
221     auto gameSettingsHandle = CServiceBroker::GetGameRenderManager().RegisterGameSettingsDialog();
222     if (gameSettingsHandle)
223     {
224       ADDON::AddonPtr addon;
225       if (CServiceBroker::GetAddonMgr().GetAddon(gameSettingsHandle->GameClientID(), addon,
226                                                  ADDON::ADDON_GAMEDLL, ADDON::OnlyEnabled::YES))
227         gameClient = std::static_pointer_cast<CGameClient>(addon);
228     }
229   }
230   m_gameClient = std::move(gameClient);
231 
232   CGUIDialog::OnInitWindow();
233 
234   if (!m_featureList)
235   {
236     m_featureList = new CGUIFeatureList(this, m_gameClient);
237     if (!m_featureList->Initialize())
238     {
239       delete m_featureList;
240       m_featureList = nullptr;
241     }
242   }
243 
244   if (!m_controllerList && m_featureList)
245   {
246     m_controllerList = new CGUIControllerList(this, m_featureList, m_gameClient);
247     if (!m_controllerList->Initialize())
248     {
249       delete m_controllerList;
250       m_controllerList = nullptr;
251     }
252   }
253 
254   // Focus the first controller so that the feature list is loaded properly
255   CGUIMessage msgFocus(GUI_MSG_SETFOCUS, GetID(), CONTROL_CONTROLLER_BUTTONS_START);
256   OnMessage(msgFocus);
257 
258   // Enable button mapping support
259   CServiceBroker::GetPeripherals().EnableButtonMapping();
260 
261   UpdateButtons();
262 
263   // subscribe to events
264   CServiceBroker::GetRepositoryUpdater().Events().Subscribe(this, &CGUIControllerWindow::OnEvent);
265   CServiceBroker::GetAddonMgr().Events().Subscribe(this, &CGUIControllerWindow::OnEvent);
266 }
267 
OnDeinitWindow(int nextWindowID)268 void CGUIControllerWindow::OnDeinitWindow(int nextWindowID)
269 {
270   CServiceBroker::GetRepositoryUpdater().Events().Unsubscribe(this);
271   CServiceBroker::GetAddonMgr().Events().Unsubscribe(this);
272 
273   if (m_controllerList)
274   {
275     m_controllerList->Deinitialize();
276     delete m_controllerList;
277     m_controllerList = nullptr;
278   }
279 
280   if (m_featureList)
281   {
282     m_featureList->Deinitialize();
283     delete m_featureList;
284     m_featureList = nullptr;
285   }
286 
287   CGUIDialog::OnDeinitWindow(nextWindowID);
288 
289   m_gameClient.reset();
290 }
291 
OnControllerFocused(unsigned int controllerIndex)292 void CGUIControllerWindow::OnControllerFocused(unsigned int controllerIndex)
293 {
294   if (m_controllerList)
295     m_controllerList->OnFocus(controllerIndex);
296 }
297 
OnControllerSelected(unsigned int controllerIndex)298 void CGUIControllerWindow::OnControllerSelected(unsigned int controllerIndex)
299 {
300   if (m_controllerList)
301     m_controllerList->OnSelect(controllerIndex);
302 }
303 
OnFeatureFocused(unsigned int buttonIndex)304 void CGUIControllerWindow::OnFeatureFocused(unsigned int buttonIndex)
305 {
306   if (m_featureList)
307     m_featureList->OnFocus(buttonIndex);
308 }
309 
OnFeatureSelected(unsigned int buttonIndex)310 void CGUIControllerWindow::OnFeatureSelected(unsigned int buttonIndex)
311 {
312   if (m_featureList)
313     m_featureList->OnSelect(buttonIndex);
314 }
315 
UpdateButtons(void)316 void CGUIControllerWindow::UpdateButtons(void)
317 {
318   using namespace ADDON;
319 
320   VECADDONS addons;
321   if (m_gameClient)
322   {
323     SET_CONTROL_HIDDEN(CONTROL_GET_MORE);
324     SET_CONTROL_HIDDEN(CONTROL_GET_ALL);
325   }
326   else
327   {
328     const bool bEnable =
329         CServiceBroker::GetAddonMgr().GetInstallableAddons(addons, ADDON::ADDON_GAME_CONTROLLER) &&
330         !addons.empty();
331     CONTROL_ENABLE_ON_CONDITION(CONTROL_GET_MORE, bEnable);
332     CONTROL_ENABLE_ON_CONDITION(CONTROL_GET_ALL, bEnable);
333   }
334 }
335 
GetMoreControllers(void)336 void CGUIControllerWindow::GetMoreControllers(void)
337 {
338   std::string strAddonId;
339   if (CGUIWindowAddonBrowser::SelectAddonID(ADDON::ADDON_GAME_CONTROLLER, strAddonId, false, true,
340                                             false, true, false) < 0)
341   {
342     // "Controller profiles"
343     // "All available controller profiles are installed."
344     HELPERS::ShowOKDialogText(CVariant{35050}, CVariant{35062});
345     return;
346   }
347 }
348 
GetAllControllers()349 void CGUIControllerWindow::GetAllControllers()
350 {
351   if (m_installer->IsRunning())
352     return;
353 
354   m_installer->Create(false);
355 }
356 
ResetController(void)357 void CGUIControllerWindow::ResetController(void)
358 {
359   if (m_controllerList)
360     m_controllerList->ResetController();
361 }
362 
ShowHelp(void)363 void CGUIControllerWindow::ShowHelp(void)
364 {
365   // "Help"
366   // <help text>
367   HELPERS::ShowOKDialogText(CVariant{10043}, CVariant{35055});
368 }
369 
ShowButtonCaptureDialog(void)370 void CGUIControllerWindow::ShowButtonCaptureDialog(void)
371 {
372   CGUIDialogIgnoreInput dialog;
373   dialog.Show();
374 }
375