2012-08-15 02:41:21 +02:00
|
|
|
/*
|
|
|
|
* This software is licensed under the terms of the MIT-License
|
2017-02-11 04:52:08 +01:00
|
|
|
* See COPYING for further information.
|
2012-08-15 02:41:21 +02:00
|
|
|
* ---
|
|
|
|
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
|
2012-08-15 02:48:19 +02:00
|
|
|
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
|
2012-08-15 02:41:21 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gamepad.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "events.h"
|
2012-08-15 16:36:39 +02:00
|
|
|
#include "global.h"
|
2012-08-15 02:41:21 +02:00
|
|
|
|
|
|
|
static struct {
|
|
|
|
int initialized;
|
2017-07-15 05:22:56 +02:00
|
|
|
SDL_GameController *device;
|
|
|
|
SDL_JoystickID instance;
|
2017-02-27 23:58:47 +01:00
|
|
|
signed char *axis;
|
2017-07-15 05:22:56 +02:00
|
|
|
|
|
|
|
struct {
|
|
|
|
int *id_map;
|
|
|
|
size_t count;
|
|
|
|
} devices;
|
2012-08-15 02:41:21 +02:00
|
|
|
} gamepad;
|
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
static void gamepad_update_device_list(void) {
|
|
|
|
int cnt = SDL_NumJoysticks();
|
|
|
|
log_info("Updating gamepad devices list");
|
|
|
|
|
|
|
|
free(gamepad.devices.id_map);
|
|
|
|
memset(&gamepad.devices, 0, sizeof(gamepad.devices));
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
if(!cnt) {
|
2012-08-15 02:41:21 +02:00
|
|
|
return;
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int *idmap_ptr = gamepad.devices.id_map = malloc(sizeof(int) * cnt);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
for(int i = 0; i < cnt; ++i) {
|
|
|
|
if(!SDL_IsGameController(i)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*idmap_ptr = i;
|
|
|
|
log_info("Gamepad device #%"PRIuMAX": %s", (uintmax_t)(idmap_ptr - gamepad.devices.id_map), SDL_GameControllerNameForIndex(i));
|
|
|
|
++idmap_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
gamepad.devices.count = (uintptr_t)(idmap_ptr - gamepad.devices.id_map);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_init(void) {
|
|
|
|
if(!config_get_int(CONFIG_GAMEPAD_ENABLED) || gamepad.initialized) {
|
2012-08-16 23:35:48 +02:00
|
|
|
return;
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
if(SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0) {
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
log_warn("SDL_InitSubSystem() failed: %s", SDL_GetError());
|
2012-08-15 02:41:21 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
gamepad_update_device_list();
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
int dev = config_get_int(CONFIG_GAMEPAD_DEVICE);
|
2017-07-15 05:22:56 +02:00
|
|
|
if(dev < 0 || dev >= gamepad.devices.count) {
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
log_warn("Device #%i is not available", dev);
|
2012-08-15 02:41:21 +02:00
|
|
|
gamepad_shutdown();
|
|
|
|
return;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
gamepad.device = SDL_GameControllerOpen(dev);
|
2012-08-15 02:41:21 +02:00
|
|
|
if(!gamepad.device) {
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
log_warn("Failed to open device %i: %s", dev, SDL_GetError());
|
2012-08-15 02:41:21 +02:00
|
|
|
gamepad_shutdown();
|
|
|
|
return;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
SDL_Joystick *joy = SDL_GameControllerGetJoystick(gamepad.device);
|
|
|
|
gamepad.instance = SDL_JoystickInstanceID(joy);
|
|
|
|
gamepad.axis = malloc(max(SDL_JoystickNumAxes(joy), 1));
|
2017-02-27 23:58:47 +01:00
|
|
|
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
log_info("Using device #%i: %s", dev, gamepad_devicename(dev));
|
2017-07-15 05:22:56 +02:00
|
|
|
SDL_GameControllerEventState(SDL_ENABLE);
|
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
gamepad.initialized = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_shutdown(void) {
|
2017-07-15 05:22:56 +02:00
|
|
|
if(!gamepad.initialized) {
|
2012-08-17 14:59:06 +02:00
|
|
|
return;
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
if(gamepad.initialized != 2) {
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
log_info("Disabled the gamepad subsystem");
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
if(gamepad.device) {
|
|
|
|
SDL_GameControllerClose(gamepad.device);
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-27 23:58:47 +01:00
|
|
|
free(gamepad.axis);
|
2017-07-15 05:22:56 +02:00
|
|
|
free(gamepad.devices.id_map);
|
2017-02-27 23:58:47 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
SDL_GameControllerEventState(SDL_IGNORE);
|
|
|
|
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
|
|
|
|
|
|
|
memset(&gamepad, 0, sizeof(gamepad));
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_restart(void) {
|
|
|
|
gamepad_shutdown();
|
|
|
|
gamepad_init();
|
|
|
|
}
|
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
int gamepad_axis2gamekey(SDL_GameControllerAxis id, int val) {
|
2017-03-06 16:32:51 +01:00
|
|
|
val *= sign(gamepad_axis_sens(id));
|
2017-02-04 14:41:15 +01:00
|
|
|
|
|
|
|
if(!val) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_LR)) {
|
2012-08-15 14:33:32 +02:00
|
|
|
return val == AXISVAL_LEFT ? KEY_LEFT : KEY_RIGHT;
|
2017-02-04 14:41:15 +01:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_UD)) {
|
2012-08-15 14:33:32 +02:00
|
|
|
return val == AXISVAL_UP ? KEY_UP : KEY_DOWN;
|
2017-02-04 14:41:15 +01:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 14:33:32 +02:00
|
|
|
return -1;
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
int gamepad_axis2menuevt(SDL_GameControllerAxis id, int val) {
|
|
|
|
if(id == SDL_CONTROLLER_AXIS_LEFTX || id == SDL_CONTROLLER_AXIS_RIGHTX)
|
2012-08-15 14:33:32 +02:00
|
|
|
return val == AXISVAL_LEFT ? E_CursorLeft : E_CursorRight;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
if(id == SDL_CONTROLLER_AXIS_LEFTY || id == SDL_CONTROLLER_AXIS_RIGHTY)
|
2012-08-15 14:33:32 +02:00
|
|
|
return val == AXISVAL_UP ? E_CursorUp : E_CursorDown;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 14:33:32 +02:00
|
|
|
return -1;
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
int gamepad_axis2gameevt(SDL_GameControllerAxis id) {
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_LR))
|
2012-08-15 16:36:39 +02:00
|
|
|
return E_PlrAxisLR;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_UD))
|
2012-08-15 16:36:39 +02:00
|
|
|
return E_PlrAxisUD;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 16:36:39 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
float gamepad_axis_sens(SDL_GameControllerAxis id) {
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_LR))
|
|
|
|
return config_get_float(CONFIG_GAMEPAD_AXIS_LR_SENS);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
if(id == config_get_int(CONFIG_GAMEPAD_AXIS_UD))
|
|
|
|
return config_get_float(CONFIG_GAMEPAD_AXIS_UD_SENS);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 17:03:53 +02:00
|
|
|
return 1.0;
|
|
|
|
}
|
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
void gamepad_axis(SDL_GameControllerAxis id, int raw, EventHandler handler, EventFlags flags, void *arg) {
|
2017-02-27 23:58:47 +01:00
|
|
|
signed char *a = gamepad.axis;
|
|
|
|
signed char val = AXISVAL(raw);
|
|
|
|
bool free = config_get_int(CONFIG_GAMEPAD_AXIS_FREE);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-27 23:58:47 +01:00
|
|
|
bool menu = flags & EF_Menu;
|
|
|
|
bool game = flags & EF_Game;
|
|
|
|
bool gp = flags & EF_Gamepad;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 17:03:53 +02:00
|
|
|
//printf("axis: %i %i %i\n", id, val, raw);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 16:36:39 +02:00
|
|
|
if(game && free) {
|
|
|
|
int evt = gamepad_axis2gameevt(id);
|
2017-02-04 14:41:15 +01:00
|
|
|
if(evt >= 0) {
|
|
|
|
double sens = gamepad_axis_sens(id);
|
2017-03-06 16:32:51 +01:00
|
|
|
int sens_sign = sign(sens);
|
2017-02-04 14:41:15 +01:00
|
|
|
|
2017-02-27 23:58:47 +01:00
|
|
|
double x = raw / (double)GAMEPAD_AXIS_MAX;
|
2017-03-06 16:32:51 +01:00
|
|
|
int in_sign = sign(x);
|
2017-02-04 14:41:15 +01:00
|
|
|
|
|
|
|
x = pow(fabs(x), 1.0 / fabs(sens)) * in_sign * sens_sign;
|
|
|
|
x = x ? x : 0;
|
2017-02-27 23:58:47 +01:00
|
|
|
x = clamp(x * GAMEPAD_AXIS_MAX, GAMEPAD_AXIS_MIN, GAMEPAD_AXIS_MAX);
|
2017-02-04 14:41:15 +01:00
|
|
|
|
|
|
|
handler(evt, x, arg);
|
|
|
|
}
|
2012-08-15 16:36:39 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
if(val) { // simulate press
|
|
|
|
if(!a[id]) {
|
|
|
|
a[id] = val;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 16:36:39 +02:00
|
|
|
if(game && !free) {
|
2012-08-15 14:33:32 +02:00
|
|
|
int key = gamepad_axis2gamekey(id, val);
|
2017-07-15 05:22:56 +02:00
|
|
|
if(key >= 0) {
|
2012-08-15 14:33:32 +02:00
|
|
|
handler(E_PlrKeyDown, key, arg);
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
2012-08-15 14:33:32 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 14:33:32 +02:00
|
|
|
if(menu) {
|
|
|
|
int evt = gamepad_axis2menuevt(id, val);
|
2017-07-15 05:22:56 +02:00
|
|
|
if(evt >= 0) {
|
2012-08-15 14:33:32 +02:00
|
|
|
handler(evt, 0, arg);
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
2012-08-15 14:33:32 +02:00
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
} else { // simulate release
|
2012-08-15 14:33:32 +02:00
|
|
|
if(game) {
|
|
|
|
int key = gamepad_axis2gamekey(id, a[id]);
|
|
|
|
handler(E_PlrKeyUp, key, arg);
|
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
a[id] = AXISVAL_NULL;
|
|
|
|
}
|
2017-02-27 23:58:47 +01:00
|
|
|
|
|
|
|
if(gp) {
|
|
|
|
// we probably need a better way to pass more than an int to the handler...
|
|
|
|
handler(E_GamepadAxis, id, arg);
|
|
|
|
handler(E_GamepadAxisValue, raw, arg);
|
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
void gamepad_button(SDL_GameControllerButton button, int state, EventHandler handler, EventFlags flags, void *arg) {
|
2012-08-15 02:41:21 +02:00
|
|
|
int menu = flags & EF_Menu;
|
|
|
|
int game = flags & EF_Game;
|
2012-08-17 00:41:33 +02:00
|
|
|
int gpad = flags & EF_Gamepad;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
int gpkey = config_gamepad_key_from_gamepad_button(button);
|
|
|
|
int key = config_key_from_gamepad_key(gpkey);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
if(state == SDL_PRESSED) {
|
2017-07-15 05:22:56 +02:00
|
|
|
if(game) switch(button) {
|
|
|
|
case SDL_CONTROLLER_BUTTON_START:
|
|
|
|
case SDL_CONTROLLER_BUTTON_BACK:
|
|
|
|
handler(E_Pause, 0, arg); break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if(key >= 0) {
|
|
|
|
handler(E_PlrKeyDown, key, arg);
|
|
|
|
} break;
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
if(menu) switch(button) {
|
|
|
|
case SDL_CONTROLLER_BUTTON_DPAD_UP: handler(E_CursorUp, 0, arg); break;
|
|
|
|
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: handler(E_CursorDown, 0, arg); break;
|
|
|
|
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: handler(E_CursorLeft, 0, arg); break;
|
|
|
|
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: handler(E_CursorRight, 0, arg); break;
|
|
|
|
|
|
|
|
case SDL_CONTROLLER_BUTTON_A:
|
|
|
|
case SDL_CONTROLLER_BUTTON_START:
|
|
|
|
handler(E_MenuAccept, 0, arg); break;
|
|
|
|
|
|
|
|
case SDL_CONTROLLER_BUTTON_B:
|
|
|
|
case SDL_CONTROLLER_BUTTON_BACK:
|
|
|
|
handler(E_MenuAbort, 0, arg); break;
|
|
|
|
|
|
|
|
default: break;
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
if(gpad) {
|
2012-08-17 00:41:33 +02:00
|
|
|
handler(E_GamepadKeyDown, button, arg);
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
2012-08-17 00:41:33 +02:00
|
|
|
} else {
|
2017-07-15 05:22:56 +02:00
|
|
|
if(game && key >= 0) {
|
2012-08-17 00:41:33 +02:00
|
|
|
handler(E_PlrKeyUp, key, arg);
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
if(gpad) {
|
2012-08-17 00:41:33 +02:00
|
|
|
handler(E_GamepadKeyUp, button, arg);
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
2012-08-17 00:41:33 +02:00
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_event(SDL_Event *event, EventHandler handler, EventFlags flags, void *arg) {
|
|
|
|
if(!gamepad.initialized)
|
|
|
|
return;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
int val;
|
2017-03-18 05:41:19 +01:00
|
|
|
int vsign;
|
2017-03-18 05:51:56 +01:00
|
|
|
float deadzone = clamp(config_get_float(CONFIG_GAMEPAD_AXIS_DEADZONE), 0, 0.999);
|
2017-03-18 05:41:19 +01:00
|
|
|
int minval = clamp(deadzone, 0, 1) * GAMEPAD_AXIS_MAX;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-15 02:41:21 +02:00
|
|
|
switch(event->type) {
|
2017-07-15 05:22:56 +02:00
|
|
|
case SDL_CONTROLLERAXISMOTION:
|
|
|
|
if(event->caxis.which == gamepad.instance) {
|
|
|
|
val = event->caxis.value;
|
|
|
|
vsign = sign(val);
|
|
|
|
val = abs(val);
|
|
|
|
|
|
|
|
if(val < minval) {
|
|
|
|
val = 0;
|
|
|
|
} else {
|
|
|
|
val = vsign * clamp((val - minval) / (1.0 - deadzone), 0, GAMEPAD_AXIS_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
gamepad_axis(event->caxis.axis, val, handler, flags, arg);
|
2017-03-18 05:41:19 +01:00
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
break;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
case SDL_CONTROLLERBUTTONDOWN:
|
|
|
|
case SDL_CONTROLLERBUTTONUP:
|
|
|
|
if(event->cbutton.which == gamepad.instance) {
|
|
|
|
gamepad_button(event->cbutton.button, event->cbutton.state, handler, flags, arg);
|
|
|
|
}
|
2012-08-15 02:41:21 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-08-16 23:35:48 +02:00
|
|
|
|
|
|
|
int gamepad_devicecount(void) {
|
2017-07-15 05:22:56 +02:00
|
|
|
return gamepad.devices.count;
|
2012-08-16 23:35:48 +02:00
|
|
|
}
|
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
const char* gamepad_devicename(int id) {
|
|
|
|
if(id < 0 || id >= gamepad.devices.count) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SDL_GameControllerNameForIndex(gamepad.devices.id_map[id]);
|
2012-08-16 23:35:48 +02:00
|
|
|
}
|
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
bool gamepad_buttonpressed(SDL_GameControllerButton btn) {
|
|
|
|
return SDL_GameControllerGetButton(gamepad.device, btn);
|
2012-08-17 20:58:23 +02:00
|
|
|
}
|
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
bool gamepad_gamekeypressed(KeyIndex key) {
|
2012-08-17 20:58:23 +02:00
|
|
|
if(!gamepad.initialized)
|
2017-02-17 17:03:49 +01:00
|
|
|
return false;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
int gpkey = config_gamepad_key_from_key(key);
|
2017-02-27 23:04:30 +01:00
|
|
|
|
|
|
|
if(gpkey < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
int cfgidx = GPKEYIDX_TO_CFGIDX(gpkey);
|
|
|
|
int button = config_get_int(cfgidx);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-02-17 17:03:49 +01:00
|
|
|
return gamepad_buttonpressed(button);
|
2012-08-17 20:58:23 +02:00
|
|
|
}
|
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
void gamepad_init_bare(void) {
|
2017-07-15 05:22:56 +02:00
|
|
|
if(gamepad.initialized) {
|
2012-08-16 23:35:48 +02:00
|
|
|
return;
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
if(SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0) {
|
Implemented a simple and consistent logging subsystem
The goal of this change is mainly to clean up Taisei's codebase and
improve its console output. I've been frustrated by files littered with
inconsistent printf/fprintf/warnx/errx calls for a long time, and now I
actually did something about it.
All the above functions are now considered deprecated and result in a
compile-time warning when used. Instead, the following macros should be
used:
log_debug(format, ...)
log_info(format, ...)
log_warn(format, ...)
log_err(format, ...)
As you can see, all of them have the same printf-like interface. But
they have different functionality and purpose:
log_debug is intended for very verbose and specific information. It
does nothing in release builds, much like assert(), so don't use
expressions with side-effects in its arguments.
log_info is for various status updates that are expected during
normal operation of the program.
log_warn is for non-critical failures or other things that may be
worth investigating, but don't inherently render the program
non-functional.
log_err is for when the only choice is to give up. Like errx, it
also terminates the program. Unlike errx, it actually calls abort(),
which means the cleanup functions are not ran -- but on the other
hand, you get a debuggable backtrace. However, if you're trying to
catch programming errors, consider using assert() instead.
All of them produce output that contains a timestamp, the log level
identifier, the calling function's name, and the formatted message.
The newline at the end of the format string is not required -- no, it is
actually *prohibited*. The logging system will take care of the line
breaks by itself, don't litter the code with that shit.
Internally, the logging system is based on the SDL_RWops abstraction,
and may have multiple, configurable destinations. This makes it easily
extensible. Currently, log_debug and log_info are set to write to
stdout, log_warn and log_err to stderr, and all of them also to the file
log.txt in the Taisei config directory.
Consequently, the nasty freopen hacks we used to make Taisei write to
log files on Windows are no longer needed -- which is a very good thing,
considering they probably would break if the configdir path contains
UTF-8 characters. SDL_RWFromFile does not suffer this limitation.
As an added bonus, it's also thread-safe.
Note about printf and fprintf: in very few cases, the logging system is
not a good substitute for these functions. That is, when you care about
writing exactly to stdout/stderr and about exactly how the output looks.
However, I insist on keeping the deprecation warnings on them to not
tempt anyone to use them for logging/debugging out of habit and/or
laziness.
For this reason, I've added a tsfprintf function to util.c. It is
functionally identical to fprintf, except it returns void. Yes, the name
is deliberately ugly. Avoid using it if possible, but if you must, only
use it to write to stdout or stderr. Do not write to actual files with
it, use SDL_RWops.
2017-03-13 03:51:58 +01:00
|
|
|
log_warn("SDL_InitSubSystem() failed: %s", SDL_GetError());
|
2012-08-16 23:35:48 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-07-15 05:22:56 +02:00
|
|
|
gamepad_update_device_list();
|
2012-08-16 23:35:48 +02:00
|
|
|
gamepad.initialized = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gamepad_shutdown_bare(void) {
|
2017-07-15 05:22:56 +02:00
|
|
|
if(gamepad.initialized == 2) {
|
2012-08-16 23:35:48 +02:00
|
|
|
gamepad_shutdown();
|
2017-07-15 05:22:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* gamepad_button_name(SDL_GameControllerButton btn) {
|
|
|
|
static const char *const map[] = {
|
|
|
|
"A",
|
|
|
|
"B",
|
|
|
|
"X",
|
|
|
|
"Y",
|
|
|
|
"Back",
|
|
|
|
"Guide",
|
|
|
|
"Start",
|
|
|
|
"Left Stick",
|
|
|
|
"Right Stick",
|
|
|
|
"Left Bumper",
|
|
|
|
"Right Bumper",
|
|
|
|
"Up",
|
|
|
|
"Down",
|
|
|
|
"Left",
|
|
|
|
"Right",
|
|
|
|
};
|
|
|
|
|
|
|
|
if(btn > SDL_CONTROLLER_BUTTON_INVALID && btn < SDL_CONTROLLER_BUTTON_MAX) {
|
|
|
|
return map[btn];
|
|
|
|
}
|
|
|
|
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* gamepad_axis_name(SDL_GameControllerAxis axis) {
|
|
|
|
static const char *const map[] = {
|
|
|
|
"Left X",
|
|
|
|
"Left Y",
|
|
|
|
"Right X",
|
|
|
|
"Right Y",
|
|
|
|
"Left Trigger",
|
|
|
|
"Right Trigger",
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if(axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) {
|
|
|
|
return map[axis];
|
|
|
|
}
|
|
|
|
|
|
|
|
return "Unknown";
|
2012-08-16 23:35:48 +02:00
|
|
|
}
|