diff --git a/include/tic80/tic80.h b/include/tic80/tic80.h index 65989db..5054869 100644 --- a/include/tic80/tic80.h +++ b/include/tic80/tic80.h @@ -34,6 +34,7 @@ extern "C" { #define TIC80_FULLWIDTH_BITS 8 #define TIC80_FULLWIDTH (1 << TIC80_FULLWIDTH_BITS) #define TIC80_FULLHEIGHT (TIC80_FULLWIDTH*9/16) +#define TIC_KEY_BUFFER 4 typedef struct { @@ -104,9 +105,12 @@ typedef struct }; } tic80_mouse; -typedef struct +typedef u8 tic_key; + +typedef union { - u8 data[4]; + tic_key keys[TIC_KEY_BUFFER]; + u32 data; } tic80_keyboard; typedef struct diff --git a/src/jsapi.c b/src/jsapi.c index c14837e..3fa311a 100644 --- a/src/jsapi.c +++ b/src/jsapi.c @@ -195,23 +195,17 @@ static duk_ret_t duk_btn(duk_context* duk) { tic_machine* machine = getDukMachine(duk); - if(machine->memory.input.gamepad) + if (duk_is_null_or_undefined(duk, 0)) { - if (duk_is_null_or_undefined(duk, 0)) - { - duk_push_uint(duk, machine->memory.ram.input.gamepads.data); - } - else - { - s32 index = duk_to_int(duk, 0) & 0xf; - duk_push_boolean(duk, machine->memory.ram.input.gamepads.data & (1 << index)); - } - - return 1; + duk_push_uint(duk, machine->memory.ram.input.gamepads.data); + } + else + { + s32 index = duk_to_int(duk, 0) & 0x1f; + duk_push_boolean(duk, machine->memory.ram.input.gamepads.data & (1 << index)); } - else duk_error(duk, DUK_ERR_ERROR, "gamepad input not declared in metadata\n"); - return 0; + return 1; } static duk_ret_t duk_btnp(duk_context* duk) @@ -219,30 +213,87 @@ static duk_ret_t duk_btnp(duk_context* duk) tic_machine* machine = getDukMachine(duk); tic_mem* memory = (tic_mem*)machine; - if(machine->memory.input.gamepad) + if (duk_is_null_or_undefined(duk, 0)) { - if (duk_is_null_or_undefined(duk, 0)) - { - duk_push_uint(duk, memory->api.btnp(memory, -1, -1, -1)); - } - else if(duk_is_null_or_undefined(duk, 1) && duk_is_null_or_undefined(duk, 2)) - { - s32 index = duk_to_int(duk, 0) & 0xf; + duk_push_uint(duk, memory->api.btnp(memory, -1, -1, -1)); + } + else if(duk_is_null_or_undefined(duk, 1) && duk_is_null_or_undefined(duk, 2)) + { + s32 index = duk_to_int(duk, 0) & 0x1f; - duk_push_boolean(duk, memory->api.btnp(memory, index, -1, -1)); + duk_push_boolean(duk, memory->api.btnp(memory, index, -1, -1)); + } + else + { + s32 index = duk_to_int(duk, 0) & 0x1f; + u32 hold = duk_to_int(duk, 1); + u32 period = duk_to_int(duk, 2); + + duk_push_boolean(duk, memory->api.btnp(memory, index, hold, period)); + } + + return 1; +} + +static s32 duk_key(duk_context* duk) +{ + tic_machine* machine = getDukMachine(duk); + tic_mem* tic = &machine->memory; + + if (duk_is_null_or_undefined(duk, 0)) + { + duk_push_uint(duk, tic->api.key(tic, tic_key_unknown)); + } + else + { + tic_key key = duk_to_int(duk, 0) + TIC_KEY_START_INDEX; + + if(key < TIC_KEYS_COUNT) + duk_push_boolean(duk, tic->api.key(tic, key)); + else + { + duk_error(duk, DUK_ERR_ERROR, "unknown keyboard code\n"); + return 0; + } + } + + return 1; +} + +static s32 duk_keyp(duk_context* duk) +{ + tic_machine* machine = getDukMachine(duk); + tic_mem* tic = &machine->memory; + + if (duk_is_null_or_undefined(duk, 0)) + { + duk_push_uint(duk, tic->api.keyp(tic, tic_key_unknown, -1, -1)); + } + else + { + tic_key key = duk_to_int(duk, 0) + TIC_KEY_START_INDEX; + + if(key >= TIC_KEYS_COUNT) + { + duk_error(duk, DUK_ERR_ERROR, "unknown keyboard code\n"); } else { - s32 index = duk_to_int(duk, 0) & 0xf; - u32 hold = duk_to_int(duk, 1); - u32 period = duk_to_int(duk, 2); + if(duk_is_null_or_undefined(duk, 1) && duk_is_null_or_undefined(duk, 2)) + { + duk_push_boolean(duk, tic->api.keyp(tic, key, -1, -1)); + return 1; + } + else + { + u32 hold = duk_to_int(duk, 1); + u32 period = duk_to_int(duk, 2); - duk_push_boolean(duk, memory->api.btnp(memory, index, hold, period)); + duk_push_boolean(duk, tic->api.keyp(tic, key, hold, period)); + return 1; + } } - - return 1; } - else duk_error(duk, DUK_ERR_ERROR, "gamepad input not declared in metadata\n"); return 0; } @@ -580,27 +631,21 @@ static duk_ret_t duk_mouse(duk_context* duk) { tic_machine* machine = getDukMachine(duk); - if(machine->memory.input.mouse) - { - const tic80_mouse* mouse = &machine->memory.ram.input.mouse; + const tic80_mouse* mouse = &machine->memory.ram.input.mouse; - duk_idx_t idx = duk_push_array(duk); - duk_push_int(duk, mouse->x); - duk_put_prop_index(duk, idx, 0); - duk_push_int(duk, mouse->y); - duk_put_prop_index(duk, idx, 1); - duk_push_boolean(duk, mouse->left); - duk_put_prop_index(duk, idx, 2); - duk_push_boolean(duk, mouse->middle); - duk_put_prop_index(duk, idx, 3); - duk_push_boolean(duk, mouse->right); - duk_put_prop_index(duk, idx, 4); + duk_idx_t idx = duk_push_array(duk); + duk_push_int(duk, mouse->x); + duk_put_prop_index(duk, idx, 0); + duk_push_int(duk, mouse->y); + duk_put_prop_index(duk, idx, 1); + duk_push_boolean(duk, mouse->left); + duk_put_prop_index(duk, idx, 2); + duk_push_boolean(duk, mouse->middle); + duk_put_prop_index(duk, idx, 3); + duk_push_boolean(duk, mouse->right); + duk_put_prop_index(duk, idx, 4); - return 1; - } - else duk_error(duk, DUK_ERR_ERROR, "mouse input not declared in metadata\n"); - - return 0; + return 1; } static duk_ret_t duk_circ(duk_context* duk) @@ -771,8 +816,12 @@ static const struct{duk_c_function func; s32 params;} ApiFunc[] = {duk_music, 4}, {duk_sync, 3}, {duk_reset, 0}, + {duk_key, 1}, + {duk_keyp, 3}, }; +STATIC_ASSERT(api_func, COUNT_OF(ApiKeywords) == COUNT_OF(ApiFunc)); + s32 duk_timeout_check(void* udata) { tic_machine* machine = (tic_machine*)udata; diff --git a/src/keycodes.c b/src/keycodes.c new file mode 100644 index 0000000..c5d9fc6 --- /dev/null +++ b/src/keycodes.c @@ -0,0 +1,227 @@ +[0] = tic_key_unknown, +[1] = tic_key_unknown, +[2] = tic_key_unknown, +[3] = tic_key_unknown, +[SDL_SCANCODE_A] = tic_key_a, +[SDL_SCANCODE_B] = tic_key_b, +[SDL_SCANCODE_C] = tic_key_c, +[SDL_SCANCODE_D] = tic_key_d, +[SDL_SCANCODE_E] = tic_key_e, +[SDL_SCANCODE_F] = tic_key_f, +[SDL_SCANCODE_G] = tic_key_g, +[SDL_SCANCODE_H] = tic_key_h, +[SDL_SCANCODE_I] = tic_key_i, +[SDL_SCANCODE_J] = tic_key_j, +[SDL_SCANCODE_K] = tic_key_k, +[SDL_SCANCODE_L] = tic_key_l, +[SDL_SCANCODE_M] = tic_key_m, +[SDL_SCANCODE_N] = tic_key_n, +[SDL_SCANCODE_O] = tic_key_o, +[SDL_SCANCODE_P] = tic_key_p, +[SDL_SCANCODE_Q] = tic_key_q, +[SDL_SCANCODE_R] = tic_key_r, +[SDL_SCANCODE_S] = tic_key_s, +[SDL_SCANCODE_T] = tic_key_t, +[SDL_SCANCODE_U] = tic_key_u, +[SDL_SCANCODE_V] = tic_key_v, +[SDL_SCANCODE_W] = tic_key_w, +[SDL_SCANCODE_X] = tic_key_x, +[SDL_SCANCODE_Y] = tic_key_y, +[SDL_SCANCODE_Z] = tic_key_z, +[SDL_SCANCODE_1] = tic_key_1, +[SDL_SCANCODE_2] = tic_key_2, +[SDL_SCANCODE_3] = tic_key_3, +[SDL_SCANCODE_4] = tic_key_4, +[SDL_SCANCODE_5] = tic_key_5, +[SDL_SCANCODE_6] = tic_key_6, +[SDL_SCANCODE_7] = tic_key_7, +[SDL_SCANCODE_8] = tic_key_8, +[SDL_SCANCODE_9] = tic_key_9, +[SDL_SCANCODE_0] = tic_key_0, +[SDL_SCANCODE_RETURN] = tic_key_return, +[SDL_SCANCODE_ESCAPE] = tic_key_escape, +[SDL_SCANCODE_BACKSPACE] = tic_key_backspace, +[SDL_SCANCODE_TAB] = tic_key_tab, +[SDL_SCANCODE_SPACE] = tic_key_space, +[SDL_SCANCODE_MINUS] = tic_key_minus, +[SDL_SCANCODE_EQUALS] = tic_key_equals, +[SDL_SCANCODE_LEFTBRACKET] = tic_key_leftbracket, +[SDL_SCANCODE_RIGHTBRACKET] = tic_key_rightbracket, +[SDL_SCANCODE_BACKSLASH] = tic_key_backslash, +[50] = tic_key_unknown, +[SDL_SCANCODE_SEMICOLON] = tic_key_semicolon, +[SDL_SCANCODE_APOSTROPHE] = tic_key_apostrophe, +[SDL_SCANCODE_GRAVE] = tic_key_grave, +[SDL_SCANCODE_COMMA] = tic_key_comma, +[SDL_SCANCODE_PERIOD] = tic_key_period, +[SDL_SCANCODE_SLASH] = tic_key_slash, +[SDL_SCANCODE_CAPSLOCK] = tic_key_capslock, +[SDL_SCANCODE_F1] = tic_key_f1, +[SDL_SCANCODE_F2] = tic_key_f2, +[SDL_SCANCODE_F3] = tic_key_f3, +[SDL_SCANCODE_F4] = tic_key_f4, +[SDL_SCANCODE_F5] = tic_key_f5, +[SDL_SCANCODE_F6] = tic_key_f6, +[SDL_SCANCODE_F7] = tic_key_f7, +[SDL_SCANCODE_F8] = tic_key_f8, +[SDL_SCANCODE_F9] = tic_key_f9, +[SDL_SCANCODE_F10] = tic_key_f10, +[SDL_SCANCODE_F11] = tic_key_f11, +[SDL_SCANCODE_F12] = tic_key_f12, +[70] = tic_key_unknown, +[71] = tic_key_unknown, +[72] = tic_key_unknown, +[SDL_SCANCODE_INSERT] = tic_key_insert, +[SDL_SCANCODE_HOME] = tic_key_home, +[SDL_SCANCODE_PAGEUP] = tic_key_pageup, +[SDL_SCANCODE_DELETE] = tic_key_delete, +[SDL_SCANCODE_END] = tic_key_end, +[SDL_SCANCODE_PAGEDOWN] = tic_key_pagedown, +[SDL_SCANCODE_RIGHT] = tic_key_right, +[SDL_SCANCODE_LEFT] = tic_key_left, +[SDL_SCANCODE_DOWN] = tic_key_down, +[SDL_SCANCODE_UP] = tic_key_up, +[83] = tic_key_unknown, +[84] = tic_key_unknown, +[85] = tic_key_unknown, +[86] = tic_key_unknown, +[87] = tic_key_unknown, +[88] = tic_key_unknown, +[89] = tic_key_unknown, +[90] = tic_key_unknown, +[91] = tic_key_unknown, +[92] = tic_key_unknown, +[93] = tic_key_unknown, +[94] = tic_key_unknown, +[95] = tic_key_unknown, +[96] = tic_key_unknown, +[97] = tic_key_unknown, +[98] = tic_key_unknown, +[99] = tic_key_unknown, +[100] = tic_key_unknown, +[101] = tic_key_unknown, +[102] = tic_key_unknown, +[103] = tic_key_unknown, +[104] = tic_key_unknown, +[105] = tic_key_unknown, +[106] = tic_key_unknown, +[107] = tic_key_unknown, +[108] = tic_key_unknown, +[109] = tic_key_unknown, +[110] = tic_key_unknown, +[111] = tic_key_unknown, +[112] = tic_key_unknown, +[113] = tic_key_unknown, +[114] = tic_key_unknown, +[115] = tic_key_unknown, +[116] = tic_key_unknown, +[117] = tic_key_unknown, +[118] = tic_key_unknown, +[119] = tic_key_unknown, +[120] = tic_key_unknown, +[121] = tic_key_unknown, +[122] = tic_key_unknown, +[123] = tic_key_unknown, +[124] = tic_key_unknown, +[125] = tic_key_unknown, +[126] = tic_key_unknown, +[127] = tic_key_unknown, +[128] = tic_key_unknown, +[129] = tic_key_unknown, +[130] = tic_key_unknown, +[131] = tic_key_unknown, +[132] = tic_key_unknown, +[133] = tic_key_unknown, +[134] = tic_key_unknown, +[135] = tic_key_unknown, +[136] = tic_key_unknown, +[137] = tic_key_unknown, +[138] = tic_key_unknown, +[139] = tic_key_unknown, +[140] = tic_key_unknown, +[141] = tic_key_unknown, +[142] = tic_key_unknown, +[143] = tic_key_unknown, +[144] = tic_key_unknown, +[145] = tic_key_unknown, +[146] = tic_key_unknown, +[147] = tic_key_unknown, +[148] = tic_key_unknown, +[149] = tic_key_unknown, +[150] = tic_key_unknown, +[151] = tic_key_unknown, +[152] = tic_key_unknown, +[153] = tic_key_unknown, +[154] = tic_key_unknown, +[155] = tic_key_unknown, +[156] = tic_key_unknown, +[157] = tic_key_unknown, +[158] = tic_key_unknown, +[159] = tic_key_unknown, +[160] = tic_key_unknown, +[161] = tic_key_unknown, +[162] = tic_key_unknown, +[163] = tic_key_unknown, +[164] = tic_key_unknown, +[165] = tic_key_unknown, +[166] = tic_key_unknown, +[167] = tic_key_unknown, +[168] = tic_key_unknown, +[169] = tic_key_unknown, +[170] = tic_key_unknown, +[171] = tic_key_unknown, +[172] = tic_key_unknown, +[173] = tic_key_unknown, +[174] = tic_key_unknown, +[175] = tic_key_unknown, +[176] = tic_key_unknown, +[177] = tic_key_unknown, +[178] = tic_key_unknown, +[179] = tic_key_unknown, +[180] = tic_key_unknown, +[181] = tic_key_unknown, +[182] = tic_key_unknown, +[183] = tic_key_unknown, +[184] = tic_key_unknown, +[185] = tic_key_unknown, +[186] = tic_key_unknown, +[187] = tic_key_unknown, +[188] = tic_key_unknown, +[189] = tic_key_unknown, +[190] = tic_key_unknown, +[191] = tic_key_unknown, +[192] = tic_key_unknown, +[193] = tic_key_unknown, +[194] = tic_key_unknown, +[195] = tic_key_unknown, +[196] = tic_key_unknown, +[197] = tic_key_unknown, +[198] = tic_key_unknown, +[199] = tic_key_unknown, +[200] = tic_key_unknown, +[201] = tic_key_unknown, +[202] = tic_key_unknown, +[203] = tic_key_unknown, +[204] = tic_key_unknown, +[205] = tic_key_unknown, +[206] = tic_key_unknown, +[207] = tic_key_unknown, +[208] = tic_key_unknown, +[209] = tic_key_unknown, +[210] = tic_key_unknown, +[211] = tic_key_unknown, +[212] = tic_key_unknown, +[213] = tic_key_unknown, +[214] = tic_key_unknown, +[215] = tic_key_unknown, +[216] = tic_key_unknown, +[217] = tic_key_unknown, +[218] = tic_key_unknown, +[219] = tic_key_unknown, +[220] = tic_key_unknown, +[221] = tic_key_unknown, +[222] = tic_key_unknown, +[223] = tic_key_unknown, +[SDL_SCANCODE_LCTRL] = tic_key_ctrl, +[SDL_SCANCODE_LSHIFT] = tic_key_shift, +[SDL_SCANCODE_LALT] = tic_key_alt, \ No newline at end of file diff --git a/src/luaapi.c b/src/luaapi.c index b8625e3..761e8d6 100644 --- a/src/luaapi.c +++ b/src/luaapi.c @@ -360,61 +360,57 @@ static s32 lua_btnp(lua_State* lua) tic_machine* machine = getLuaMachine(lua); tic_mem* memory = (tic_mem*)machine; - if(machine->memory.input.gamepad) + s32 top = lua_gettop(lua); + + if (top == 0) { - s32 top = lua_gettop(lua); - - if (top == 0) - { - lua_pushinteger(lua, memory->api.btnp(memory, -1, -1, -1)); - } - else if(top == 1) - { - s32 index = getLuaNumber(lua, 1) & 0xf; - - lua_pushboolean(lua, memory->api.btnp(memory, index, -1, -1)); - } - else if (top == 3) - { - s32 index = getLuaNumber(lua, 1) & 0xf; - u32 hold = getLuaNumber(lua, 2); - u32 period = getLuaNumber(lua, 3); - - lua_pushboolean(lua, memory->api.btnp(memory, index, hold, period)); - } - else luaL_error(lua, "invalid params, btnp [ id [ hold period ] ]\n"); - - return 1; + lua_pushinteger(lua, memory->api.btnp(memory, -1, -1, -1)); } - else luaL_error(lua, "gamepad input not declared in metadata\n"); + else if(top == 1) + { + s32 index = getLuaNumber(lua, 1) & 0x1f; - return 0; + lua_pushboolean(lua, memory->api.btnp(memory, index, -1, -1)); + } + else if (top == 3) + { + s32 index = getLuaNumber(lua, 1) & 0x1f; + u32 hold = getLuaNumber(lua, 2); + u32 period = getLuaNumber(lua, 3); + + lua_pushboolean(lua, memory->api.btnp(memory, index, hold, period)); + } + else + { + luaL_error(lua, "invalid params, btnp [ id [ hold period ] ]\n"); + return 0; + } + + return 1; } static s32 lua_btn(lua_State* lua) { tic_machine* machine = getLuaMachine(lua); - if(machine->memory.input.gamepad) + s32 top = lua_gettop(lua); + + if (top == 0) { - s32 top = lua_gettop(lua); - - if (top == 0) - { - lua_pushinteger(lua, machine->memory.ram.input.gamepads.data); - } - else if (top == 1) - { - s32 index = getLuaNumber(lua, 1) & 0xf; - lua_pushboolean(lua, machine->memory.ram.input.gamepads.data & (1 << index)); - } - else luaL_error(lua, "invalid params, btn [ id ]\n"); - - return 1; + lua_pushinteger(lua, machine->memory.ram.input.gamepads.data); } - else luaL_error(lua, "gamepad input not declared in metadata\n"); + else if (top == 1) + { + u32 index = getLuaNumber(lua, 1) & 0x1f; + lua_pushboolean(lua, machine->memory.ram.input.gamepads.data & (1 << index)); + } + else + { + luaL_error(lua, "invalid params, btn [ id ]\n"); + return 0; + } - return 0; + return 1; } static s32 lua_spr(lua_State* lua) @@ -784,6 +780,80 @@ static s32 lua_reset(lua_State* lua) return 0; } +static s32 lua_key(lua_State* lua) +{ + tic_machine* machine = getLuaMachine(lua); + tic_mem* tic = &machine->memory; + + s32 top = lua_gettop(lua); + + if (top == 0) + { + lua_pushinteger(lua, tic->api.key(tic, tic_key_unknown)); + } + else if (top == 1) + { + tic_key key = getLuaNumber(lua, 1) + TIC_KEY_START_INDEX; + + if(key < TIC_KEYS_COUNT) + lua_pushboolean(lua, tic->api.key(tic, key)); + else + { + luaL_error(lua, "unknown keyboard code\n"); + return 0; + } + } + else + { + luaL_error(lua, "invalid params, key [code]\n"); + return 0; + } + + return 1; +} + +static s32 lua_keyp(lua_State* lua) +{ + tic_machine* machine = getLuaMachine(lua); + tic_mem* tic = &machine->memory; + + s32 top = lua_gettop(lua); + + if (top == 0) + { + lua_pushinteger(lua, tic->api.keyp(tic, tic_key_unknown, -1, -1)); + } + else + { + tic_key key = getLuaNumber(lua, 1) + TIC_KEY_START_INDEX; + + if(key >= TIC_KEYS_COUNT) + { + luaL_error(lua, "unknown keyboard code\n"); + } + else + { + if(top == 1) + { + lua_pushboolean(lua, tic->api.keyp(tic, key, -1, -1)); + + return 1; + } + else if(top == 3) + { + u32 hold = getLuaNumber(lua, 2); + u32 period = getLuaNumber(lua, 3); + + lua_pushboolean(lua, tic->api.keyp(tic, key, hold, period)); + return 1; + } + else luaL_error(lua, "invalid params, keyp [ code [ hold period ] ]\n"); + } + } + + return 0; +} + static s32 lua_memcpy(lua_State* lua) { s32 top = lua_gettop(lua); @@ -1033,21 +1103,15 @@ static s32 lua_mouse(lua_State *lua) { tic_machine* machine = getLuaMachine(lua); - if(machine->memory.input.mouse) - { - const tic80_mouse* mouse = &machine->memory.ram.input.mouse; + const tic80_mouse* mouse = &machine->memory.ram.input.mouse; - lua_pushinteger(lua, mouse->x); - lua_pushinteger(lua, mouse->y); - lua_pushboolean(lua, mouse->left); - lua_pushboolean(lua, mouse->middle); - lua_pushboolean(lua, mouse->right); + lua_pushinteger(lua, mouse->x); + lua_pushinteger(lua, mouse->y); + lua_pushboolean(lua, mouse->left); + lua_pushboolean(lua, mouse->middle); + lua_pushboolean(lua, mouse->right); - return 5; - } - else luaL_error(lua, "mouse input not declared in metadata\n"); - - return 0; + return 5; } static s32 lua_dofile(lua_State *lua) @@ -1087,7 +1151,8 @@ static const lua_CFunction ApiFunc[] = lua_rectb, lua_spr, lua_btn, lua_btnp, lua_sfx, lua_map, lua_mget, lua_mset, lua_peek, lua_poke, lua_peek4, lua_poke4, lua_memcpy, lua_memset, lua_trace, lua_pmem, lua_time, lua_exit, lua_font, lua_mouse, - lua_circ, lua_circb, lua_tri, lua_textri, lua_clip, lua_music, lua_sync, lua_reset + lua_circ, lua_circb, lua_tri, lua_textri, lua_clip, lua_music, lua_sync, lua_reset, + lua_key, lua_keyp }; STATIC_ASSERT(api_func, COUNT_OF(ApiKeywords) == COUNT_OF(ApiFunc)); diff --git a/src/machine.h b/src/machine.h index 4ad3891..bdb8dca 100644 --- a/src/machine.h +++ b/src/machine.h @@ -31,7 +31,7 @@ #define API_KEYWORDS {"TIC", "scanline", "OVR", "print", "cls", "pix", "line", "rect", "rectb", \ "spr", "btn", "btnp", "sfx", "map", "mget", "mset", "peek", "poke", "peek4", "poke4", \ "memcpy", "memset", "trace", "pmem", "time", "exit", "font", "mouse", "circ", "circb", "tri", "textri", \ - "clip", "music", "sync", "reset"} + "clip", "music", "sync", "reset", "key", "keyp"} typedef struct { @@ -69,6 +69,13 @@ typedef struct u32 holds[sizeof(tic80_gamepads) * BITS_IN_BYTE]; } gamepads; + struct + { + tic80_keyboard previous; + + u32 holds[TIC_KEYS_COUNT]; + } keyboard; + Clip clip; tic_sound_register_data registers[TIC_SOUND_CHANNELS]; diff --git a/src/studio.c b/src/studio.c index 9caff94..9b6e540 100644 --- a/src/studio.c +++ b/src/studio.c @@ -1904,7 +1904,19 @@ static void processMouseInput() static void processKeyboardInput() { + static const u8 KeyboardCodes[] = + { + #include "keycodes.c" + }; + tic80_input* input = &studio.tic->ram.input; + input->keyboard.data = 0; + + studio.keyboard = SDL_GetKeyboardState(NULL); + + for(s32 i = 0, c = 0; i < COUNT_OF(KeyboardCodes) && c < COUNT_OF(input->keyboard.keys); i++) + if(studio.keyboard[i] && KeyboardCodes[i] > tic_key_unknown) + input->keyboard.keys[c++] = KeyboardCodes[i]; } #if defined(TIC80_PRO) diff --git a/src/tic.c b/src/tic.c index bc05039..bc956fa 100644 --- a/src/tic.c +++ b/src/tic.c @@ -100,13 +100,13 @@ static inline s32 note2freq(double note) static inline s32 freq2period(double freq) { - if(freq == 0.0) return MAX_PERIOD_VALUE; + if(freq == 0.0) return MAX_PERIOD_VALUE; enum {Rate = CLOCKRATE / ENVELOPE_VALUES}; s32 period = round((double)Rate / freq - 1.0); - if(period < MIN_PERIOD_VALUE) return MIN_PERIOD_VALUE; - if(period > MAX_PERIOD_VALUE) return MAX_PERIOD_VALUE; + if(period < MIN_PERIOD_VALUE) return MIN_PERIOD_VALUE; + if(period > MAX_PERIOD_VALUE) return MAX_PERIOD_VALUE; return period; } @@ -933,7 +933,7 @@ static void api_tri(tic_mem* memory, s32 x1, s32 y1, s32 x2, s32 y2, s32 x3, s32 s32 xl = max(SidesBuffer.Left[y], machine->state.clip.l); s32 xr = min(SidesBuffer.Right[y]+1, machine->state.clip.r); machine->state.drawhline(&machine->memory, xl, xr, y, final_color); - } + } } @@ -1244,6 +1244,15 @@ static bool isNoiseWaveform(const tic_waveform* wave) return memcmp(&NoiseWave.data, &wave->data, sizeof(tic_waveform)) == 0; } +static bool isKeyPressed(const tic80_keyboard* input, tic_key key) +{ + for(s32 i = 0; i < TIC_KEY_BUFFER; i++) + if(input->keys[i] == key) + return true; + + return false; +} + static void api_tick_start(tic_mem* memory, const tic_sfx* sfxsrc, const tic_music* music) { tic_machine* machine = (tic_machine*)memory; @@ -1276,6 +1285,18 @@ static void api_tick_start(tic_mem* memory, const tic_sfx* sfxsrc, const tic_mus else *hold = 0; } + // process keyboard + for(s32 i = TIC_KEY_START_INDEX; i < TIC_KEYS_COUNT; i++) + { + bool prevDown = isKeyPressed(&machine->state.keyboard.previous, i); + bool down = isKeyPressed(&memory->ram.input.keyboard, i); + + u32* hold = &machine->state.keyboard.holds[i]; + + if(prevDown && down) (*hold)++; + else *hold = 0; + } + machine->state.setpix = setPixelDma; machine->state.getpix = getPixelDma; machine->state.synced = 0; @@ -1287,6 +1308,7 @@ static void api_tick_end(tic_mem* memory) tic_machine* machine = (tic_machine*)memory; machine->state.gamepads.previous.data = machine->memory.ram.input.gamepads.data; + machine->state.keyboard.previous.data = machine->memory.ram.input.keyboard.data; enum {EndTime = CLOCKRATE / TIC_FRAMERATE}; for (s32 i = 0; i < TIC_SOUND_CHANNELS; ++i ) @@ -1626,6 +1648,58 @@ static u32 api_btnp(tic_mem* tic, s32 index, s32 hold, s32 period) return ((~previous.data) & machine->memory.ram.input.gamepads.data) & (1 << index); } +static u32 api_key(tic_mem* tic, tic_key key) +{ + return key >= TIC_KEY_START_INDEX + ? isKeyPressed(&tic->ram.input.keyboard, key) + : tic->ram.input.keyboard.data; +} + +static u32 api_keyp(tic_mem* tic, tic_key key, s32 hold, s32 period) +{ + tic_machine* machine = (tic_machine*)tic; + + if(key >= TIC_KEY_START_INDEX) + { + bool prevDown = hold >= 0 && period >= 0 && machine->state.keyboard.holds[key] >= hold + ? period && machine->state.keyboard.holds[key] % period + ? isKeyPressed(&machine->state.keyboard.previous, key) + : false + : isKeyPressed(&machine->state.keyboard.previous, key); + + bool down = isKeyPressed(&tic->ram.input.keyboard, key); + + return !prevDown && down; + } + + tic80_keyboard prev = {.data = 0}; + + for(s32 i = 0; i < TIC_KEY_BUFFER; i++) + { + tic_key key = tic->ram.input.keyboard.keys[i]; + + if(key) + { + bool wasPressed = false; + + for(s32 p = 0; p < TIC_KEY_BUFFER; p++) + { + if(machine->state.keyboard.previous.keys[p] == key) + { + wasPressed = true; + break; + } + } + + if(!wasPressed) + prev.keys[i] = key; + } + } + + return prev.data; +} + + static void api_load(tic_cartridge* cart, const u8* buffer, s32 size, bool palette) { const u8* end = buffer + size; @@ -1853,6 +1927,8 @@ static void initApi(tic_api* api) INIT_API(resume); INIT_API(sync); INIT_API(btnp); + INIT_API(key); + INIT_API(keyp); INIT_API(load); INIT_API(save); INIT_API(tick_start); diff --git a/src/tic.h b/src/tic.h index 428f076..fcded04 100644 --- a/src/tic.h +++ b/src/tic.h @@ -417,3 +417,92 @@ typedef union u8 data[TIC_RAM_SIZE]; } tic_ram; +enum +{ + tic_key_unknown, + tic_key_up, + tic_key_down, + tic_key_left, + tic_key_right, + tic_key_a, + tic_key_b, + tic_key_c, + tic_key_d, + tic_key_e, + tic_key_f, + tic_key_g, + tic_key_h, + tic_key_i, + tic_key_j, + tic_key_k, + tic_key_l, + tic_key_m, + tic_key_n, + tic_key_o, + tic_key_p, + tic_key_q, + tic_key_r, + tic_key_s, + tic_key_t, + tic_key_u, + tic_key_v, + tic_key_w, + tic_key_x, + tic_key_y, + tic_key_z, + tic_key_0, + tic_key_1, + tic_key_2, + tic_key_3, + tic_key_4, + tic_key_5, + tic_key_6, + tic_key_7, + tic_key_8, + tic_key_9, + tic_key_return, + tic_key_escape, + tic_key_backspace, + tic_key_tab, + tic_key_space, + tic_key_minus, + tic_key_equals, + tic_key_leftbracket, + tic_key_rightbracket, + tic_key_backslash, + tic_key_semicolon, + tic_key_apostrophe, + tic_key_grave, + tic_key_comma, + tic_key_period, + tic_key_slash, + tic_key_capslock, + tic_key_f1, + tic_key_f2, + tic_key_f3, + tic_key_f4, + tic_key_f5, + tic_key_f6, + tic_key_f7, + tic_key_f8, + tic_key_f9, + tic_key_f10, + tic_key_f11, + tic_key_f12, + tic_key_insert, + tic_key_home, + tic_key_pageup, + tic_key_delete, + tic_key_end, + tic_key_pagedown, + tic_key_ctrl, + tic_key_shift, + tic_key_alt, + + //////////////// + + tic_last_key +}; + +#define TIC_KEY_START_INDEX (tic_key_up) +#define TIC_KEYS_COUNT (tic_last_key) diff --git a/src/ticapi.h b/src/ticapi.h index 1766441..98a11e6 100644 --- a/src/ticapi.h +++ b/src/ticapi.h @@ -154,6 +154,8 @@ typedef struct void (*resume) (tic_mem* memory); void (*sync) (tic_mem* memory, u32 mask, s32 bank, bool toCart); u32 (*btnp) (tic_mem* memory, s32 id, s32 hold, s32 period); + u32 (*key) (tic_mem* memory, tic_key key); + u32 (*keyp) (tic_mem* memory, tic_key key, s32 hold, s32 period); void (*load) (tic_cartridge* rom, const u8* buffer, s32 size, bool palette); s32 (*save) (const tic_cartridge* rom, u8* buffer);