You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
344 lines
10 KiB
344 lines
10 KiB
//======================================================================== |
|
// Joystick input test |
|
// Copyright (c) Camilla Löwy <elmindreda@glfw.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. |
|
// |
|
//======================================================================== |
|
// |
|
// This test displays the state of every button and axis of every connected |
|
// joystick and/or gamepad |
|
// |
|
//======================================================================== |
|
|
|
#include <glad/gl.h> |
|
#define GLFW_INCLUDE_NONE |
|
#include <GLFW/glfw3.h> |
|
|
|
#define NK_IMPLEMENTATION |
|
#define NK_INCLUDE_FIXED_TYPES |
|
#define NK_INCLUDE_FONT_BAKING |
|
#define NK_INCLUDE_DEFAULT_FONT |
|
#define NK_INCLUDE_DEFAULT_ALLOCATOR |
|
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT |
|
#define NK_INCLUDE_STANDARD_VARARGS |
|
#define NK_BUTTON_TRIGGER_ON_RELEASE |
|
#include <nuklear.h> |
|
|
|
#define NK_GLFW_GL2_IMPLEMENTATION |
|
#include <nuklear_glfw_gl2.h> |
|
|
|
#include <stdio.h> |
|
#include <string.h> |
|
#include <stdlib.h> |
|
|
|
#ifdef _MSC_VER |
|
#define strdup(x) _strdup(x) |
|
#endif |
|
|
|
static GLFWwindow* window; |
|
static int joysticks[GLFW_JOYSTICK_LAST + 1]; |
|
static int joystick_count = 0; |
|
|
|
static void error_callback(int error, const char* description) |
|
{ |
|
fprintf(stderr, "Error: %s\n", description); |
|
} |
|
|
|
static void joystick_callback(int jid, int event) |
|
{ |
|
if (event == GLFW_CONNECTED) |
|
joysticks[joystick_count++] = jid; |
|
else if (event == GLFW_DISCONNECTED) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < joystick_count; i++) |
|
{ |
|
if (joysticks[i] == jid) |
|
break; |
|
} |
|
|
|
for (i = i + 1; i < joystick_count; i++) |
|
joysticks[i - 1] = joysticks[i]; |
|
|
|
joystick_count--; |
|
} |
|
|
|
if (!glfwGetWindowAttrib(window, GLFW_FOCUSED)) |
|
glfwRequestWindowAttention(window); |
|
} |
|
|
|
static void drop_callback(GLFWwindow* window, int count, const char* paths[]) |
|
{ |
|
int i; |
|
|
|
for (i = 0; i < count; i++) |
|
{ |
|
long size; |
|
char* text; |
|
FILE* stream = fopen(paths[i], "rb"); |
|
if (!stream) |
|
continue; |
|
|
|
fseek(stream, 0, SEEK_END); |
|
size = ftell(stream); |
|
fseek(stream, 0, SEEK_SET); |
|
|
|
text = malloc(size + 1); |
|
text[size] = '\0'; |
|
if (fread(text, 1, size, stream) == size) |
|
glfwUpdateGamepadMappings(text); |
|
|
|
free(text); |
|
fclose(stream); |
|
} |
|
} |
|
|
|
static const char* joystick_label(int jid) |
|
{ |
|
static char label[1024]; |
|
snprintf(label, sizeof(label), "%i: %s", jid + 1, glfwGetJoystickName(jid)); |
|
return label; |
|
} |
|
|
|
static void hat_widget(struct nk_context* nk, unsigned char state) |
|
{ |
|
float radius; |
|
struct nk_rect area; |
|
struct nk_vec2 center; |
|
|
|
if (nk_widget(&area, nk) == NK_WIDGET_INVALID) |
|
return; |
|
|
|
center = nk_vec2(area.x + area.w / 2.f, area.y + area.h / 2.f); |
|
radius = NK_MIN(area.w, area.h) / 2.f; |
|
|
|
nk_stroke_circle(nk_window_get_canvas(nk), |
|
nk_rect(center.x - radius, |
|
center.y - radius, |
|
radius * 2.f, |
|
radius * 2.f), |
|
1.f, |
|
nk_rgb(175, 175, 175)); |
|
|
|
if (state) |
|
{ |
|
const float angles[] = |
|
{ |
|
0.f, 0.f, |
|
NK_PI * 1.5f, NK_PI * 1.75f, |
|
NK_PI, 0.f, |
|
NK_PI * 1.25f, 0.f, |
|
NK_PI * 0.5f, NK_PI * 0.25f, |
|
0.f, 0.f, |
|
NK_PI * 0.75f, 0.f, |
|
}; |
|
const float cosa = nk_cos(angles[state]); |
|
const float sina = nk_sin(angles[state]); |
|
const struct nk_vec2 p0 = nk_vec2(0.f, -radius); |
|
const struct nk_vec2 p1 = nk_vec2( radius / 2.f, -radius / 3.f); |
|
const struct nk_vec2 p2 = nk_vec2(-radius / 2.f, -radius / 3.f); |
|
|
|
nk_fill_triangle(nk_window_get_canvas(nk), |
|
center.x + cosa * p0.x + sina * p0.y, |
|
center.y + cosa * p0.y - sina * p0.x, |
|
center.x + cosa * p1.x + sina * p1.y, |
|
center.y + cosa * p1.y - sina * p1.x, |
|
center.x + cosa * p2.x + sina * p2.y, |
|
center.y + cosa * p2.y - sina * p2.x, |
|
nk_rgb(175, 175, 175)); |
|
} |
|
} |
|
|
|
int main(void) |
|
{ |
|
int jid, hat_buttons = GLFW_FALSE; |
|
struct nk_context* nk; |
|
struct nk_font_atlas* atlas; |
|
|
|
memset(joysticks, 0, sizeof(joysticks)); |
|
|
|
glfwSetErrorCallback(error_callback); |
|
|
|
if (!glfwInit()) |
|
exit(EXIT_FAILURE); |
|
|
|
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); |
|
|
|
window = glfwCreateWindow(800, 600, "Joystick Test", NULL, NULL); |
|
if (!window) |
|
{ |
|
glfwTerminate(); |
|
exit(EXIT_FAILURE); |
|
} |
|
|
|
glfwMakeContextCurrent(window); |
|
gladLoadGL(glfwGetProcAddress); |
|
glfwSwapInterval(1); |
|
|
|
nk = nk_glfw3_init(window, NK_GLFW3_INSTALL_CALLBACKS); |
|
nk_glfw3_font_stash_begin(&atlas); |
|
nk_glfw3_font_stash_end(); |
|
|
|
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++) |
|
{ |
|
if (glfwJoystickPresent(jid)) |
|
joysticks[joystick_count++] = jid; |
|
} |
|
|
|
glfwSetJoystickCallback(joystick_callback); |
|
glfwSetDropCallback(window, drop_callback); |
|
|
|
while (!glfwWindowShouldClose(window)) |
|
{ |
|
int i, width, height; |
|
|
|
glfwGetWindowSize(window, &width, &height); |
|
|
|
glClear(GL_COLOR_BUFFER_BIT); |
|
nk_glfw3_new_frame(); |
|
|
|
if (nk_begin(nk, |
|
"Joysticks", |
|
nk_rect(width - 200.f, 0.f, 200.f, (float) height), |
|
NK_WINDOW_MINIMIZABLE | |
|
NK_WINDOW_TITLE)) |
|
{ |
|
nk_layout_row_dynamic(nk, 30, 1); |
|
|
|
nk_checkbox_label(nk, "Hat buttons", &hat_buttons); |
|
|
|
if (joystick_count) |
|
{ |
|
for (i = 0; i < joystick_count; i++) |
|
{ |
|
if (nk_button_label(nk, joystick_label(joysticks[i]))) |
|
nk_window_set_focus(nk, joystick_label(joysticks[i])); |
|
} |
|
} |
|
else |
|
nk_label(nk, "No joysticks connected", NK_TEXT_LEFT); |
|
} |
|
|
|
nk_end(nk); |
|
|
|
for (i = 0; i < joystick_count; i++) |
|
{ |
|
if (nk_begin(nk, |
|
joystick_label(joysticks[i]), |
|
nk_rect(i * 20.f, i * 20.f, 550.f, 570.f), |
|
NK_WINDOW_BORDER | |
|
NK_WINDOW_MOVABLE | |
|
NK_WINDOW_SCALABLE | |
|
NK_WINDOW_MINIMIZABLE | |
|
NK_WINDOW_TITLE)) |
|
{ |
|
int j, axis_count, button_count, hat_count; |
|
const float* axes; |
|
const unsigned char* buttons; |
|
const unsigned char* hats; |
|
GLFWgamepadstate state; |
|
|
|
nk_layout_row_dynamic(nk, 30, 1); |
|
nk_labelf(nk, NK_TEXT_LEFT, "Hardware GUID %s", |
|
glfwGetJoystickGUID(joysticks[i])); |
|
nk_label(nk, "Joystick state", NK_TEXT_LEFT); |
|
|
|
axes = glfwGetJoystickAxes(joysticks[i], &axis_count); |
|
buttons = glfwGetJoystickButtons(joysticks[i], &button_count); |
|
hats = glfwGetJoystickHats(joysticks[i], &hat_count); |
|
|
|
if (!hat_buttons) |
|
button_count -= hat_count * 4; |
|
|
|
for (j = 0; j < axis_count; j++) |
|
nk_slide_float(nk, -1.f, axes[j], 1.f, 0.1f); |
|
|
|
nk_layout_row_dynamic(nk, 30, 12); |
|
|
|
for (j = 0; j < button_count; j++) |
|
{ |
|
char name[16]; |
|
snprintf(name, sizeof(name), "%i", j + 1); |
|
nk_select_label(nk, name, NK_TEXT_CENTERED, buttons[j]); |
|
} |
|
|
|
nk_layout_row_dynamic(nk, 30, 8); |
|
|
|
for (j = 0; j < hat_count; j++) |
|
hat_widget(nk, hats[j]); |
|
|
|
nk_layout_row_dynamic(nk, 30, 1); |
|
|
|
if (glfwGetGamepadState(joysticks[i], &state)) |
|
{ |
|
int hat = 0; |
|
const char* names[GLFW_GAMEPAD_BUTTON_LAST + 1 - 4] = |
|
{ |
|
"A", "B", "X", "Y", |
|
"LB", "RB", |
|
"Back", "Start", "Guide", |
|
"LT", "RT", |
|
}; |
|
|
|
nk_labelf(nk, NK_TEXT_LEFT, |
|
"Gamepad state: %s", |
|
glfwGetGamepadName(joysticks[i])); |
|
|
|
nk_layout_row_dynamic(nk, 30, 2); |
|
|
|
for (j = 0; j <= GLFW_GAMEPAD_AXIS_LAST; j++) |
|
nk_slide_float(nk, -1.f, state.axes[j], 1.f, 0.1f); |
|
|
|
nk_layout_row_dynamic(nk, 30, GLFW_GAMEPAD_BUTTON_LAST + 1 - 4); |
|
|
|
for (j = 0; j <= GLFW_GAMEPAD_BUTTON_LAST - 4; j++) |
|
nk_select_label(nk, names[j], NK_TEXT_CENTERED, state.buttons[j]); |
|
|
|
if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP]) |
|
hat |= GLFW_HAT_UP; |
|
if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT]) |
|
hat |= GLFW_HAT_RIGHT; |
|
if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN]) |
|
hat |= GLFW_HAT_DOWN; |
|
if (state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT]) |
|
hat |= GLFW_HAT_LEFT; |
|
|
|
nk_layout_row_dynamic(nk, 30, 8); |
|
hat_widget(nk, hat); |
|
} |
|
else |
|
nk_label(nk, "Joystick has no gamepad mapping", NK_TEXT_LEFT); |
|
} |
|
|
|
nk_end(nk); |
|
} |
|
|
|
nk_glfw3_render(NK_ANTI_ALIASING_ON); |
|
|
|
glfwSwapBuffers(window); |
|
glfwPollEvents(); |
|
} |
|
|
|
glfwTerminate(); |
|
exit(EXIT_SUCCESS); |
|
} |
|
|
|
|