152 lines
3.7 KiB
C
152 lines
3.7 KiB
C
#include <stdio.h>
|
|
#include <gb.h>
|
|
#include <r_io.h>
|
|
#include <r_util.h>
|
|
#include <SDL2/SDL.h>
|
|
|
|
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);
|
|
}
|