From 419da7889c576a6f8b219cddfcabd6d5e2c24012 Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Mon, 18 Nov 2019 21:58:54 -0800 Subject: [PATCH] Implement mouse and keyboard input support The popolytan demo now has a functional menu, albeit without text. --- cg.c | 48 +++++++------ cg.h | 1 + hll/SACT2.c | 40 +++++++---- input.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++ input.h | 144 +++++++++++++++++++++++++++++++++++++ meson.build | 1 + 6 files changed, 404 insertions(+), 34 deletions(-) create mode 100644 input.c create mode 100644 input.h diff --git a/cg.c b/cg.c index 63523f4..f1f4935 100644 --- a/cg.c +++ b/cg.c @@ -43,19 +43,24 @@ static enum cg_type check_cgformat(uint8_t *data) return ALCG_UNKNOWN; } +void _cg_free(struct cg *cg) +{ + if (!cg) + return; + if (cg->s) { + if (cg->no >= 0) + free(cg->s->pixels); + SDL_FreeSurface(cg->s); + } +} + /* * Free CG data * cg: object to free */ void cg_free(struct cg *cg) { - if (!cg) - return; - if (cg->s) { - if (cg->no < 0) - free(cg->s->pixels); - SDL_FreeSurface(cg->s); - } + _cg_free(cg); free(cg); } @@ -101,21 +106,24 @@ bool cg_load(struct cg *cg, int no) return true; } +void _cg_init(struct cg *cg, int width, int height, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + cg->no = -1; + cg->rect.w = width; + cg->rect.h = height; + cg->color = (SDL_Color) { .r = r, .g = g, .b = b, .a = a }; + cg->s = NULL; +} + +void cg_reinit(struct cg *cg, int width, int height, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + _cg_free(cg); + _cg_init(cg, width, height, r, g, b, a); +} + struct cg *cg_init(int width, int height, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { struct cg *cg = calloc(1, sizeof(struct cg)); - *cg = (struct cg) { - .no = -1, - .rect = { - .w = width, - .h = height - }, - .color = { - .r = r, - .g = g, - .b = b, - .a = a - } - }; + _cg_init(cg, width, height, r, g, b, a); return cg; } diff --git a/cg.h b/cg.h index ad9659b..89b0f30 100644 --- a/cg.h +++ b/cg.h @@ -51,6 +51,7 @@ struct cg { bool cg_exists(int no); bool cg_load(struct cg *cg, int no); struct cg *cg_init(int width, int height, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +void cg_reinit(struct cg *cg, int width, int height, uint8_t r, uint8_t g, uint8_t b, uint8_t a); void cg_free(struct cg *cg); #endif /* SYSTEM4_CG_H */ diff --git a/hll/SACT2.c b/hll/SACT2.c index b242528..fe37fec 100644 --- a/hll/SACT2.c +++ b/hll/SACT2.c @@ -20,6 +20,7 @@ #include "../system4.h" #include "../vm.h" #include "../cg.h" +#include "../input.h" #include "../queue.h" #include "../sdl_core.h" @@ -83,6 +84,7 @@ hll_unimplemented(SACT2, GetMainSurfaceNumber) // int Update(void) hll_defun(Update, _) { + handle_events(); struct SACT2_sprite *p; TAILQ_FOREACH_REVERSE(p, &sprite_list, listhead, entry) { if (!p->cg->show) @@ -162,14 +164,13 @@ hll_defun(SP_Create, args) int b = args[5].i; int a = args[6].i; - if (sprites[sp].used) { - TAILQ_REMOVE(&sprite_list, &sprites[sp], entry); - cg_free(sprites[sp].cg); + if (sprites[sp].used && sprites[sp].cg) { + cg_reinit(sprites[sp].cg, width, height, r, g, b, a); + } else { + sprites[sp].used = true; + sprites[sp].cg = cg_init(width, height, r, g, b, a); + sprite_register(&sprites[sp]); } - - sprites[sp].used = true; - sprites[sp].cg = cg_init(width, height, r, g, b, a); - sprite_register(&sprites[sp]); hll_return(1); } @@ -319,8 +320,18 @@ hll_unimplemented(SACT2, SP_GetTextPosY) hll_unimplemented(SACT2, SP_GetTextLineSpace) // int SP_IsPtIn(int nSP, int nX, int nY) hll_unimplemented(SACT2, SP_IsPtIn) + // int SP_IsPtInRect(int nSP, int nX, int nY) -hll_unimplemented(SACT2, SP_IsPtInRect) +hll_defun(SP_IsPtInRect, args) +{ + struct SACT2_sprite *sp = &sprites[args[0].i]; + Point p = { .x = args[1].i, .y = args[2].i }; + + if (!sp->used) + hll_return(0); + hll_return(!!SDL_PointInRect(&p, &sp->cg->rect)); +} + // int GAME_MSG_GetNumof(void) hll_unimplemented(SACT2, GAME_MSG_GetNumof) // void GAME_MSG_Get(int nIndex, ref string text) @@ -335,14 +346,12 @@ hll_unimplemented(SACT2, StringPopFront) // int Mouse_GetPos(ref int pnX, ref int pnY) hll_defun(Mouse_GetPos, args) { - hll_unimplemented_warning(SACT2, Mouse_GetPos); - *args[0].iref = 0; - *args[1].iref = 0; - hll_return(0); + mouse_get_pos(args[0].iref, args[1].iref); + hll_return(mouse_focus && keyboard_focus); } // int Mouse_SetPos(int nX, int nY) -hll_unimplemented(SACT2, Mouse_SetPos) +hll_warn_unimplemented(SACT2, Mouse_SetPos, 1) // void Mouse_ClearWheel(void) hll_warn_unimplemented(SACT2, Mouse_ClearWheel, 0) @@ -388,7 +397,10 @@ hll_defun(Joypad_GetDigitalStickStatus, args) hll_warn_unimplemented(SACT2, Key_ClearFlag, 1) // int Key_IsDown(int nKeyCode) -hll_warn_unimplemented(SACT2, Key_IsDown, 0) +hll_defun(Key_IsDown, args) +{ + hll_return(key_is_down(args[0].i)); +} // int Timer_Get(void) hll_defun(Timer_Get, _) diff --git a/input.c b/input.c new file mode 100644 index 0000000..b3d1f9b --- /dev/null +++ b/input.c @@ -0,0 +1,204 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * 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, see . + */ + +#include +#include "system4.h" +#include "sdl_private.h" +#include "input.h" + +bool key_state[VK_NR_KEYCODES]; +static enum sact_keycode sdl_keytable[]; + +bool mouse_focus = true; +bool keyboard_focus = true; + +static SDL_Scancode sact_to_sdl_button(enum sact_keycode code) +{ + switch (code) { + case VK_LBUTTON: return SDL_BUTTON_LEFT; + case VK_RBUTTON: return SDL_BUTTON_RIGHT; + case VK_MBUTTON: return SDL_BUTTON_MIDDLE; + default: return 0; + } +} + +bool key_is_down(enum sact_keycode code) +{ + int button = sact_to_sdl_button(code); + if (button) + return SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(button); + return key_state[code]; +} + +static void key_event(SDL_KeyboardEvent *e, bool pressed) +{ + enum sact_keycode code = sdl_keytable[e->keysym.scancode]; + if (code) + key_state[code] = pressed; +} + +void mouse_get_pos(int *x, int *y) +{ + SDL_GetMouseState(x, y); +} + +void handle_events(void) +{ + SDL_Event e; + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_QUIT: + sys_exit(0); + break; + case SDL_WINDOWEVENT: + switch (e.window.event) { + case SDL_WINDOWEVENT_EXPOSED: + sdl.dirty = true; + break; + case SDL_WINDOWEVENT_ENTER: + mouse_focus = true; + break; + case SDL_WINDOWEVENT_LEAVE: + mouse_focus = false; + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + keyboard_focus = true; + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + keyboard_focus = false; + break; + } + break; + case SDL_KEYDOWN: + key_event(&e.key, true); + break; + case SDL_KEYUP: + key_event(&e.key, false); + break; + default: + break; + } + } +} + +static enum sact_keycode sdl_keytable[] = { + [SDL_SCANCODE_0] = VK_0, + [SDL_SCANCODE_1] = VK_1, + [SDL_SCANCODE_2] = VK_2, + [SDL_SCANCODE_3] = VK_3, + [SDL_SCANCODE_4] = VK_4, + [SDL_SCANCODE_5] = VK_5, + [SDL_SCANCODE_6] = VK_6, + [SDL_SCANCODE_7] = VK_7, + [SDL_SCANCODE_8] = VK_8, + [SDL_SCANCODE_9] = VK_9, + [SDL_SCANCODE_A] = VK_A, + [SDL_SCANCODE_B] = VK_B, + [SDL_SCANCODE_C] = VK_C, + [SDL_SCANCODE_D] = VK_D, + [SDL_SCANCODE_E] = VK_E, + [SDL_SCANCODE_F] = VK_F, + [SDL_SCANCODE_G] = VK_G, + [SDL_SCANCODE_H] = VK_H, + [SDL_SCANCODE_I] = VK_I, + [SDL_SCANCODE_J] = VK_J, + [SDL_SCANCODE_K] = VK_K, + [SDL_SCANCODE_L] = VK_L, + [SDL_SCANCODE_M] = VK_M, + [SDL_SCANCODE_N] = VK_N, + [SDL_SCANCODE_O] = VK_O, + [SDL_SCANCODE_P] = VK_P, + [SDL_SCANCODE_Q] = VK_Q, + [SDL_SCANCODE_R] = VK_R, + [SDL_SCANCODE_S] = VK_S, + [SDL_SCANCODE_T] = VK_T, + [SDL_SCANCODE_U] = VK_U, + [SDL_SCANCODE_V] = VK_V, + [SDL_SCANCODE_W] = VK_W, + [SDL_SCANCODE_X] = VK_X, + [SDL_SCANCODE_Y] = VK_Y, + [SDL_SCANCODE_Z] = VK_Z, + [SDL_SCANCODE_BACKSPACE] = VK_BACK, + [SDL_SCANCODE_TAB] = VK_TAB, + [SDL_SCANCODE_CLEAR] = VK_CLEAR, + [SDL_SCANCODE_RETURN] = VK_RETURN, + [SDL_SCANCODE_LSHIFT] = VK_SHIFT, + [SDL_SCANCODE_RSHIFT] = VK_SHIFT, + [SDL_SCANCODE_LCTRL] = VK_CONTROL, + [SDL_SCANCODE_RCTRL] = VK_CONTROL, + [SDL_SCANCODE_LALT] = VK_MENU, + [SDL_SCANCODE_RALT] = VK_MENU, + [SDL_SCANCODE_PAUSE] = VK_PAUSE, + [SDL_SCANCODE_CAPSLOCK] = VK_CAPITAL, + [SDL_SCANCODE_ESCAPE] = VK_ESCAPE, + [SDL_SCANCODE_SPACE] = VK_SPACE, + [SDL_SCANCODE_PAGEUP] = VK_PRIOR, + [SDL_SCANCODE_PAGEDOWN] = VK_NEXT, + [SDL_SCANCODE_END] = VK_END, + [SDL_SCANCODE_HOME] = VK_HOME, + [SDL_SCANCODE_LEFT] = VK_LEFT, + [SDL_SCANCODE_UP] = VK_UP, + [SDL_SCANCODE_RIGHT] = VK_RIGHT, + [SDL_SCANCODE_DOWN] = VK_DOWN, + [SDL_SCANCODE_SELECT] = VK_SELECT, + [SDL_SCANCODE_EXECUTE] = VK_EXECUTE, + [SDL_SCANCODE_PRINTSCREEN] = VK_SNAPSHOT, + [SDL_SCANCODE_INSERT] = VK_INSERT, + [SDL_SCANCODE_DELETE] = VK_DELETE, + [SDL_SCANCODE_HELP] = VK_HELP, + [SDL_SCANCODE_KP_0] = VK_NUMPAD0, + [SDL_SCANCODE_KP_1] = VK_NUMPAD1, + [SDL_SCANCODE_KP_2] = VK_NUMPAD2, + [SDL_SCANCODE_KP_3] = VK_NUMPAD3, + [SDL_SCANCODE_KP_4] = VK_NUMPAD4, + [SDL_SCANCODE_KP_5] = VK_NUMPAD5, + [SDL_SCANCODE_KP_6] = VK_NUMPAD6, + [SDL_SCANCODE_KP_7] = VK_NUMPAD7, + [SDL_SCANCODE_KP_8] = VK_NUMPAD8, + [SDL_SCANCODE_KP_9] = VK_NUMPAD9, + [SDL_SCANCODE_KP_MULTIPLY] = VK_MULTIPLY, + [SDL_SCANCODE_KP_PLUS] = VK_ADD, + [SDL_SCANCODE_KP_VERTICALBAR] = VK_SEPARATOR, // ??? + [SDL_SCANCODE_KP_MINUS] = VK_SUBTRACT, + [SDL_SCANCODE_KP_PERIOD] = VK_DECIMAL, + [SDL_SCANCODE_KP_DIVIDE] = VK_DIVIDE, + [SDL_SCANCODE_F1] = VK_F1, + [SDL_SCANCODE_F2] = VK_F2, + [SDL_SCANCODE_F3] = VK_F3, + [SDL_SCANCODE_F4] = VK_F4, + [SDL_SCANCODE_F5] = VK_F5, + [SDL_SCANCODE_F6] = VK_F6, + [SDL_SCANCODE_F7] = VK_F7, + [SDL_SCANCODE_F8] = VK_F8, + [SDL_SCANCODE_F9] = VK_F9, + [SDL_SCANCODE_F10] = VK_F10, + [SDL_SCANCODE_F11] = VK_F11, + [SDL_SCANCODE_F12] = VK_F12, + [SDL_SCANCODE_F13] = VK_F13, + [SDL_SCANCODE_F14] = VK_F14, + [SDL_SCANCODE_F15] = VK_F15, + [SDL_SCANCODE_F16] = VK_F16, + [SDL_SCANCODE_F17] = VK_F17, + [SDL_SCANCODE_F18] = VK_F18, + [SDL_SCANCODE_F19] = VK_F19, + [SDL_SCANCODE_F20] = VK_F20, + [SDL_SCANCODE_F21] = VK_F21, + [SDL_SCANCODE_F22] = VK_F22, + [SDL_SCANCODE_F23] = VK_F23, + [SDL_SCANCODE_F24] = VK_F24, + [SDL_SCANCODE_NUMLOCKCLEAR] = VK_NUMLOCK, + [SDL_SCANCODE_SCROLLLOCK] = VK_SCROLL, +}; diff --git a/input.h b/input.h new file mode 100644 index 0000000..3f5111c --- /dev/null +++ b/input.h @@ -0,0 +1,144 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * 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, see . + */ + +#ifndef SYSTEM4_INPUT_H +#define SYSTEM4_INPUT_H + +#include +#include + +enum sact_keycode { + VK_LBUTTON = 0x01, // マウスの左ボタン + VK_RBUTTON = 0x02, // マウスの右ボタン + VK_MBUTTON = 0x04, // マウスの中央ボタンもしくはホイールクリック + VK_BACK = 0x08, // Backspace + VK_TAB = 0x09, // Tab + VK_CLEAR = 0x0c, // Clear(不明) + VK_RETURN = 0x0d, // Enter + VK_SHIFT = 0x10, // Shift + VK_CONTROL = 0x11, // Ctrl + VK_MENU = 0x12, // Alt([Alt]+[何か]の形でシステムが使用するので、通常は使用不可) + VK_PAUSE = 0x13, // Pause(通常は使用不可) + VK_CAPITAL = 0x14, // CapsLock(通常は使用不可) + VK_KANA = 0x15, // 英数カナ(不明) + VK_KANJI = 0x19, // (不明) + VK_ESCAPE = 0x1b, // Esc + VK_CONVERT = 0x1c, // (不明) + VK_NOCONVERT = 0x1d, // (不明) + VK_SPACE = 0x20, // space + VK_PRIOR = 0x21, // PageUp + VK_NEXT = 0x22, // PageDown + VK_END = 0x23, // End + VK_HOME = 0x24, // Home + VK_LEFT = 0x25, // ← + VK_UP = 0x26, // ↑ + VK_RIGHT = 0x27, // → + VK_DOWN = 0x28, // ↓ + VK_SELECT = 0x29, // Select(不明) + VK_EXECUTE = 0x2B, // Execute(不明) + VK_SNAPSHOT = 0x2C, // PrintScrn(使用不可) + VK_INSERT = 0x2D, // Insert,Ins + VK_DELETE = 0x2E, // Delete,Del + VK_HELP = 0x2F, // Help(不明) + VK_0 = 0x30, // テンキーはVK_NUMPAD0 + VK_1 = 0x31, // テンキーはVK_NUMPAD1 + VK_2 = 0x32, // テンキーはVK_NUMPAD2 + VK_3 = 0x33, // テンキーはVK_NUMPAD3 + VK_4 = 0x34, // テンキーはVK_NUMPAD4 + VK_5 = 0x35, // テンキーはVK_NUMPAD5 + VK_6 = 0x36, // テンキーはVK_NUMPAD6 + VK_7 = 0x37, // テンキーはVK_NUMPAD7 + VK_8 = 0x38, // テンキーはVK_NUMPAD8 + VK_9 = 0x39, // テンキーはVK_NUMPAD9 + VK_A = 0x41, // 'A'で代用可 + VK_B = 0x42, // 'B'で代用可 + VK_C = 0x43, // 'C'で代用可 + VK_D = 0x44, // 'D'で代用可 + VK_E = 0x45, // 'E'で代用可 + VK_F = 0x46, // 'F'で代用可 + VK_G = 0x47, // 'G'で代用可 + VK_H = 0x48, // 'H'で代用可 + VK_I = 0x49, // 'I'で代用可 + VK_J = 0x4a, // 'J'で代用可 + VK_K = 0x4b, // 'K'で代用可 + VK_L = 0x4c, // 'L'で代用可 + VK_M = 0x4d, // 'M'で代用可 + VK_N = 0x4e, // 'N'で代用可 + VK_O = 0x4f, // 'O'で代用可 + VK_P = 0x50, // 'P'で代用可 + VK_Q = 0x51, // 'Q'で代用可 + VK_R = 0x52, // 'R'で代用可 + VK_S = 0x53, // 'S'で代用可 + VK_T = 0x54, // 'T'で代用可 + VK_U = 0x55, // 'U'で代用可 + VK_V = 0x56, // 'V'で代用可 + VK_W = 0x57, // 'W'で代用可 + VK_X = 0x58, // 'X'で代用可 + VK_Y = 0x59, // 'Y'で代用可 + VK_Z = 0x5a, // 'Z'で代用可 + VK_NUMPAD0 = 0x60, // テンキーの0 + VK_NUMPAD1 = 0x61, // テンキーの1 + VK_NUMPAD2 = 0x62, // テンキーの2 + VK_NUMPAD3 = 0x63, // テンキーの3 + VK_NUMPAD4 = 0x64, // テンキーの4 + VK_NUMPAD5 = 0x65, // テンキーの5 + VK_NUMPAD6 = 0x66, // テンキーの6 + VK_NUMPAD7 = 0x67, // テンキーの7 + VK_NUMPAD8 = 0x68, // テンキーの8 + VK_NUMPAD9 = 0x69, // テンキーの9 + VK_MULTIPLY = 0x6a, // テンキーの* + VK_ADD = 0x6b, // テンキーの+ + VK_SEPARATOR = 0x6c, // Separator(不明) + VK_SUBTRACT = 0x6d, // テンキーの- + VK_DECIMAL = 0x6e, // テンキーの. + VK_DIVIDE = 0x6f, // テンキーの/ + VK_F1 = 0x70, // F1 + VK_F2 = 0x71, // F2 + VK_F3 = 0x72, // F3 + VK_F4 = 0x73, // F4 + VK_F5 = 0x74, // F5 + VK_F6 = 0x75, // F6 + VK_F7 = 0x76, // F7 + VK_F8 = 0x77, // F8 + VK_F9 = 0x78, // F9 + VK_F10 = 0x79, // F10(使用不可) + VK_F11 = 0x7A, // F11 + VK_F12 = 0x7B, // F12 + VK_F13 = 0x7C, // F13 + VK_F14 = 0x7D, // F14 + VK_F15 = 0x7E, // F15 + VK_F16 = 0x7F, // F16 + VK_F17 = 0x80, // F17 + VK_F18 = 0x81, // F18 + VK_F19 = 0x82, // F19 + VK_F20 = 0x83, // F20 + VK_F21 = 0x84, // F21 + VK_F22 = 0x85, // F22 + VK_F23 = 0x86, // F23 + VK_F24 = 0x87, // F24 + VK_NUMLOCK = 0x90, // NumLock(通常は使用不可) + VK_SCROLL = 0x91, // ScrollLock(通常は使用不可) + VK_NR_KEYCODES +}; + +bool mouse_focus; +bool keyboard_focus; + +void handle_events(void); +bool key_is_down(enum sact_keycode code); +void mouse_get_pos(int *x, int *y); + +#endif /* SYSTEM4_INPUT_H */ diff --git a/meson.build b/meson.build index ba8f5e6..81158be 100644 --- a/meson.build +++ b/meson.build @@ -10,6 +10,7 @@ xsystem4 = ['ald.c', 'cg.c', 'qnt.c', 'ini.c', + 'input.c', 'page.c', 'sdl_draw.c', 'sdl_video.c',