Initial Commit
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal 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
6
CMakeLists.txt
Normal 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
6
jstick.hpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void jstick_read_events();
|
212
main.cpp
Normal file
212
main.cpp
Normal 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;
|
||||||
|
}
|
Reference in New Issue
Block a user