diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp index 181d2b620..eed352c4f 100644 --- a/Source/Engine/Input/Input.cpp +++ b/Source/Engine/Input/Input.cpp @@ -508,16 +508,14 @@ float Input::GetGamepadAxis(InputGamepadIndex gamepad, GamepadAxis axis) { if (gamepad == InputGamepadIndex::All) { - float val = 0; + float result = 0.0f; for (auto g : Gamepads) { - val += g->GetAxis(axis); - if(val >= 1) - return 1; - if (val <= -1) - return -1; + float v = g->GetAxis(axis); + if (Math::Abs(v) > Math::Abs(result)) + result = v; } - return val; + return result; } else { diff --git a/Source/Engine/Platform/Base/WindowsManager.cpp b/Source/Engine/Platform/Base/WindowsManager.cpp index ef2d50b71..422812338 100644 --- a/Source/Engine/Platform/Base/WindowsManager.cpp +++ b/Source/Engine/Platform/Base/WindowsManager.cpp @@ -63,7 +63,7 @@ void WindowsManagerService::Update() WindowsManager::WindowsLocker.Lock(); for (auto& win : WindowsManager::Windows) { - if (win->IsVisible()) + if (win && win->IsVisible()) win->OnUpdate(deltaTime); } WindowsManager::WindowsLocker.Unlock(); diff --git a/Source/Engine/Platform/Linux/LinuxInput.cpp b/Source/Engine/Platform/Linux/LinuxInput.cpp index 149879ac2..b0c854cc2 100644 --- a/Source/Engine/Platform/Linux/LinuxInput.cpp +++ b/Source/Engine/Platform/Linux/LinuxInput.cpp @@ -1,42 +1,41 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + #if PLATFORM_LINUX +#include "LinuxInput.h" +#include "Engine/Core/Log.h" +#include "Engine/Profiler/ProfilerCPU.h" +#include +#include #include #include #include #include #include -#include "LinuxInput.h" -#include "Engine/Core/Log.h" -using namespace std; - -struct LinuxInputDevice { - u_int32_t uid[4]; - string name; - string handler; +struct LinuxInputDevice +{ + uint32 uid[4]; + std::string name; + std::string handler; bool isGamepad; }; static int foundGamepads; static float lastUpdateTime; static LinuxInputDevice inputDevices[LINUXINPUT_MAX_GAMEPADS]; -static LinuxGamepad *linuxGamepads[LINUXINPUT_MAX_GAMEPADS]; -void LinuxInput::Init() { - for (int i = 0; i < LINUXINPUT_MAX_GAMEPADS; i++) - { - linuxGamepads[i] = nullptr; - } +void LinuxInput::Init() +{ foundGamepads = 0; - // this will delay gamepad detection - lastUpdateTime = Platform::GetTimeSeconds(); + lastUpdateTime = -1000; } void LinuxInput::DetectGamePads() { - string line; + std::string line; std::ifstream devs("/proc/bus/input/devices"); - + foundGamepads = 0; if (devs.is_open()) { @@ -46,31 +45,39 @@ void LinuxInput::DetectGamePads() { int quoteIndex = line.find('"'); inputDevices[foundGamepads].name = line.substr(quoteIndex+1, line.length() - quoteIndex - 2); - } else if (line[0] == 'I') + } + else if (line[0] == 'I') { int startIndex = 0; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) + { int equalsIndex = line.find('=', startIndex); - if (equalsIndex > 0) { - istringstream part(line.substr(equalsIndex+1, 4)); + if (equalsIndex > 0) + { + std::istringstream part(line.substr(equalsIndex + 1, 4)); part >> std::hex >> inputDevices[foundGamepads].uid[i]; } - startIndex = equalsIndex+1; + startIndex = equalsIndex + 1; } - } else if (line[0] == 'H') + } + else if (line[0] == 'H') { int eventIndex = line.find("event"); - if (eventIndex > 0) { + if (eventIndex > 0) + { int end = line.find(' ', eventIndex); - if (end > 0) { + if (end > 0) + { inputDevices[foundGamepads].handler = "/dev/input/" + line.substr(eventIndex, end - eventIndex); } } - } else if (line[0] == 'B') + } + else if (line[0] == 'B') { int keyIndex = line.find("KEY="); - if (keyIndex >= 0) { - // there should be five groups of 64 bits each + if (keyIndex >= 0) + { + // There should be five groups of 64 bits each std::istringstream group(line.substr(keyIndex+4)); unsigned long int n64, msb; int foundGroups = 0; @@ -85,42 +92,56 @@ void LinuxInput::DetectGamePads() inputDevices[foundGamepads].isGamepad = (msb & 1lu<<48) > 0; } - } else if (line.length() == 0) + } + else if (line.length() == 0) { if (inputDevices[foundGamepads].isGamepad && foundGamepads < (LINUXINPUT_MAX_GAMEPADS-1)) - { - foundGamepads++; - } + { + foundGamepads++; + } } } devs.close(); } //DumpDevices(); -}; +} void LinuxInput::UpdateState() { const float time = (float)Platform::GetTimeSeconds(); - if (time - lastUpdateTime > 5.0f) + if (time - lastUpdateTime > 1.0f) { + PROFILE_CPU_NAMED("Input.ScanGamepads"); DetectGamePads(); lastUpdateTime = time; for (int i = 0; i < foundGamepads; i++) { - if (linuxGamepads[i] == nullptr) + auto& inputDevice = inputDevices[i]; + + // Skip duplicates + bool duplicate = false; + for (Gamepad* g : Input::Gamepads) { - linuxGamepads[i] = new LinuxGamepad(inputDevices[i].uid, inputDevices[i].name); - linuxGamepads[i]->dev = inputDevices[i].handler; - linuxGamepads[i]->fd = -1; - Input::Gamepads.Add(linuxGamepads[i]); - Input::OnGamepadsChanged(); - LOG(Info, "Gamepad {} added", linuxGamepads[i]->GetName()); + if (((LinuxGamepad*)g)->dev == inputDevice.handler.c_str()) + { + duplicate = true; + break; + } } + if (duplicate) + continue; + + // Add gamepad + auto linuxGamepad = New(inputDevice.uid, String(inputDevice.name.c_str())); + linuxGamepad->dev = StringAnsi(inputDevice.handler.c_str()); + linuxGamepad->fd = -1; + Input::Gamepads.Add(linuxGamepad); + Input::OnGamepadsChanged(); + LOG(Info, "Added gamepad '{}'", linuxGamepad->GetName()); } } } -// from WindowsInput.cpp float NormalizeInputAxis(const int axisVal) { // Normalize [-32768..32767] -> [-1..1] @@ -134,7 +155,8 @@ float NormalizeInputTrigger(const int axisVal) return float(axisVal) / 1023.0f; } -LinuxGamepad::LinuxGamepad(u_int32_t uid[4], string name) : Gamepad(Guid(uid[0], uid[1], uid[2], uid[3]), String(name.c_str())) +LinuxGamepad::LinuxGamepad(uint32 uid[4], const String& name) + : Gamepad(Guid(uid[0], uid[1], uid[2], uid[3]), name) { fd = -1; for (int i = 0; i < (int32)GamepadButton::MAX; i++) @@ -149,15 +171,16 @@ LinuxGamepad::LinuxGamepad(u_int32_t uid[4], string name) : Gamepad(Guid(uid[0], LinuxGamepad::~LinuxGamepad() { - if (fd >= 0) close(fd); + if (fd >= 0) + close(fd); } bool LinuxGamepad::UpdateState() { if (fd < 0) { - fd = open(dev.c_str(), O_RDONLY|O_NONBLOCK); - //cout << "opened " << dev << endl; + fd = open(dev.Get(), O_RDONLY | O_NONBLOCK); + //std::cout << "opened " << dev.Get() << std::endl; } input_event event; int caughtEvents = 0; @@ -166,29 +189,32 @@ bool LinuxGamepad::UpdateState() ssize_t r = read(fd, &event, sizeof(event)); if (r < 0) { - if (errno != EAGAIN) { - LOG(Warning, "Lost connection to gamepad, errno={0}", errno); + if (errno != EAGAIN) + { + LOG(Warning, "Lost connection to gamepad '{1}', errno={0}", errno, GetName()); close(fd); fd = -1; + return true; } break; } if (r == 0) break; if (r < sizeof(event) || r != 24) { - LOG(Warning, "got a shortened package from the kernel {0}", r); + LOG(Warning, "Gamepad '{1}' got a shortened package from the kernel {0}", r, GetName()); break; } if (event.type > EV_MAX) { - LOG(Warning, "got an invalid event type from the kernel {0}", event.type); + LOG(Warning, "Gamepad '{1}' got an invalid event type from the kernel {0}", event.type, GetName()); break; } caughtEvents++; - //cout << "got an event " << event.type << ", code " << event.code << ", value " << event.value << endl; + //std::cout << "got an event " << event.type << ", code " << event.code << ", value " << event.value << std::endl; if (event.type == EV_KEY) { - switch (event.code) { + switch (event.code) + { case BTN_A: _state.Buttons[(int32)GamepadButton::A] = !!event.value; break; case BTN_B: _state.Buttons[(int32)GamepadButton::B] = !!event.value; break; case BTN_X: _state.Buttons[(int32)GamepadButton::X] = !!event.value; break; @@ -204,9 +230,11 @@ bool LinuxGamepad::UpdateState() case BTN_DPAD_LEFT: _state.Buttons[(int32)GamepadButton::DPadLeft] = !!event.value; break; case BTN_DPAD_RIGHT: _state.Buttons[(int32)GamepadButton::DPadRight] = !!event.value; break; } - } else if (event.type == EV_ABS) + } + else if (event.type == EV_ABS) { - switch (event.code) { + switch (event.code) + { case ABS_X: _state.Axis[(int32)GamepadAxis::LeftStickX] = NormalizeInputAxis(event.value); _state.Buttons[(int32)GamepadButton::LeftStickLeft] = event.value < -TRIGGER_THRESHOLD; @@ -238,33 +266,38 @@ bool LinuxGamepad::UpdateState() } } } - /* - if (caughtEvents > 0) + + /*if (caughtEvents > 0) { LOG(Info, "Caught events: {}", caughtEvents); - cout << "left stick x: " << _state.Axis[(int32)GamepadAxis::LeftStickX] << endl; - cout << "left stick y: " << _state.Axis[(int32)GamepadAxis::LeftStickY] << endl; - cout << "left trigger: " << _state.Axis[(int32)GamepadAxis::LeftTrigger] << endl; - cout << "right stick x: " << _state.Axis[(int32)GamepadAxis::RightStickX] << endl; - cout << "right stick y: " << _state.Axis[(int32)GamepadAxis::RightStickY] << endl; - cout << "right trigger: " << _state.Axis[(int32)GamepadAxis::RightTrigger] << endl; - cout << "button A: " << _state.Buttons[(int32)GamepadButton::A] << endl; - cout << "layout A: " << (int32)Layout.Buttons[(int32)GamepadButton::A] << endl; - } - */ + std::cout << "left stick x: " << _state.Axis[(int32)GamepadAxis::LeftStickX] << std::endl; + std::cout << "left stick y: " << _state.Axis[(int32)GamepadAxis::LeftStickY] << std::endl; + std::cout << "left trigger: " << _state.Axis[(int32)GamepadAxis::LeftTrigger] << std::endl; + std::cout << "right stick x: " << _state.Axis[(int32)GamepadAxis::RightStickX] << std::endl; + std::cout << "right stick y: " << _state.Axis[(int32)GamepadAxis::RightStickY] << std::endl; + std::cout << "right trigger: " << _state.Axis[(int32)GamepadAxis::RightTrigger] << std::endl; + std::cout << "button A: " << _state.Buttons[(int32)GamepadButton::A] << std::endl; + std::cout << "layout A: " << (int32)Layout.Buttons[(int32)GamepadButton::A] << std::endl; + }*/ + return false; } +#if BUILD_DEBUG + void LinuxInput::DumpDevices() { - for (int i = 0; i < foundGamepads; i++) { + for (int i = 0; i < foundGamepads; i++) + { char buf[36]; snprintf(buf, 36, "%04x %04x %04x %04x", inputDevices[i].uid[0], inputDevices[i].uid[1], inputDevices[i].uid[2], inputDevices[i].uid[3]); - cout << buf << endl; - cout << inputDevices[i].name << endl; - cout << inputDevices[i].handler << endl; - cout << (inputDevices[i].isGamepad ? "Gamepad" : "other") << endl; + std::cout << buf << std::endl; + std::cout << inputDevices[i].name << std::endl; + std::cout << inputDevices[i].handler << std::endl; + std::cout << (inputDevices[i].isGamepad ? "Gamepad" : "other") << std::endl; } } -#endif \ No newline at end of file +#endif + +#endif diff --git a/Source/Engine/Platform/Linux/LinuxInput.h b/Source/Engine/Platform/Linux/LinuxInput.h index c103487df..2c0ed7211 100644 --- a/Source/Engine/Platform/Linux/LinuxInput.h +++ b/Source/Engine/Platform/Linux/LinuxInput.h @@ -1,39 +1,34 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + #if PLATFORM_LINUX -#include -#include "/usr/include/linux/input-event-codes.h" -#include "/usr/include/linux/input.h" #include "Engine/Input/Input.h" #include "Engine/Input/Gamepad.h" -using namespace std; - #define LINUXINPUT_MAX_GAMEPADS 8 #define LINUXINPUT_MAX_GAMEPAD_EVENTS_PER_FRAME 32 #define TRIGGER_THRESHOLD 1000 class LinuxGamepad : public Gamepad { - struct State { - bool Buttons[32]; - float Axis[32]; - }; - public: - LinuxGamepad(u_int32_t uid[], string name); - ~LinuxGamepad(); +public: int fd; - string dev; - State _state; + StringAnsi dev; + + LinuxGamepad(uint32 uid[], const String& name); + ~LinuxGamepad(); bool UpdateState(); }; class LinuxInput { - public: +public: static void UpdateState(); static void DetectGamePads(); +#if BUILD_DEBUG static void DumpDevices(); +#endif static void Init(); }; -#endif \ No newline at end of file +#endif