diff options
author | Anton Fedchin <afedchin@users.noreply.github.com> | 2018-04-18 10:00:01 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-18 10:00:01 +0300 |
commit | b3a4aed5d5fe8d2236a557a497bf0249f06405c3 (patch) | |
tree | 3e26ded58fafcbbd33a9c7d478d420af69c1888a | |
parent | e132890066c77d1de2f65e3ff03ac2cbc72a6abf (diff) | |
parent | 03891868531d1ff82a31420c84a820a7a4e8c871 (diff) |
Merge pull request #13778 from afedchin/win-remotes
[Windows] remote control re-design.
-rw-r--r-- | xbmc/Application.cpp | 3 | ||||
-rw-r--r-- | xbmc/cores/ExternalPlayer/ExternalPlayer.cpp | 7 | ||||
-rw-r--r-- | xbmc/input/CMakeLists.txt | 1 | ||||
-rw-r--r-- | xbmc/input/InputManager.cpp | 100 | ||||
-rw-r--r-- | xbmc/input/InputManager.h | 57 | ||||
-rw-r--r-- | xbmc/input/remote/IRemoteControl.h | 102 | ||||
-rw-r--r-- | xbmc/network/EventClient.cpp | 11 | ||||
-rw-r--r-- | xbmc/platform/win10/input/RemoteControlXbox.cpp | 78 | ||||
-rw-r--r-- | xbmc/platform/win10/input/RemoteControlXbox.h | 31 | ||||
-rw-r--r-- | xbmc/platform/win32/input/IRServerSuite.cpp | 225 | ||||
-rw-r--r-- | xbmc/platform/win32/input/IRServerSuite.h | 47 | ||||
-rw-r--r-- | xbmc/windowing/win10/WinEventsWin10.cpp | 16 | ||||
-rw-r--r-- | xbmc/windowing/win10/WinEventsWin10.h | 12 | ||||
-rw-r--r-- | xbmc/windowing/win10/WinSystemWin10.cpp | 5 | ||||
-rw-r--r-- | xbmc/windowing/windows/WinSystemWin32.cpp | 3 | ||||
-rw-r--r-- | xbmc/windowing/windows/WinSystemWin32.h | 3 |
16 files changed, 182 insertions, 519 deletions
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index fe3b7f0f1b..d71f6c28c2 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -2898,9 +2898,6 @@ void CApplication::Stop(int exitCode) m_pActiveAE->Shutdown(); m_pActiveAE.reset(); - CLog::Log(LOGNOTICE, "closing down remote control service"); - CServiceBroker::GetInputManager().DisableRemoteControl(); - // unregister ffmpeg lock manager call back av_lockmgr_register(NULL); diff --git a/xbmc/cores/ExternalPlayer/ExternalPlayer.cpp b/xbmc/cores/ExternalPlayer/ExternalPlayer.cpp index 584d6c2dad..96c9af5ad4 100644 --- a/xbmc/cores/ExternalPlayer/ExternalPlayer.cpp +++ b/xbmc/cores/ExternalPlayer/ExternalPlayer.cpp @@ -459,14 +459,7 @@ bool CExternalPlayer::ExecuteAppLinux(const char* strSwitches) { CLog::Log(LOGNOTICE, "%s: %s", __FUNCTION__, strSwitches); - bool remoteUsed = CServiceBroker::GetInputManager().IsRemoteControlEnabled(); - CServiceBroker::GetInputManager().DisableRemoteControl(); - int ret = system(strSwitches); - - if (remoteUsed) - CServiceBroker::GetInputManager().EnableRemoteControl(); - if (ret != 0) { CLog::Log(LOGNOTICE, "%s: Failure: %d", __FUNCTION__, ret); diff --git a/xbmc/input/CMakeLists.txt b/xbmc/input/CMakeLists.txt index a84e2f5ff0..54fa86cd0c 100644 --- a/xbmc/input/CMakeLists.txt +++ b/xbmc/input/CMakeLists.txt @@ -26,7 +26,6 @@ set(SOURCES Action.cpp XBMC_keytable.cpp) set(HEADERS hardware/IHardwareInput.h - remote/IRemoteControl.h remote/IRRemote.h Action.h ActionIDs.h diff --git a/xbmc/input/InputManager.cpp b/xbmc/input/InputManager.cpp index ec3dc8d897..bd9e613594 100644 --- a/xbmc/input/InputManager.cpp +++ b/xbmc/input/InputManager.cpp @@ -60,12 +60,9 @@ using EVENTSERVER::CEventServer; using namespace KODI; using namespace MESSAGING; -CreateRemoteControlFunc CInputManager::m_createRemoteControl = nullptr; - CInputManager::CInputManager(const CAppParamParser ¶ms) : m_keymapEnvironment(new CKeymapEnvironment), m_buttonTranslator(new CButtonTranslator), - m_irTranslator(new CIRTranslator()), m_customControllerTranslator(new CCustomControllerTranslator), m_touchTranslator(new CTouchTranslator), m_joystickTranslator(new CJoystickMapper), @@ -77,15 +74,6 @@ CInputManager::CInputManager(const CAppParamParser ¶ms) : RegisterKeyboardDriverHandler(m_keyboardEasterEgg.get()); - if (m_createRemoteControl) - m_RemoteControl.reset(m_createRemoteControl()); - - if (!params.RemoteControlName().empty()) - SetRemoteControlName(params.RemoteControlName()); - - if (!params.RemoteControlEnabled()) - DisableRemoteControl(); - // Register settings std::set<std::string> settingSet; settingSet.insert(CSettings::SETTING_INPUT_ENABLEMOUSE); @@ -96,8 +84,6 @@ CInputManager::~CInputManager() { Deinitialize(); - m_RemoteControl.reset(); - // Unregister settings CServiceBroker::GetSettings().UnregisterCallback(this); @@ -110,8 +96,6 @@ CInputManager::~CInputManager() void CInputManager::InitializeInputs() { - if (m_RemoteControl) - m_RemoteControl->Initialize(); m_Keyboard.Initialize(); m_Mouse.Initialize(); @@ -120,23 +104,6 @@ void CInputManager::InitializeInputs() void CInputManager::Deinitialize() { - if (m_RemoteControl) - m_RemoteControl->Disconnect(); -} - -bool CInputManager::ProcessRemote(int windowId) -{ - if (!m_RemoteControl) - return false; - - m_RemoteControl->Update(); - if (m_RemoteControl->GetButton()) - { - CKey key(m_RemoteControl->GetButton(), m_RemoteControl->GetHoldTimeMs()); - m_RemoteControl->Reset(); - return OnKey(key); - } - return false; } bool CInputManager::ProcessPeripherals(float frameTime) @@ -354,7 +321,6 @@ void CInputManager::QueueAction(const CAction& action) bool CInputManager::Process(int windowId, float frameTime) { // process input actions - ProcessRemote(windowId); ProcessEventServer(windowId, frameTime); ProcessPeripherals(frameTime); ProcessQueuedActions(); @@ -746,10 +712,6 @@ bool CInputManager::HasBuiltin(const std::string& command) int CInputManager::ExecuteBuiltin(const std::string& execute, const std::vector<std::string>& params) { - if (HasRemoteControl()) - { - return -1; - } return 0; } @@ -788,54 +750,6 @@ void CInputManager::SetMouseState(MOUSE_STATE mouseState) m_Mouse.SetState(mouseState); } -bool CInputManager::HasRemoteControl() -{ - return m_RemoteControl ? true : false; -} - -bool CInputManager::IsRemoteControlEnabled() -{ - return m_RemoteControl && m_RemoteControl->IsInUse(); -} - -bool CInputManager::IsRemoteControlInitialized() -{ - return m_RemoteControl && m_RemoteControl->IsInitialized(); -} - -void CInputManager::EnableRemoteControl() -{ - if (!m_RemoteControl) - return; - - m_RemoteControl->SetEnabled(true); - if (!m_RemoteControl->IsInitialized()) - { - m_RemoteControl->Initialize(); - } -} - -void CInputManager::DisableRemoteControl() -{ - if (m_RemoteControl) - { - m_RemoteControl->Disconnect(); - m_RemoteControl->SetEnabled(false); - } -} - -void CInputManager::InitializeRemoteControl() -{ - if (m_RemoteControl && !m_RemoteControl->IsInitialized()) - m_RemoteControl->Initialize(); -} - -void CInputManager::SetRemoteControlName(const std::string& name) -{ - if (m_RemoteControl) - m_RemoteControl->SetDeviceName(name); -} - void CInputManager::OnSettingChanged(std::shared_ptr<const CSetting> setting) { if (setting == nullptr) @@ -898,8 +812,6 @@ bool CInputManager::LoadKeymaps() if (m_buttonTranslator->Load()) { - if (m_RemoteControl) - m_irTranslator->Load(m_RemoteControl->GetMapFile()); bSuccess = true; } @@ -917,7 +829,6 @@ bool CInputManager::ReloadKeymaps() void CInputManager::ClearKeymaps() { m_buttonTranslator->Clear(); - m_irTranslator->Clear(); SetChanged(); NotifyObservers(ObservableMessageButtonMapsChanged); @@ -961,11 +872,6 @@ std::vector<std::shared_ptr<const IWindowKeymap>> CInputManager::GetJoystickKeym return m_joystickTranslator->GetJoystickKeymaps(); } -int CInputManager::TranslateLircRemoteString(const std::string &szDevice, const std::string &szButton) -{ - return m_irTranslator->TranslateButton(szDevice, szButton); -} - void CInputManager::RegisterKeyboardDriverHandler(KEYBOARD::IKeyboardDriverHandler* handler) { if (std::find(m_keyboardHandlers.begin(), m_keyboardHandlers.end(), handler) == m_keyboardHandlers.end()) @@ -987,9 +893,3 @@ void CInputManager::UnregisterMouseDriverHandler(MOUSE::IMouseDriverHandler* han { m_mouseHandlers.erase(std::remove(m_mouseHandlers.begin(), m_mouseHandlers.end(), handler), m_mouseHandlers.end()); } - -void CInputManager::RegisterRemoteControl(CreateRemoteControlFunc createFunc) -{ - m_createRemoteControl = createFunc; -} - diff --git a/xbmc/input/InputManager.h b/xbmc/input/InputManager.h index c62d875821..c6e628b739 100644 --- a/xbmc/input/InputManager.h +++ b/xbmc/input/InputManager.h @@ -29,7 +29,6 @@ #include "input/mouse/interfaces/IMouseInputProvider.h" #include "input/mouse/MouseStat.h" #include "input/KeyboardStat.h" -#include "input/remote/IRemoteControl.h" #include "interfaces/IActionListener.h" #include "settings/lib/ISettingCallback.h" #include "threads/CriticalSection.h" @@ -38,7 +37,6 @@ class CAppParamParser; class CButtonTranslator; class CCustomControllerTranslator; -class CIRTranslator; class CJoystickMapper; class CKey; class CProfilesManager; @@ -60,7 +58,6 @@ namespace MOUSE } } -using CreateRemoteControlFunc = KODI::REMOTE::IRemoteControl* (*)(); /// \addtogroup input /// \{ @@ -84,13 +81,6 @@ public: CInputManager const& operator=(CInputManager const&) = delete; ~CInputManager() override; - /*! \brief decode an input event from remote controls. - * - * \param windowId Currently active window - * \return true if event is handled, false otherwise - */ - bool ProcessRemote(int windowId); - /*! \brief decode a mouse event and reset idle timers. * * \param windowId Currently active window @@ -188,46 +178,6 @@ public: */ void SetMouseResolution(int maxX, int maxY, float speedX, float speedY); - /*! \brief Enable the remote control - * - */ - void EnableRemoteControl(); - - /*! \brief Disable the remote control - * - */ - void DisableRemoteControl(); - - /*! \brief Try to connect to a remote control to listen for commands - * - */ - void InitializeRemoteControl(); - - /*! \brief Check if the remote control exists - * - * \return true if remote control is exists, false otherwise - */ - bool HasRemoteControl(); - - /*! \brief Check if the remote control is enabled - * - * \return true if remote control is enabled, false otherwise - */ - bool IsRemoteControlEnabled(); - - /*! \brief Check if the remote control is initialized - * - * \return true if initialized, false otherwise - */ - bool IsRemoteControlInitialized(); - - /*! \brief Set the device name to use with LIRC, does nothing - * if IRServerSuite is used - * - * \param[in] name Name of the device to use with LIRC - */ - void SetRemoteControlName(const std::string& name); - /*! \brief Returns whether or not we can handle a given built-in command. * */ @@ -267,8 +217,6 @@ public: std::vector<std::shared_ptr<const IWindowKeymap>> GetJoystickKeymaps() const; - int TranslateLircRemoteString(const std::string &szDevice, const std::string &szButton); - /*! * \brief Queue an action to be processed on the next call to Process() */ @@ -286,8 +234,6 @@ public: virtual void RegisterMouseDriverHandler(KODI::MOUSE::IMouseDriverHandler* handler); virtual void UnregisterMouseDriverHandler(KODI::MOUSE::IMouseDriverHandler* handler); - static void RegisterRemoteControl(CreateRemoteControlFunc createFunc); - private: /*! \brief Process keyboard event and translate into an action @@ -346,17 +292,14 @@ private: // Button translation std::unique_ptr<IKeymapEnvironment> m_keymapEnvironment; std::unique_ptr<CButtonTranslator> m_buttonTranslator; - std::unique_ptr<CIRTranslator> m_irTranslator; std::unique_ptr<CCustomControllerTranslator> m_customControllerTranslator; std::unique_ptr<CTouchTranslator> m_touchTranslator; std::unique_ptr<CJoystickMapper> m_joystickTranslator; - std::unique_ptr<KODI::REMOTE::IRemoteControl> m_RemoteControl; std::vector<KODI::KEYBOARD::IKeyboardDriverHandler*> m_keyboardHandlers; std::vector<KODI::MOUSE::IMouseDriverHandler*> m_mouseHandlers; std::unique_ptr<KODI::KEYBOARD::IKeyboardDriverHandler> m_keyboardEasterEgg; - static CreateRemoteControlFunc m_createRemoteControl; }; /// \} diff --git a/xbmc/input/remote/IRemoteControl.h b/xbmc/input/remote/IRemoteControl.h deleted file mode 100644 index b3c9dde82f..0000000000 --- a/xbmc/input/remote/IRemoteControl.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2018 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 <stdint.h> - -namespace KODI -{ - namespace REMOTE - { -/*! - * \brief Interface for remote control - */ -class IRemoteControl -{ -public: - virtual ~IRemoteControl() = default; - - /*! - * \brief Get IR mappings file name - */ - virtual std::string GetMapFile() = 0; - - /*! - * \brief Call once during input manager initialization - */ - virtual void Initialize() = 0; - - /*! - * \brief Deinitialize remote control - */ - virtual void Disconnect() = 0; - - /*! - * \brief Get the button code read from IR - * All codes are defined into IRRemote.h - * - * \return A predefined button code from IRRemote.h - */ - virtual uint16_t GetButton() const = 0; - - /*! - * \brief Get the time in milliseconds while a button was hold - * - * \return A hold time in milliseconds - */ - virtual uint32_t GetHoldTimeMs() const = 0; - - /*! - * \brief Update button state - */ - virtual void Update() = 0; - - /*! - * \brief Reset button state - */ - virtual void Reset() = 0; - - /*! - * \brief Get the initialized status - */ - virtual bool IsInitialized() const = 0; - - /*! - * \brief Set enabled status - */ - virtual void SetEnabled(bool bEnabled) = 0; - - /*! - * \brief Set a name for a device - */ - virtual void SetDeviceName(const std::string& name) = 0; - - /*! - * \brief Add a command to send to a bus - */ - virtual void AddSendCommand(const std::string& command) = 0; - - /*! - * \brief Get the in-use status - */ - virtual bool IsInUse() const = 0; -}; - } -} diff --git a/xbmc/network/EventClient.cpp b/xbmc/network/EventClient.cpp index 96c4814f92..c8d9bee60c 100644 --- a/xbmc/network/EventClient.cpp +++ b/xbmc/network/EventClient.cpp @@ -90,16 +90,7 @@ void CEventButtonState::Load() else if ( (m_mapName.length() > 3) && (StringUtils::StartsWith(m_mapName, "LI:")) ) // starts with LI: ? { - if (CServiceBroker::GetInputManager().HasRemoteControl()) - { - std::string lircDevice = m_mapName.substr(3); - m_iKeyCode = CServiceBroker::GetInputManager().TranslateLircRemoteString( lircDevice.c_str(), - m_buttonName.c_str() ); - } - else - { - CLog::Log(LOGERROR, "ES: LIRC support not enabled"); - } + CLog::Log(LOGNOTICE, "ES: LIRC support not implemented"); } else { diff --git a/xbmc/platform/win10/input/RemoteControlXbox.cpp b/xbmc/platform/win10/input/RemoteControlXbox.cpp index 560b1ce3c5..681d9cdd02 100644 --- a/xbmc/platform/win10/input/RemoteControlXbox.cpp +++ b/xbmc/platform/win10/input/RemoteControlXbox.cpp @@ -19,11 +19,10 @@ */ #include "RemoteControlXbox.h" -#include "input/InputManager.h" +#include "Application.h" #include "input/remote/IRRemote.h" #include "threads/SystemClock.h" #include "utils/log.h" -#include "ServiceBroker.h" #define XBOX_REMOTE_DEVICE_ID L"GIP:0000F50000000001" #define XBOX_REMOTE_DEVICE_NAME "Xbox One Game Controller" @@ -33,29 +32,10 @@ using namespace Windows::Media; using namespace Windows::System; using namespace Windows::UI::Core; -KODI::REMOTE::IRemoteControl* CRemoteControlXbox::CreateInstance() -{ - return new CRemoteControlXbox(); -} - -void CRemoteControlXbox::Register() -{ - CInputManager::RegisterRemoteControl(CRemoteControlXbox::CreateInstance); -} - -bool CRemoteControlXbox::IsRemoteControlId(const std::wstring &deviceId) -{ - return deviceId.compare(XBOX_REMOTE_DEVICE_ID) == 0; -} - CRemoteControlXbox::CRemoteControlXbox() - : m_button(0) - , m_lastButton(0) - , m_bInitialized(false) - , m_holdTime(0) + : m_bInitialized(false) , m_firstClickTime(0) , m_lastKey(VirtualKey::None) - , m_deviceName(XBOX_REMOTE_DEVICE_NAME) { } @@ -65,9 +45,9 @@ CRemoteControlXbox::~CRemoteControlXbox() Disconnect(); } -std::string CRemoteControlXbox::GetMapFile() +bool CRemoteControlXbox::IsRemoteDevice(const std::wstring &deviceId) const { - return ""; + return deviceId.compare(XBOX_REMOTE_DEVICE_ID) == 0; } void CRemoteControlXbox::Disconnect() @@ -83,19 +63,13 @@ void CRemoteControlXbox::Disconnect() m_bInitialized = false; } -void CRemoteControlXbox::Reset() -{ - m_button = 0; - m_holdTime = 0; -} - void CRemoteControlXbox::Initialize() { auto dispatcher = CoreWindow::GetForCurrentThread()->Dispatcher; m_token = dispatcher->AcceleratorKeyActivated += ref new TypedEventHandler<CoreDispatcher^, AcceleratorKeyEventArgs^> ([this](CoreDispatcher^ sender, AcceleratorKeyEventArgs^ args) { - if (IsRemoteControlId(args->DeviceId->Data())) + if (IsRemoteDevice(args->DeviceId->Data())) HandleAcceleratorKey(sender, args); }); @@ -112,33 +86,17 @@ void CRemoteControlXbox::Initialize() m_bInitialized = true; } -void CRemoteControlXbox::Update() -{ - if (m_lastButton != 0) - { - m_button = m_lastButton; - m_lastButton = 0; - } -} - -uint16_t CRemoteControlXbox::GetButton() const -{ - return m_button; -} - -uint32_t CRemoteControlXbox::GetHoldTimeMs() const -{ - return m_holdTime; -} - - - void CRemoteControlXbox::HandleAcceleratorKey(CoreDispatcher^ sender, AcceleratorKeyEventArgs^ args) { auto button = TranslateVirtualKey(args->VirtualKey); if (!button) return; + XBMC_Event newEvent; + newEvent.type = XBMC_BUTTON; + newEvent.keybutton.button = button; + newEvent.keybutton.holdtime = 0; + switch (args->EventType) { case CoreAcceleratorKeyEventType::KeyDown: @@ -148,23 +106,21 @@ void CRemoteControlXbox::HandleAcceleratorKey(CoreDispatcher^ sender, Accelerato { m_lastKey = args->VirtualKey; m_firstClickTime = XbmcThreads::SystemClockMillis(); - m_holdTime = 0; } else - m_holdTime = XbmcThreads::SystemClockMillis() - m_firstClickTime; + newEvent.keybutton.holdtime = XbmcThreads::SystemClockMillis() - m_firstClickTime; - m_lastButton = button; + g_application.OnEvent(newEvent); break; } case CoreAcceleratorKeyEventType::KeyUp: case CoreAcceleratorKeyEventType::SystemKeyUp: { if (m_lastKey == args->VirtualKey) - m_holdTime = XbmcThreads::SystemClockMillis() - m_firstClickTime; - else - m_holdTime = 0; + newEvent.keybutton.holdtime = XbmcThreads::SystemClockMillis() - m_firstClickTime; m_lastKey = VirtualKey::None; + g_application.OnEvent(newEvent); break; } case CoreAcceleratorKeyEventType::Character: @@ -180,7 +136,11 @@ void CRemoteControlXbox::HandleAcceleratorKey(CoreDispatcher^ sender, Accelerato void CRemoteControlXbox::HandleMediaButton(Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs^ args) { - m_lastButton = TranslateMediaKey(args->Button); + XBMC_Event newEvent; + newEvent.type = XBMC_BUTTON; + newEvent.keybutton.button = TranslateMediaKey(args->Button);; + newEvent.keybutton.holdtime = 0; + g_application.OnEvent(newEvent); } int32_t CRemoteControlXbox::TranslateVirtualKey(Windows::System::VirtualKey vk) diff --git a/xbmc/platform/win10/input/RemoteControlXbox.h b/xbmc/platform/win10/input/RemoteControlXbox.h index 50598badfe..2562ce8bdd 100644 --- a/xbmc/platform/win10/input/RemoteControlXbox.h +++ b/xbmc/platform/win10/input/RemoteControlXbox.h @@ -19,32 +19,16 @@ * */ -#include "input/remote/IRemoteControl.h" #include <string> -class CRemoteControlXbox : public KODI::REMOTE::IRemoteControl +class CRemoteControlXbox { public: CRemoteControlXbox(); virtual ~CRemoteControlXbox(); - void Initialize() override; - void Disconnect() override; - void Reset() override; - void Update() override; - uint16_t GetButton() const override; - uint32_t GetHoldTimeMs() const override; - bool IsInitialized() const override { return m_bInitialized; } - std::string GetMapFile() override; - - void SetEnabled(bool) override { } - void SetDeviceName(const std::string&) override { } - void AddSendCommand(const std::string&) override { } - bool IsInUse() const override { return false; } - - static KODI::REMOTE::IRemoteControl* CreateInstance(); - static void Register(); - - static bool IsRemoteControlId(const std::wstring &deviceId); + void Initialize(); + void Disconnect(); + bool IsRemoteDevice(const std::wstring &deviceId) const; private: void HandleAcceleratorKey(Windows::UI::Core::CoreDispatcher^ sender, Windows::UI::Core::AcceleratorKeyEventArgs^ args); @@ -52,14 +36,9 @@ private: int32_t TranslateVirtualKey(Windows::System::VirtualKey vk); int32_t TranslateMediaKey(Windows::Media::SystemMediaTransportControlsButton mk); - int32_t m_button; - int32_t m_lastButton; - uint32_t m_holdTime; - uint32_t m_firstClickTime; bool m_bInitialized; - std::string m_deviceName; + uint32_t m_firstClickTime; Windows::Foundation::EventRegistrationToken m_token; Windows::Foundation::EventRegistrationToken m_mediatoken; Windows::System::VirtualKey m_lastKey; - Windows::Media::SystemMediaTransportControlsButton m_lastMediaButton; }; diff --git a/xbmc/platform/win32/input/IRServerSuite.cpp b/xbmc/platform/win32/input/IRServerSuite.cpp index 865c2d0692..5841b5ef3d 100644 --- a/xbmc/platform/win32/input/IRServerSuite.cpp +++ b/xbmc/platform/win32/input/IRServerSuite.cpp @@ -19,54 +19,37 @@ */ #include "IRServerSuite.h" +#include "Application.h" #include "IrssMessage.h" -#include "input/InputManager.h" +#include "platform/win32/CharsetConverter.h" +#include "profiles/ProfilesManager.h" #include "utils/log.h" #include "ServiceBroker.h" -#include "platform/win32/CharsetConverter.h" -#include <Ws2tcpip.h> + +#include <WS2tcpip.h> #define IRSS_PORT 24000 #define IRSS_MAP_FILENAME "IRSSmap.xml" -KODI::REMOTE::IRemoteControl* CRemoteControl::CreateInstance() -{ - return new CRemoteControl(); -} - -void CRemoteControl::Register() -{ - CInputManager::RegisterRemoteControl(CRemoteControl::CreateInstance); -} - -CRemoteControl::CRemoteControl() +CIRServerSuite::CIRServerSuite() : CThread("RemoteControl") - , m_button(0) , m_bInitialized(false) , m_socket(INVALID_SOCKET) , m_isConnecting(false) { } -CRemoteControl::~CRemoteControl() -{ - Disconnect(); -} - -std::string CRemoteControl::GetMapFile() -{ - return IRSS_MAP_FILENAME; -} - -void CRemoteControl::Disconnect() +CIRServerSuite::~CIRServerSuite() { m_event.Set(); - + { + CSingleLock lock(m_critSection); + Close(); + } StopThread(); - Close(); } -void CRemoteControl::Close() +void CIRServerSuite::Close() { m_isConnecting = false; if (m_socket != INVALID_SOCKET) @@ -83,41 +66,41 @@ void CRemoteControl::Close() } } -void CRemoteControl::Reset() +void CIRServerSuite::Initialize() { - m_button = 0; -} - -void CRemoteControl::Initialize() -{ - if (m_isConnecting || m_bInitialized || IsRunning()) - return; - //trying to connect when there is nothing to connect to is kinda slow so kick it off in a thread. Create(); + SetPriority(GetMinPriority()); } -void CRemoteControl::Process() +void CIRServerSuite::Process() { - unsigned int iMsRetryDelay = 5000; - int iAttempt = 0; + m_profileId = CServiceBroker::GetProfileManager().GetCurrentProfileId(); + m_irTranslator.Load(IRSS_MAP_FILENAME); + // try to connect 60 times @ a 5 second interval (5 minutes) // multiple tries because irss service might be up and running a little later then xbmc on boot. - while (!m_bStop && iAttempt <= 60) + while (!m_bStop) { - if (Connect(iAttempt == 0)) - break; - - if(iAttempt == 0) - CLog::Log(LOGINFO, "CRemoteControl::Process - failed to connect to irss, will keep retrying every %d seconds", iMsRetryDelay / 1000); + if (!Connect(true)) + { + CLog::LogF(LOGINFO, "failed to connect to irss, will keep retrying every 5 seconds"); + if (AbortableWait(m_event, 5000) == WAIT_SIGNALED) + break; + continue; + } - ++iAttempt; - - if (AbortableWait(m_event, iMsRetryDelay) == WAIT_INTERRUPTED) - break; + while (!m_bStop) + { + if (!ReadNext()) + { + break; + } + } } + Close(); } -bool CRemoteControl::Connect(bool logMessages) +bool CIRServerSuite::Connect(bool logMessages) { char namebuf[NI_MAXHOST], portbuf[NI_MAXSERV]; struct addrinfo hints = {}; @@ -134,7 +117,7 @@ bool CRemoteControl::Connect(bool logMessages) if(res) { if (logMessages) - CLog::Log(LOGDEBUG, "CRemoteControl::Connect - getaddrinfo failed: %s", + CLog::LogF(LOGDEBUG, "getaddrinfo failed: %s", KODI::PLATFORM::WINDOWS::FromW(gai_strerror(res))); return false; } @@ -148,7 +131,7 @@ bool CRemoteControl::Connect(bool logMessages) } if (logMessages) - CLog::Log(LOGDEBUG, "CRemoteControl::Connect - connecting to: %s:%s ...", namebuf, portbuf); + CLog::LogF(LOGDEBUG, "connecting to: %s:%s ...", namebuf, portbuf); m_socket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if(m_socket == INVALID_SOCKET) @@ -165,7 +148,7 @@ bool CRemoteControl::Connect(bool logMessages) if(m_socket == INVALID_SOCKET) { if (logMessages) - CLog::Log(LOGDEBUG, "CRemoteControl::Connect - failed to connect"); + CLog::LogF(LOGDEBUG, "failed to connect"); Close(); return false; } @@ -174,7 +157,7 @@ bool CRemoteControl::Connect(bool logMessages) if (ioctlsocket(m_socket, FIONBIO, &iMode) == SOCKET_ERROR) { if (logMessages) - CLog::Log(LOGERROR, "IRServerSuite: failed to set socket to non-blocking."); + CLog::LogF(LOGERROR, "failed to set socket to non-blocking."); Close(); return false; } @@ -184,14 +167,14 @@ bool CRemoteControl::Connect(bool logMessages) if (!SendPacket(mess)) { if (logMessages) - CLog::Log(LOGERROR, "IRServerSuite: failed to send RegisterClient packet."); + CLog::LogF(LOGERROR, "failed to send RegisterClient packet."); return false; } m_isConnecting = true; return true; } -bool CRemoteControl::SendPacket(CIrssMessage& message) +bool CIRServerSuite::SendPacket(CIrssMessage& message) { int iSize = 0; char* bytes = message.ToBytes(iSize); @@ -212,19 +195,25 @@ bool CRemoteControl::SendPacket(CIrssMessage& message) return true; } - -void CRemoteControl::Update() +bool CIRServerSuite::ReadNext() { if ((!m_bInitialized && !m_isConnecting) || (m_socket == INVALID_SOCKET)) { - return; + return false; } CIrssMessage mess; - if (!ReadPacket(mess)) + int res = ReadPacket(mess); + if (res < 0) { - return; + Close(); + return false; } + + // nothing received + if (!res) + return true; + switch (mess.GetType()) { case IRSSMT_RegisterClient: @@ -233,7 +222,8 @@ void CRemoteControl::Update() { //uh oh, it failed to register Close(); - CLog::Log(LOGERROR, "IRServerSuite: failed to register XBMC as a client."); + CLog::LogF(LOGERROR, "failed to register application as a client."); + return false; } else { @@ -242,17 +232,20 @@ void CRemoteControl::Update() CIrssMessage mess(IRSSMT_DetectedReceivers, IRSSMF_Request); if (!SendPacket(mess)) { - CLog::Log(LOGERROR, "IRServerSuite: failed to send AvailableReceivers packet."); + CLog::LogF(LOGERROR, "failed to send `AvailableReceivers` packet."); + return false; } mess.SetType(IRSSMT_AvailableReceivers); if (!SendPacket(mess)) { - CLog::Log(LOGERROR, "IRServerSuite: failed to send AvailableReceivers packet."); + CLog::LogF(LOGERROR, "failed to send `AvailableReceivers` packet."); + return false; } mess.SetType(IRSSMT_ActiveReceivers); if (!SendPacket(mess)) { - CLog::Log(LOGERROR, "IRServerSuite: failed to send AvailableReceivers packet."); + CLog::LogF(LOGERROR, "failed to send `AvailableReceivers` packet."); + return false; } } break; @@ -261,11 +254,11 @@ void CRemoteControl::Update() break; case IRSSMT_Error: //I suppose the errormessage is in the packet somewhere... - CLog::Log(LOGERROR, "IRServerSuite: we got an error message."); + CLog::LogF(LOGERROR, "we got an error message."); break; case IRSSMT_ServerShutdown: Close(); - break; + return false; case IRSSMT_ServerSuspend: //should we do something? break; @@ -281,7 +274,7 @@ void CRemoteControl::Update() char* availablereceivers = new char[size + 1]; memcpy(availablereceivers, data, size); availablereceivers[size] = '\0'; - CLog::Log(LOGINFO, "IRServerSuite: Available receivers: %s", availablereceivers); + CLog::LogF(LOGINFO, "available receivers: %s", availablereceivers); delete[] availablereceivers; } } @@ -295,7 +288,7 @@ void CRemoteControl::Update() char* detectedreceivers = new char[size + 1]; memcpy(detectedreceivers, data, size); detectedreceivers[size] = '\0'; - CLog::Log(LOGINFO, "IRServerSuite: Detected receivers: %s", detectedreceivers); + CLog::LogF(LOGINFO, "detected receivers: %s", detectedreceivers); delete[] detectedreceivers; } } @@ -309,15 +302,16 @@ void CRemoteControl::Update() char* activereceivers = new char[size + 1]; memcpy(activereceivers, data, size); activereceivers[size] = '\0'; - CLog::Log(LOGINFO, "IRServerSuite: Active receivers: %s", activereceivers); + CLog::LogF(LOGINFO, "active receivers: %s", activereceivers); delete[] activereceivers; } } break; } + return true; } -bool CRemoteControl::HandleRemoteEvent(CIrssMessage& message) +bool CIRServerSuite::HandleRemoteEvent(CIrssMessage& message) { try { @@ -330,7 +324,7 @@ bool CRemoteControl::HandleRemoteEvent(CIrssMessage& message) uint32_t keycodelength; if (datalen == 0) { - CLog::Log(LOGERROR, "IRServerSuite: no data in remote message."); + CLog::LogF(LOGERROR, "no data in remote message."); return false; } if (datalen <= 8) @@ -350,14 +344,14 @@ bool CRemoteControl::HandleRemoteEvent(CIrssMessage& message) //devicename itself if (datalen < 4 + devicenamelength) { - CLog::Log(LOGERROR, "IRServerSuite: invalid data in remote message (size: %u).", datalen); + CLog::LogF(LOGERROR, "invalid data in remote message (size: %u).", datalen); return false; } deviceName = new char[devicenamelength + 1]; memcpy(deviceName, data + 4, devicenamelength); if (datalen < 8 + devicenamelength) { - CLog::Log(LOGERROR, "IRServerSuite: invalid data in remote message (size: %u).", datalen); + CLog::LogF(LOGERROR, "invalid data in remote message (size: %u).", datalen); delete[] deviceName; return false; } @@ -366,7 +360,7 @@ bool CRemoteControl::HandleRemoteEvent(CIrssMessage& message) //keycode itself if (datalen < 8 + devicenamelength + keycodelength) { - CLog::Log(LOGERROR, "IRServerSuite: invalid data in remote message (size: %u).", datalen); + CLog::LogF(LOGERROR, "invalid data in remote message (size: %u).", datalen); delete[] deviceName; return false; } @@ -375,9 +369,22 @@ bool CRemoteControl::HandleRemoteEvent(CIrssMessage& message) } deviceName[devicenamelength] = '\0'; keycode[keycodelength] = '\0'; + + if (m_profileId != CServiceBroker::GetProfileManager().GetCurrentProfileId()) + { + m_profileId = CServiceBroker::GetProfileManager().GetCurrentProfileId(); + m_irTranslator.Load(IRSS_MAP_FILENAME); + } + //translate to a buttoncode xbmc understands - m_button = CServiceBroker::GetInputManager().TranslateLircRemoteString(deviceName, keycode); - CLog::Log(LOGDEBUG, "IRServerSuite, RemoteEvent: %s %s", deviceName, keycode); + CLog::LogF(LOGDEBUG, "remoteEvent: %s %s", deviceName, keycode); + unsigned button = m_irTranslator.TranslateButton(deviceName, keycode); + + XBMC_Event newEvent; + newEvent.type = XBMC_BUTTON; + newEvent.keybutton.button = button; + newEvent.keybutton.holdtime = 0; + g_application.OnEvent(newEvent); delete[] deviceName; delete[] keycode; @@ -385,12 +392,12 @@ bool CRemoteControl::HandleRemoteEvent(CIrssMessage& message) } catch(...) { - CLog::Log(LOGERROR, "IRServerSuite: exception while processing RemoteEvent."); + CLog::LogF(LOGERROR, "exception while processing RemoteEvent."); return false; } } -int CRemoteControl::ReadN(char *buffer, int n) +int CIRServerSuite::ReadN(char *buffer, int n) { int nOriginalSize = n; memset(buffer, 0, n); @@ -398,7 +405,10 @@ int CRemoteControl::ReadN(char *buffer, int n) while (n > 0) { int nBytes = 0; - nBytes = recv(m_socket, ptr, n, 0); + { + CSingleLock lock(m_critSection); + nBytes = recv(m_socket, ptr, n, 0); + } if (WSAGetLastError() == WSAEWOULDBLOCK) { @@ -408,7 +418,7 @@ int CRemoteControl::ReadN(char *buffer, int n) { if (!m_isConnecting) { - CLog::Log(LOGERROR, "%s, IRServerSuite recv error %d", __FUNCTION__, GetLastError()); + CLog::LogF(LOGERROR, "recv error %d", WSAGetLastError()); } Close(); return -1; @@ -416,7 +426,7 @@ int CRemoteControl::ReadN(char *buffer, int n) if (nBytes == 0) { - CLog::Log(LOGDEBUG,"%s, IRServerSuite socket closed by server", __FUNCTION__); + CLog::LogF(LOGDEBUG, "socket closed by server"); Close(); break; } @@ -428,15 +438,20 @@ int CRemoteControl::ReadN(char *buffer, int n) return nOriginalSize - n; } -bool CRemoteControl::WriteN(const char *buffer, int n) +bool CIRServerSuite::WriteN(const char *buffer, int n) { const char *ptr = buffer; while (n > 0) { - int nBytes = send(m_socket, ptr, n, 0); + int nBytes; + { + CSingleLock lock(m_critSection); + nBytes = send(m_socket, ptr, n, 0); + } + if (nBytes < 0) { - CLog::Log(LOGERROR, "%s, IRServerSuite send error %d (%d bytes)", __FUNCTION__, GetLastError(), n); + CLog::LogF(LOGERROR, "send error %d (%d bytes)", WSAGetLastError(), n); Close(); return false; } @@ -451,50 +466,46 @@ bool CRemoteControl::WriteN(const char *buffer, int n) return n == 0; } -bool CRemoteControl::ReadPacket(CIrssMessage &message) +int CIRServerSuite::ReadPacket(CIrssMessage &message) { try { char sizebuf[4]; int iRead = ReadN(&sizebuf[0], 4); - if (iRead <= 0) return false; //nothing to read + if (iRead <= 0) + return iRead; // error or nothing to read + if (iRead != 4) { - CLog::Log(LOGERROR, "IRServerSuite: failed to read packetsize."); - return false; + CLog::LogF(LOGERROR, "failed to read packetsize."); + return -1; } + uint32_t size = 0; memcpy(&size, &sizebuf[0], 4); size = ntohl(size); char* messagebytes = new char[size]; + if (ReadN(messagebytes, size) != size) { - CLog::Log(LOGERROR, "IRServerSuite: failed to read packet."); + CLog::LogF(LOGERROR, "failed to read packet."); delete[] messagebytes; return false; } + if (!CIrssMessage::FromBytes(messagebytes, size, message)) { - CLog::Log(LOGERROR, "IRServerSuite: invalid packet received (size: %u).", size); + CLog::LogF(LOGERROR, "invalid packet received (size: %u).", size); delete[] messagebytes; - return false; + return -1; } + delete[] messagebytes; - return true; + return size; } catch(...) { - CLog::Log(LOGERROR, "IRServerSuite: exception while processing packet."); - return false; + CLog::LogF(LOGERROR, "exception while processing packet."); + return -1; } } - -uint16_t CRemoteControl::GetButton() const -{ - return m_button; -} - -uint32_t CRemoteControl::GetHoldTimeMs() const -{ - return 0; -} diff --git a/xbmc/platform/win32/input/IRServerSuite.h b/xbmc/platform/win32/input/IRServerSuite.h index 05b9bff46c..385a07db1b 100644 --- a/xbmc/platform/win32/input/IRServerSuite.h +++ b/xbmc/platform/win32/input/IRServerSuite.h @@ -20,53 +20,38 @@ */ #include "IrssMessage.h" -#include "input/remote/IRemoteControl.h" +#include "input/IRTranslator.h" #include "threads/Thread.h" #include "threads/Event.h" #include <winsock2.h> #include <string> -class CRemoteControl : public KODI::REMOTE::IRemoteControl, CThread +class CIRServerSuite : public CThread { public: - CRemoteControl(); - virtual ~CRemoteControl(); - void Initialize() override; - void Disconnect() override; - void Reset() override; - void Update() override; - uint16_t GetButton() const override; - uint32_t GetHoldTimeMs() const override; - bool IsInitialized() const override { return m_bInitialized; } - std::string GetMapFile() override; - - void SetEnabled(bool) override { } - void SetDeviceName(const std::string&) override { } - void AddSendCommand(const std::string&) override { } - bool IsInUse() const override { return false; } - - static IRemoteControl* CreateInstance(); - static void Register(); + CIRServerSuite(); + virtual ~CIRServerSuite(); + void Initialize(); protected: virtual void Process(); + bool ReadNext(); private: - WORD m_button; - bool m_bInitialized; - SOCKET m_socket; - bool m_isConnecting; - std::string m_deviceName; - std::string m_keyCode; - CEvent m_event; - bool SendPacket(CIrssMessage& message); - bool ReadPacket(CIrssMessage& message); - int ReadN(char *buffer, int n); + int ReadPacket(CIrssMessage& message); + int ReadN(char *buffer, int n); bool WriteN(const char *buffer, int n); bool Connect(bool logMessages); void Close(); - bool HandleRemoteEvent(CIrssMessage& message); + + bool m_bInitialized; + bool m_isConnecting; + int m_profileId; + SOCKET m_socket; + CEvent m_event; + CCriticalSection m_critSection; + CIRTranslator m_irTranslator; }; diff --git a/xbmc/windowing/win10/WinEventsWin10.cpp b/xbmc/windowing/win10/WinEventsWin10.cpp index 7916425f73..79a62943f0 100644 --- a/xbmc/windowing/win10/WinEventsWin10.cpp +++ b/xbmc/windowing/win10/WinEventsWin10.cpp @@ -18,6 +18,7 @@ * */ +#include "WinEventsWin10.h" #include "Application.h" #include "guilib/GUIComponent.h" #include "guilib/GUIWindowManager.h" @@ -28,9 +29,9 @@ #include "input/ActionIDs.h" #include "interfaces/AnnouncementManager.h" #include "messaging/ApplicationMessenger.h" +#include "platform/win10/AsyncHelpers.h" #include "platform/win10/input/RemoteControlXbox.h" #include "rendering/dx/DeviceResources.h" -#include "platform/win10/AsyncHelpers.h" #include "rendering/dx/RenderContext.h" #include "ServiceBroker.h" #include "utils/log.h" @@ -38,7 +39,6 @@ #include "utils/Variant.h" #include "windowing/windows/WinKeyMap.h" #include "xbmc/GUIUserMessages.h" -#include "WinEventsWin10.h" using namespace Windows::Devices::Input; using namespace Windows::Foundation; @@ -58,6 +58,9 @@ static Point GetScreenPoint(Point point) return Point(DX::ConvertDipsToPixels(point.X, dpi), DX::ConvertDipsToPixels(point.Y, dpi)); } +CWinEventsWin10::CWinEventsWin10() = default; +CWinEventsWin10::~CWinEventsWin10() = default; + void CWinEventsWin10::InitOSKeymap(void) { KODI::WINDOWING::WINDOWS::DIB_InitOSKeymap(); @@ -182,6 +185,11 @@ void CWinEventsWin10::InitEventHandlers(CoreWindow^ window) m_smtc->IsEnabled = true; CAnnouncementManager::GetInstance().AddAnnouncer(this); } + if (CSysInfo::GetWindowsDeviceFamily() == CSysInfo::WindowsDeviceFamily::Xbox) + { + m_remote = std::make_unique<CRemoteControlXbox>(); + m_remote->Initialize(); + } } void CWinEventsWin10::UpdateWindowSize() @@ -461,8 +469,8 @@ void CWinEventsWin10::OnAcceleratorKeyActivated(CoreDispatcher^ sender, Accelera static auto lockedState = CoreVirtualKeyStates::Locked; static VirtualKey keyStore = VirtualKey::None; - if ( CSysInfo::GetWindowsDeviceFamily() == CSysInfo::WindowsDeviceFamily::Xbox - && CRemoteControlXbox::IsRemoteControlId(args->DeviceId->Data())) + // skip if device is remote control + if (m_remote && m_remote->IsRemoteDevice(args->DeviceId->Data())) return; bool isDown = false; diff --git a/xbmc/windowing/win10/WinEventsWin10.h b/xbmc/windowing/win10/WinEventsWin10.h index 98348ed5e3..70a41ddfab 100644 --- a/xbmc/windowing/win10/WinEventsWin10.h +++ b/xbmc/windowing/win10/WinEventsWin10.h @@ -17,10 +17,6 @@ * <http://www.gnu.org/licenses/>. * */ - -#ifndef WINDOW_EVENTS_WIN10_H -#define WINDOW_EVENTS_WIN10_H - #pragma once #include "interfaces/IAnnouncer.h" @@ -28,10 +24,15 @@ #include <concurrent_queue.h> #include <cmath> +class CRemoteControlXbox; + class CWinEventsWin10 : public IWinEvents , public ANNOUNCEMENT::IAnnouncer { public: + CWinEventsWin10(); + virtual ~CWinEventsWin10(); + void MessagePush(XBMC_Event *newEvent); bool MessagePump() override; virtual size_t GetQueueSize(); @@ -83,6 +84,5 @@ private: float m_logicalHeight{ 0 }; float m_logicalPosX{ 0 }; float m_logicalPosY{ 0 }; + std::unique_ptr<CRemoteControlXbox> m_remote; }; - -#endif // WINDOW_EVENTS_WIN10_H diff --git a/xbmc/windowing/win10/WinSystemWin10.cpp b/xbmc/windowing/win10/WinSystemWin10.cpp index 113d54d01b..e0884b449c 100644 --- a/xbmc/windowing/win10/WinSystemWin10.cpp +++ b/xbmc/windowing/win10/WinSystemWin10.cpp @@ -26,7 +26,6 @@ #include "windowing/GraphicContext.h" #include "messaging/ApplicationMessenger.h" #include "platform/win10/AsyncHelpers.h" -#include "platform/win10/input/RemoteControlXbox.h" #include "platform/win10/powermanagement/Win10PowerSyscall.h" #include "platform/win32/CharsetConverter.h" #include "rendering/dx/DirectXHelper.h" @@ -74,10 +73,6 @@ CWinSystemWin10::CWinSystemWin10() { CAESinkWASAPI::Register(); } - else if (CSysInfo::GetWindowsDeviceFamily() == CSysInfo::WindowsDeviceFamily::Xbox) - { - CRemoteControlXbox::Register(); - } CPowerSyscall::Register(); } diff --git a/xbmc/windowing/windows/WinSystemWin32.cpp b/xbmc/windowing/windows/WinSystemWin32.cpp index 726ac13ab6..4cde0d3e24 100644 --- a/xbmc/windowing/windows/WinSystemWin32.cpp +++ b/xbmc/windowing/windows/WinSystemWin32.cpp @@ -69,7 +69,8 @@ CWinSystemWin32::CWinSystemWin32() CAESinkDirectSound::Register(); CAESinkWASAPI::Register(); CWin32PowerSyscall::Register(); - CRemoteControl::Register(); + m_irss.reset(new CIRServerSuite()); + m_irss->Initialize(); } CWinSystemWin32::~CWinSystemWin32() diff --git a/xbmc/windowing/windows/WinSystemWin32.h b/xbmc/windowing/windows/WinSystemWin32.h index 7a4ee9a955..16ad8cb084 100644 --- a/xbmc/windowing/windows/WinSystemWin32.h +++ b/xbmc/windowing/windows/WinSystemWin32.h @@ -167,6 +167,8 @@ DECLARE_HANDLE(HGESTUREINFO); #undef IsMinimized #endif +class CIRServerSuite; + class CWinSystemWin32 : public CWinSystemBase { public: @@ -274,6 +276,7 @@ protected: bool m_inFocus; bool m_bMinimized; bool m_bSizeMoveEnabled{ false }; + std::unique_ptr<CIRServerSuite> m_irss; }; extern HWND g_hWnd; |