Files
Cesarus85--ringfall-mjolnir-vr/source/interface/event_manager.c
T
Stefan MaierandClaude Opus 5.5 0badc451cb Join online games with a short code in VR
A hosted game gets an 8-character join code (Crockford base 32) besides
its invite link, shown under the lobby's buttons. On the system link list,
X opens the game's keyboard to type a code in; the code's topic and key
come from a slow PBKDF2 derivation, the host answers an ask on that topic
through the signalling brokers with its invite sealed with the key, and
the joiner joins as with the link. Codes in join_link.txt work too.

Also: the clipboard text last seen is kept from run to run, so a run's
own invite is not joined again at the next start; in menus a held stick
repeats after 350 ms and then every 90 ms, and its threshold is 70%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:32:50 +02:00

440 lines
11 KiB
C

/*
EVENT_MANAGER.C
symbols in this file:
000CB700 0030:
_event_manager_initialize (0000)
000CB730 0020:
_event_manager_dispose (0000)
000CB750 0020:
_event_manager_flush (0000)
000CB770 0010:
_event_manager_suppress (0000)
000CB780 00c0:
_get_next_event (0000)
000CB840 0010:
_event_manager_time_of_last_event (0000)
000CB850 0300:
_code_000cb850 (0000)
000CBB50 0110:
_event_manager_update (0000)
002706D8 0066:
??_C@_0GG@GKBBBOFI@event?5?$CG?$CG?5?$CI?$CIlocal_player_index?$DO?$DN0@ (0000)
00270740 0029:
??_C@_0CJ@HBEODFJG@c?3?2halo?2SOURCE?2interface?2event_m@ (0000)
00453B60 0168:
_event_manager_globals (0000)
*/
/* ---------- headers */
#include "cseries.h"
#include "cseries_windows.h"
#include "event_manager.h"
#include "input.h"
/* ---------- constants */
enum
{
_event_type_null,
_event_type_left_stick,
_event_type_right_stick,
_event_type_button,
#ifdef HALO_ANDROID
/* (the VR port's: a headset's controllers' thumbsticks are pushed as
far less readily than a gamepad's) */
STICK_EVENT_THRESHOLD = 22937,
#else
STICK_EVENT_THRESHOLD = 29490,
#endif
STICK_EVENT_REPEAT_MILLISECONDS = 250
};
/* ---------- macros */
/* ---------- structures */
struct event_manager_state
{
boolean initialized;
boolean suppressed;
short __unknown2;
unsigned long time_of_last_event;
struct event_record events[MAXIMUM_GAMEPADS][8];
};
struct event_manager_globals
{
struct event_manager_state state;
unsigned long stick_event_times[NUMBER_OF_GAMEPAD_STICKS][MAXIMUM_GAMEPADS];
long previous_stick_axes[NUMBER_OF_GAMEPAD_STICKS][2][MAXIMUM_GAMEPADS];
};
typedef char verify_event_manager_state_size[
sizeof(struct event_manager_state) == 0x108 ? 1 : -1];
typedef char verify_event_manager_globals_size[
sizeof(struct event_manager_globals) == 0x168 ? 1 : -1];
#ifdef HALO_ANDROID
/* The VR port's: a stick held moves on once after a pause, then quickly,
as menus do now (the Xbox's moved on every quarter second, which in a
headset, with the keyboard's letters to cross, is slow going). */
enum
{
STICK_REPEAT_FIRST_MILLISECONDS = 350,
STICK_REPEAT_MILLISECONDS = 90,
};
static short stick_repeats[NUMBER_OF_GAMEPAD_STICKS][MAXIMUM_GAMEPADS];
#define STICK_REPEAT_INTERVAL(stick, controller_index) \
(stick_repeats[stick][controller_index] ? STICK_REPEAT_MILLISECONDS : STICK_REPEAT_FIRST_MILLISECONDS)
#else
#define STICK_REPEAT_INTERVAL(stick, controller_index) STICK_EVENT_REPEAT_MILLISECONDS
#endif
/* ---------- prototypes */
static void queue_event(
struct event_record *event,
short controller_index);
/* ---------- globals */
struct event_manager_globals event_manager_globals = { 0 };
/* ---------- public code */
#ifdef HALO_ANDROID
/* an event the stick posts: a fresh push (it was within the threshold on
that axis) starts the count of repeats again */
static void stick_note_event(
short stick,
short controller_index,
long x,
long y,
unsigned long time)
{
boolean fresh =
(ABS(x) >= STICK_EVENT_THRESHOLD &&
ABS(event_manager_globals.previous_stick_axes[stick][0][controller_index]) < STICK_EVENT_THRESHOLD) ||
(ABS(y) >= STICK_EVENT_THRESHOLD &&
ABS(event_manager_globals.previous_stick_axes[stick][1][controller_index]) < STICK_EVENT_THRESHOLD);
(void)time;
if (fresh)
stick_repeats[stick][controller_index] = 0;
else if (stick_repeats[stick][controller_index] < SHORT_MAX)
stick_repeats[stick][controller_index]++;
}
#endif
void event_manager_initialize(
void)
{
csmemset(&event_manager_globals.state, 0, sizeof(event_manager_globals.state));
event_manager_globals.state.time_of_last_event = system_milliseconds();
event_manager_globals.state.initialized = TRUE;
return;
}
void event_manager_dispose(
void)
{
csmemset(&event_manager_globals.state, 0, sizeof(event_manager_globals.state));
return;
}
void event_manager_flush(
void)
{
csmemset(event_manager_globals.state.events, 0, sizeof(event_manager_globals.state.events));
return;
}
void event_manager_suppress(
boolean suppress)
{
event_manager_globals.state.suppressed = suppress;
return;
}
boolean get_next_event(
struct event_record *event,
short local_player_index)
{
boolean result = FALSE;
match_assert(
"c:\\halo\\SOURCE\\interface\\event_manager.c",
211,
event && ((local_player_index>=0 && local_player_index<MAXIMUM_GAMEPADS) || local_player_index==NONE));
if (event_manager_globals.state.initialized)
{
if (local_player_index == NONE)
{
local_player_index = 0;
while (!result)
{
if (local_player_index >= MAXIMUM_GAMEPADS)
break;
result = get_next_event(event, local_player_index);
local_player_index++;
}
}
else
{
long event_index;
for (event_index = 7; event_index >= 0; event_index--)
{
if (event_manager_globals.state.events[local_player_index][event_index].type != 0)
{
*event = event_manager_globals.state.events[local_player_index][event_index];
event_manager_globals.state.events[local_player_index][event_index].type = 0;
return TRUE;
}
}
}
}
return result;
}
unsigned long event_manager_time_of_last_event(
void)
{
return event_manager_globals.state.time_of_last_event;
}
void event_manager_post_button(
short controller_index,
short button_index)
{
struct event_record event = {0};
if (!event_manager_globals.state.initialized ||
controller_index < 0 ||
controller_index >= MAXIMUM_GAMEPADS)
{
return;
}
event.type = _event_type_button;
event.data.button.index = (byte)button_index;
event.data.button.value = 1;
queue_event(&event, controller_index);
return;
}
/* ---------- private code */
static void queue_event(
struct event_record *event,
short controller_index)
{
unsigned long time;
boolean post = TRUE;
if (event_manager_globals.state.suppressed)
return;
time = system_milliseconds();
if (event->type == _event_type_left_stick)
{
long x = event->data.stick.x;
long y = event->data.stick.y;
if (ABS(x) < STICK_EVENT_THRESHOLD && ABS(y) < STICK_EVENT_THRESHOLD)
{
post = FALSE;
}
else if (!((ABS(x) >= STICK_EVENT_THRESHOLD &&
ABS(event_manager_globals.previous_stick_axes[_gamepad_stick_left][0][controller_index]) < STICK_EVENT_THRESHOLD) ||
(ABS(y) >= STICK_EVENT_THRESHOLD &&
ABS(event_manager_globals.previous_stick_axes[_gamepad_stick_left][1][controller_index]) < STICK_EVENT_THRESHOLD) ||
time - event_manager_globals.stick_event_times[_gamepad_stick_left][controller_index] >=
STICK_REPEAT_INTERVAL(_gamepad_stick_left, controller_index)))
{
post = FALSE;
}
else
{
#ifdef HALO_ANDROID
stick_note_event(_gamepad_stick_left, controller_index, x, y, time);
#endif
event_manager_globals.stick_event_times[_gamepad_stick_left][controller_index] = time;
post = TRUE;
if (ABS(x) >= STICK_EVENT_THRESHOLD)
{
switch (x >= 0 ? 1 : -1)
{
case 1:
x = event->data.stick.x = 32767;
break;
case -1:
x = event->data.stick.x = -32768;
break;
}
}
if (ABS(y) >= STICK_EVENT_THRESHOLD)
{
switch (y >= 0 ? 1 : -1)
{
case 1:
y = event->data.stick.y = 32767;
break;
case -1:
y = event->data.stick.y = -32768;
break;
}
}
}
event_manager_globals.previous_stick_axes[_gamepad_stick_left][0][controller_index] = x;
event_manager_globals.previous_stick_axes[_gamepad_stick_left][1][controller_index] = y;
}
else if (event->type == _event_type_right_stick)
{
long x = event->data.stick.x;
long y = event->data.stick.y;
if (ABS(x) < STICK_EVENT_THRESHOLD && ABS(y) < STICK_EVENT_THRESHOLD)
{
post = FALSE;
}
else if (!((ABS(x) >= STICK_EVENT_THRESHOLD &&
ABS(event_manager_globals.previous_stick_axes[_gamepad_stick_right][0][controller_index]) < STICK_EVENT_THRESHOLD) ||
(ABS(y) >= STICK_EVENT_THRESHOLD &&
ABS(event_manager_globals.previous_stick_axes[_gamepad_stick_right][1][controller_index]) < STICK_EVENT_THRESHOLD) ||
time - event_manager_globals.stick_event_times[_gamepad_stick_right][controller_index] >=
STICK_REPEAT_INTERVAL(_gamepad_stick_right, controller_index)))
{
post = FALSE;
}
else
{
#ifdef HALO_ANDROID
stick_note_event(_gamepad_stick_right, controller_index, x, y, time);
#endif
event_manager_globals.stick_event_times[_gamepad_stick_right][controller_index] = time;
post = TRUE;
if (ABS(x) >= STICK_EVENT_THRESHOLD)
{
switch (x >= 0 ? 1 : -1)
{
case 1:
x = event->data.stick.x = 32767;
break;
case -1:
x = event->data.stick.x = -32768;
break;
}
}
if (ABS(y) >= STICK_EVENT_THRESHOLD)
{
switch (y >= 0 ? 1 : -1)
{
case 1:
y = event->data.stick.y = 32767;
break;
case -1:
y = event->data.stick.y = -32768;
break;
}
}
}
event_manager_globals.previous_stick_axes[_gamepad_stick_right][0][controller_index] = x;
event_manager_globals.previous_stick_axes[_gamepad_stick_right][1][controller_index] = y;
}
if (post)
{
event->controller_index = controller_index;
csmemmove(
event_manager_globals.state.events[controller_index],
&event_manager_globals.state.events[controller_index][1],
sizeof(event_manager_globals.state.events[controller_index]) - sizeof(struct event_record));
event_manager_globals.state.events[controller_index][0] = *event;
if (event->type != _event_type_null)
{
event_manager_globals.state.time_of_last_event = time;
}
}
return;
}
void event_manager_update(
void)
{
short gamepad_index;
if (!event_manager_globals.state.initialized)
return;
for (gamepad_index = 0; gamepad_index < MAXIMUM_GAMEPADS; gamepad_index++)
{
boolean posted = FALSE;
if (input_has_gamepad(gamepad_index))
{
struct gamepad_state const *state = input_get_gamepad_state(gamepad_index);
if (state)
{
struct event_record event;
short button_index;
if (state->sticks[_gamepad_stick_left].x != 0 ||
state->sticks[_gamepad_stick_left].y != 0)
{
event.type = _event_type_left_stick;
event.data.stick = state->sticks[_gamepad_stick_left];
queue_event(&event, gamepad_index);
posted = TRUE;
}
if (state->sticks[_gamepad_stick_right].x != 0 ||
state->sticks[_gamepad_stick_right].y != 0)
{
event.type = _event_type_right_stick;
event.data.stick = state->sticks[_gamepad_stick_right];
queue_event(&event, gamepad_index);
posted = TRUE;
}
for (button_index = 0; button_index < NUMBER_OF_GAMEPAD_BUTTONS; button_index++)
{
byte value = state->buttons[button_index];
if (value)
{
event.type = _event_type_button;
event.data.button.index = (byte)button_index;
event.data.button.value = value;
queue_event(&event, gamepad_index);
posted = TRUE;
}
}
}
}
if (!posted)
{
struct event_record event = {0};
queue_event(&event, gamepad_index);
}
}
return;
}