mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
input: udev and DirectInput controllers are read through the snapshot bridge
The snapshot bridge copies a controller out of its driver once a poll, and every read until the next poll - a core's state query, the hotkeys, the menu - is served from the copy. It is switched on driver by driver, when a driver has been checked for what the bridge assumes: that get_buttons() says what button() says, that hats and axes answer through button() and axis(), and that state() is the common loop over the binds. Windows RawInput and XInput were on it. udev (Linux) and dinput (the DirectInput-only Windows driver) join. udev needed nothing: get_buttons() hands over the sixty-four bits button() reads, and state() is the common loop as written. Its axes past the sixteenth, which a copy does not hold, are read from the driver as before. dinput had no get_buttons(); it has one, over the button array button() reads. Its state() compares an axis against the threshold as integers, which comes to the same as the common loop's division at every threshold. RETROARCH_INPUT_SNAPSHOT=0 in the environment reads the drivers directly; it was a Windows-only switch and is one everywhere now. samples/input/joypad_bridge_checked, in CI: each driver's source is included and its pad table filled by hand, four thousand random pads each, and for random binds and thresholds what the bridge would read is compared with the driver's own button(), axis() and state(). udev on the host, DirectInput under Wine. Both agree throughout. Not run with a controller: there is none on this box and Wine shows none. The frontend-overhead harness and the Windows and X11 runs of the frontend pass with the drivers on the bridge and no pad attached.
This commit is contained in:
1 parent
47b838a95c
commit
c49ff4ce1d
8 files changed
+382
-5
No files matched your search
@@ -29,7 +29,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
timeout-minutes: 20
|
||||
run: |
|
||||
pkgs="build-essential libusb-1.0-0-dev libx11-dev libxtst-dev libxi-dev xvfb gcc-mingw-w64-x86-64 wine64"
|
||||
pkgs="build-essential libusb-1.0-0-dev libudev-dev libx11-dev libxtst-dev libxi-dev xvfb gcc-mingw-w64-x86-64 wine64"
|
||||
if dpkg -s $pkgs >/dev/null 2>&1; then
|
||||
echo "All packages already present on runner image; skipping apt."
|
||||
exit 0
|
||||
@@ -64,6 +64,21 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Build and run joypad_bridge_checked (udev on the host, DirectInput under Wine)
|
||||
shell: bash
|
||||
working-directory: samples/input/joypad_bridge_checked
|
||||
run: |
|
||||
set -eu
|
||||
# Two joypad drivers the snapshot bridge serves, held to what
|
||||
# it assumes of them: over random pads, binds and thresholds,
|
||||
# what the bridge would read - buttons through get_buttons(),
|
||||
# hats and axes through button() and axis(), the RetroPad
|
||||
# mask through the common loop - is what the driver's own
|
||||
# button(), axis() and state() say.
|
||||
make clean all
|
||||
timeout 120 make check
|
||||
make clean
|
||||
|
||||
- name: gfx/ does not reach into input state
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
@@ -432,6 +432,27 @@ static int32_t dinput_joypad_button(unsigned port, uint16_t joykey)
|
||||
return dinput_joypad_button_state(&g_pads[port], joykey);
|
||||
}
|
||||
|
||||
/* Every plain button of the pad at once, as dinput_joypad_button()
|
||||
* gives them one by one. Hats are not buttons here: they are read
|
||||
* through dinput_joypad_button() with a hat key. This is what lets the
|
||||
* frontend copy the pad once a poll (the snapshot bridge in
|
||||
* input_driver.c) instead of calling in for each button. */
|
||||
static void dinput_joypad_get_buttons(unsigned port, input_bits_t *state)
|
||||
{
|
||||
unsigned i;
|
||||
const struct dinput_joypad_data *pad;
|
||||
|
||||
BIT256_CLEAR_ALL_PTR(state);
|
||||
if (port >= MAX_USERS)
|
||||
return;
|
||||
pad = &g_pads[port];
|
||||
if (!pad->joypad)
|
||||
return;
|
||||
for (i = 0; i < ARRAY_SIZE_RGB_BUTTONS; i++)
|
||||
if (pad->joy_state.rgbButtons[i])
|
||||
BIT256_SET_PTR(state, i);
|
||||
}
|
||||
|
||||
static int16_t dinput_joypad_axis(unsigned port, uint32_t joyaxis)
|
||||
{
|
||||
if (port >= MAX_USERS)
|
||||
@@ -823,7 +844,7 @@ input_device_driver_t dinput_joypad = {
|
||||
dinput_joypad_destroy,
|
||||
dinput_joypad_button,
|
||||
dinput_joypad_state,
|
||||
NULL,
|
||||
dinput_joypad_get_buttons,
|
||||
dinput_joypad_axis,
|
||||
dinput_joypad_poll,
|
||||
dinput_joypad_set_rumble,
|
||||
|
||||
+17
-3
@@ -627,6 +627,20 @@ void input_driver_set_snapshot_bridge(bool on)
|
||||
* out in place, and compares an axis against the threshold as 32-bit
|
||||
* integers, which agrees with the common loop at every threshold.
|
||||
*
|
||||
* - udev (udev_joypad.c, Linux). get_buttons() hands over the same
|
||||
* sixty-four bits button() reads, and its state() is the common
|
||||
* loop as written. It has more axes than a copy holds; the ones
|
||||
* past the sixteenth are read from the driver as before.
|
||||
*
|
||||
* - dinput (dinput_joypad.c, the DirectInput-only Windows driver). It
|
||||
* had no get_buttons(); it has one now, over the same button array
|
||||
* button() reads. Its state() compares an axis against the
|
||||
* threshold as 32-bit integers, as winraw_joypad's does.
|
||||
*
|
||||
* samples/input/joypad_bridge_checked holds udev and dinput to that:
|
||||
* for random pads, binds and thresholds, what the bridge would make
|
||||
* of the driver's answers is what the driver's own state() says.
|
||||
*
|
||||
* Asked several times a frame, so the answer is kept with the driver
|
||||
* it was for. */
|
||||
static bool input_snapshot_driver_checked(const input_device_driver_t *drv)
|
||||
@@ -639,8 +653,9 @@ static bool input_snapshot_driver_checked(const input_device_driver_t *drv)
|
||||
asked = drv;
|
||||
answer = drv->ident
|
||||
&& ( string_is_equal(drv->ident, "xinput")
|
||||
|| string_is_equal(drv->ident, "winraw_joypad"));
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
|
||||
|| string_is_equal(drv->ident, "winraw_joypad")
|
||||
|| string_is_equal(drv->ident, "udev")
|
||||
|| string_is_equal(drv->ident, "dinput"));
|
||||
/* While drivers are being switched over: RETROARCH_INPUT_SNAPSHOT=0
|
||||
* in the environment reads the driver directly, so a problem can
|
||||
* be tried with and without the bridge on one build. */
|
||||
@@ -650,7 +665,6 @@ static bool input_snapshot_driver_checked(const input_device_driver_t *drv)
|
||||
if (env && env[0] == '0')
|
||||
answer = false;
|
||||
}
|
||||
#endif
|
||||
if (answer && drv->get_buttons && drv->button && drv->axis)
|
||||
RARCH_LOG("[Input] Controllers of the \"%s\" driver are read"
|
||||
" through a snapshot taken once a poll.\n", drv->ident);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Two joypad drivers held to what the snapshot bridge assumes of them:
|
||||
# udev on the host, DirectInput cross-built and run under Wine. Each
|
||||
# test includes its driver's source and fills the pad table by hand.
|
||||
REPO_ROOT := ../../..
|
||||
MINGW_CC ?= x86_64-w64-mingw32-gcc
|
||||
WINE ?= $(shell command -v wine || command -v wine64 || echo /usr/lib/wine/wine64)
|
||||
|
||||
INCS := -I$(REPO_ROOT) -I$(REPO_ROOT)/libretro-common/include \
|
||||
-I$(REPO_ROOT)/deps -I$(REPO_ROOT)/input/include -I$(REPO_ROOT)/gfx/include
|
||||
|
||||
all: udev_checked_test dinput_checked_test.exe
|
||||
|
||||
udev_checked_test: udev_checked_test.c bridge_view.h stubs.c $(REPO_ROOT)/input/drivers_joypad/udev_joypad.c
|
||||
$(CC) -O1 -Wall -Wno-unused -DRARCH_INTERNAL -DHAVE_UDEV $(INCS) \
|
||||
-o $@ udev_checked_test.c stubs.c \
|
||||
$(REPO_ROOT)/libretro-common/compat/compat_strl.c -ludev
|
||||
|
||||
dinput_checked_test.exe: dinput_checked_test.c bridge_view.h stubs.c $(REPO_ROOT)/input/drivers_joypad/dinput_joypad.c
|
||||
$(MINGW_CC) -std=gnu99 -O1 -Wall -Wno-unused -DRARCH_INTERNAL -DHAVE_DINPUT \
|
||||
-DHAVE_MENU -DHAVE_THREADS -D_WIN32_WINNT=0x0601 $(INCS) \
|
||||
-o $@ dinput_checked_test.c stubs.c \
|
||||
$(REPO_ROOT)/libretro-common/compat/compat_strl.c -ldinput8 -ldxguid
|
||||
|
||||
check: all
|
||||
./udev_checked_test
|
||||
WINEDEBUG=-all $(WINE) ./dinput_checked_test.exe
|
||||
|
||||
clean:
|
||||
rm -f udev_checked_test dinput_checked_test.exe
|
||||
|
||||
.PHONY: all check clean
|
||||
@@ -0,0 +1,161 @@
|
||||
/* What the snapshot bridge (input_driver.c) makes of a joypad driver's
|
||||
* answers, written out without the copy: the buttons as get_buttons()
|
||||
* hands them over, a hat as its four directions through button(), an
|
||||
* axis as its two directions through axis() put back together, and the
|
||||
* RetroPad mask as the common loop over the binds.
|
||||
*
|
||||
* A driver is put on the bridge when this is what its own button(),
|
||||
* axis() and state() say. The tests here hold a driver to it over
|
||||
* random pads, binds and thresholds. */
|
||||
#ifndef BRIDGE_VIEW_H
|
||||
#define BRIDGE_VIEW_H
|
||||
|
||||
#define BV_AXES 16 /* INPUT_SNAPSHOT_AXES */
|
||||
#define BV_HATS 4 /* INPUT_SNAPSHOT_HATS */
|
||||
|
||||
static int32_t bv_button(const input_device_driver_t *drv,
|
||||
unsigned pad, uint16_t joykey)
|
||||
{
|
||||
uint16_t dir = GET_HAT_DIR(joykey);
|
||||
input_bits_t bits;
|
||||
|
||||
if (dir)
|
||||
{
|
||||
unsigned h = GET_HAT(joykey);
|
||||
if ( h >= BV_HATS
|
||||
|| ( dir != HAT_UP_MASK && dir != HAT_DOWN_MASK
|
||||
&& dir != HAT_LEFT_MASK && dir != HAT_RIGHT_MASK))
|
||||
return drv->button(pad, joykey);
|
||||
return drv->button(pad, (uint16_t)HAT_MAP(h, dir)) ? 1 : 0;
|
||||
}
|
||||
if (joykey >= 256)
|
||||
return drv->button(pad, joykey);
|
||||
drv->get_buttons(pad, &bits);
|
||||
return BIT256_GET(bits, joykey) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int16_t bv_axis(const input_device_driver_t *drv,
|
||||
unsigned pad, uint32_t joyaxis)
|
||||
{
|
||||
bool negative = AXIS_NEG_GET(joyaxis) < BV_AXES;
|
||||
unsigned i = negative ? AXIS_NEG_GET(joyaxis) : AXIS_POS_GET(joyaxis);
|
||||
int16_t value;
|
||||
|
||||
if (i >= BV_AXES)
|
||||
return drv->axis(pad, joyaxis);
|
||||
value = (int16_t)(drv->axis(pad, AXIS_POS(i)) + drv->axis(pad, AXIS_NEG(i)));
|
||||
if (negative)
|
||||
return (value < 0) ? value : 0;
|
||||
return (value > 0) ? value : 0;
|
||||
}
|
||||
|
||||
static int16_t bv_state(const input_device_driver_t *drv,
|
||||
rarch_joypad_info_t *info, const struct retro_keybind *binds)
|
||||
{
|
||||
unsigned i;
|
||||
int16_t ret = 0;
|
||||
uint16_t pad = info->joy_idx;
|
||||
|
||||
for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
|
||||
{
|
||||
const uint64_t joykey = (binds[i].joykey != NO_BTN)
|
||||
? binds[i].joykey : info->auto_binds[i].joykey;
|
||||
const uint32_t joyaxis = (binds[i].joyaxis != AXIS_NONE)
|
||||
? binds[i].joyaxis : info->auto_binds[i].joyaxis;
|
||||
if ( (uint16_t)joykey != NO_BTN
|
||||
&& bv_button(drv, pad, (uint16_t)joykey))
|
||||
ret |= (1 << i);
|
||||
else if (joyaxis != AXIS_NONE
|
||||
&& ((float)abs(bv_axis(drv, pad, joyaxis)) / 0x8000)
|
||||
> info->axis_threshold)
|
||||
ret |= (1 << i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ---- the comparison, the same for every driver --------------------- */
|
||||
|
||||
static unsigned bv_seed = 0x2545F491u;
|
||||
static unsigned bv_rand(void)
|
||||
{
|
||||
bv_seed ^= bv_seed << 13;
|
||||
bv_seed ^= bv_seed >> 17;
|
||||
bv_seed ^= bv_seed << 5;
|
||||
return bv_seed;
|
||||
}
|
||||
|
||||
static void bv_random_binds(struct retro_keybind *b)
|
||||
{
|
||||
static const uint16_t dirs[4] = {
|
||||
HAT_UP_MASK, HAT_DOWN_MASK, HAT_LEFT_MASK, HAT_RIGHT_MASK };
|
||||
unsigned i;
|
||||
for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
|
||||
{
|
||||
unsigned k = bv_rand() % 10;
|
||||
unsigned a = bv_rand() % 10;
|
||||
if (k < 3)
|
||||
b[i].joykey = NO_BTN;
|
||||
else if (k < 8)
|
||||
b[i].joykey = bv_rand() % 140; /* past what any pad has, too */
|
||||
else
|
||||
b[i].joykey = HAT_MAP(bv_rand() % 5, dirs[bv_rand() % 4]);
|
||||
if (a < 4)
|
||||
b[i].joyaxis = AXIS_NONE;
|
||||
else if (a < 7)
|
||||
b[i].joyaxis = AXIS_POS(bv_rand() % 20);
|
||||
else
|
||||
b[i].joyaxis = AXIS_NEG(bv_rand() % 20);
|
||||
}
|
||||
}
|
||||
|
||||
/* The driver's pad @pad has just been filled with something random.
|
||||
* Returns the number of disagreements. */
|
||||
static unsigned bv_compare(const input_device_driver_t *drv, unsigned pad)
|
||||
{
|
||||
static const float thresholds[] = { 0.0f, 0.01f, 0.25f, 0.5f, 0.75f, 0.999f, 1.0f };
|
||||
static const uint16_t dirs[4] = {
|
||||
HAT_UP_MASK, HAT_DOWN_MASK, HAT_LEFT_MASK, HAT_RIGHT_MASK };
|
||||
struct retro_keybind binds[RARCH_BIND_LIST_END];
|
||||
struct retro_keybind autos[RARCH_BIND_LIST_END];
|
||||
rarch_joypad_info_t info;
|
||||
unsigned bad = 0, i, t;
|
||||
|
||||
/* every button, hat direction and axis direction on its own */
|
||||
for (i = 0; i < 300; i++)
|
||||
if ((bv_button(drv, pad, (uint16_t)i) != 0) != (drv->button(pad, (uint16_t)i) != 0))
|
||||
bad++;
|
||||
for (i = 0; i < 5; i++)
|
||||
for (t = 0; t < 4; t++)
|
||||
{
|
||||
uint16_t key = (uint16_t)HAT_MAP(i, dirs[t]);
|
||||
if ((bv_button(drv, pad, key) != 0) != (drv->button(pad, key) != 0))
|
||||
bad++;
|
||||
}
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
if (bv_axis(drv, pad, AXIS_POS(i)) != drv->axis(pad, AXIS_POS(i)))
|
||||
bad++;
|
||||
if (bv_axis(drv, pad, AXIS_NEG(i)) != drv->axis(pad, AXIS_NEG(i)))
|
||||
bad++;
|
||||
}
|
||||
|
||||
/* and the RetroPad mask, over binds and thresholds */
|
||||
memset(binds, 0, sizeof(binds));
|
||||
memset(autos, 0, sizeof(autos));
|
||||
info.auto_binds = autos;
|
||||
info.joy_idx = (uint16_t)pad;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
bv_random_binds(binds);
|
||||
bv_random_binds(autos);
|
||||
for (t = 0; t < sizeof(thresholds) / sizeof(thresholds[0]); t++)
|
||||
{
|
||||
info.axis_threshold = thresholds[t];
|
||||
if (drv->state(&info, binds, pad) != bv_state(drv, &info, binds))
|
||||
bad++;
|
||||
}
|
||||
}
|
||||
return bad;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
/* The DirectInput joypad driver, held to what the snapshot bridge
|
||||
* assumes of a driver it serves (see bridge_view.h). The driver source
|
||||
* is included for its pad table, which is filled here by hand: no
|
||||
* device is opened, so it runs under Wine with none. */
|
||||
#include "../../../input/drivers_joypad/dinput_joypad.c"
|
||||
|
||||
#include "bridge_view.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static const DWORD povs[] = {
|
||||
0xFFFFFFFF, 0, 4500, 9000, 13500, 18000, 22500, 27000, 31500,
|
||||
100, 36000 };
|
||||
unsigned n, i, bad = 0;
|
||||
|
||||
for (n = 0; n < 4000; n++)
|
||||
{
|
||||
struct dinput_joypad_data *pad = &g_pads[n % 3];
|
||||
LONG *axes[8];
|
||||
|
||||
pad->joypad = (LPDIRECTINPUTDEVICE8)(uintptr_t)1; /* never called through */
|
||||
for (i = 0; i < sizeof(pad->joy_state.rgbButtons); i++)
|
||||
pad->joy_state.rgbButtons[i] = (bv_rand() & 1) ? 0x80 : 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
pad->joy_state.rgdwPOV[i] = povs[bv_rand() % (sizeof(povs) / sizeof(povs[0]))];
|
||||
axes[0] = &pad->joy_state.lX; axes[1] = &pad->joy_state.lY;
|
||||
axes[2] = &pad->joy_state.lZ; axes[3] = &pad->joy_state.lRx;
|
||||
axes[4] = &pad->joy_state.lRy; axes[5] = &pad->joy_state.lRz;
|
||||
axes[6] = &pad->joy_state.rglSlider[0];
|
||||
axes[7] = &pad->joy_state.rglSlider[1];
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
unsigned r = bv_rand() % 8;
|
||||
*axes[i] = (r == 0) ? 0
|
||||
: (r == 1) ? 0x7fff
|
||||
: (r == 2) ? -0x7fff
|
||||
: (r == 3) ? -0x8000
|
||||
: (LONG)(int16_t)bv_rand();
|
||||
}
|
||||
bad += bv_compare(&dinput_joypad, n % 3);
|
||||
}
|
||||
|
||||
/* a port with no pad on it has no buttons */
|
||||
{
|
||||
input_bits_t bits;
|
||||
g_pads[5].joypad = NULL;
|
||||
g_pads[5].joy_state.rgbButtons[3] = 0x80;
|
||||
dinput_joypad_get_buttons(5, &bits);
|
||||
for (i = 0; i < 256; i++)
|
||||
if (BIT256_GET(bits, i))
|
||||
bad++;
|
||||
}
|
||||
|
||||
if (bad)
|
||||
{
|
||||
printf("FAIL dinput_checked_test: %u disagreements\n", bad);
|
||||
return 1;
|
||||
}
|
||||
printf("PASS dinput_checked_test: 4000 random pads; what the bridge would"
|
||||
" read is what the driver says\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/* What the two driver files reach for and these tests never call. No
|
||||
* header is included, so the types need not match: nothing here runs. */
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
void RARCH_LOG(const char *fmt, ...) { (void)fmt; }
|
||||
void RARCH_DBG(const char *fmt, ...) { (void)fmt; }
|
||||
void RARCH_WARN(const char *fmt, ...) { (void)fmt; }
|
||||
void RARCH_ERR(const char *fmt, ...) { (void)fmt; }
|
||||
|
||||
void *config_get_ptr(void) { return NULL; }
|
||||
int input_autoconfigure_connect(void) { return 0; }
|
||||
int input_autoconfigure_disconnect(void) { return 0; }
|
||||
const char *input_config_get_device_name(unsigned port) { (void)port; return NULL; }
|
||||
void *task_init(void) { return NULL; }
|
||||
int task_queue_push(void *t) { (void)t; return 0; }
|
||||
void task_set_flags(void *t, unsigned a, int b) { (void)t; (void)a; (void)b; }
|
||||
unsigned long long video_driver_window_get(void) { return 0; }
|
||||
|
||||
#define CMD(name) int name(void) { return 0; }
|
||||
CMD(command_audio_reinit) CMD(command_close_content) CMD(command_drivers_reinit)
|
||||
CMD(command_get_config_param) CMD(command_get_playlist) CMD(command_get_status)
|
||||
CMD(command_help) CMD(command_list_cores) CMD(command_list_playlists)
|
||||
CMD(command_load_content) CMD(command_load_core) CMD(command_load_savefiles)
|
||||
CMD(command_load_state_slot) CMD(command_play_replay_slot) CMD(command_read_memory)
|
||||
CMD(command_save_savefiles) CMD(command_save_state_slot) CMD(command_seek_replay)
|
||||
CMD(command_show_osd_msg) CMD(command_start_core) CMD(command_unload_core)
|
||||
CMD(command_version) CMD(command_video_reinit) CMD(command_write_memory)
|
||||
@@ -0,0 +1,45 @@
|
||||
/* The udev joypad driver, held to what the snapshot bridge assumes of
|
||||
* a driver it serves (see bridge_view.h). The driver source is
|
||||
* included for its pad table, which is filled here by hand: no
|
||||
* device is opened. */
|
||||
#include "../../../input/drivers_joypad/udev_joypad.c"
|
||||
|
||||
#include "bridge_view.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned n, i, bad = 0;
|
||||
|
||||
for (n = 0; n < 4000; n++)
|
||||
{
|
||||
struct udev_joypad *pad = &udev_pads[n % 3];
|
||||
|
||||
pad->fd = 1; /* as a connected pad has one */
|
||||
pad->buttons = ((uint64_t)bv_rand() << 32) | bv_rand();
|
||||
for (i = 0; i < NUM_HATS; i++)
|
||||
{
|
||||
pad->hats[i][0] = (int8_t)((int)(bv_rand() % 3) - 1);
|
||||
pad->hats[i][1] = (int8_t)((int)(bv_rand() % 3) - 1);
|
||||
}
|
||||
for (i = 0; i < NUM_AXES; i++)
|
||||
{
|
||||
unsigned r = bv_rand() % 8;
|
||||
pad->axes[i] = (r == 0) ? 0
|
||||
: (r == 1) ? 0x7fff
|
||||
: (r == 2) ? -0x7fff
|
||||
: (r == 3) ? (int16_t)-0x8000
|
||||
: (int16_t)bv_rand();
|
||||
pad->neg_trigger[i] = (bv_rand() & 1) != 0;
|
||||
}
|
||||
bad += bv_compare(&udev_joypad, n % 3);
|
||||
}
|
||||
|
||||
if (bad)
|
||||
{
|
||||
printf("FAIL udev_checked_test: %u disagreements\n", bad);
|
||||
return 1;
|
||||
}
|
||||
printf("PASS udev_checked_test: 4000 random pads; what the bridge would"
|
||||
" read is what the driver says\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user