/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #pragma once #include "EventPacket.h" #include "ServiceBroker.h" #include "Socket.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "threads/CriticalSection.h" #include "threads/Thread.h" #include #include #include #include #include namespace EVENTCLIENT { #define ES_FLAG_UNICODE 0x80000000 // new 16bit key flag to support real unicode over EventServer class CEventAction { public: CEventAction() { actionType = 0; } CEventAction(const char* action, unsigned char type): actionName(action) { actionType = type; } std::string actionName; unsigned char actionType; }; class CEventButtonState { public: CEventButtonState() { m_iKeyCode = 0; m_fAmount = 0.0f; m_bUseAmount = false; m_bRepeat = false; m_bActive = false; m_bAxis = false; m_iControllerNumber = 0; m_iNextRepeat = {}; } CEventButtonState(unsigned int iKeyCode, std::string mapName, std::string buttonName, float fAmount, bool isAxis, bool bRepeat, bool bUseAmount) : m_buttonName(std::move(buttonName)), m_mapName(std::move(mapName)) { m_iKeyCode = iKeyCode; m_fAmount = fAmount; m_bUseAmount = bUseAmount; m_bRepeat = bRepeat; m_bActive = true; m_bAxis = isAxis; m_iControllerNumber = 0; m_iNextRepeat = {}; Load(); } void Reset() { m_bActive = false; } void SetActive() { m_bActive = true; } bool Active() const { return m_bActive; } bool Repeat() const { return m_bRepeat; } int ControllerNumber() const { return m_iControllerNumber; } bool Axis() const { return m_bAxis; } unsigned int KeyCode() const { return m_iKeyCode; } float Amount() const { return m_fAmount; } void Load(); const std::string& JoystickName() const { return m_joystickName; } const std::string& CustomControllerName() const { return m_customControllerName; } // data unsigned int m_iKeyCode; unsigned short m_iControllerNumber; std::string m_buttonName; std::string m_mapName; std::string m_joystickName; std::string m_customControllerName; float m_fAmount; bool m_bUseAmount; bool m_bRepeat; bool m_bActive; bool m_bAxis; std::chrono::time_point m_iNextRepeat; }; /**********************************************************************/ /* UDP EventClient Class */ /**********************************************************************/ // - clients timeout if they don't receive at least 1 ping in 1 minute // - sequence packets timeout after 5 seconds class CEventClient { public: CEventClient() { Initialize(); } explicit CEventClient(SOCKETS::CAddress& addr): m_remoteAddr(addr) { Initialize(); } void Initialize() { m_bGreeted = false; m_iMouseX = 0; m_iMouseY = 0; m_iCurrentSeqLen = 0; m_lastPing = 0; m_lastSeq = 0; m_iRemotePort = 0; m_bMouseMoved = false; m_bSequenceError = false; RefreshSettings(); } const std::string& Name() const { return m_deviceName; } void RefreshSettings() { const std::shared_ptr settings = CServiceBroker::GetSettingsComponent()->GetSettings(); m_iRepeatDelay = std::chrono::milliseconds(settings->GetInt(CSettings::SETTING_SERVICES_ESINITIALDELAY)); m_iRepeatSpeed = std::chrono::milliseconds( settings->GetInt(CSettings::SETTING_SERVICES_ESCONTINUOUSDELAY)); } SOCKETS::CAddress& Address() { return m_remoteAddr; } virtual ~CEventClient() { FreePacketQueues(); } // add packet to queue bool AddPacket(std::unique_ptr packet); // return true if client received ping with the last 1 minute bool Alive() const; // process the packet queue bool ProcessQueue(); // process the queued up events (packets) void ProcessEvents(); // gets the next action in the action queue bool GetNextAction(CEventAction& action); // deallocate all packets in the queues void FreePacketQueues(); // return event states unsigned int GetButtonCode(std::string& strMapName, bool& isAxis, float& amount, bool &isJoystick); // update mouse position bool GetMousePos(float& x, float& y); protected: bool ProcessPacket(EVENTPACKET::CEventPacket *packet); // packet handlers virtual bool OnPacketHELO(EVENTPACKET::CEventPacket *packet); virtual bool OnPacketBYE(EVENTPACKET::CEventPacket *packet); virtual bool OnPacketBUTTON(EVENTPACKET::CEventPacket *packet); virtual bool OnPacketMOUSE(EVENTPACKET::CEventPacket *packet); virtual bool OnPacketNOTIFICATION(EVENTPACKET::CEventPacket *packet); virtual bool OnPacketLOG(EVENTPACKET::CEventPacket *packet); virtual bool OnPacketACTION(EVENTPACKET::CEventPacket *packet); bool CheckButtonRepeat(std::chrono::time_point& next); // returns true if the client has received the HELO packet bool Greeted() { return m_bGreeted; } // reset the timeout counter void ResetTimeout() { m_lastPing = time(NULL); } // helper functions // Parses a null terminated string from payload. // After parsing successfully: // 1. payload is incremented to end of string // 2. psize is decremented by length of string // 3. parsedVal contains the parsed string // 4. true is returned bool ParseString(unsigned char* &payload, int &psize, std::string& parsedVal); // Parses a single byte (same behavior as ParseString) bool ParseByte(unsigned char* &payload, int &psize, unsigned char& parsedVal); // Parse a single 32-bit integer (converts from network order to host order) bool ParseUInt32(unsigned char* &payload, int &psize, unsigned int& parsedVal); // Parse a single 16-bit integer (converts from network order to host order) bool ParseUInt16(unsigned char* &payload, int &psize, unsigned short& parsedVal); std::string m_deviceName; int m_iCurrentSeqLen; time_t m_lastPing; time_t m_lastSeq; int m_iRemotePort; bool m_bGreeted; std::chrono::milliseconds m_iRepeatDelay; std::chrono::milliseconds m_iRepeatSpeed; unsigned int m_iMouseX; unsigned int m_iMouseY; bool m_bMouseMoved; bool m_bSequenceError; SOCKETS::CAddress m_remoteAddr; EVENTPACKET::LogoType m_eLogoType; CCriticalSection m_critSection; std::map> m_seqPackets; std::queue> m_readyPackets; // button and mouse state std::list m_buttonQueue; std::queue m_actionQueue; CEventButtonState m_currentButton; }; }