1 /*
2  *  Copyright (C) 2005-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 "WinEventsWin10.h"
10 
11 #include "AppInboundProtocol.h"
12 #include "Application.h"
13 #include "GUIUserMessages.h"
14 #include "ServiceBroker.h"
15 #include "guilib/GUIComponent.h"
16 #include "guilib/GUIWindowManager.h"
17 #include "input/actions/Action.h"
18 #include "input/actions/ActionIDs.h"
19 #include "input/mouse/MouseStat.h"
20 #include "input/touch/generic/GenericTouchInputHandler.h"
21 #include "interfaces/AnnouncementManager.h"
22 #include "messaging/ApplicationMessenger.h"
23 #include "rendering/dx/DeviceResources.h"
24 #include "rendering/dx/RenderContext.h"
25 #include "settings/AdvancedSettings.h"
26 #include "settings/SettingsComponent.h"
27 #include "utils/SystemInfo.h"
28 #include "utils/Variant.h"
29 #include "utils/log.h"
30 #include "windowing/windows/WinKeyMap.h"
31 
32 #include "platform/win10/input/RemoteControlXbox.h"
33 
34 #include <winrt/Windows.Devices.Input.h>
35 
36 namespace winrt
37 {
38   using namespace Windows::Foundation;
39 }
40 using namespace winrt::Windows::ApplicationModel::Core;
41 using namespace winrt::Windows::Devices::Input;
42 using namespace winrt::Windows::Graphics::Display;
43 using namespace winrt::Windows::Media;
44 using namespace winrt::Windows::System;
45 using namespace winrt::Windows::UI::Core;
46 using namespace winrt::Windows::UI::Input;
47 using namespace winrt::Windows::UI::ViewManagement;
48 
49 using namespace PERIPHERALS;
50 using namespace KODI::MESSAGING;
51 
GetScreenPoint(winrt::Point point)52 static winrt::Point GetScreenPoint(winrt::Point point)
53 {
54   auto dpi = DX::DeviceResources::Get()->GetDpi();
55   return winrt::Point(DX::ConvertDipsToPixels(point.X, dpi), DX::ConvertDipsToPixels(point.Y, dpi));
56 }
57 
58 CWinEventsWin10::CWinEventsWin10() = default;
59 CWinEventsWin10::~CWinEventsWin10() = default;
60 
InitOSKeymap(void)61 void CWinEventsWin10::InitOSKeymap(void)
62 {
63   KODI::WINDOWING::WINDOWS::DIB_InitOSKeymap();
64 }
65 
MessagePush(XBMC_Event * newEvent)66 void CWinEventsWin10::MessagePush(XBMC_Event *newEvent)
67 {
68   // push input events in the queue they may init modal dialog which init
69   // deeper message loop and call the deeper MessagePump from there.
70   if ( newEvent->type == XBMC_KEYDOWN
71     || newEvent->type == XBMC_KEYUP
72     || newEvent->type == XBMC_MOUSEMOTION
73     || newEvent->type == XBMC_MOUSEBUTTONDOWN
74     || newEvent->type == XBMC_MOUSEBUTTONUP
75     || newEvent->type == XBMC_TOUCH)
76   {
77     m_events.push(*newEvent);
78   }
79   else
80   {
81     std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
82     if (appPort)
83       appPort->OnEvent(*newEvent);
84   }
85 }
86 
MessagePump()87 bool CWinEventsWin10::MessagePump()
88 {
89   bool ret = false;
90   std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
91 
92   // processes all pending events and exits immediately
93   CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
94 
95   XBMC_Event pumpEvent;
96   while (m_events.try_pop(pumpEvent))
97   {
98     if (appPort)
99       ret |= appPort->OnEvent(pumpEvent);
100 
101     if (pumpEvent.type == XBMC_MOUSEBUTTONUP)
102       CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_UNFOCUS_ALL, 0, 0, 0, 0);
103   }
104   return ret;
105 }
106 
GetQueueSize()107 size_t CWinEventsWin10::GetQueueSize()
108 {
109   return m_events.unsafe_size();
110 }
111 
InitEventHandlers(const CoreWindow & window)112 void CWinEventsWin10::InitEventHandlers(const CoreWindow& window)
113 {
114   CWinEventsWin10::InitOSKeymap();
115 
116   //window->SetPointerCapture();
117 
118   // window
119   window.SizeChanged({ this, &CWinEventsWin10::OnWindowSizeChanged });
120   window.ResizeStarted({ this, &CWinEventsWin10::OnWindowResizeStarted });
121   window.ResizeCompleted({ this, &CWinEventsWin10::OnWindowResizeCompleted });
122   window.Closed({ this, &CWinEventsWin10::OnWindowClosed});
123   window.VisibilityChanged(CWinEventsWin10::OnVisibilityChanged);
124   window.Activated(CWinEventsWin10::OnWindowActivationChanged);
125   // mouse, touch and pen
126   window.PointerPressed({ this, &CWinEventsWin10::OnPointerPressed });
127   window.PointerMoved({ this, &CWinEventsWin10::OnPointerMoved });
128   window.PointerReleased({ this, &CWinEventsWin10::OnPointerReleased });
129   window.PointerExited({ this, &CWinEventsWin10::OnPointerExited });
130   window.PointerWheelChanged({ this, &CWinEventsWin10::OnPointerWheelChanged });
131   // keyboard
132   window.Dispatcher().AcceleratorKeyActivated({ this, &CWinEventsWin10::OnAcceleratorKeyActivated });
133   // display
134   DisplayInformation currentDisplayInformation = DisplayInformation::GetForCurrentView();
135   currentDisplayInformation.DpiChanged(CWinEventsWin10::OnDpiChanged);
136   currentDisplayInformation.OrientationChanged(CWinEventsWin10::OnOrientationChanged);
137   DisplayInformation::DisplayContentsInvalidated(CWinEventsWin10::OnDisplayContentsInvalidated);
138   // system
139   SystemNavigationManager sysNavManager = SystemNavigationManager::GetForCurrentView();
140   sysNavManager.BackRequested(CWinEventsWin10::OnBackRequested);
141 
142   // requirement for backgroup playback
143   m_smtc = SystemMediaTransportControls::GetForCurrentView();
144   if (m_smtc)
145   {
146     m_smtc.IsPlayEnabled(true);
147     m_smtc.IsPauseEnabled(true);
148     m_smtc.IsStopEnabled(true);
149     m_smtc.IsRecordEnabled(true);
150     m_smtc.IsNextEnabled(true);
151     m_smtc.IsPreviousEnabled(true);
152     m_smtc.IsFastForwardEnabled(true);
153     m_smtc.IsRewindEnabled(true);
154     m_smtc.IsChannelUpEnabled(true);
155     m_smtc.IsChannelDownEnabled(true);
156     if (CSysInfo::GetWindowsDeviceFamily() != CSysInfo::WindowsDeviceFamily::Xbox)
157     {
158       m_smtc.ButtonPressed(CWinEventsWin10::OnSystemMediaButtonPressed);
159     }
160     m_smtc.IsEnabled(true);;
161     CServiceBroker::GetAnnouncementManager()->AddAnnouncer(this);
162   }
163   if (CSysInfo::GetWindowsDeviceFamily() == CSysInfo::WindowsDeviceFamily::Xbox)
164   {
165     m_remote = std::make_unique<CRemoteControlXbox>();
166     m_remote->Initialize();
167   }
168 }
169 
UpdateWindowSize()170 void CWinEventsWin10::UpdateWindowSize()
171 {
172   auto size = DX::DeviceResources::Get()->GetOutputSize();
173 
174   CLog::Log(LOGDEBUG, __FUNCTION__": window resize event %f x %f (as:%s)", size.Width, size.Height, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen ? "true" : "false");
175 
176   auto appView = ApplicationView::GetForCurrentView();
177   appView.SetDesiredBoundsMode(ApplicationViewBoundsMode::UseCoreWindow);
178 
179   // seems app has lost FS mode it may occurs if an user use core window's button
180   if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen && !appView.IsFullScreenMode())
181     CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_fullScreen = false;
182 
183   XBMC_Event newEvent;
184   memset(&newEvent, 0, sizeof(newEvent));
185   newEvent.type = XBMC_VIDEORESIZE;
186   newEvent.resize.w = size.Width;
187   newEvent.resize.h = size.Height;
188   if (g_application.GetRenderGUI() && !DX::Windowing()->IsAlteringWindow() && newEvent.resize.w > 0 && newEvent.resize.h > 0)
189     MessagePush(&newEvent);
190 }
191 
OnResize(float width,float height)192 void CWinEventsWin10::OnResize(float width, float height)
193 {
194   CLog::Log(LOGDEBUG, __FUNCTION__": window size changed.");
195   m_logicalWidth = width;
196   m_logicalHeight = height;
197   m_bResized = true;
198 
199   if (m_sizeChanging)
200     return;
201 
202   HandleWindowSizeChanged();
203 }
204 
205 // Window event handlers.
OnWindowSizeChanged(const CoreWindow &,const WindowSizeChangedEventArgs & args)206 void CWinEventsWin10::OnWindowSizeChanged(const CoreWindow&, const WindowSizeChangedEventArgs& args)
207 {
208   OnResize(args.Size().Width, args.Size().Height);
209 }
210 
OnWindowResizeStarted(const CoreWindow & sender,const winrt::IInspectable &)211 void CWinEventsWin10::OnWindowResizeStarted(const CoreWindow& sender, const winrt::IInspectable&)
212 {
213   CLog::Log(LOGDEBUG, __FUNCTION__": window resize started.");
214   m_logicalPosX = sender.Bounds().X;
215   m_logicalPosY = sender.Bounds().Y;
216   m_sizeChanging = true;
217 }
218 
OnWindowResizeCompleted(const CoreWindow & sender,const winrt::IInspectable &)219 void CWinEventsWin10::OnWindowResizeCompleted(const CoreWindow& sender, const winrt::IInspectable&)
220 {
221   CLog::Log(LOGDEBUG, __FUNCTION__": window resize completed.");
222   m_sizeChanging = false;
223 
224   if (m_logicalPosX != sender.Bounds().X || m_logicalPosY != sender.Bounds().Y)
225     m_bMoved = true;
226 
227   HandleWindowSizeChanged();
228 }
229 
HandleWindowSizeChanged()230 void CWinEventsWin10::HandleWindowSizeChanged()
231 {
232   CLog::Log(LOGDEBUG, __FUNCTION__": window size/move handled.");
233   if (m_bMoved)
234   {
235     // it will get position from CoreWindow
236     DX::Windowing()->OnMove(0, 0);
237   }
238   if (m_bResized)
239   {
240     DX::Windowing()->OnResize(m_logicalWidth, m_logicalHeight);
241     UpdateWindowSize();
242   }
243   m_bResized = false;
244   m_bMoved = false;
245 }
246 
OnVisibilityChanged(const CoreWindow & sender,const VisibilityChangedEventArgs & args)247 void CWinEventsWin10::OnVisibilityChanged(const CoreWindow& sender, const VisibilityChangedEventArgs& args)
248 {
249   bool active = g_application.GetRenderGUI();
250   std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
251   if (appPort)
252     appPort->SetRenderGUI(args.Visible());
253 
254   if (g_application.GetRenderGUI() != active)
255     DX::Windowing()->NotifyAppActiveChange(g_application.GetRenderGUI());
256   CLog::Log(LOGDEBUG, __FUNCTION__": window is %s", g_application.GetRenderGUI() ? "shown" : "hidden");
257 }
258 
OnWindowActivationChanged(const CoreWindow & sender,const WindowActivatedEventArgs & args)259 void CWinEventsWin10::OnWindowActivationChanged(const CoreWindow& sender, const WindowActivatedEventArgs& args)
260 {
261   bool active = g_application.GetRenderGUI();
262   if (args.WindowActivationState() == CoreWindowActivationState::Deactivated)
263   {
264     std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
265     if (appPort)
266       appPort->SetRenderGUI(DX::Windowing()->WindowedMode());
267   }
268   else if (args.WindowActivationState() == CoreWindowActivationState::PointerActivated
269     || args.WindowActivationState() == CoreWindowActivationState::CodeActivated)
270   {
271     std::shared_ptr<CAppInboundProtocol> appPort = CServiceBroker::GetAppPort();
272     if (appPort)
273       appPort->SetRenderGUI(true);
274   }
275   if (g_application.GetRenderGUI() != active)
276     DX::Windowing()->NotifyAppActiveChange(g_application.GetRenderGUI());
277   CLog::Log(LOGDEBUG, __FUNCTION__": window is %s", g_application.GetRenderGUI() ? "active" : "inactive");
278 }
279 
OnWindowClosed(const CoreWindow & sender,const CoreWindowEventArgs & args)280 void CWinEventsWin10::OnWindowClosed(const CoreWindow& sender, const CoreWindowEventArgs& args)
281 {
282   // send quit command to the application if it's still running
283   if (!g_application.m_bStop)
284   {
285     XBMC_Event newEvent;
286     memset(&newEvent, 0, sizeof(newEvent));
287     newEvent.type = XBMC_QUIT;
288     MessagePush(&newEvent);
289   }
290 }
291 
OnPointerPressed(const CoreWindow &,const PointerEventArgs & args)292 void CWinEventsWin10::OnPointerPressed(const CoreWindow&, const PointerEventArgs& args)
293 {
294   XBMC_Event newEvent;
295   memset(&newEvent, 0, sizeof(newEvent));
296 
297   PointerPoint point = args.CurrentPoint();
298   auto position = GetScreenPoint(point.Position());
299 
300   if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Touch)
301   {
302     CGenericTouchInputHandler::GetInstance().HandleTouchInput(TouchInputDown, position.X, position.Y, point.Timestamp(), 0, 10);
303     return;
304   }
305   else
306   {
307     newEvent.type = XBMC_MOUSEBUTTONDOWN;
308     newEvent.button.x = position.X;
309     newEvent.button.y = position.Y;
310     if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Mouse)
311     {
312       if (point.Properties().IsLeftButtonPressed())
313         newEvent.button.button = XBMC_BUTTON_LEFT;
314       else if (point.Properties().IsMiddleButtonPressed())
315         newEvent.button.button = XBMC_BUTTON_MIDDLE;
316       else if (point.Properties().IsRightButtonPressed())
317         newEvent.button.button = XBMC_BUTTON_RIGHT;
318     }
319     else if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Pen)
320     {
321       // pen
322       // TODO
323     }
324   }
325   MessagePush(&newEvent);
326 }
327 
OnPointerMoved(const CoreWindow &,const PointerEventArgs & args)328 void CWinEventsWin10::OnPointerMoved(const CoreWindow&, const PointerEventArgs& args)
329 {
330   PointerPoint point = args.CurrentPoint();
331   auto position = GetScreenPoint(point.Position());
332 
333   if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Touch)
334   {
335     if (point.IsInContact())
336     {
337       CGenericTouchInputHandler::GetInstance().UpdateTouchPointer(0, position.X, position.Y, point.Timestamp(), 10.f);
338       CGenericTouchInputHandler::GetInstance().HandleTouchInput(TouchInputMove, position.X, position.Y, point.Timestamp(), 0, 10.f);
339     }
340     return;
341   }
342 
343   XBMC_Event newEvent;
344   memset(&newEvent, 0, sizeof(newEvent));
345   newEvent.type = XBMC_MOUSEMOTION;
346   newEvent.motion.x = position.X;
347   newEvent.motion.y = position.Y;
348   MessagePush(&newEvent);
349 }
350 
OnPointerReleased(const CoreWindow &,const PointerEventArgs & args)351 void CWinEventsWin10::OnPointerReleased(const CoreWindow&, const PointerEventArgs& args)
352 {
353   PointerPoint point = args.CurrentPoint();
354   auto position = GetScreenPoint(point.Position());
355 
356   if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Touch)
357   {
358     CGenericTouchInputHandler::GetInstance().HandleTouchInput(TouchInputUp, position.X, position.Y, point.Timestamp(), 0, 10);
359     return;
360   }
361 
362   XBMC_Event newEvent;
363   memset(&newEvent, 0, sizeof(newEvent));
364   newEvent.type = XBMC_MOUSEBUTTONUP;
365   newEvent.button.x = position.X;
366   newEvent.button.y = position.Y;
367 
368   if (point.Properties().PointerUpdateKind() == PointerUpdateKind::LeftButtonReleased)
369     newEvent.button.button = XBMC_BUTTON_LEFT;
370   else if (point.Properties().PointerUpdateKind() == PointerUpdateKind::MiddleButtonReleased)
371     newEvent.button.button = XBMC_BUTTON_MIDDLE;
372   else if (point.Properties().PointerUpdateKind() == PointerUpdateKind::RightButtonReleased)
373     newEvent.button.button = XBMC_BUTTON_RIGHT;
374 
375   MessagePush(&newEvent);
376 }
377 
OnPointerExited(const CoreWindow &,const PointerEventArgs & args)378 void CWinEventsWin10::OnPointerExited(const CoreWindow&, const PointerEventArgs& args)
379 {
380   const PointerPoint& point = args.CurrentPoint();
381   auto position = GetScreenPoint(point.Position());
382 
383   if (point.PointerDevice().PointerDeviceType() == PointerDeviceType::Touch)
384   {
385     CGenericTouchInputHandler::GetInstance().HandleTouchInput(TouchInputAbort, position.X, position.Y, point.Timestamp(), 0, 10);
386   }
387 }
388 
OnPointerWheelChanged(const CoreWindow &,const PointerEventArgs & args)389 void CWinEventsWin10::OnPointerWheelChanged(const CoreWindow&, const PointerEventArgs& args)
390 {
391   XBMC_Event newEvent;
392   memset(&newEvent, 0, sizeof(newEvent));
393   newEvent.type = XBMC_MOUSEBUTTONDOWN;
394   newEvent.button.x = args.CurrentPoint().Position().X;
395   newEvent.button.y = args.CurrentPoint().Position().Y;
396   newEvent.button.button = args.CurrentPoint().Properties().MouseWheelDelta() > 0 ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN;
397   MessagePush(&newEvent);
398   newEvent.type = XBMC_MOUSEBUTTONUP;
399   MessagePush(&newEvent);
400 }
401 
Kodi_KeyEvent(unsigned int vkey,unsigned scancode,unsigned keycode,bool isDown)402 void CWinEventsWin10::Kodi_KeyEvent(unsigned int vkey, unsigned scancode, unsigned keycode, bool isDown)
403 {
404   using State = CoreVirtualKeyStates;
405 
406   XBMC_keysym keysym;
407   memset(&keysym, 0, sizeof(keysym));
408   keysym.scancode = scancode;
409   keysym.sym = KODI::WINDOWING::WINDOWS::VK_keymap[vkey];
410   keysym.unicode = keycode;
411 
412   auto window = CoreWindow::GetForCurrentThread();
413 
414   uint16_t mod = (uint16_t)XBMCKMOD_NONE;
415   // If left control and right alt are down this usually means that AltGr is down
416   if ((window.GetKeyState(VirtualKey::LeftControl) & State::Down) == State::Down
417     && (window.GetKeyState(VirtualKey::RightMenu) & State::Down) == State::Down)
418   {
419     mod |= XBMCKMOD_MODE;
420     mod |= XBMCKMOD_MODE;
421   }
422   else
423   {
424     if ((window.GetKeyState(VirtualKey::LeftControl) & State::Down) == State::Down)
425       mod |= XBMCKMOD_LCTRL;
426     if ((window.GetKeyState(VirtualKey::RightMenu) & State::Down) == State::Down)
427       mod |= XBMCKMOD_RALT;
428   }
429 
430   // Check the remaining modifiers
431   if ((window.GetKeyState(VirtualKey::LeftShift) & State::Down) == State::Down)
432     mod |= XBMCKMOD_LSHIFT;
433   if ((window.GetKeyState(VirtualKey::RightShift) & State::Down) == State::Down)
434     mod |= XBMCKMOD_RSHIFT;
435   if ((window.GetKeyState(VirtualKey::RightControl) & State::Down) == State::Down)
436     mod |= XBMCKMOD_RCTRL;
437   if ((window.GetKeyState(VirtualKey::LeftMenu) & State::Down) == State::Down)
438     mod |= XBMCKMOD_LALT;
439   if ((window.GetKeyState(VirtualKey::LeftWindows) & State::Down) == State::Down)
440     mod |= XBMCKMOD_LSUPER;
441   if ((window.GetKeyState(VirtualKey::RightWindows) & State::Down) == State::Down)
442     mod |= XBMCKMOD_LSUPER;
443 
444   keysym.mod = static_cast<XBMCMod>(mod);
445 
446   XBMC_Event newEvent;
447   memset(&newEvent, 0, sizeof(newEvent));
448   newEvent.type = isDown ? XBMC_KEYDOWN : XBMC_KEYUP;
449   newEvent.key.keysym = keysym;
450   MessagePush(&newEvent);
451 }
452 
OnAcceleratorKeyActivated(const CoreDispatcher &,const AcceleratorKeyEventArgs & args)453 void CWinEventsWin10::OnAcceleratorKeyActivated(const CoreDispatcher&, const AcceleratorKeyEventArgs& args)
454 {
455   static auto lockedState = CoreVirtualKeyStates::Locked;
456   static VirtualKey keyStore = VirtualKey::None;
457 
458   // skip if device is remote control
459   if (m_remote && m_remote->IsRemoteDevice(args.DeviceId().c_str()))
460     return;
461 
462   bool isDown = false;
463   unsigned keyCode = 0;
464   unsigned vk = static_cast<unsigned>(args.VirtualKey());
465 
466   auto window = CoreWindow::GetForCurrentThread();
467   bool numLockLocked = ((window.GetKeyState(VirtualKey::NumberKeyLock) & lockedState) == lockedState);
468 
469   switch (args.EventType())
470   {
471   case CoreAcceleratorKeyEventType::KeyDown:
472   case CoreAcceleratorKeyEventType::SystemKeyDown:
473   {
474     if ( (vk == 0x08) // VK_BACK
475       || (vk == 0x09) // VK_TAB
476       || (vk == 0x0C) // VK_CLEAR
477       || (vk == 0x0D) // VK_RETURN
478       || (vk == 0x1B) // VK_ESCAPE
479       || (vk == 0x20) // VK_SPACE
480       || (vk >= 0x30 && vk <= 0x39) // numeric keys
481       || (vk >= 0x41 && vk <= 0x5A) // alphabetic keys
482       || (vk >= 0x60 && vk <= 0x69 && numLockLocked) // keypad numeric (if numlock is on)
483       || (vk >= 0x6A && vk <= 0x6F) // keypad keys except numeric
484       || (vk >= 0x92 && vk <= 0x96) // OEM specific
485       || (vk >= 0xBA && vk <= 0xC0) // OEM specific
486       || (vk >= 0xDB && vk <= 0xDF) // OEM specific
487       || (vk >= 0xE1 && vk <= 0xF5 && vk != 0xE5 && vk != 0xE7 && vk != 0xE8) // OEM specific
488       )
489     {
490       // store this for character events, because VirtualKey is key code on character event.
491       keyStore = args.VirtualKey();
492       return;
493     }
494     isDown = true;
495     break;
496   }
497   case CoreAcceleratorKeyEventType::KeyUp:
498   case CoreAcceleratorKeyEventType::SystemKeyUp:
499     break;
500   case CoreAcceleratorKeyEventType::Character:
501   case CoreAcceleratorKeyEventType::SystemCharacter:
502   case CoreAcceleratorKeyEventType::UnicodeCharacter:
503   case CoreAcceleratorKeyEventType::DeadCharacter:
504   case CoreAcceleratorKeyEventType::SystemDeadCharacter:
505   {
506     // VirtualKey is KeyCode
507     keyCode = static_cast<unsigned>(args.VirtualKey());
508     // rewrite vk with stored value
509     vk = static_cast<unsigned>(keyStore);
510     // reset stored value
511     keyStore = VirtualKey::None;
512     isDown = true;
513   }
514   default:
515     break;
516   }
517 
518   Kodi_KeyEvent(vk, args.KeyStatus().ScanCode, keyCode, isDown);
519   args.Handled(true);
520 }
521 
522 // DisplayInformation event handlers.
OnDpiChanged(const DisplayInformation & sender,const winrt::IInspectable &)523 void CWinEventsWin10::OnDpiChanged(const DisplayInformation& sender, const winrt::IInspectable&)
524 {
525   // Note: The value for LogicalDpi retrieved here may not match the effective DPI of the app
526   // if it is being scaled for high resolution devices. Once the DPI is set on DeviceResources,
527   // you should always retrieve it using the GetDpi method.
528   // See DeviceResources.cpp for more details.
529   //critical_section::scoped_lock lock(m_deviceResources->GetCriticalSection());
530   RECT resizeRect = { 0,0,0,0 };
531   DX::Windowing()->DPIChanged(sender.LogicalDpi(), resizeRect);
532   CGenericTouchInputHandler::GetInstance().SetScreenDPI(DX::DisplayMetrics::Dpi100);
533 }
534 
OnOrientationChanged(const DisplayInformation &,const winrt::IInspectable &)535 void CWinEventsWin10::OnOrientationChanged(const DisplayInformation&, const winrt::IInspectable&)
536 {
537   //critical_section::scoped_lock lock(m_deviceResources->GetCriticalSection());
538   //m_deviceResources->SetCurrentOrientation(sender->CurrentOrientation);
539 
540   //auto size = DX::DeviceResources::Get()->GetOutputSize();
541   //UpdateWindowSize(size.Width, size.Height);
542 }
543 
OnDisplayContentsInvalidated(const DisplayInformation &,const winrt::IInspectable &)544 void CWinEventsWin10::OnDisplayContentsInvalidated(const DisplayInformation&, const winrt::IInspectable&)
545 {
546   CLog::Log(LOGDEBUG, __FUNCTION__": onevent.");
547   DX::DeviceResources::Get()->ValidateDevice();
548 }
549 
OnBackRequested(const winrt::IInspectable &,const BackRequestedEventArgs & args)550 void CWinEventsWin10::OnBackRequested(const winrt::IInspectable&, const BackRequestedEventArgs& args)
551 {
552   // handle this only on windows mobile
553   if (CSysInfo::GetWindowsDeviceFamily() == CSysInfo::WindowsDeviceFamily::Mobile)
554   {
555     CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(ACTION_NAV_BACK)));
556   }
557   args.Handled(true);
558 }
559 
OnSystemMediaButtonPressed(const SystemMediaTransportControls &,const SystemMediaTransportControlsButtonPressedEventArgs & args)560 void CWinEventsWin10::OnSystemMediaButtonPressed(const SystemMediaTransportControls&, const SystemMediaTransportControlsButtonPressedEventArgs& args)
561 {
562   int action = ACTION_NONE;
563   switch (args.Button())
564   {
565   case SystemMediaTransportControlsButton::ChannelDown:
566     action = ACTION_CHANNEL_DOWN;
567     break;
568   case SystemMediaTransportControlsButton::ChannelUp:
569     action = ACTION_CHANNEL_UP;
570     break;
571   case SystemMediaTransportControlsButton::FastForward:
572     action = ACTION_PLAYER_FORWARD;
573     break;
574   case SystemMediaTransportControlsButton::Rewind:
575     action = ACTION_PLAYER_REWIND;
576     break;
577   case SystemMediaTransportControlsButton::Next:
578     action = ACTION_NEXT_ITEM;
579     break;
580   case SystemMediaTransportControlsButton::Previous:
581     action = ACTION_PREV_ITEM;
582     break;
583   case SystemMediaTransportControlsButton::Pause:
584   case SystemMediaTransportControlsButton::Play:
585     action = ACTION_PLAYER_PLAYPAUSE;
586     break;
587   case SystemMediaTransportControlsButton::Stop:
588     action = ACTION_STOP;
589     break;
590   case SystemMediaTransportControlsButton::Record:
591     action = ACTION_RECORD;
592     break;
593   default:
594     break;
595   }
596   if (action != ACTION_NONE)
597   {
598     CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(action)));
599   }
600 }
601 
Announce(ANNOUNCEMENT::AnnouncementFlag flag,const std::string & sender,const std::string & message,const CVariant & data)602 void CWinEventsWin10::Announce(ANNOUNCEMENT::AnnouncementFlag flag,
603                                const std::string& sender,
604                                const std::string& message,
605                                const CVariant& data)
606 {
607   if (flag & ANNOUNCEMENT::Player)
608   {
609     double speed = 1.0;
610     if (data.isMember("player") && data["player"].isMember("speed"))
611       speed = data["player"]["speed"].asDouble(1.0);
612 
613     bool changed = false;
614     MediaPlaybackStatus status = MediaPlaybackStatus::Changing;
615 
616     if (message == "OnPlay" || message == "OnResume")
617     {
618       changed = true;
619       status = MediaPlaybackStatus::Playing;
620     }
621     else if (message == "OnStop")
622     {
623       changed = true;
624       status = MediaPlaybackStatus::Stopped;
625     }
626     else if (message == "OnPause")
627     {
628       changed = true;
629       status = MediaPlaybackStatus::Paused;
630     }
631     else if (message == "OnSpeedChanged")
632     {
633       changed = true;
634       status = speed != 0.0 ? MediaPlaybackStatus::Playing : MediaPlaybackStatus::Paused;
635     }
636 
637     if (changed)
638     {
639       try
640       {
641         auto dispatcher = CoreApplication::MainView().Dispatcher();
642         if (dispatcher)
643         {
644           dispatcher.RunAsync(CoreDispatcherPriority::Normal, DispatchedHandler([status, speed]
645           {
646             auto smtc = SystemMediaTransportControls::GetForCurrentView();
647             if (!smtc)
648               return;
649 
650             smtc.PlaybackStatus(status);
651             smtc.PlaybackRate(speed);
652           }));
653         }
654       }
655       catch (const winrt::hresult_error&)
656       {
657       }
658     }
659   }
660 }
661