diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index cc23fbaa..13542862 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -20,6 +20,7 @@ else(SFML_OS_IOS) add_subdirectory(window) endif() if(SFML_BUILD_GRAPHICS) + add_subdirectory(joystick) add_subdirectory(opengl) add_subdirectory(shader) if(SFML_OS_WINDOWS) diff --git a/examples/joystick/CMakeLists.txt b/examples/joystick/CMakeLists.txt new file mode 100644 index 00000000..f04dc7fc --- /dev/null +++ b/examples/joystick/CMakeLists.txt @@ -0,0 +1,11 @@ + +set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/joystick) + +# all source files +set(SRC ${SRCROOT}/Joystick.cpp) + +# define the joystick target +sfml_add_example(joystick GUI_APP + SOURCES ${SRC} + DEPENDS sfml-graphics sfml-window sfml-system + RESOURCES_DIR resources) diff --git a/examples/joystick/Joystick.cpp b/examples/joystick/Joystick.cpp new file mode 100644 index 00000000..0ff7cf91 --- /dev/null +++ b/examples/joystick/Joystick.cpp @@ -0,0 +1,238 @@ + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace +{ + struct JoystickObject + { + sf::Text label; + sf::Text value; + }; + + typedef std::map Texts; + Texts texts; + std::ostringstream sstr; + float threshold = 0.1f; + + // Axes labels in as C strings + const char* axislabels[] = {"X", "Y", "Z", "R", "U", "V", "PovX", "PovY"}; + + // Helper to set text entries to a specified value + template + void set(const char* label, const T& value) + { + sstr.str(""); + sstr << value; + texts[label].value.setString(sstr.str()); + } + + // Update joystick identification + void updateIdentification(unsigned int index) + { + sstr.str(""); + sstr << "Joystick " << index << ":"; + texts["ID"].label.setString(sstr.str()); + texts["ID"].value.setString(sf::Joystick::getIdentification(index).name); + } + + // Update joystick axes + void updateAxes(unsigned int index) + { + for (unsigned int j = 0; j < sf::Joystick::AxisCount; ++j) + { + if (sf::Joystick::hasAxis(index, static_cast(j))) + set(axislabels[j], sf::Joystick::getAxisPosition(index, static_cast(j))); + } + } + + // Update joystick buttons + void updateButtons(unsigned int index) + { + for (unsigned int j = 0; j < sf::Joystick::getButtonCount(index); ++j) + { + sstr.str(""); + sstr << "Button " << j; + + set(sstr.str().c_str(), sf::Joystick::isButtonPressed(index, j)); + } + } + + // Helper to update displayed joystick values + void updateValues(unsigned int index) + { + if (sf::Joystick::isConnected(index)) { + // Update the label-value sf::Text objects based on the current joystick state + updateIdentification(index); + updateAxes(index); + updateButtons(index); + } + } +} + + +//////////////////////////////////////////////////////////// +/// Entry point of application +/// +/// \return Application exit code +/// +//////////////////////////////////////////////////////////// +int main() +{ + // Create the window of the application + sf::RenderWindow window(sf::VideoMode(400, 680), "Joystick", sf::Style::Close); + window.setVerticalSyncEnabled(true); + + // Load the text font + sf::Font font; + if (!font.loadFromFile("resources/sansation.ttf")) + return EXIT_FAILURE; + + // Set up our string conversion parameters + sstr.precision(2); + sstr.setf(std::ios::fixed | std::ios::boolalpha); + + // Set up our joystick identification sf::Text objects + texts["ID"].label.setPosition(5.f, 5.f); + texts["ID"].value.setPosition(80.f, 5.f); + + texts["ID"].label.setString(""); + texts["ID"].value.setString(""); + + // Set up our threshold sf::Text objects + sstr.str(""); + sstr << threshold << " (Change with up/down arrow keys)"; + + texts["Threshold"].label.setPosition(5.f, 5.f + 2 * font.getLineSpacing(14)); + texts["Threshold"].value.setPosition(80.f, 5.f + 2 * font.getLineSpacing(14)); + + texts["Threshold"].label.setString("Threshold:"); + texts["Threshold"].value.setString(sstr.str()); + + // Set up our label-value sf::Text objects + for (unsigned int i = 0; i < sf::Joystick::AxisCount; ++i) + { + JoystickObject& object = texts[axislabels[i]]; + + object.label.setPosition(5.f, 5.f + ((i + 4) * font.getLineSpacing(14))); + object.label.setString(std::string(axislabels[i]) + ":"); + + object.value.setPosition(80.f, 5.f + ((i + 4) * font.getLineSpacing(14))); + object.value.setString("N/A"); + } + + for (unsigned int i = 0; i < sf::Joystick::ButtonCount; ++i) + { + sstr.str(""); + sstr << "Button " << i; + JoystickObject& object = texts[sstr.str()]; + + object.label.setPosition(5.f, 5.f + ((sf::Joystick::AxisCount + i + 4) * font.getLineSpacing(14))); + object.label.setString(sstr.str() + ":"); + + object.value.setPosition(80.f, 5.f + ((sf::Joystick::AxisCount + i + 4) * font.getLineSpacing(14))); + object.value.setString("N/A"); + } + + for (Texts::iterator it = texts.begin(); it != texts.end(); ++it) + { + it->second.label.setFont(font); + it->second.label.setCharacterSize(14); + it->second.label.setFillColor(sf::Color::White); + + it->second.value.setFont(font); + it->second.value.setCharacterSize(14); + it->second.value.setFillColor(sf::Color::White); + } + + // Update initially displayed joystick values if a joystick is already connected on startup + for (unsigned int i = 0; i < sf::Joystick::Count; ++i) + { + if (sf::Joystick::isConnected(i)) + { + updateValues(i); + break; + } + } + + while (window.isOpen()) + { + // Handle events + sf::Event event; + while (window.pollEvent(event)) + { + // Window closed or escape key pressed: exit + if ((event.type == sf::Event::Closed) || + ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))) + { + window.close(); + break; + } + else if ((event.type == sf::Event::JoystickButtonPressed) || + (event.type == sf::Event::JoystickButtonReleased) || + (event.type == sf::Event::JoystickMoved) || + (event.type == sf::Event::JoystickConnected)) + { + // Update displayed joystick values + updateValues(event.joystickConnect.joystickId); + } + else if (event.type == sf::Event::JoystickDisconnected) + { + // Reset displayed joystick values to empty + for (Texts::iterator it = texts.begin(); it != texts.end(); ++it) + it->second.value.setString("N/A"); + + texts["ID"].label.setString(""); + texts["ID"].value.setString(""); + + sstr.str(""); + sstr << threshold << " (Change with up/down arrow keys)"; + + texts["Threshold"].value.setString(sstr.str()); + } + } + + // Update threshold if the user wants to change it + float newThreshold = threshold; + + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) + newThreshold += 0.1f; + + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) + newThreshold -= 0.1f; + + newThreshold = std::min(std::max(newThreshold, 0.1f), 100.0f); + + if (newThreshold != threshold) + { + threshold = newThreshold; + window.setJoystickThreshold(threshold); + + sstr.str(""); + sstr << threshold << " (Change with up/down arrow keys)"; + + texts["Threshold"].value.setString(sstr.str()); + } + + // Clear the window + window.clear(); + + // Draw the label-value sf::Text objects + for (Texts::const_iterator it = texts.begin(); it != texts.end(); ++it) + { + window.draw(it->second.label); + window.draw(it->second.value); + } + + // Display things on screen + window.display(); + } +} diff --git a/examples/joystick/resources/sansation.ttf b/examples/joystick/resources/sansation.ttf new file mode 100644 index 00000000..d85fbc81 Binary files /dev/null and b/examples/joystick/resources/sansation.ttf differ