diff --git a/CMakeLists.txt b/CMakeLists.txt index 63ab622e..cdcca81c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,7 +149,7 @@ endif() # For miscellaneous files if(SFML_OS_WINDOWS OR SFML_OS_IOS) set(DEFAULT_INSTALL_MISC_DIR .) -elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD) +elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD) set(DEFAULT_INSTALL_MISC_DIR share/SFML) elseif(SFML_OS_MACOSX) set(DEFAULT_INSTALL_MISC_DIR /usr/local/share/SFML) @@ -291,7 +291,7 @@ endif() # on Linux and BSD-like OS, install pkg-config files by default set(SFML_INSTALL_PKGCONFIG_DEFAULT FALSE) -if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD) +if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD) set(SFML_INSTALL_PKGCONFIG_DEFAULT TRUE) endif() diff --git a/cmake/Config.cmake b/cmake/Config.cmake index ec382089..116eddda 100644 --- a/cmake/Config.cmake +++ b/cmake/Config.cmake @@ -35,6 +35,10 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "^OpenBSD$") set(SFML_OS_OPENBSD 1) # don't use the OpenGL ES implementation on OpenBSD set(OPENGL_ES 0) +elseif(CMAKE_SYSTEM_NAME MATCHES "^NetBSD$") + set(SFML_OS_NETBSD 1) + # don't use the OpenGL ES implementation on NetBSD + set(OPENGL_ES 0) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") if(IOS) set(SFML_OS_IOS 1) @@ -73,7 +77,7 @@ endif() # this could be e.g. macports on mac or msys2 on windows etc. set(SFML_PKGCONFIG_DIR "/${CMAKE_INSTALL_LIBDIR}/pkgconfig") -if(SFML_OS_FREEBSD OR SFML_OS_OPENBSD) +if(SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD) set(SFML_PKGCONFIG_DIR "/libdata/pkgconfig") endif() diff --git a/include/SFML/Config.hpp b/include/SFML/Config.hpp index 3f282f2a..2dd98eee 100644 --- a/include/SFML/Config.hpp +++ b/include/SFML/Config.hpp @@ -91,6 +91,11 @@ // OpenBSD #define SFML_SYSTEM_OPENBSD + #elif defined(__NetBSD__) + + // NetBSD + #define SFML_SYSTEM_NETBSD + #else // Unsupported UNIX system diff --git a/include/SFML/OpenGL.hpp b/include/SFML/OpenGL.hpp index 45a3ac3d..65f4acae 100644 --- a/include/SFML/OpenGL.hpp +++ b/include/SFML/OpenGL.hpp @@ -45,7 +45,7 @@ #include -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD) #if defined(SFML_OPENGL_ES) #include diff --git a/include/SFML/Window/WindowHandle.hpp b/include/SFML/Window/WindowHandle.hpp index 624ca737..16cc3b11 100644 --- a/include/SFML/Window/WindowHandle.hpp +++ b/include/SFML/Window/WindowHandle.hpp @@ -42,7 +42,7 @@ namespace sf // Window handle is HWND (HWND__*) on Windows typedef HWND__* WindowHandle; -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD) // Window handle is Window (unsigned long) on Unix - X11 typedef unsigned long WindowHandle; diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index 982f4c40..55cb17f1 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -81,7 +81,7 @@ if(SFML_OS_WINDOWS) # make sure that we use the Unicode version of the Win API functions add_definitions(-DUNICODE -D_UNICODE) -elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD) +elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD) set(PLATFORM_SRC ${SRCROOT}/Unix/CursorImpl.hpp ${SRCROOT}/Unix/CursorImpl.cpp @@ -124,6 +124,13 @@ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD) ${SRCROOT}/OpenBSD/JoystickImpl.cpp ${SRCROOT}/OpenBSD/JoystickImpl.hpp ) + elseif(SFML_OS_NETBSD) + set(PLATFORM_SRC + ${PLATFORM_SRC} + ${SRCROOT}/NetBSD/JoystickImpl.cpp + ${SRCROOT}/NetBSD/JoystickImpl.hpp + ) + endif() source_group("unix" FILES ${PLATFORM_SRC}) elseif(SFML_OS_MACOSX) @@ -243,7 +250,7 @@ endif() target_include_directories(sfml-window PRIVATE "${PROJECT_SOURCE_DIR}/extlibs/headers/vulkan") # find and setup usage for external libraries -if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OPENBSD) +if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD) sfml_find_package(X11 INCLUDE "X11_INCLUDE_DIR" LINK "X11_X11_LIB" "X11_Xrandr_LIB" "X11_Xcursor_LIB") target_link_libraries(sfml-window PRIVATE X11) endif() diff --git a/src/SFML/Window/ClipboardImpl.hpp b/src/SFML/Window/ClipboardImpl.hpp index d0d2c324..60b459a3 100644 --- a/src/SFML/Window/ClipboardImpl.hpp +++ b/src/SFML/Window/ClipboardImpl.hpp @@ -32,7 +32,7 @@ #if defined(SFML_SYSTEM_WINDOWS) #include -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD) #include #elif defined(SFML_SYSTEM_MACOS) #include diff --git a/src/SFML/Window/CursorImpl.hpp b/src/SFML/Window/CursorImpl.hpp index bf507b2c..33750569 100644 --- a/src/SFML/Window/CursorImpl.hpp +++ b/src/SFML/Window/CursorImpl.hpp @@ -34,7 +34,7 @@ #include -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD) #include diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp index 00d4a200..ed247fa2 100644 --- a/src/SFML/Window/GlContext.cpp +++ b/src/SFML/Window/GlContext.cpp @@ -57,7 +57,7 @@ #endif -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD) #if defined(SFML_OPENGL_ES) diff --git a/src/SFML/Window/InputImpl.hpp b/src/SFML/Window/InputImpl.hpp index 4294bdb4..4ae97bdf 100644 --- a/src/SFML/Window/InputImpl.hpp +++ b/src/SFML/Window/InputImpl.hpp @@ -32,7 +32,7 @@ #if defined(SFML_SYSTEM_WINDOWS) #include -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD) #include #elif defined(SFML_SYSTEM_MACOS) #include diff --git a/src/SFML/Window/JoystickImpl.hpp b/src/SFML/Window/JoystickImpl.hpp index e6835526..2637e9b0 100644 --- a/src/SFML/Window/JoystickImpl.hpp +++ b/src/SFML/Window/JoystickImpl.hpp @@ -94,6 +94,10 @@ struct JoystickState #include +#elif defined(SFML_SYSTEM_NETBSD) + + #include + #elif defined(SFML_SYSTEM_MACOS) #include diff --git a/src/SFML/Window/NetBSD/JoystickImpl.cpp b/src/SFML/Window/NetBSD/JoystickImpl.cpp new file mode 100644 index 00000000..ef647d75 --- /dev/null +++ b/src/SFML/Window/NetBSD/JoystickImpl.cpp @@ -0,0 +1,351 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2020 Laurent Gomila (laurent@sfml-dev.org) +// 2013-2013 David Demelier (demelier.david@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////// +/// \brief This file implements NetBSD driver joystick +/// +//////////////////////////////////////////////////////////// + + +namespace +{ + std::map plugged; + std::map > hatValueMap; + + bool isJoystick(const char *name) + { + int file = ::open(name, O_RDONLY | O_NONBLOCK); + int id; + + if (file < 0) + return false; + + report_desc_t desc = hid_get_report_desc(file); + + if (!desc) + { + ::close(file); + return false; + } + + if (ioctl(file, USB_GET_REPORT_ID, &id) < 0) + { + ::close(file); + return false; + } + + hid_data_t data = hid_start_parse(desc, 1 << hid_input, id); + + if (!data) + { + hid_dispose_report_desc(desc); + ::close(file); + return false; + } + + hid_item_t item; + + // Assume it isn't + bool result = false; + + while (hid_get_item(data, &item) > 0) + { + if ((item.kind == hid_collection) && (HID_PAGE(item.usage) == HUP_GENERIC_DESKTOP)) + { + if ((HID_USAGE(item.usage) == HUG_JOYSTICK) || (HID_USAGE(item.usage) == HUG_GAME_PAD)) + { + result = true; + } + } + } + + hid_end_parse(data); + hid_dispose_report_desc(desc); + ::close(file); + + return result; + } + + void updatePluggedList() + { + /* + * Devices /dev/uhid are shared between joystick and any other + * human interface device. We need to iterate over all found devices + * and check if they are joysticks. The index of JoystickImpl::open + * does not match the /dev/uhid device! + */ + DIR* directory = opendir("/dev"); + + if (directory) + { + int joystickCount = 0; + struct dirent* directoryEntry = readdir(directory); + + while (directoryEntry && joystickCount < sf::Joystick::Count) + { + if (!std::strncmp(directoryEntry->d_name, "uhid", 4)) + { + std::string name("/dev/"); + name += directoryEntry->d_name; + + if (isJoystick(name.c_str())) + plugged[joystickCount++] = name; + } + + directoryEntry = readdir(directory); + } + + closedir(directory); + } + } + + int usageToAxis(int usage) + { + switch (usage) + { + case HUG_X: return sf::Joystick::X; + case HUG_Y: return sf::Joystick::Y; + case HUG_Z: return sf::Joystick::Z; + case HUG_RZ: return sf::Joystick::R; + case HUG_RX: return sf::Joystick::U; + case HUG_RY: return sf::Joystick::V; + default: return -1; + } + } + + void hatValueToSfml(int value, sf::priv::JoystickState& state) + { + state.axes[sf::Joystick::PovX] = hatValueMap[value].first; + state.axes[sf::Joystick::PovY] = hatValueMap[value].second; + } +} + + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +void JoystickImpl::initialize() +{ + hid_init(NULL); + + // Do an initial scan + updatePluggedList(); + + // Map of hat values + hatValueMap[0] = std::make_pair( 0, 0); // center + + hatValueMap[1] = std::make_pair( 0, -100); // top + hatValueMap[3] = std::make_pair( 100, 0); // right + hatValueMap[5] = std::make_pair( 0, 100); // bottom + hatValueMap[7] = std::make_pair(-100, 0); // left + + hatValueMap[2] = std::make_pair( 100, -100); // top-right + hatValueMap[4] = std::make_pair( 100, 100); // bottom-right + hatValueMap[6] = std::make_pair(-100, 100); // bottom-left + hatValueMap[8] = std::make_pair(-100, -100); // top-left +} + + +//////////////////////////////////////////////////////////// +void JoystickImpl::cleanup() +{ +} + + +//////////////////////////////////////////////////////////// +bool JoystickImpl::isConnected(unsigned int index) +{ + return plugged.find(index) != plugged.end(); +} + + +//////////////////////////////////////////////////////////// +bool JoystickImpl::open(unsigned int index) +{ + if (isConnected(index)) + { + // Open the joystick's file descriptor (read-only and non-blocking) + m_file = ::open(plugged[index].c_str(), O_RDONLY | O_NONBLOCK); + if (m_file >= 0) + { + // Reset the joystick state + m_state = JoystickState(); + + // Get the report descriptor + m_desc = hid_get_report_desc(m_file); + if (!m_desc) + { + ::close(m_file); + return false; + } + + // And the id + if (ioctl(m_file, USB_GET_REPORT_ID, &m_id) < 0) + { + ::close(m_file); + return false; + } + + // Then allocate a buffer for data retrieval + m_length = hid_report_size(m_desc, hid_input, m_id); + m_buffer.resize(m_length); + + m_state.connected = true; + + return true; + } + } + + return false; +} + + +//////////////////////////////////////////////////////////// +void JoystickImpl::close() +{ + ::close(m_file); + hid_dispose_report_desc(m_desc); +} + + +//////////////////////////////////////////////////////////// +JoystickCaps JoystickImpl::getCapabilities() const +{ + JoystickCaps caps; + hid_item_t item; + + hid_data_t data = hid_start_parse(m_desc, 1 << hid_input, m_id); + + while (hid_get_item(data, &item)) + { + if (item.kind == hid_input) + { + int usage = HID_USAGE(item.usage); + + if (usage == HUP_BUTTON) + { + caps.buttonCount++; + break; + } + else if (usage == HUP_GENERIC_DESKTOP) + { + int axis = usageToAxis(usage); + + if (usage == HUG_HAT_SWITCH) + { + caps.axes[Joystick::PovX] = true; + caps.axes[Joystick::PovY] = true; + } + else if (axis != -1) + { + caps.axes[axis] = true; + } + } + } + } + + hid_end_parse(data); + + return caps; +} + + +//////////////////////////////////////////////////////////// +Joystick::Identification JoystickImpl::getIdentification() const +{ + return m_identification; +} + + +//////////////////////////////////////////////////////////// +JoystickState JoystickImpl::JoystickImpl::update() +{ + while (read(m_file, &m_buffer[0], m_length) == m_length) + { + hid_data_t data = hid_start_parse(m_desc, 1 << hid_input, m_id); + + // No memory? + if (!data) + continue; + + int buttonIndex = 0; + hid_item_t item; + + while (hid_get_item(data, &item)) + { + if (item.kind == hid_input) + { + int usage = HID_USAGE(item.usage); + + if (usage == HUP_BUTTON) + { + m_state.buttons[buttonIndex++] = hid_get_data(&m_buffer[0], &item); + } + else if (usage == HUP_GENERIC_DESKTOP) + { + int value = hid_get_data(&m_buffer[0], &item); + int axis = usageToAxis(usage); + + if (usage == HUG_HAT_SWITCH) + { + hatValueToSfml(value, m_state); + } + else if (axis != -1) + { + int minimum = item.logical_minimum; + int maximum = item.logical_maximum; + + value = (value - minimum) * 200 / (maximum - minimum) - 100; + m_state.axes[axis] = value; + } + } + } + } + + hid_end_parse(data); + } + + return m_state; +} + +} // namespace priv + +} // namespace sf diff --git a/src/SFML/Window/NetBSD/JoystickImpl.hpp b/src/SFML/Window/NetBSD/JoystickImpl.hpp new file mode 100644 index 00000000..d91b166c --- /dev/null +++ b/src/SFML/Window/NetBSD/JoystickImpl.hpp @@ -0,0 +1,130 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2020 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_JOYSTICKIMPLNETBSD_HPP +#define SFML_JOYSTICKIMPLNETBSD_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief FreeBSD implementation of joysticks +/// +/// This code has been tested on FreeBSD 9.1 only. +//////////////////////////////////////////////////////////// +class JoystickImpl +{ +public: + + //////////////////////////////////////////////////////////// + /// \brief Perform the global initialization of the joystick module + /// + //////////////////////////////////////////////////////////// + static void initialize(); + + //////////////////////////////////////////////////////////// + /// \brief Perform the global cleanup of the joystick module + /// + //////////////////////////////////////////////////////////// + static void cleanup(); + + //////////////////////////////////////////////////////////// + /// \brief Check if a joystick is currently connected + /// + /// \param index Index of the joystick to check + /// + /// \return True if the joystick is connected, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isConnected(unsigned int index); + + //////////////////////////////////////////////////////////// + /// \brief Open the joystick + /// + /// \param index Index assigned to the joystick + /// + /// \return True on success, false on failure + /// + //////////////////////////////////////////////////////////// + bool open(unsigned int index); + + //////////////////////////////////////////////////////////// + /// \brief Close the joystick + /// + //////////////////////////////////////////////////////////// + void close(); + + //////////////////////////////////////////////////////////// + /// \brief Get the joystick capabilities + /// + /// \return Joystick capabilities + /// + //////////////////////////////////////////////////////////// + JoystickCaps getCapabilities() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the joystick identification + /// + /// \return Joystick identification + /// + //////////////////////////////////////////////////////////// + Joystick::Identification getIdentification() const; + + //////////////////////////////////////////////////////////// + /// \brief Update the joystick and get its new state + /// + /// \return Joystick state + /// + //////////////////////////////////////////////////////////// + JoystickState update(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + int m_file; ///< File descriptor of the joystick + report_desc_t m_desc; ///< USB report descriptor + int m_id; ///< USB id + std::vector m_buffer; ///< USB HID buffer + int m_length; ///< Buffer length + Joystick::Identification m_identification; ///< Joystick identification + JoystickState m_state; ///< Current state of the joystick +}; + +} // namespace priv + +} // namespace sf + + +#endif // SFML_JOYSTICKIMPLNETBSD_HPP diff --git a/src/SFML/Window/SensorImpl.hpp b/src/SFML/Window/SensorImpl.hpp index cd50911a..65796ada 100644 --- a/src/SFML/Window/SensorImpl.hpp +++ b/src/SFML/Window/SensorImpl.hpp @@ -35,7 +35,7 @@ #include -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD) #include diff --git a/src/SFML/Window/Vulkan.cpp b/src/SFML/Window/Vulkan.cpp index 1a13beeb..6749bd27 100644 --- a/src/SFML/Window/Vulkan.cpp +++ b/src/SFML/Window/Vulkan.cpp @@ -32,7 +32,7 @@ #include typedef sf::priv::VulkanImplWin32 VulkanImplType; -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD) #include typedef sf::priv::VulkanImplX11 VulkanImplType; diff --git a/src/SFML/Window/WindowImpl.cpp b/src/SFML/Window/WindowImpl.cpp index afbfddf8..d251f4eb 100644 --- a/src/SFML/Window/WindowImpl.cpp +++ b/src/SFML/Window/WindowImpl.cpp @@ -41,7 +41,7 @@ #include typedef sf::priv::VulkanImplWin32 VulkanImplType; -#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) +#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD) #include typedef sf::priv::WindowImplX11 WindowImplType;