Initial Commit

This commit is contained in:
2025-03-07 12:29:41 -05:00
commit 54355f07bc
4 changed files with 232 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@@ -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

6
CMakeLists.txt Normal file
View File

@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.30)
project(jstick)
set(CMAKE_CXX_STANDARD 20)
add_executable(jstick main.cpp)

6
jstick.hpp Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
void jstick_read_events();

212
main.cpp Normal file
View File

@@ -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 <fcntl.h>
#include <cstdio>
#include <unistd.h>
#include <linux/joystick.h>
#include <cstdint>
#include <cstring>
#include <string>
#include <iostream>
#include <filesystem>
/// 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;
}