#include #include #include #include #include static bool __check(RIO *io, const char *pathname, bool many) { return r_str_startswith (pathname, "gb_joypad://"); } static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) { if (!r_str_startswith (pathname, "gb_joypad://")) { return NULL; } GBJoypad *joypad = NULL; sscanf (pathname, "gb_joypad://%p", &joypad); RIODesc *desc = r_io_desc_new (io, &r_io_plugin_gb_joypad, pathname, R_PERM_RWX, mode, joypad); return desc; } static ut64 __lseek(RIO* io, RIODesc *desc, ut64 offset, int whence) { GBJoypad *joypad = (GBJoypad *)desc->data; ut64 seek = (joypad->odata & 0x40) >> 6; switch (whence) { case R_IO_SEEK_SET: seek = R_MIN (1, offset); break; case R_IO_SEEK_CUR: seek = R_MIN (1, seek + offset); break; case R_IO_SEEK_END: seek = 1; break; } joypad->odata = (joypad->odata & 0x3f) | (seek << 6); return seek; } static int __read(RIO *io, RIODesc *desc, ut8 *buf, int len) { GBJoypad *joypad = (GBJoypad *)desc->data; if (!len || (joypad->odata & 0x40)) { return 0; } #if 0 joypad->data = buf[0] & 0xf; #else buf[0] = joypad->data & 0x3f; #endif joypad->odata |= 0x40; return 1; } static int __write(RIO *io, RIODesc *desc, const ut8 *buf, int len) { GBJoypad *joypad = (GBJoypad *)desc->data; if (!len || (joypad->odata & 0x40)) { return 0; } joypad->odata |= 0x40; joypad->data = (buf[0] & 0x30) | (joypad->data & 0xf); return 1; } static bool __close(RIODesc *desc) { return true; } RIOPlugin r_io_plugin_gb_joypad = { .meta = { .name = "gb_joypad", .desc = "gb_joypad", .license = "LGPL", }, .uris = "gb_joypad://", .open = __open, .close = __close, .read = __read, .check = __check, .seek = __lseek, .write = __write, }; bool gb_joypad_init (GBJoypad *joypad, RIO *io) { if (!joypad || !io) { return false; } joypad[0] = (const GBJoypad){0}; char uri[64]; memset (uri, 0x00, sizeof (char) * 64); sprintf (uri, "gb_joypad://%p", joypad); RIODesc *desc = r_io_desc_open_plugin (io, &r_io_plugin_gb_joypad, uri, R_PERM_RWX, 0); if (!desc) { return false; } if (!r_io_map_add (io, desc->fd, R_PERM_RWX, 0, 0xff00, 1)) { r_io_desc_close (desc); return false; } joypad->fd = desc->fd; const ut8 *keys = SDL_GetKeyboardState (NULL); memcpy (&joypad->keys, &keys, sizeof (ut8 *)); joypad->up = SDL_SCANCODE_W; joypad->down = SDL_SCANCODE_S; joypad->left = SDL_SCANCODE_A; joypad->right = SDL_SCANCODE_D; joypad->a = SDL_SCANCODE_L; joypad->b = SDL_SCANCODE_K; joypad->start = SDL_SCANCODE_SPACE; joypad->select = SDL_SCANCODE_KP_ENTER; return true; } void gb_joypad_continue(GB *gb) { GBJoypad *joypad = &gb->joypad; joypad->odata &= 0xc0; joypad->odata |= joypad->data & 0x3f; SDL_PumpEvents (); ut8 ndata = 0; if (!(joypad->data & 0x10)) { //d-pad const ut8 data = (~joypad->data) & 0xf; ndata = !!joypad->keys[joypad->right]; ndata |= (!!joypad->keys[joypad->left]) << 1; ndata |= (!!joypad->keys[joypad->up]) << 2; ndata |= (!!joypad->keys[joypad->down]) << 3; // on a real gameboy you cannot press up and down, or left and right at the same time if ((ndata & 0x3) == 0x3) { ndata = (ndata & 0xc) | (data & 0x3); } if ((ndata & 0xc) == 0xc) { ndata = (ndata & 0x3) | (data & 0xc); } } if (!(joypad->data & 0x20)) { //buttons ndata |= !!joypad->keys[joypad->a]; ndata |= (!!joypad->keys[joypad->b]) << 1; ndata |= (!!joypad->keys[joypad->select]) << 2; ndata |= (!!joypad->keys[joypad->start]) << 3; } joypad->data = (joypad->data & 0x30) | (ndata ^ 0xf); if (joypad->odata & ndata) { gb_interrupts_request (gb, GB_INTERRUPT_JOYPAD); } } void gb_joypad_fini (GBJoypad *joypad, RIO *io) { if (!joypad || !io) { return; } r_io_fd_close (io, joypad->fd); }