From 54355f07bc1ff974c75209ff4052f0ed5d858918 Mon Sep 17 00:00:00 2001 From: josh Date: Fri, 7 Mar 2025 12:29:41 -0500 Subject: [PATCH] Initial Commit --- .idea/.gitignore | 8 ++ CMakeLists.txt | 6 ++ jstick.hpp | 6 ++ main.cpp | 212 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 CMakeLists.txt create mode 100644 jstick.hpp create mode 100644 main.cpp diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..453e7a5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.30) +project(jstick) + +set(CMAKE_CXX_STANDARD 20) + +add_executable(jstick main.cpp) diff --git a/jstick.hpp b/jstick.hpp new file mode 100644 index 0000000..631b250 --- /dev/null +++ b/jstick.hpp @@ -0,0 +1,6 @@ +#pragma once + + + + +void jstick_read_events(); \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..aacfc60 --- /dev/null +++ b/main.cpp @@ -0,0 +1,212 @@ +/** + * Author: Jason White + * + * Description: + * Reads joystick/gamepad events and displays them. + * + * Compile: + * gcc joystick.c -o joystick + * + * Run: + * ./joystick [/dev/input/jsX] + * + * See also: + * https://www.kernel.org/doc/Documentation/input/joystick-api.txt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/// Reads a joystick event from the joystick device. +/// @returns 0 on success. Otherwise -1 is returned. +int read_event(int fd, struct js_event *event) +{ + ssize_t bytes; + + bytes = read(fd, event, sizeof(*event)); + + if (bytes == sizeof(*event)) + return 0; + + /// Error, could not read full event. + return -1; +} + +/// @returns the number of axes on the controller or 0 if an error occurs. +size_t get_axis_count(int fd) +{ + __u8 axes; + + if (ioctl(fd, JSIOCGAXES, &axes) == -1) + return 0; + + return axes; +} + +/// @returns the number of buttons on the controller or 0 if an error occurs. +size_t get_button_count(int fd) +{ + __u8 buttons; + if (ioctl(fd, JSIOCGBUTTONS, &buttons) == -1) + return 0; + + return buttons; +} + +/// Current state of an axis. +struct axis_state { + short x, y; +}; + +/// Keeps track of the current axis state. +/// @note This function assumes that axes are numbered starting from 0, and that +/// the X axis is an even number, and the Y axis is an odd number. However, this +/// is usually a safe assumption. +/// @returns the axis that the event indicated. +size_t get_axis_state(struct js_event *event, struct axis_state axes[3]) +{ + size_t axis = event->number / 2; + + if (axis < 3) + { + if (event->number % 2 == 0) + axes[axis].x = event->value; + else + axes[axis].y = event->value; + } + + return axis; +} + +uint8_t get_num_axes(int joystick_handle) { + char num_axes; + ioctl(joystick_handle, JSIOCGAXES, &num_axes); + return num_axes; +} + +std::string get_joystick_name(int joystick_handle) +{ + char name_buf[128]; + if (ioctl(joystick_handle, JSIOCGNAME(sizeof(name_buf)), name_buf) < 0) + strncpy(name_buf, "Unknown", sizeof(name_buf)); + return std::string(name_buf); +} + +int get_joystick_driver_ver(int joystick_handle) +{ + int version; + ioctl(joystick_handle, JSIOCGVERSION, &version); + return version; +} + +bool check_for_joystick_device() +{ + return std::filesystem::exists("/dev/input/js0"); +} + +int js; +bool device_open; + +bool connect_device() { + js = open("/dev/input/js0", O_NONBLOCK); + + if (js == -1) + perror("Could not open joystick"); + + + std::cout << get_joystick_name(js) << std::endl; + std::cout << get_joystick_driver_ver(js) << std::endl; + std::cout << get_axis_count(js) << std::endl; +} + +void disconnect_device() { + close(js); +} + +int main(int argc, char *argv[]) +{ + const char *device; + + struct js_event event; + struct axis_state axes[3] = {0}; + size_t axis; + + //if (argc > 1) + // device = argv[1]; + //else + // device = "/dev/input/js0"; + // + // js = open(device, O_NONBLOCK); + + if (js == -1) + perror("Could not open joystick"); + + + std::cout << get_joystick_name(js) << std::endl; + std::cout << get_joystick_driver_ver(js) << std::endl; + std::cout << get_axis_count(js) << std::endl; + + /// This loop will exit if the controller is unplugged. + + bool had = false; + + while (1) + { + bool has_file = check_for_joystick_device(); + + if (has_file && !had) { + if (js == -1) + { + std::cout << "Controller plugged in!" << std::endl; + js = open(device, O_NONBLOCK); + + if (js == -1) + perror("Could not open joystick"); + } + + } else if (!has_file && had) { + std::cout << "Controller unplugged!" << std::endl; + if (js != -1) { + close(js); + js = -1; + } + + + } + + had = has_file; + + + while (read_event(js, &event) == 0) + { + switch (event.type) + { + case JS_EVENT_BUTTON: + printf("Button %u %s\n", event.number, event.value ? "pressed" : "released"); + break; + case JS_EVENT_AXIS: + axis = get_axis_state(&event, axes); + if (axis < 3) + printf("Axis %zu at (%6d, %6d)\n", axis, axes[axis].x, axes[axis].y); + break; + case JS_EVENT_INIT: + default: + /// Ignore init events. + break; + } + + fflush(stdout); + } + } + + + close(js); + return 0; +}