Files
kichikuou_xsystem35-sdl2/src/event.c
T
kichikuou c7c0f69ec4 Split sdl_core.h to event.h and editor.h
And rename sdl_event.c to event.c, sdl_input.c to editor.c.
2025-06-11 10:12:25 +09:00

647 lines
17 KiB
C

/*
* Copyright (C) 2000- Fumihiko Murata <fmurata@p1.tcnet.ne.jp>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "config.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <SDL.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#include "event.h"
#include "portab.h"
#include "system.h"
#include "debugger.h"
#include "nact.h"
#include "gfx.h"
#include "gfx_private.h"
#include "scheduler.h"
#include "menu.h"
#include "input.h"
#include "msgskip.h"
#include "hacks.h"
static void get_event(void);
static void keyEventProsess(SDL_KeyboardEvent *e, bool pressed);
bool (*event_custom_handler)(const SDL_Event *);
static uint32_t custom_event_type = (uint32_t)-1;
enum CustomEventCode {
SIMULATE_RIGHT_BUTTON,
DEBUGGER_COMMAND,
};
/* pointer の状態 */
static int mousex, mousey, mouseb;
static int mouse_wheel_up, mouse_wheel_down;
bool RawKeyInfo[256];
/* SDL Joystick */
static int joyinfo=0;
static int keytable[SDL_NUM_SCANCODES] = {
[SDL_SCANCODE_A] = KEY_A,
[SDL_SCANCODE_B] = KEY_B,
[SDL_SCANCODE_C] = KEY_C,
[SDL_SCANCODE_D] = KEY_D,
[SDL_SCANCODE_E] = KEY_E,
[SDL_SCANCODE_F] = KEY_F,
[SDL_SCANCODE_G] = KEY_G,
[SDL_SCANCODE_H] = KEY_H,
[SDL_SCANCODE_I] = KEY_I,
[SDL_SCANCODE_J] = KEY_J,
[SDL_SCANCODE_K] = KEY_K,
[SDL_SCANCODE_L] = KEY_L,
[SDL_SCANCODE_M] = KEY_M,
[SDL_SCANCODE_N] = KEY_N,
[SDL_SCANCODE_O] = KEY_O,
[SDL_SCANCODE_P] = KEY_P,
[SDL_SCANCODE_Q] = KEY_Q,
[SDL_SCANCODE_R] = KEY_R,
[SDL_SCANCODE_S] = KEY_S,
[SDL_SCANCODE_T] = KEY_T,
[SDL_SCANCODE_U] = KEY_U,
[SDL_SCANCODE_V] = KEY_V,
[SDL_SCANCODE_W] = KEY_W,
[SDL_SCANCODE_X] = KEY_X,
[SDL_SCANCODE_Y] = KEY_Y,
[SDL_SCANCODE_Z] = KEY_Z,
[SDL_SCANCODE_1] = KEY_1,
[SDL_SCANCODE_2] = KEY_2,
[SDL_SCANCODE_3] = KEY_3,
[SDL_SCANCODE_4] = KEY_4,
[SDL_SCANCODE_5] = KEY_5,
[SDL_SCANCODE_6] = KEY_6,
[SDL_SCANCODE_7] = KEY_7,
[SDL_SCANCODE_8] = KEY_8,
[SDL_SCANCODE_9] = KEY_9,
[SDL_SCANCODE_0] = KEY_0,
[SDL_SCANCODE_RETURN] = KEY_RETURN,
[SDL_SCANCODE_ESCAPE] = KEY_ESCAPE,
[SDL_SCANCODE_BACKSPACE] = KEY_BACKSPACE,
[SDL_SCANCODE_TAB] = KEY_TAB,
[SDL_SCANCODE_SPACE] = KEY_SPACE,
// SDL_SCANCODE_MINUS
// SDL_SCANCODE_EQUALS
// SDL_SCANCODE_LEFTBRACKET
// SDL_SCANCODE_RIGHTBRACKET
// SDL_SCANCODE_BACKSLASH
// SDL_SCANCODE_NONUSHASH
// SDL_SCANCODE_SEMICOLON
// SDL_SCANCODE_APOSTROPHE
// SDL_SCANCODE_GRAVE
// SDL_SCANCODE_COMMA
// SDL_SCANCODE_PERIOD
// SDL_SCANCODE_SLASH
[SDL_SCANCODE_CAPSLOCK] = KEY_CAPSLOCK,
[SDL_SCANCODE_F1] = KEY_F1,
[SDL_SCANCODE_F2] = KEY_F2,
[SDL_SCANCODE_F3] = KEY_F3,
[SDL_SCANCODE_F4] = KEY_F4,
[SDL_SCANCODE_F5] = KEY_F5,
[SDL_SCANCODE_F6] = KEY_F6,
[SDL_SCANCODE_F7] = KEY_F7,
[SDL_SCANCODE_F8] = KEY_F8,
[SDL_SCANCODE_F9] = KEY_F9,
[SDL_SCANCODE_F10] = KEY_F10,
[SDL_SCANCODE_F11] = KEY_F11,
[SDL_SCANCODE_F12] = KEY_F12,
[SDL_SCANCODE_PRINTSCREEN] = KEY_PRINTSCREEN,
[SDL_SCANCODE_SCROLLLOCK] = KEY_SCROLLLOCK,
[SDL_SCANCODE_PAUSE] = KEY_PAUSE,
[SDL_SCANCODE_INSERT] = KEY_INSERT,
[SDL_SCANCODE_HOME] = KEY_HOME,
[SDL_SCANCODE_PAGEUP] = KEY_PAGEUP,
[SDL_SCANCODE_DELETE] = KEY_DELETE,
[SDL_SCANCODE_END] = KEY_END,
[SDL_SCANCODE_PAGEDOWN] = KEY_PAGEDOWN,
[SDL_SCANCODE_RIGHT] = KEY_RIGHT,
[SDL_SCANCODE_LEFT] = KEY_LEFT,
[SDL_SCANCODE_DOWN] = KEY_DOWN,
[SDL_SCANCODE_UP] = KEY_UP,
[SDL_SCANCODE_KP_DIVIDE] = KEY_PAD_DIVIDE,
[SDL_SCANCODE_KP_MULTIPLY] = KEY_PAD_MULTIPLY,
[SDL_SCANCODE_KP_MINUS] = KEY_PAD_MINUS,
[SDL_SCANCODE_KP_PLUS] = KEY_PAD_PLUS,
[SDL_SCANCODE_KP_ENTER] = KEY_RETURN,
[SDL_SCANCODE_KP_1] = KEY_PAD_1,
[SDL_SCANCODE_KP_2] = KEY_PAD_2,
[SDL_SCANCODE_KP_3] = KEY_PAD_3,
[SDL_SCANCODE_KP_4] = KEY_PAD_4,
[SDL_SCANCODE_KP_5] = KEY_PAD_5,
[SDL_SCANCODE_KP_6] = KEY_PAD_6,
[SDL_SCANCODE_KP_7] = KEY_PAD_7,
[SDL_SCANCODE_KP_8] = KEY_PAD_8,
[SDL_SCANCODE_KP_9] = KEY_PAD_9,
[SDL_SCANCODE_KP_0] = KEY_PAD_0,
[SDL_SCANCODE_KP_PERIOD] = KEY_PAD_PERIOD,
[SDL_SCANCODE_KP_EQUALS] = KEY_PAD_EQUALS,
[SDL_SCANCODE_F13] = KEY_F13,
[SDL_SCANCODE_F14] = KEY_F14,
[SDL_SCANCODE_F15] = KEY_F15,
[SDL_SCANCODE_F16] = KEY_F16,
[SDL_SCANCODE_F17] = KEY_F17,
[SDL_SCANCODE_F18] = KEY_F18,
[SDL_SCANCODE_F19] = KEY_F19,
[SDL_SCANCODE_F20] = KEY_F20,
[SDL_SCANCODE_F21] = KEY_F21,
[SDL_SCANCODE_F22] = KEY_F22,
[SDL_SCANCODE_F23] = KEY_F23,
[SDL_SCANCODE_F24] = KEY_F24,
[SDL_SCANCODE_EXECUTE] = KEY_EXECUTE,
[SDL_SCANCODE_HELP] = KEY_HELP,
[SDL_SCANCODE_SELECT] = KEY_SELECT,
[SDL_SCANCODE_CLEAR] = KEY_CLEAR,
[SDL_SCANCODE_SEPARATOR] = KEY_SEPARATOR,
[SDL_SCANCODE_LCTRL] = KEY_CTRL,
[SDL_SCANCODE_LSHIFT] = KEY_SHIFT,
[SDL_SCANCODE_LALT] = KEY_ALT,
[SDL_SCANCODE_RCTRL] = KEY_CTRL,
[SDL_SCANCODE_RSHIFT] = KEY_SHIFT,
[SDL_SCANCODE_RALT] = KEY_ALT,
};
static int joy_device_index = -1;
static SDL_Joystick *js;
static bool joy_open(int index) {
if (js)
return false;
js = SDL_JoystickOpen(index);
if (!js)
return false;
const char *name = SDL_JoystickName(js);
int axes = SDL_JoystickNumAxes(js);
int buttons = SDL_JoystickNumButtons(js);
SDL_JoystickEventState(SDL_ENABLE);
NOTICE("SDL joystick '%s' %d axes %d buttons", name, axes, buttons);
return true;
}
static bool joy_init(void) {
SDL_Init(SDL_INIT_JOYSTICK);
if (joy_device_index >= 0)
return joy_open(joy_device_index);
for (int i = 0; i < SDL_NumJoysticks(); i++) {
if (joy_open(i))
return true;
}
return false;
}
void event_init(void) {
if (custom_event_type == (uint32_t)-1)
custom_event_type = SDL_RegisterEvents(1);
joy_init();
}
void event_remove(void) {
if (js) {
SDL_JoystickClose(js);
js = NULL;
}
}
void event_set_joy_device_index(int index) {
joy_device_index = index;
}
static int mouse_to_rawkey(int button) {
switch(button) {
case SDL_BUTTON_LEFT:
return KEY_MOUSE_LEFT;
case SDL_BUTTON_MIDDLE:
return KEY_MOUSE_MIDDLE;
case SDL_BUTTON_RIGHT:
return KEY_MOUSE_RIGHT;
}
return 0;
}
static int mouse_to_agsevent(int button) {
switch(button) {
case SDL_BUTTON_LEFT:
return AGSEVENT_BUTTON_LEFT;
case SDL_BUTTON_MIDDLE:
return AGSEVENT_BUTTON_MID;
case SDL_BUTTON_RIGHT:
return AGSEVENT_BUTTON_RIGHT;
}
return 0;
}
EMSCRIPTEN_KEEPALIVE
void send_agsevent(enum agsevent_type type, int code) {
if (!nact->ags.eventcb)
return;
agsevent_t agse = {
.type = type,
.code = code,
.mousex = mousex,
.mousey = mousey
};
nact->ags.eventcb(&agse); // Async in emscripten
#ifdef __EMSCRIPTEN__
// HACK: this ensures that callers of this function are instrumented.
// This is necessary because ASYNCIFY_PROPAGATE_ADD does not work:
// https://github.com/emscripten-core/emscripten/issues/23015
emscripten_sleep(0);
#endif
}
void event_set_mouse_location(int x, int y) {
// scale mouse x and y
float scalex, scaley;
SDL_RenderGetScale(gfx_renderer, &scalex, &scaley);
x *= scalex;
y *= scaley;
// calculate window borders
int logw, logh;
SDL_RenderGetLogicalSize(gfx_renderer, &logw, &logh);
float scalew, scaleh;
scalew = logw * scalex;
scaleh = logh * scaley;
int winw, winh;
SDL_GetWindowSize(gfx_window, &winw, &winh);
float border_left = (winw - scalew) / 2;
float border_top = (winh - scaleh) / 2;
// offset x and y by window borders
x += border_left;
y += border_top;
SDL_WarpMouseInWindow(gfx_window, x, y);
}
void event_set_mouse_internal_location(int x, int y) {
mousex = x;
mousey = y;
send_agsevent(AGSEVENT_MOUSE_MOTION, 0);
}
// Stores a deferred touch event (valid if .timestamp != 0) to add a delay
// between mouse pointer movement and mouse button state change caused by a
// touch event. This prevents the game from processing a button down event
// before reading the pointer position.
static SDL_TouchFingerEvent deferred_touch_event;
#define TOUCH_EVENT_DELAY 20
static void defer_touch_event(SDL_TouchFingerEvent *e) {
switch (deferred_touch_event.type) {
case SDL_FINGERDOWN:
mouseb |= 1 << SDL_BUTTON_LEFT;
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_LEFT)] = true;
break;
case SDL_FINGERUP:
mouseb &= ~(1 << SDL_BUTTON_LEFT | 1 << SDL_BUTTON_RIGHT);
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_LEFT)] = false;
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_RIGHT)] = false;
break;
}
if (e)
deferred_touch_event = *e;
else
deferred_touch_event.timestamp = 0;
}
static void fire_deferred_touch_event(void) {
if (deferred_touch_event.timestamp && deferred_touch_event.timestamp + TOUCH_EVENT_DELAY < SDL_GetTicks()) {
defer_touch_event(NULL);
}
}
// Improves map navigation of Rance4 v2. See also the function comment of
// rance4_Y3_IM_hack() in cmdy.c.
static void rance4v2_hack(void) {
// Do not wait for vsync while a mouse button or an arrow key is pressed.
if (mouseb ||
(RawKeyInfo[KEY_UP] || RawKeyInfo[KEY_PAD_8]) ||
(RawKeyInfo[KEY_DOWN] || RawKeyInfo[KEY_PAD_2]) ||
(RawKeyInfo[KEY_LEFT] || RawKeyInfo[KEY_PAD_4]) ||
(RawKeyInfo[KEY_RIGHT] || RawKeyInfo[KEY_PAD_6]))
cancel_yield();
}
void event_handle_event(SDL_Event *e) {
if (event_custom_handler && event_custom_handler(e))
return;
switch (e->type) {
case SDL_QUIT:
menu_quitmenu_open();
break;
case SDL_WINDOWEVENT:
switch (e->window.event) {
case SDL_WINDOWEVENT_EXPOSED:
gfx_dirty = true;
break;
}
break;
#ifdef _WIN32
case SDL_SYSWMEVENT:
win_menu_onSysWMEvent(e->syswm.msg);
break;
#endif
case SDL_APP_DIDENTERFOREGROUND:
gfx_dirty = true;
break;
case SDL_KEYDOWN:
keyEventProsess(&e->key, true);
break;
case SDL_KEYUP:
keyEventProsess(&e->key, false);
switch (e->key.keysym.sym) {
case SDLK_F1:
msgskip_activate(!msgskip_isActivated());
break;
case SDLK_F4:
gfx_setFullscreen(!gfx_fullscreen);
break;
}
#ifdef __ANDROID__
if (e->key.keysym.scancode == SDL_SCANCODE_AC_BACK) {
menu_quitmenu_open();
}
#endif
break;
case SDL_MOUSEMOTION:
event_set_mouse_internal_location(e->motion.x, e->motion.y);
#ifdef _WIN32
win_menu_onMouseMotion(e->motion.x, e->motion.y);
#endif
break;
case SDL_MOUSEWHEEL:
{
int y = e->wheel.y * (e->wheel.direction == SDL_MOUSEWHEEL_FLIPPED ? -1 : 1);
if (y > 0)
mouse_wheel_up += y;
else if (y < 0)
mouse_wheel_down -= y;
send_agsevent(AGSEVENT_MOUSE_WHEEL, y);
break;
}
case SDL_MOUSEBUTTONDOWN:
mouseb |= (1 << e->button.button);
RawKeyInfo[mouse_to_rawkey(e->button.button)] = true;
send_agsevent(AGSEVENT_BUTTON_PRESS, mouse_to_agsevent(e->button.button));
break;
case SDL_MOUSEBUTTONUP:
mouseb &= (0xffffffff ^ (1 << e->button.button));
RawKeyInfo[mouse_to_rawkey(e->button.button)] = false;
send_agsevent(AGSEVENT_BUTTON_RELEASE, mouse_to_agsevent(e->button.button));
if (e->button.button == 2) {
menu_open();
}
break;
case SDL_FINGERDOWN:
if (SDL_GetNumTouchFingers(e->tfinger.touchId) >= 2) {
mouseb &= ~(1 << SDL_BUTTON_LEFT);
mouseb |= 1 << SDL_BUTTON_RIGHT;
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_LEFT)] = false;
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_RIGHT)] = true;
send_agsevent(AGSEVENT_BUTTON_PRESS, AGSEVENT_BUTTON_RIGHT);
} else {
// SDL_RendererEventWatch clamps touch locations outside of the
// viewport to 0.0-1.0. Treat such events as right-clicks.
int button;
if (e->tfinger.x == 0.0f || e->tfinger.x == 1.0f || e->tfinger.y == 0.0f || e->tfinger.y == 1.0f) {
button = SDL_BUTTON_RIGHT;
mouseb |= 1 << SDL_BUTTON_RIGHT;
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_RIGHT)] = true;
} else {
button = SDL_BUTTON_LEFT;
mousex = e->tfinger.x * view_w;
mousey = e->tfinger.y * view_h;
send_agsevent(AGSEVENT_MOUSE_MOTION, 0);
defer_touch_event(&e->tfinger);
}
send_agsevent(AGSEVENT_BUTTON_PRESS, mouse_to_agsevent(button));
}
break;
case SDL_FINGERUP:
if (SDL_GetNumTouchFingers(e->tfinger.touchId) == 0) {
int ags_button = (mouseb & 1 << SDL_BUTTON_LEFT) ? AGSEVENT_BUTTON_LEFT : AGSEVENT_BUTTON_RIGHT;
mousex = e->tfinger.x * view_w;
mousey = e->tfinger.y * view_h;
send_agsevent(AGSEVENT_BUTTON_RELEASE, ags_button);
defer_touch_event(&e->tfinger);
}
break;
case SDL_FINGERMOTION:
mousex = e->tfinger.x * view_w;
mousey = e->tfinger.y * view_h;
send_agsevent(AGSEVENT_MOUSE_MOTION, 0);
break;
case SDL_JOYDEVICEADDED:
joy_open(e->jdevice.which);
break;
case SDL_JOYAXISMOTION:
if (abs(e->jaxis.value) < 0x4000) {
joyinfo &= e->jaxis.axis == 0 ? ~0xc : ~3;
} else {
int i = (e->jaxis.axis == 0 ? 2 : 0) +
(e->jaxis.value > 0 ? 1 : 0);
joyinfo |= 1 << i;
}
break;
case SDL_JOYBALLMOTION:
break;
case SDL_JOYHATMOTION:
joyinfo &= ~(SYS35KEY_UP | SYS35KEY_DOWN | SYS35KEY_LEFT | SYS35KEY_RIGHT);
switch (e->jhat.value) {
case SDL_HAT_UP: joyinfo |= SYS35KEY_UP; break;
case SDL_HAT_DOWN: joyinfo |= SYS35KEY_DOWN; break;
case SDL_HAT_LEFT: joyinfo |= SYS35KEY_LEFT; break;
case SDL_HAT_RIGHT: joyinfo |= SYS35KEY_RIGHT; break;
case SDL_HAT_LEFTUP: joyinfo |= SYS35KEY_LEFT | SYS35KEY_UP; break;
case SDL_HAT_RIGHTUP: joyinfo |= SYS35KEY_RIGHT | SYS35KEY_UP; break;
case SDL_HAT_LEFTDOWN: joyinfo |= SYS35KEY_LEFT | SYS35KEY_DOWN; break;
case SDL_HAT_RIGHTDOWN: joyinfo |= SYS35KEY_RIGHT | SYS35KEY_DOWN; break;
}
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
{
int mask = 0;
switch (e->jbutton.button) {
case 0: case 1: case 2: case 3:
mask = 1 << (e->jbutton.button + 4);
break;
#ifdef __EMSCRIPTEN__
// Gamepads known to browsers get a "standard" mapping where D-pad
// keys are mapped to buttons 12-15.
case 12: mask = SYS35KEY_UP; break;
case 13: mask = SYS35KEY_DOWN; break;
case 14: mask = SYS35KEY_LEFT; break;
case 15: mask = SYS35KEY_RIGHT; break;
#endif
}
if (mask) {
if (e->jbutton.state == SDL_PRESSED)
joyinfo |= mask;
else
joyinfo &= ~mask;
}
}
break;
default:
if (e->type == custom_event_type) {
switch (e->user.code) {
case SIMULATE_RIGHT_BUTTON:
if ((intptr_t)e->user.data1) {
mouseb |= 1 << SDL_BUTTON_RIGHT;
RawKeyInfo[KEY_MOUSE_RIGHT] = true;
send_agsevent(AGSEVENT_BUTTON_PRESS, AGSEVENT_BUTTON_RIGHT);
} else {
mouseb &= ~(1 << SDL_BUTTON_RIGHT);
RawKeyInfo[KEY_MOUSE_RIGHT] = false;
send_agsevent(AGSEVENT_BUTTON_RELEASE, AGSEVENT_BUTTON_RIGHT);
}
break;
case DEBUGGER_COMMAND:
dbg_post_command(e->user.data1);
break;
}
}
break;
}
}
/* Event処理 */
static void get_event(void) {
enum scheduler_event scheduler_event = SCHEDULER_EVENT_INPUT_CHECK_MISS;
fire_deferred_touch_event();
SDL_Event e;
while (SDL_PollEvent(&e)) {
scheduler_event = SCHEDULER_EVENT_INPUT_CHECK_HIT;
event_handle_event(&e);
}
scheduler_on_event(scheduler_event);
if (game_id == GAME_RANCE4_V2)
rance4v2_hack();
}
/* キー情報の取得 */
static void keyEventProsess(SDL_KeyboardEvent *e, bool pressed) {
int code = keytable[e->keysym.scancode];
RawKeyInfo[code] = pressed;
send_agsevent(pressed ? AGSEVENT_KEY_PRESS : AGSEVENT_KEY_RELEASE, code);
}
int event_get_key(void) {
int rt;
get_event();
rt = ((RawKeyInfo[KEY_UP] || RawKeyInfo[KEY_PAD_8]) |
((RawKeyInfo[KEY_DOWN] || RawKeyInfo[KEY_PAD_2]) << 1) |
((RawKeyInfo[KEY_LEFT] || RawKeyInfo[KEY_PAD_4]) << 2) |
((RawKeyInfo[KEY_RIGHT] || RawKeyInfo[KEY_PAD_6]) << 3) |
(RawKeyInfo[KEY_RETURN] << 4) |
(RawKeyInfo[KEY_SPACE ] << 5) |
(RawKeyInfo[KEY_ESCAPE] << 6) |
(RawKeyInfo[KEY_TAB] << 7));
return rt;
}
int event_get_mouse(SDL_Point *p) {
get_event();
if (p) {
p->x = mousex;
p->y = mousey;
}
int m1 = mouseb & (1 << 1) ? SYS35KEY_RET : 0;
int m2 = mouseb & (1 << 3) ? SYS35KEY_SPC : 0;
return m1 | m2;
}
void event_get_wheel(int *forward, int *back) {
*forward = mouse_wheel_up;
*back = mouse_wheel_down;
#ifdef __EMSCRIPTEN__
EM_ASM( xsystem35.texthook.disableWheelEvent(100) );
#endif
}
void event_clear_wheel(void) {
mouse_wheel_up = mouse_wheel_down = 0;
}
int event_get_joy(void) {
get_event();
return joyinfo;
}
void event_post_debugger_command(void *data) {
SDL_Event event = {
.user = {
.type = custom_event_type,
.code = DEBUGGER_COMMAND,
.data1 = data
}
};
SDL_PushEvent(&event);
}
#ifdef __EMSCRIPTEN__
EMSCRIPTEN_KEEPALIVE
void simulate_right_button(int pressed) {
SDL_Event event = {
.user = {
.type = custom_event_type,
.code = SIMULATE_RIGHT_BUTTON,
.data1 = (void*)pressed
}
};
SDL_PushEvent(&event);
}
#endif