Merge branch 'master' of https://github.com/libretro/RetroArch into emscripten
Conflicts: gfx/gl.c
This commit is contained in:
commit
87844cc486
|
@ -49,3 +49,14 @@ DerivedData
|
|||
apple/tmp
|
||||
apple/modules/*.dylib
|
||||
apple/*.mobileprovision
|
||||
/Cg/
|
||||
/GL/
|
||||
/SDL/
|
||||
/ffmpeg/
|
||||
/freetype2/
|
||||
/ft2build.h
|
||||
/iconv.h
|
||||
/libxml2/
|
||||
/phoenix/
|
||||
/python/
|
||||
/rsound.h
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>RetroArch_</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
</natures>
|
||||
</projectDescription>
|
3
AUTHORS
3
AUTHORS
|
@ -20,6 +20,9 @@ Daniel De Matteis - <libretro@gmail.com>
|
|||
- Blackberry 10/Playbook port
|
||||
- iOS port patches
|
||||
|
||||
Tobias Jakobi - <TBA>
|
||||
- OMAP graphics driver
|
||||
|
||||
Jason Fetters - <TBA>
|
||||
- Phoenix Java frontend
|
||||
- Android port patches
|
||||
|
|
20
Makefile
20
Makefile
|
@ -3,6 +3,7 @@ include config.mk
|
|||
TARGET = retroarch tools/retroarch-joyconfig tools/retrolaunch/retrolaunch
|
||||
|
||||
OBJ = frontend/frontend.o \
|
||||
frontend/frontend_context.o \
|
||||
retroarch.o \
|
||||
file.o \
|
||||
file_path.o \
|
||||
|
@ -92,7 +93,7 @@ ifeq ($(HAVE_RGUI), 1)
|
|||
endif
|
||||
|
||||
ifeq ($(HAVE_THREADS), 1)
|
||||
OBJ += autosave.o thread.o gfx/thread_wrapper.o
|
||||
OBJ += autosave.o thread.o gfx/thread_wrapper.o audio/thread_wrapper.o
|
||||
ifeq ($(findstring Haiku,$(OS)),)
|
||||
LIBS += -lpthread
|
||||
endif
|
||||
|
@ -185,13 +186,18 @@ ifeq ($(HAVE_SDL), 1)
|
|||
LIBS += $(SDL_LIBS)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_OMAP), 1)
|
||||
OBJ += gfx/omap_gfx.o gfx/fbdev.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_OPENGL), 1)
|
||||
OBJ += gfx/gl.o \
|
||||
gfx/gfx_context.o \
|
||||
gfx/fonts/gl_font.o \
|
||||
gfx/fonts/gl_raster_font.o \
|
||||
gfx/math/matrix.o \
|
||||
gfx/state_tracker.o
|
||||
gfx/state_tracker.o \
|
||||
gfx/glsym/rglgen.o
|
||||
|
||||
ifeq ($(HAVE_KMS), 1)
|
||||
OBJ += gfx/context/drm_egl_ctx.o
|
||||
|
@ -218,12 +224,14 @@ ifeq ($(HAVE_OPENGL), 1)
|
|||
ifeq ($(HAVE_GLES), 1)
|
||||
LIBS += -lGLESv2
|
||||
DEFINES += -DHAVE_OPENGLES -DHAVE_OPENGLES2
|
||||
OBJ += gfx/glsym/glsym_es2.o
|
||||
else
|
||||
DEFINES += -DHAVE_GL_SYNC
|
||||
OBJ += gfx/glsym/glsym_gl.o
|
||||
ifeq ($(OSX), 1)
|
||||
LIBS += -framework OpenGL
|
||||
else
|
||||
LIBS += -lGL
|
||||
DEFINES += -DHAVE_GL_SYNC
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -329,6 +337,11 @@ ifeq ($(DEBUG), 1)
|
|||
OPTIMIZE_FLAG = -O0
|
||||
endif
|
||||
|
||||
ifeq ($(GL_DEBUG), 1)
|
||||
CFLAGS += -DGL_DEBUG
|
||||
CXXFLAGS += -DGL_DEBUG
|
||||
endif
|
||||
|
||||
CFLAGS += -Wall $(OPTIMIZE_FLAG) $(INCLUDE_DIRS) -g -I.
|
||||
ifeq ($(CXX_BUILD), 1)
|
||||
LD = $(CXX)
|
||||
|
@ -419,6 +432,7 @@ clean:
|
|||
rm -f audio/*.o
|
||||
rm -f conf/*.o
|
||||
rm -f gfx/*.o
|
||||
rm -f gfx/glsym/*.o
|
||||
rm -f gfx/rpng/*.o
|
||||
rm -f gfx/fonts/*.o
|
||||
rm -f gfx/math/*.o
|
||||
|
|
|
@ -19,7 +19,7 @@ endif
|
|||
STRIP = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-strip.exe
|
||||
|
||||
PPU_CFLAGS += -I. -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC
|
||||
PPU_SRCS = frontend/frontend_salamander.c file_path.c compat/compat.c conf/config_file.c
|
||||
PPU_SRCS = frontend/frontend_salamander.c frontend/frontend_context.c file_path.c compat/compat.c conf/config_file.c
|
||||
|
||||
ifeq ($(HAVE_LOGGER), 1)
|
||||
PPU_CFLAGS += -DHAVE_LOGGER -Iconsole/logger
|
||||
|
|
|
@ -92,7 +92,7 @@ endif
|
|||
|
||||
RSXGL_DEFINES = -D__RSX__ -DGL3_PROTOTYPES
|
||||
|
||||
SHARED_FLAGS := -DHAVE_FILEBROWSER $(RSXGL_DEFINES) -DHAVE_OPENGL -DHAVE_EGL -DHAVE_OPENGL_MODERN -DHAVE_GLSL -DHAVE_VID_CONTEXT -DHAVE_FBO -DHAVE_MOUSE -DRARCH_CONSOLE -DHAVE_ZLIB -DWANT_MINIZ -DHAVE_RARCH_MAIN_WRAP -DHAVE_RARCH_MAIN_IMPLEMENTATION -DHAVE_SYSMODULES -DHAVE_SYSUTILS -DHAVE_GRIFFIN=1 -DHAVE_NETPLAY=1 -DHAVE_SOCKET_LEGACY=1 -DPACKAGE_VERSION=\"0.9.8\" -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" -DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT) -Wno-char-subscripts
|
||||
SHARED_FLAGS := -DHAVE_FILEBROWSER $(RSXGL_DEFINES) -DHAVE_OPENGL -DHAVE_EGL -DHAVE_OPENGL_MODERN -DHAVE_GLSL -DHAVE_VID_CONTEXT -DHAVE_FBO -DHAVE_MOUSE -DRARCH_CONSOLE -DHAVE_ZLIB -DWANT_MINIZ -DHAVE_RARCH_MAIN_WRAP -DHAVE_RARCH_MAIN_IMPLEMENTATION -DHAVE_SYSMODULES -DHAVE_SYSUTILS -DHAVE_GRIFFIN=1 -DHAVE_NETPLAY=1 -DHAVE_SOCKET_LEGACY=1 -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" -DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT) -Wno-char-subscripts
|
||||
CFLAGS += -std=gnu99 $(SHARED_FLAGS)
|
||||
CXXFLAGS += $(SHARED_FLAGS)
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ LIBS := -lfat -lwiiuse -logc -lbte
|
|||
|
||||
APP_BOOTER_DIR = wii/app_booter
|
||||
|
||||
OBJ = frontend/frontend_salamander.o file_path.o compat/compat.o conf/config_file.o $(APP_BOOTER_DIR)/app_booter.binobj
|
||||
OBJ = frontend/frontend_salamander.o frontend/frontend_context.o file_path.o compat/compat.o conf/config_file.o $(APP_BOOTER_DIR)/app_booter.binobj
|
||||
|
||||
ifeq ($(HAVE_LOGGER), 1)
|
||||
CFLAGS += -DHAVE_LOGGER
|
||||
|
@ -53,7 +53,7 @@ CFLAGS += -DHAVE_FILE_LOGGER
|
|||
CFLAGS += -Iconsole/logger
|
||||
endif
|
||||
|
||||
CFLAGS += -std=gnu99 -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_RARCH_EXEC -DGEKKO -DPACKAGE_VERSION=\"0.9.8\" -Wno-char-subscripts
|
||||
CFLAGS += -std=gnu99 -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_RARCH_EXEC -DGEKKO -Wno-char-subscripts
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -g
|
||||
|
|
27
Makefile.win
27
Makefile.win
|
@ -2,6 +2,7 @@ TARGET = retroarch.exe
|
|||
JTARGET = tools/retroarch-joyconfig.exe
|
||||
|
||||
OBJ = frontend/frontend.o \
|
||||
frontend/frontend_context.o \
|
||||
retroarch.o \
|
||||
file.o \
|
||||
file_path.o \
|
||||
|
@ -53,6 +54,7 @@ HAVE_DINPUT = 1
|
|||
HAVE_XAUDIO = 1
|
||||
HAVE_DSOUND = 1
|
||||
HAVE_OPENGL = 1
|
||||
HAVE_FBO = 1
|
||||
HAVE_DYLIB = 1
|
||||
HAVE_D3D9 = 1
|
||||
HAVE_NETPLAY = 1
|
||||
|
@ -68,7 +70,6 @@ ifeq ($(SLIM),)
|
|||
HAVE_FREETYPE = 1
|
||||
HAVE_ZLIB = 1
|
||||
HAVE_RSOUND = 1
|
||||
HAVE_FBO = 1
|
||||
HAVE_CG = 1
|
||||
HAVE_PYTHON = 1
|
||||
HAVE_FFMPEG = 1
|
||||
|
@ -77,7 +78,7 @@ endif
|
|||
libretro ?= -lretro
|
||||
|
||||
LIBS = -lm
|
||||
DEFINES = -I. -DHAVE_SCREENSHOTS -DHAVE_BSV_MOVIE -DPACKAGE_VERSION=\"0.9.9.3\"
|
||||
DEFINES = -I. -DHAVE_SCREENSHOTS -DHAVE_BSV_MOVIE
|
||||
LDFLAGS = -L. -static-libgcc
|
||||
|
||||
ifeq ($(TDM_GCC),)
|
||||
|
@ -108,12 +109,12 @@ ifeq ($(HAVE_SDL), 1)
|
|||
endif
|
||||
|
||||
ifeq ($(HAVE_THREADS), 1)
|
||||
OBJ += autosave.o thread.o gfx/thread_wrapper.o
|
||||
OBJ += autosave.o thread.o gfx/thread_wrapper.o audio/thread_wrapper.o
|
||||
DEFINES += -DHAVE_THREADS
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_OPENGL), 1)
|
||||
OBJ += gfx/gl.o gfx/math/matrix.o gfx/fonts/gl_font.o gfx/fonts/gl_raster_font.o gfx/gfx_context.o gfx/context/wgl_ctx.o gfx/shader_glsl.o
|
||||
OBJ += gfx/gl.o gfx/math/matrix.o gfx/fonts/gl_font.o gfx/fonts/gl_raster_font.o gfx/gfx_context.o gfx/context/wgl_ctx.o gfx/shader_glsl.o gfx/glsym/rglgen.o gfx/glsym/glsym_gl.o
|
||||
DEFINES += -DHAVE_OPENGL -DHAVE_OVERLAY -DHAVE_GLSL -DHAVE_GL_SYNC
|
||||
LIBS += -lopengl32 -lgdi32 -lcomdlg32
|
||||
endif
|
||||
|
@ -236,6 +237,11 @@ else
|
|||
LDCXXFLAGS += -s
|
||||
endif
|
||||
|
||||
ifeq ($(GL_DEBUG), 1)
|
||||
CFLAGS += -DGL_DEBUG
|
||||
CXXFLAGS += -DGL_DEBUG
|
||||
endif
|
||||
|
||||
CFLAGS += -Wall -Wno-unused-result -Wno-unused-variable -I.
|
||||
CXXFLAGS += -Wall -Wno-unused-result -Wno-unused-variable -I. -std=c++0x -D__STDC_CONSTANT_MACROS
|
||||
ifeq ($(CXX_BUILD), 1)
|
||||
|
@ -286,6 +292,7 @@ clean:
|
|||
rm -f conf/*.o
|
||||
rm -f gfx/scaler/*.o
|
||||
rm -f gfx/*.o
|
||||
rm -f gfx/glsym/*.o
|
||||
rm -f gfx/d3d9/*.o
|
||||
rm -f gfx/context/*.o
|
||||
rm -f gfx/math/*.o
|
||||
|
@ -299,21 +306,21 @@ clean:
|
|||
rm -f tools/*.o
|
||||
|
||||
dist_x86: all
|
||||
zip -r retroarch-win32-0.9.9.zip $(TARGET) $(JTARGET) retroarch.cfg
|
||||
zip -r retroarch-win32-0.9.9.4.zip $(TARGET) $(JTARGET) retroarch.cfg
|
||||
|
||||
dist_x86_64: all
|
||||
zip -r retroarch-win64-0.9.9.zip $(TARGET) $(JTARGET) retroarch.cfg
|
||||
zip -r retroarch-win64-0.9.9.4.zip $(TARGET) $(JTARGET) retroarch.cfg
|
||||
|
||||
libs_x86:
|
||||
wget https://github.com/downloads/Themaister/RetroArch/RetroArch-win32-libs.zip --no-check-certificate
|
||||
wget http://themaister.net/retroarch-dl/RetroArch-win32-libs.zip
|
||||
unzip RetroArch-win32-libs.zip
|
||||
wget https://github.com/downloads/Themaister/RetroArch/RetroArch-win32-headers.zip --no-check-certificate
|
||||
wget http://themaister.net/retroarch-dl/RetroArch-win32-headers.zip
|
||||
unzip RetroArch-win32-headers.zip
|
||||
|
||||
libs_x86_64:
|
||||
wget https://github.com/downloads/Themaister/RetroArch/RetroArch-win64-libs.zip --no-check-certificate
|
||||
wget http://themaister.net/retroarch-dl/RetroArch-win64-libs.zip
|
||||
unzip RetroArch-win64-libs.zip
|
||||
wget https://github.com/downloads/Themaister/RetroArch/RetroArch-win64-headers.zip --no-check-certificate
|
||||
wget http://themaister.net/retroarch-dl/RetroArch-win64-headers.zip
|
||||
unzip RetroArch-win64-headers.zip
|
||||
|
||||
.PHONY: all install uninstall clean dist_x86 dist_x86_64 libs_x86 libs_x86_64
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
float dzone_min;
|
||||
float dzone_max;
|
||||
} dpad_values_t;
|
||||
int16_t lx, ly;
|
||||
int16_t rx, ry;
|
||||
} analog_t;
|
||||
|
||||
#define PRESSED_UP(x, y) ((y <= dzone_min))
|
||||
#define PRESSED_DOWN(x, y) ((y >= dzone_max))
|
||||
|
@ -42,8 +42,7 @@ static unsigned pads_connected;
|
|||
static int state_device_ids[MAX_PADS];
|
||||
static uint64_t state[MAX_PADS];
|
||||
static uint64_t keycode_lut[LAST_KEYCODE];
|
||||
dpad_values_t dpad_state[MAX_PADS];
|
||||
|
||||
analog_t analog_state[MAX_PADS];
|
||||
|
||||
struct input_pointer
|
||||
{
|
||||
|
@ -61,10 +60,12 @@ enum
|
|||
AXIS_Z = 11,
|
||||
AXIS_RZ = 14,
|
||||
AXIS_HAT_X = 15,
|
||||
AXIS_HAT_Y = 16
|
||||
AXIS_HAT_Y = 16,
|
||||
AXIS_LTRIGGER = 17,
|
||||
AXIS_RTRIGGER = 18,
|
||||
};
|
||||
|
||||
void (*engine_handle_dpad)(AInputEvent*, size_t, int, char*, size_t, int, bool);
|
||||
void (*engine_handle_dpad)(AInputEvent*, size_t, int, char*, size_t, int, bool, unsigned);
|
||||
|
||||
extern float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
|
||||
int32_t axis, size_t pointer_index);
|
||||
|
@ -183,21 +184,25 @@ void engine_handle_cmd(void)
|
|||
|
||||
static void engine_handle_dpad_default(AInputEvent *event,
|
||||
size_t motion_pointer, int state_id, char *msg, size_t msg_sizeof,
|
||||
int source, bool debug_enable)
|
||||
int source, bool debug_enable, unsigned emulation)
|
||||
{
|
||||
uint64_t *state_cur = &state[state_id];
|
||||
float dzone_min = dpad_state[state_id].dzone_min;
|
||||
float dzone_max = dpad_state[state_id].dzone_max;
|
||||
float dzone_min = -g_settings.input.axis_threshold;
|
||||
float dzone_max = g_settings.input.axis_threshold;
|
||||
float x = AMotionEvent_getX(event, motion_pointer);
|
||||
float y = AMotionEvent_getY(event, motion_pointer);
|
||||
|
||||
*state_cur &= ~((1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) |
|
||||
(1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) |
|
||||
(1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN));
|
||||
*state_cur |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0;
|
||||
*state_cur |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0;
|
||||
*state_cur |= PRESSED_UP(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0;
|
||||
*state_cur |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0;
|
||||
|
||||
if (emulation == ANALOG_DPAD_LSTICK)
|
||||
{
|
||||
*state_cur |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0;
|
||||
*state_cur |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0;
|
||||
*state_cur |= PRESSED_UP(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0;
|
||||
*state_cur |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0;
|
||||
}
|
||||
|
||||
if (debug_enable)
|
||||
snprintf(msg, msg_sizeof, "Pad %d : x = %.2f, y = %.2f, src %d.\n",
|
||||
|
@ -206,31 +211,34 @@ static void engine_handle_dpad_default(AInputEvent *event,
|
|||
|
||||
static void engine_handle_dpad_getaxisvalue(AInputEvent *event,
|
||||
size_t motion_pointer, int state_id, char *msg, size_t msg_sizeof, int source,
|
||||
bool debug_enable)
|
||||
bool debug_enable, unsigned emulation)
|
||||
{
|
||||
uint64_t *state_cur = &state[state_id];
|
||||
float dzone_min = dpad_state[state_id].dzone_min;
|
||||
float dzone_max = dpad_state[state_id].dzone_max;
|
||||
float dzone_min = -g_settings.input.axis_threshold;
|
||||
float dzone_max = g_settings.input.axis_threshold;
|
||||
float x = AMotionEvent_getAxisValue(event, AXIS_X, motion_pointer);
|
||||
float y = AMotionEvent_getAxisValue(event, AXIS_Y, motion_pointer);
|
||||
float z = AMotionEvent_getAxisValue(event, AXIS_Z, motion_pointer);
|
||||
float rz = AMotionEvent_getAxisValue(event, AXIS_RZ, motion_pointer);
|
||||
float hatx = AMotionEvent_getAxisValue(event, AXIS_HAT_X, motion_pointer);
|
||||
float haty = AMotionEvent_getAxisValue(event, AXIS_HAT_Y, motion_pointer);
|
||||
float ltrig = AMotionEvent_getAxisValue(event, AXIS_LTRIGGER, motion_pointer);
|
||||
float rtrig = AMotionEvent_getAxisValue(event, AXIS_RTRIGGER, motion_pointer);
|
||||
|
||||
*state_cur &= ~((1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) |
|
||||
(1ULL << RETRO_DEVICE_ID_JOYPAD_L2) | (1ULL << RETRO_DEVICE_ID_JOYPAD_R2) |
|
||||
(1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) |
|
||||
(1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN));
|
||||
|
||||
/* On some devices the dpad sends AXIS_HAT_X / AXIS_HAT_Y events, use those first if the returned values are nonzero */
|
||||
if (fabs(hatx) > 0.0001 || fabs(haty) > 0.0001)
|
||||
if (fabsf(hatx) > 0.0001f || fabsf(haty) > 0.0001f)
|
||||
{
|
||||
*state_cur |= PRESSED_LEFT(hatx, haty) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0;
|
||||
*state_cur |= PRESSED_RIGHT(hatx, haty) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0;
|
||||
*state_cur |= PRESSED_UP(hatx, haty) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0;
|
||||
*state_cur |= PRESSED_DOWN(hatx, haty) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0;
|
||||
}
|
||||
else
|
||||
else if (emulation == ANALOG_DPAD_LSTICK)
|
||||
{
|
||||
*state_cur |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0;
|
||||
*state_cur |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0;
|
||||
|
@ -238,6 +246,19 @@ static void engine_handle_dpad_getaxisvalue(AInputEvent *event,
|
|||
*state_cur |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0;
|
||||
}
|
||||
|
||||
if (ltrig > 0.5f)
|
||||
*state_cur |= 1ULL << RETRO_DEVICE_ID_JOYPAD_L2;
|
||||
if (rtrig > 0.5f)
|
||||
*state_cur |= 1ULL << RETRO_DEVICE_ID_JOYPAD_R2;
|
||||
|
||||
if (emulation == ANALOG_DPAD_DUALANALOG)
|
||||
{
|
||||
analog_state[state_id].lx = x * 0x7fff;
|
||||
analog_state[state_id].ly = y * 0x7fff;
|
||||
analog_state[state_id].rx = z * 0x7fff;
|
||||
analog_state[state_id].ry = rz * 0x7fff;
|
||||
}
|
||||
|
||||
if (debug_enable)
|
||||
snprintf(msg, msg_sizeof, "Pad %d : x %.2f, y %.2f, z %.2f, rz %.2f, src %d.\n",
|
||||
state_id, x, y, z, rz, source);
|
||||
|
@ -248,7 +269,7 @@ static void *android_input_init(void)
|
|||
unsigned i, j, k;
|
||||
pads_connected = 0;
|
||||
|
||||
for(j = 0; j < LAST_KEYCODE; j++)
|
||||
for (j = 0; j < LAST_KEYCODE; j++)
|
||||
keycode_lut[j] = 0;
|
||||
|
||||
if (!g_settings.input.autodetect_enable)
|
||||
|
@ -267,9 +288,9 @@ static void *android_input_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < MAX_PADS; i++)
|
||||
for (i = 0; i < MAX_PADS; i++)
|
||||
{
|
||||
for(j = 0; j < RARCH_FIRST_META_KEY; j++)
|
||||
for (j = 0; j < RARCH_FIRST_META_KEY; j++)
|
||||
{
|
||||
g_settings.input.binds[i][j].id = i;
|
||||
g_settings.input.binds[i][j].joykey = 0;
|
||||
|
@ -292,8 +313,6 @@ static void *android_input_init(void)
|
|||
g_settings.input.binds[i][RETRO_DEVICE_ID_JOYPAD_L3].joykey = (1ULL << RETRO_DEVICE_ID_JOYPAD_L3);
|
||||
g_settings.input.binds[i][RETRO_DEVICE_ID_JOYPAD_R3].joykey = (1ULL << RETRO_DEVICE_ID_JOYPAD_R3);
|
||||
|
||||
dpad_state[i].dzone_min = -0.99f;
|
||||
dpad_state[i].dzone_max = 0.99f;
|
||||
g_settings.input.dpad_emulation[i] = ANALOG_DPAD_LSTICK;
|
||||
}
|
||||
|
||||
|
@ -351,6 +370,7 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
strlcpy(g_settings.input.device_names[port], "Logitech Rumblepad 2",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
|
||||
keycode_lut[AKEYCODE_BUTTON_2] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_1] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_9] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
|
||||
|
@ -403,7 +423,7 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
break;
|
||||
case DEVICE_GAMEMID:
|
||||
g_settings.input.device[port] = device;
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
|
||||
strlcpy(g_settings.input.device_names[port], "GameMID",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
|
||||
|
@ -482,9 +502,6 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
g_settings.input.device[port] = device;
|
||||
strlcpy(g_settings.input.device_names[port], "TTT THT Arcade",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
dpad_state[id].dzone_min = -2.00f;
|
||||
dpad_state[id].dzone_max = 1.00f;
|
||||
|
||||
|
||||
/* same as Rumblepad 2 - merge? */
|
||||
//keycode_lut[AKEYCODE_BUTTON_7] |= ((RETRO_DEVICE_ID_JOYPAD_L2+1) << shift);
|
||||
|
@ -623,8 +640,6 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
g_settings.input.device[port] = device;
|
||||
strlcpy(g_settings.input.device_names[port], "Huijia USB SNES",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
dpad_state[id].dzone_min = -1.00f;
|
||||
dpad_state[id].dzone_max = 1.00f;
|
||||
|
||||
keycode_lut[AKEYCODE_BUTTON_3] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_4] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
|
||||
|
@ -639,8 +654,6 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
g_settings.input.device[port] = device;
|
||||
strlcpy(g_settings.input.device_names[port], "Super Smartjoy",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
dpad_state[id].dzone_min = -1.00f;
|
||||
dpad_state[id].dzone_max = 1.00f;
|
||||
|
||||
keycode_lut[AKEYCODE_BUTTON_3] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_4] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
|
||||
|
@ -708,7 +721,9 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
strlcpy(g_settings.input.device_names[port], "Xbox",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
|
||||
/* TODO: left and right triggers for Xbox 1*/
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
|
||||
keycode_lut[AKEYCODE_BUTTON_MODE] |= ((RARCH_MENU_TOGGLE + 1) << shift);
|
||||
keycode_lut[AKEYCODE_BACK] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_SELECT] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_START] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_THUMBL] |= ((RETRO_DEVICE_ID_JOYPAD_L3+1) << shift);
|
||||
|
@ -725,6 +740,7 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
strlcpy(g_settings.input.device_names[port], "WiseGroup PlayStation2",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
|
||||
keycode_lut[AKEYCODE_BUTTON_13] |= ((RETRO_DEVICE_ID_JOYPAD_UP+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_15] |= ((RETRO_DEVICE_ID_JOYPAD_DOWN+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_16] |= ((RETRO_DEVICE_ID_JOYPAD_LEFT+1) << shift);
|
||||
|
@ -823,52 +839,29 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
keycode_lut[AKEYCODE_ESCAPE] |= ((RARCH_QUIT_KEY+1) << shift);
|
||||
break;
|
||||
case DEVICE_PLAYSTATION3_VERSION1:
|
||||
g_settings.input.device[port] = device;
|
||||
strlcpy(g_settings.input.device_names[port], "PlayStation3 Ver.1",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
keycode_lut[AKEYCODE_DPAD_UP] |= ((RETRO_DEVICE_ID_JOYPAD_UP+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_DOWN] |= ((RETRO_DEVICE_ID_JOYPAD_DOWN+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_LEFT] |= ((RETRO_DEVICE_ID_JOYPAD_LEFT+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_RIGHT] |= ((RETRO_DEVICE_ID_JOYPAD_RIGHT+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_A] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_X] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_SELECT] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_START] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_Y] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_B] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_L1] |= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_R1] |= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_L2] |= ((RETRO_DEVICE_ID_JOYPAD_L2+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_R2] |= ((RETRO_DEVICE_ID_JOYPAD_R2+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_THUMBL] |= ((RETRO_DEVICE_ID_JOYPAD_L3+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_THUMBR] |= ((RETRO_DEVICE_ID_JOYPAD_R3+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_1] |= ((RARCH_MENU_TOGGLE+1) << shift);
|
||||
break;
|
||||
case DEVICE_PLAYSTATION3_VERSION2:
|
||||
g_settings.input.device[port] = device;
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
strlcpy(g_settings.input.device_names[port], "PlayStation3 Ver.2",
|
||||
strlcpy(g_settings.input.device_names[port], "PlayStation3",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
keycode_lut[AKEYCODE_DPAD_UP] |= ((RETRO_DEVICE_ID_JOYPAD_UP+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_DOWN] |= ((RETRO_DEVICE_ID_JOYPAD_DOWN+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_LEFT] |= ((RETRO_DEVICE_ID_JOYPAD_LEFT+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_RIGHT] |= ((RETRO_DEVICE_ID_JOYPAD_RIGHT+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_1] |= ((RARCH_MENU_TOGGLE+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_A] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_X] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_A] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_X] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_SELECT] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_START] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_Y] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_B] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_B] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_Y] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_L1] |= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_R1] |= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_L2] |= ((RETRO_DEVICE_ID_JOYPAD_L2+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_R2] |= ((RETRO_DEVICE_ID_JOYPAD_R2+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_THUMBL] |= ((RETRO_DEVICE_ID_JOYPAD_L3+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_THUMBR] |= ((RETRO_DEVICE_ID_JOYPAD_R3+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_1] |= ((RARCH_MENU_TOGGLE+1) << shift);
|
||||
break;
|
||||
case DEVICE_MOGA:
|
||||
g_settings.input.device[port] = device;
|
||||
|
@ -1045,8 +1038,6 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
g_settings.input.device[port] = device;
|
||||
strlcpy(g_settings.input.device_names[port], "Buffalo BGC FC801",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
dpad_state[id].dzone_min = -1.00f;
|
||||
dpad_state[id].dzone_max = 1.00f;
|
||||
|
||||
keycode_lut[AKEYCODE_BUTTON_1] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_2] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
|
||||
|
@ -1199,6 +1190,7 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
strlcpy(g_settings.input.device_names[port], "OUYA",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
|
||||
keycode_lut[AKEYCODE_DPAD_UP] |= ((RETRO_DEVICE_ID_JOYPAD_UP+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_DOWN] |= ((RETRO_DEVICE_ID_JOYPAD_DOWN+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_LEFT] |= ((RETRO_DEVICE_ID_JOYPAD_LEFT+1) << shift);
|
||||
|
@ -1323,6 +1315,22 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
keycode_lut[AKEYCODE_DPAD_LEFT] |= ((RETRO_DEVICE_ID_JOYPAD_LEFT+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_RIGHT]|= ((RETRO_DEVICE_ID_JOYPAD_RIGHT+1) << shift);
|
||||
break;
|
||||
case ICADE_PROFILE_IPEGA_PG9017_MODE2:
|
||||
strlcpy(g_settings.input.device_names[port], "iPega PG-9017 (Mode2)",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
keycode_lut[AKEYCODE_M] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
|
||||
keycode_lut[AKEYCODE_J] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
|
||||
keycode_lut[AKEYCODE_K] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
|
||||
keycode_lut[AKEYCODE_I] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
|
||||
keycode_lut[AKEYCODE_Q] |= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
|
||||
keycode_lut[AKEYCODE_P] |= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
|
||||
keycode_lut[AKEYCODE_R] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
|
||||
keycode_lut[AKEYCODE_Y] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_UP] |= ((RETRO_DEVICE_ID_JOYPAD_UP+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_DOWN] |= ((RETRO_DEVICE_ID_JOYPAD_DOWN+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_LEFT] |= ((RETRO_DEVICE_ID_JOYPAD_LEFT+1) << shift);
|
||||
keycode_lut[AKEYCODE_DPAD_RIGHT]|= ((RETRO_DEVICE_ID_JOYPAD_RIGHT+1) << shift);
|
||||
break;
|
||||
case ICADE_PROFILE_GAMESTOP_WIRELESS:
|
||||
strlcpy(g_settings.input.device_names[port], "Gamestop Wireless",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
|
@ -1447,6 +1455,21 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
keycode_lut[AKEYCODE_BUTTON_L1]|= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_R1]|= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
|
||||
break;
|
||||
case DEVICE_NVIDIA_SHIELD:
|
||||
g_settings.input.device[port] = device;
|
||||
strlcpy(g_settings.input.device_names[port], "NVIDIA Shield",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_DUALANALOG;
|
||||
keycode_lut[AKEYCODE_BUTTON_B] |= ((RETRO_DEVICE_ID_JOYPAD_A+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_A] |= ((RETRO_DEVICE_ID_JOYPAD_B+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_Y] |= ((RETRO_DEVICE_ID_JOYPAD_X+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_X] |= ((RETRO_DEVICE_ID_JOYPAD_Y+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_L1] |= ((RETRO_DEVICE_ID_JOYPAD_L+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_R1] |= ((RETRO_DEVICE_ID_JOYPAD_R+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_START] |= ((RARCH_MENU_TOGGLE+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_THUMBL] |= ((RETRO_DEVICE_ID_JOYPAD_SELECT+1) << shift);
|
||||
keycode_lut[AKEYCODE_BUTTON_THUMBR] |= ((RETRO_DEVICE_ID_JOYPAD_START+1) << shift);
|
||||
break;
|
||||
case DEVICE_CCPCREATIONS_WIIUSE_IME:
|
||||
g_settings.input.device[port] = device;
|
||||
strlcpy(g_settings.input.device_names[port], "ccpCreations WiiUse IME",
|
||||
|
@ -1570,8 +1593,9 @@ static void android_input_set_keybinds(void *data, unsigned device,
|
|||
static void android_input_poll(void *data)
|
||||
{
|
||||
int ident;
|
||||
uint64_t lifecycle_mask = (1ULL << RARCH_RESET) | (1ULL << RARCH_REWIND) | (1ULL << RARCH_FAST_FORWARD_KEY) | (1ULL << RARCH_FAST_FORWARD_HOLD_KEY) | (1ULL << RARCH_MUTE) | (1ULL << RARCH_SAVE_STATE_KEY) | (1ULL << RARCH_LOAD_STATE_KEY) | (1ULL << RARCH_STATE_SLOT_PLUS) | (1ULL << RARCH_STATE_SLOT_MINUS) | (1ULL << RARCH_QUIT_KEY) | (1ULL << RARCH_MENU_TOGGLE);
|
||||
uint64_t *lifecycle_state = &g_extern.lifecycle_state;
|
||||
*lifecycle_state &= ~((1ULL << RARCH_RESET) | (1ULL << RARCH_REWIND) | (1ULL << RARCH_FAST_FORWARD_KEY) | (1ULL << RARCH_FAST_FORWARD_HOLD_KEY) | (1ULL << RARCH_MUTE) | (1ULL << RARCH_SAVE_STATE_KEY) | (1ULL << RARCH_LOAD_STATE_KEY) | (1ULL << RARCH_STATE_SLOT_PLUS) | (1ULL << RARCH_STATE_SLOT_MINUS) | (1ULL << RARCH_QUIT_KEY));
|
||||
*lifecycle_state &= ~lifecycle_mask;
|
||||
|
||||
while ((ident = ALooper_pollAll((input_key_pressed_func(RARCH_PAUSE_TOGGLE)) ? -1 : 0,
|
||||
NULL, NULL, NULL)) >= 0)
|
||||
|
@ -1585,20 +1609,21 @@ static void android_input_poll(void *data)
|
|||
// Read all pending events.
|
||||
while (AInputQueue_hasEvents(android_app->inputQueue))
|
||||
{
|
||||
if (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0)
|
||||
int processed = 0;
|
||||
while (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0)
|
||||
{
|
||||
bool long_msg_enable = false;
|
||||
int32_t handled = 1;
|
||||
int action = 0;
|
||||
char msg[128];
|
||||
int source, id, keycode, type_event, state_id;
|
||||
//int predispatched;
|
||||
int predispatched;
|
||||
|
||||
msg[0] = 0;
|
||||
//predispatched =AInputQueue_preDispatchEvent(android_app->inputQueue,event);
|
||||
predispatched = AInputQueue_preDispatchEvent(android_app->inputQueue,event);
|
||||
|
||||
//if (predispatched)
|
||||
//continue;
|
||||
if (predispatched)
|
||||
continue;
|
||||
|
||||
source = AInputEvent_getSource(event);
|
||||
id = AInputEvent_getDeviceId(event);
|
||||
|
@ -1621,9 +1646,25 @@ static void android_input_poll(void *data)
|
|||
if (state_id < 0)
|
||||
{
|
||||
state_id = pads_connected;
|
||||
state_device_ids[pads_connected++] = id;
|
||||
if (g_settings.input.autodetect_enable)
|
||||
{
|
||||
bool primary = false;
|
||||
input_autodetect_setup(android_app, msg, sizeof(msg), state_id, id, source, &primary);
|
||||
|
||||
if (primary)
|
||||
{
|
||||
RARCH_LOG("Found primary input device.\n");
|
||||
memmove(state_device_ids + 1, state_device_ids, pads_connected * sizeof(state_device_ids[0]));
|
||||
state_id = 0;
|
||||
state_device_ids[0] = id;
|
||||
pads_connected++;
|
||||
}
|
||||
else
|
||||
state_device_ids[pads_connected++] = id;
|
||||
}
|
||||
else
|
||||
state_device_ids[pads_connected++] = id;
|
||||
|
||||
input_autodetect_setup(android_app, msg, sizeof(msg), state_id, id, source);
|
||||
long_msg_enable = true;
|
||||
}
|
||||
|
||||
|
@ -1674,7 +1715,8 @@ static void android_input_poll(void *data)
|
|||
if (source & ~(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE))
|
||||
{
|
||||
if (g_settings.input.dpad_emulation[state_id] != ANALOG_DPAD_NONE)
|
||||
engine_handle_dpad(event, motion_pointer, state_id, msg, sizeof(msg), source, debug_enable);
|
||||
engine_handle_dpad(event, motion_pointer, state_id, msg, sizeof(msg), source, debug_enable,
|
||||
g_settings.input.dpad_emulation[state_id]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1712,9 +1754,6 @@ static void android_input_poll(void *data)
|
|||
}
|
||||
else if (type_event == AINPUT_EVENT_TYPE_KEY)
|
||||
{
|
||||
if (debug_enable)
|
||||
snprintf(msg, sizeof(msg), "Pad %d : %d, ac = %d, src = %d.\n", state_id, keycode, action, source);
|
||||
|
||||
/* Hack - we have to decrease the unpacked value by 1
|
||||
* because we 'added' 1 to each entry in the LUT -
|
||||
* RETRO_DEVICE_ID_JOYPAD_B is 0
|
||||
|
@ -1724,28 +1763,40 @@ static void android_input_poll(void *data)
|
|||
int action = AKeyEvent_getAction(event);
|
||||
uint64_t *key = NULL;
|
||||
|
||||
if(input_state < (1ULL << RARCH_FIRST_META_KEY))
|
||||
if (debug_enable)
|
||||
snprintf(msg, sizeof(msg), "Pad %d : %d, ac = %d, src = %d.\n", state_id, keycode, action, source);
|
||||
|
||||
if (input_state < (1ULL << RARCH_FIRST_META_KEY))
|
||||
key = &state[state_id];
|
||||
else if(input_state)
|
||||
else if (input_state/* && action == AKEY_EVENT_ACTION_DOWN*/)
|
||||
key = &g_extern.lifecycle_state;
|
||||
|
||||
if(key != NULL)
|
||||
if (key != NULL)
|
||||
{
|
||||
if (action == AKEY_EVENT_ACTION_UP)
|
||||
// some controllers send both the up and down events at once when the button is released for "special" buttons, like menu buttons
|
||||
// work around that by only using down events for meta keys (which get cleared every poll anyway)
|
||||
if (action == AKEY_EVENT_ACTION_UP && !(input_state & lifecycle_mask))
|
||||
*key &= ~(input_state);
|
||||
else if (action == AKEY_EVENT_ACTION_DOWN)
|
||||
*key |= input_state;
|
||||
}
|
||||
|
||||
if((keycode == AKEYCODE_VOLUME_UP || keycode == AKEYCODE_VOLUME_DOWN) && keycode_lut[keycode] == 0)
|
||||
if ((keycode == AKEYCODE_VOLUME_UP || keycode == AKEYCODE_VOLUME_DOWN) && keycode_lut[keycode] == 0)
|
||||
handled = 0;
|
||||
}
|
||||
|
||||
if (msg[0] != 0)
|
||||
{
|
||||
msg_queue_clear(g_extern.msg_queue);
|
||||
msg_queue_push(g_extern.msg_queue, msg, 0, long_msg_enable ? 180 : 30);
|
||||
RARCH_LOG("Input debug: %s\n", msg);
|
||||
}
|
||||
|
||||
AInputQueue_finishEvent(android_app->inputQueue, event, handled);
|
||||
processed = 1;
|
||||
}
|
||||
if (processed == 0)
|
||||
RARCH_WARN("Failure reading next input event: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
else if (ident == LOOPER_ID_MAIN)
|
||||
|
@ -1759,8 +1810,22 @@ static int16_t android_input_state(void *data, const struct retro_keybind **bind
|
|||
{
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
return ((state[port] & binds[port][id].joykey) && (port < pads_connected));
|
||||
case RETRO_DEVICE_ANALOG:
|
||||
if (port >= pads_connected)
|
||||
return 0;
|
||||
switch ((index << 1) | id)
|
||||
{
|
||||
case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_X:
|
||||
return analog_state[port].lx;
|
||||
case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_Y:
|
||||
return analog_state[port].ly;
|
||||
case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_X:
|
||||
return analog_state[port].rx;
|
||||
case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_Y:
|
||||
return analog_state[port].ry;
|
||||
}
|
||||
case RETRO_DEVICE_POINTER:
|
||||
switch(id)
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_POINTER_X:
|
||||
return pointer[index].x;
|
||||
|
@ -1772,7 +1837,7 @@ static int16_t android_input_state(void *data, const struct retro_keybind **bind
|
|||
return 0;
|
||||
}
|
||||
case RARCH_DEVICE_POINTER_SCREEN:
|
||||
switch(id)
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_POINTER_X:
|
||||
return pointer[index].full_x;
|
||||
|
|
|
@ -67,7 +67,7 @@ end:
|
|||
(*vm)->DetachCurrentThread(vm);
|
||||
}
|
||||
|
||||
void input_autodetect_setup (void *data, char *msg, size_t sizeof_msg, unsigned port, unsigned id, int source)
|
||||
void input_autodetect_setup(void *data, char *msg, size_t sizeof_msg, unsigned port, unsigned id, int source, bool *primary)
|
||||
{
|
||||
struct android_app *android_app = (struct android_app*)data;
|
||||
|
||||
|
@ -101,150 +101,153 @@ void input_autodetect_setup (void *data, char *msg, size_t sizeof_msg, unsigned
|
|||
}
|
||||
}
|
||||
|
||||
if (g_settings.input.autodetect_enable)
|
||||
device = 0;
|
||||
|
||||
if (strstr(name_buf,"Logitech") && strstr(name_buf, "RumblePad 2"))
|
||||
device = DEVICE_LOGITECH_RUMBLEPAD2;
|
||||
else if (strstr(name_buf, "Logitech") && strstr(name_buf, "Dual Action"))
|
||||
device = DEVICE_LOGITECH_DUAL_ACTION;
|
||||
else if (strstr(name_buf, "Logitech") && strstr(name_buf, "Precision"))
|
||||
device = DEVICE_LOGITECH_PRECISION_GAMEPAD;
|
||||
else if (strstr(name_buf, "iControlPad-")) // followed by a 4 (hex) char HW id
|
||||
device = DEVICE_ICONTROLPAD_HID_JOYSTICK;
|
||||
else if (strstr(name_buf, "SEGA VIRTUA STICK High Grade"))
|
||||
device = DEVICE_SEGA_VIRTUA_STICK_HIGH_GRADE;
|
||||
else if (strstr(name_buf, "TTT THT Arcade console 2P USB Play"))
|
||||
device = DEVICE_TTT_THT_ARCADE;
|
||||
else if (strstr(name_buf, "TOMMO NEOGEOX Arcade Stick"))
|
||||
device = DEVICE_TOMMO_NEOGEOX_ARCADE;
|
||||
else if (strstr(name_buf, "Onlive Wireless Controller"))
|
||||
device = DEVICE_ONLIVE_WIRELESS_CONTROLLER;
|
||||
else if (strstr(name_buf, "MadCatz") && strstr(name_buf, "PC USB Wired Stick"))
|
||||
device = DEVICE_MADCATZ_PC_USB_STICK;
|
||||
else if (strstr(name_buf, "Logicool") && strstr(name_buf, "RumblePad 2"))
|
||||
device = DEVICE_LOGICOOL_RUMBLEPAD2;
|
||||
else if (strstr(name_buf, "Sun4i-keypad"))
|
||||
device = DEVICE_IDROID_X360;
|
||||
else if (strstr(name_buf, "Zeemote") && strstr(name_buf, "Steelseries free"))
|
||||
device = DEVICE_ZEEMOTE_STEELSERIES;
|
||||
else if (strstr(name_buf, "HuiJia USB GamePad"))
|
||||
device = DEVICE_HUIJIA_USB_SNES;
|
||||
else if (strstr(name_buf, "Smartjoy Family Super Smartjoy 2"))
|
||||
device = DEVICE_SUPER_SMARTJOY;
|
||||
else if (strstr(name_buf, "Jess Tech Dual Analog Rumble Pad"))
|
||||
device = DEVICE_SAITEK_RUMBLE_P480;
|
||||
else if (strstr(name_buf, "Microsoft"))
|
||||
{
|
||||
device = 0;
|
||||
|
||||
if (strstr(name_buf,"Logitech") && strstr(name_buf, "RumblePad 2"))
|
||||
device = DEVICE_LOGITECH_RUMBLEPAD2;
|
||||
else if (strstr(name_buf, "Logitech") && strstr(name_buf, "Dual Action"))
|
||||
device = DEVICE_LOGITECH_DUAL_ACTION;
|
||||
else if (strstr(name_buf, "Logitech") && strstr(name_buf, "Precision"))
|
||||
device = DEVICE_LOGITECH_PRECISION_GAMEPAD;
|
||||
else if (strstr(name_buf, "iControlPad-")) // followed by a 4 (hex) char HW id
|
||||
device = DEVICE_ICONTROLPAD_HID_JOYSTICK;
|
||||
else if (strstr(name_buf, "SEGA VIRTUA STICK High Grade"))
|
||||
device = DEVICE_SEGA_VIRTUA_STICK_HIGH_GRADE;
|
||||
else if (strstr(name_buf, "TTT THT Arcade console 2P USB Play"))
|
||||
device = DEVICE_TTT_THT_ARCADE;
|
||||
else if (strstr(name_buf, "TOMMO NEOGEOX Arcade Stick"))
|
||||
device = DEVICE_TOMMO_NEOGEOX_ARCADE;
|
||||
else if (strstr(name_buf, "Onlive Wireless Controller"))
|
||||
device = DEVICE_ONLIVE_WIRELESS_CONTROLLER;
|
||||
else if (strstr(name_buf, "MadCatz") && strstr(name_buf, "PC USB Wired Stick"))
|
||||
device = DEVICE_MADCATZ_PC_USB_STICK;
|
||||
else if (strstr(name_buf, "Logicool") && strstr(name_buf, "RumblePad 2"))
|
||||
device = DEVICE_LOGICOOL_RUMBLEPAD2;
|
||||
else if (strstr(name_buf, "Sun4i-keypad"))
|
||||
device = DEVICE_IDROID_X360;
|
||||
else if (strstr(name_buf, "Zeemote") && strstr(name_buf, "Steelseries free"))
|
||||
device = DEVICE_ZEEMOTE_STEELSERIES;
|
||||
else if (strstr(name_buf, "HuiJia USB GamePad"))
|
||||
device = DEVICE_HUIJIA_USB_SNES;
|
||||
else if (strstr(name_buf, "Smartjoy Family Super Smartjoy 2"))
|
||||
device = DEVICE_SUPER_SMARTJOY;
|
||||
else if (strstr(name_buf, "Jess Tech Dual Analog Rumble Pad"))
|
||||
device = DEVICE_SAITEK_RUMBLE_P480;
|
||||
else if (strstr(name_buf, "Microsoft"))
|
||||
{
|
||||
if (strstr(name_buf, "Dual Strike"))
|
||||
device = DEVICE_MS_SIDEWINDER_DUAL_STRIKE;
|
||||
else if (strstr(name_buf, "SideWinder"))
|
||||
device = DEVICE_MS_SIDEWINDER;
|
||||
else if (strstr(name_buf, "X-Box 360") || strstr(name_buf, "X-Box")
|
||||
|| strstr(name_buf, "Xbox 360 Wireless Receiver"))
|
||||
device = DEVICE_MS_XBOX;
|
||||
}
|
||||
else if (strstr(name_buf, "WiseGroup"))
|
||||
{
|
||||
if (strstr(name_buf, "TigerGame") || strstr(name_buf, "Game Controller Adapter")
|
||||
|| strstr(name_buf, "JC-PS102U") || strstr(name_buf, "Dual USB Joypad"))
|
||||
{
|
||||
if (strstr(name_buf, "WiseGroup"))
|
||||
device = DEVICE_WISEGROUP_PLAYSTATION2;
|
||||
else if (strstr(name_buf, "JC-PS102U"))
|
||||
device = DEVICE_JCPS102_PLAYSTATION2;
|
||||
else
|
||||
device = DEVICE_GENERIC_PLAYSTATION2_CONVERTER;
|
||||
}
|
||||
}
|
||||
else if (strstr(name_buf, "PLAYSTATION(R)3") || strstr(name_buf, "Dualshock3")
|
||||
|| strstr(name_buf,"Sixaxis") || strstr(name_buf, "Gasia,Co") ||
|
||||
(strstr(name_buf, "Gamepad 0") || strstr(name_buf, "Gamepad 1") ||
|
||||
strstr(name_buf, "Gamepad 2") || strstr(name_buf, "Gamepad 3")))
|
||||
{
|
||||
if (strstr(name_buf, "Gamepad 0") || strstr(name_buf, "Gamepad 1") ||
|
||||
strstr(name_buf, "Gamepad 2") || strstr(name_buf, "Gamepad 3"))
|
||||
device = DEVICE_PLAYSTATION3_VERSION1;
|
||||
else
|
||||
device = DEVICE_PLAYSTATION3_VERSION2;
|
||||
}
|
||||
else if (strstr(name_buf, "MOGA"))
|
||||
device = DEVICE_MOGA;
|
||||
else if (strstr(name_buf, "Sony Navigation Controller"))
|
||||
device = DEVICE_PSMOVE_NAVI;
|
||||
else if (strstr(name_buf, "OUYA Game Controller"))
|
||||
device = DEVICE_OUYA;
|
||||
else if (strstr(name_buf, "adc joystick"))
|
||||
device = DEVICE_JXD_S7300B;
|
||||
else if (strstr(name_buf, "idroid:con"))
|
||||
device = DEVICE_IDROID_CON;
|
||||
else if (strstr(name_buf, "NYKO PLAYPAD PRO"))
|
||||
device = DEVICE_NYKO_PLAYPAD_PRO;
|
||||
else if (strstr(name_buf, "2-Axis, 8-Button"))
|
||||
device = DEVICE_GENIUS_MAXFIRE_G08XU;
|
||||
else if (strstr(name_buf, "USB,2-axis 8-button gamepad"))
|
||||
device = DEVICE_USB_2_AXIS_8_BUTTON_GAMEPAD;
|
||||
else if (strstr(name_buf, "BUFFALO BGC-FC801"))
|
||||
device = DEVICE_BUFFALO_BGC_FC801;
|
||||
else if (strstr(name_buf, "RetroUSB.com RetroPad"))
|
||||
device = DEVICE_RETROUSB_RETROPAD;
|
||||
else if (strstr(name_buf, "RetroUSB.com SNES RetroPort"))
|
||||
device = DEVICE_RETROUSB_SNES_RETROPORT;
|
||||
else if (strstr(name_buf, "CYPRESS USB"))
|
||||
device = DEVICE_CYPRESS_USB;
|
||||
else if (strstr(name_buf, "Mayflash Wii Classic"))
|
||||
device = DEVICE_MAYFLASH_WII_CLASSIC;
|
||||
else if (strstr(name_buf, "SZMy-power LTD CO. Dual Box WII"))
|
||||
device = DEVICE_SZMY_POWER_DUAL_BOX_WII;
|
||||
else if (strstr(name_buf, "Toodles 2008 ChImp"))
|
||||
device = DEVICE_TOODLES_2008_CHIMP;
|
||||
else if (strstr(name_buf, "joy_key"))
|
||||
device = DEVICE_ARCHOS_GAMEPAD;
|
||||
else if (strstr(name_buf, "matrix_keyboard"))
|
||||
device = DEVICE_JXD_S5110;
|
||||
else if (strstr(name_buf, "keypad-zeus") || (strstr(name_buf, "keypad-game-zeus")))
|
||||
device = DEVICE_XPERIA_PLAY;
|
||||
else if (strstr(name_buf, "Broadcom Bluetooth HID"))
|
||||
device = DEVICE_BROADCOM_BLUETOOTH_HID;
|
||||
else if (strstr(name_buf, "USB Gamepad"))
|
||||
device = DEVICE_THRUST_PREDATOR;
|
||||
else if (strstr(name_buf, "DragonRise"))
|
||||
device = DEVICE_DRAGONRISE;
|
||||
else if (strstr(name_buf, "Thrustmaster T Mini"))
|
||||
device = DEVICE_THRUSTMASTER_T_MINI;
|
||||
else if (strstr(name_buf, "2Axes 11Keys Game Pad"))
|
||||
device = DEVICE_TOMEE_NES_USB;
|
||||
else if (strstr(name_buf, "rk29-keypad") || strstr(name_buf, "GAMEMID"))
|
||||
device = DEVICE_GAMEMID;
|
||||
else if (strstr(name_buf, "USB Gamepad"))
|
||||
device = DEVICE_DEFENDER_GAME_RACER_CLASSIC;
|
||||
else if (strstr(name_buf, "HOLTEK JC - U912F vibration game"))
|
||||
device = DEVICE_HOLTEK_JC_U912F;
|
||||
|
||||
if (strstr(current_ime, "net.obsidianx.android.mogaime"))
|
||||
{
|
||||
device = DEVICE_MOGA_IME;
|
||||
snprintf(name_buf, sizeof(name_buf), "MOGA IME");
|
||||
}
|
||||
else if (strstr(current_ime, "com.ccpcreations.android.WiiUseAndroid"))
|
||||
{
|
||||
device = DEVICE_CCPCREATIONS_WIIUSE_IME;
|
||||
snprintf(name_buf, sizeof(name_buf), "ccpcreations WiiUse");
|
||||
}
|
||||
else if (strstr(current_ime, "com.hexad.bluezime"))
|
||||
{
|
||||
device = DEVICE_ICONTROLPAD_BLUEZ_IME;
|
||||
snprintf(name_buf, sizeof(name_buf), "iControlpad SPP mode (using Bluez IME)");
|
||||
}
|
||||
|
||||
if (source == AINPUT_SOURCE_KEYBOARD && device != DEVICE_XPERIA_PLAY)
|
||||
device = DEVICE_KEYBOARD_RETROPAD;
|
||||
|
||||
if (driver.input->set_keybinds)
|
||||
driver.input->set_keybinds(driver.input_data, device, port, id,
|
||||
(1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS));
|
||||
if (strstr(name_buf, "Dual Strike"))
|
||||
device = DEVICE_MS_SIDEWINDER_DUAL_STRIKE;
|
||||
else if (strstr(name_buf, "SideWinder"))
|
||||
device = DEVICE_MS_SIDEWINDER;
|
||||
else if (strstr(name_buf, "X-Box 360") || strstr(name_buf, "X-Box")
|
||||
|| strstr(name_buf, "Xbox 360 Wireless Receiver"))
|
||||
device = DEVICE_MS_XBOX;
|
||||
}
|
||||
else if (strstr(name_buf, "WiseGroup"))
|
||||
{
|
||||
if (strstr(name_buf, "TigerGame") || strstr(name_buf, "Game Controller Adapter")
|
||||
|| strstr(name_buf, "JC-PS102U") || strstr(name_buf, "Dual USB Joypad"))
|
||||
{
|
||||
if (strstr(name_buf, "WiseGroup"))
|
||||
device = DEVICE_WISEGROUP_PLAYSTATION2;
|
||||
else if (strstr(name_buf, "JC-PS102U"))
|
||||
device = DEVICE_JCPS102_PLAYSTATION2;
|
||||
else
|
||||
device = DEVICE_GENERIC_PLAYSTATION2_CONVERTER;
|
||||
}
|
||||
}
|
||||
else if (strstr(name_buf, "PLAYSTATION(R)3") || strstr(name_buf, "Dualshock3")
|
||||
|| strstr(name_buf,"Sixaxis") || strstr(name_buf, "Gasia,Co") ||
|
||||
(strstr(name_buf, "Gamepad 0") || strstr(name_buf, "Gamepad 1") ||
|
||||
strstr(name_buf, "Gamepad 2") || strstr(name_buf, "Gamepad 3")))
|
||||
{
|
||||
if (strstr(name_buf, "Gamepad 0") || strstr(name_buf, "Gamepad 1") ||
|
||||
strstr(name_buf, "Gamepad 2") || strstr(name_buf, "Gamepad 3"))
|
||||
device = DEVICE_PLAYSTATION3_VERSION1;
|
||||
else
|
||||
device = DEVICE_PLAYSTATION3_VERSION2;
|
||||
}
|
||||
else if (strstr(name_buf, "MOGA"))
|
||||
device = DEVICE_MOGA;
|
||||
else if (strstr(name_buf, "Sony Navigation Controller"))
|
||||
device = DEVICE_PSMOVE_NAVI;
|
||||
else if (strstr(name_buf, "OUYA Game Controller"))
|
||||
device = DEVICE_OUYA;
|
||||
else if (strstr(name_buf, "adc joystick"))
|
||||
device = DEVICE_JXD_S7300B;
|
||||
else if (strstr(name_buf, "idroid:con"))
|
||||
device = DEVICE_IDROID_CON;
|
||||
else if (strstr(name_buf, "NYKO PLAYPAD PRO"))
|
||||
device = DEVICE_NYKO_PLAYPAD_PRO;
|
||||
else if (strstr(name_buf, "2-Axis, 8-Button"))
|
||||
device = DEVICE_GENIUS_MAXFIRE_G08XU;
|
||||
else if (strstr(name_buf, "USB,2-axis 8-button gamepad"))
|
||||
device = DEVICE_USB_2_AXIS_8_BUTTON_GAMEPAD;
|
||||
else if (strstr(name_buf, "BUFFALO BGC-FC801"))
|
||||
device = DEVICE_BUFFALO_BGC_FC801;
|
||||
else if (strstr(name_buf, "RetroUSB.com RetroPad"))
|
||||
device = DEVICE_RETROUSB_RETROPAD;
|
||||
else if (strstr(name_buf, "RetroUSB.com SNES RetroPort"))
|
||||
device = DEVICE_RETROUSB_SNES_RETROPORT;
|
||||
else if (strstr(name_buf, "CYPRESS USB"))
|
||||
device = DEVICE_CYPRESS_USB;
|
||||
else if (strstr(name_buf, "Mayflash Wii Classic"))
|
||||
device = DEVICE_MAYFLASH_WII_CLASSIC;
|
||||
else if (strstr(name_buf, "SZMy-power LTD CO. Dual Box WII"))
|
||||
device = DEVICE_SZMY_POWER_DUAL_BOX_WII;
|
||||
else if (strstr(name_buf, "Toodles 2008 ChImp"))
|
||||
device = DEVICE_TOODLES_2008_CHIMP;
|
||||
else if (strstr(name_buf, "joy_key"))
|
||||
device = DEVICE_ARCHOS_GAMEPAD;
|
||||
else if (strstr(name_buf, "matrix_keyboard"))
|
||||
device = DEVICE_JXD_S5110;
|
||||
else if (strstr(name_buf, "keypad-zeus") || (strstr(name_buf, "keypad-game-zeus")))
|
||||
device = DEVICE_XPERIA_PLAY;
|
||||
else if (strstr(name_buf, "Broadcom Bluetooth HID"))
|
||||
device = DEVICE_BROADCOM_BLUETOOTH_HID;
|
||||
else if (strstr(name_buf, "USB Gamepad"))
|
||||
device = DEVICE_THRUST_PREDATOR;
|
||||
else if (strstr(name_buf, "DragonRise"))
|
||||
device = DEVICE_DRAGONRISE;
|
||||
else if (strstr(name_buf, "Thrustmaster T Mini"))
|
||||
device = DEVICE_THRUSTMASTER_T_MINI;
|
||||
else if (strstr(name_buf, "2Axes 11Keys Game Pad"))
|
||||
device = DEVICE_TOMEE_NES_USB;
|
||||
else if (strstr(name_buf, "rk29-keypad") || strstr(name_buf, "GAMEMID"))
|
||||
device = DEVICE_GAMEMID;
|
||||
else if (strstr(name_buf, "USB Gamepad"))
|
||||
device = DEVICE_DEFENDER_GAME_RACER_CLASSIC;
|
||||
else if (strstr(name_buf, "HOLTEK JC - U912F vibration game"))
|
||||
device = DEVICE_HOLTEK_JC_U912F;
|
||||
else if (strstr(name_buf, "NVIDIA Controller"))
|
||||
{
|
||||
device = DEVICE_NVIDIA_SHIELD;
|
||||
port = 0; // Shield is always player 1.
|
||||
*primary = true;
|
||||
}
|
||||
|
||||
if (strstr(current_ime, "net.obsidianx.android.mogaime"))
|
||||
{
|
||||
device = DEVICE_MOGA_IME;
|
||||
snprintf(name_buf, sizeof(name_buf), "MOGA IME");
|
||||
}
|
||||
else if (strstr(current_ime, "com.ccpcreations.android.WiiUseAndroid"))
|
||||
{
|
||||
device = DEVICE_CCPCREATIONS_WIIUSE_IME;
|
||||
snprintf(name_buf, sizeof(name_buf), "ccpcreations WiiUse");
|
||||
}
|
||||
else if (strstr(current_ime, "com.hexad.bluezime"))
|
||||
{
|
||||
device = DEVICE_ICONTROLPAD_BLUEZ_IME;
|
||||
snprintf(name_buf, sizeof(name_buf), "iControlpad SPP mode (using Bluez IME)");
|
||||
}
|
||||
|
||||
if (source == AINPUT_SOURCE_KEYBOARD && device != DEVICE_XPERIA_PLAY)
|
||||
device = DEVICE_KEYBOARD_RETROPAD;
|
||||
|
||||
if (driver.input->set_keybinds)
|
||||
driver.input->set_keybinds(driver.input_data, device, port, id,
|
||||
(1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS));
|
||||
|
||||
if (name_buf[0] != 0)
|
||||
snprintf(msg, sizeof_msg, "Port %d: %s.\n", port, name_buf);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
enum {
|
||||
ICADE_PROFILE_RED_SAMURAI = 0,
|
||||
ICADE_PROFILE_IPEGA_PG9017,
|
||||
ICADE_PROFILE_IPEGA_PG9017_MODE2,
|
||||
ICADE_PROFILE_GAMESTOP_WIRELESS,
|
||||
} icade_profile_enums;
|
||||
|
||||
|
@ -60,6 +61,7 @@ enum {
|
|||
AKEYCODE_NUMPAD_7 = 151,
|
||||
AKEYCODE_NUMPAD_8 = 152,
|
||||
AKEYCODE_NUMPAD_9 = 153,
|
||||
AKEYCODE_WINDOW = 171,
|
||||
AKEYCODE_BUTTON_1 = 188,
|
||||
AKEYCODE_BUTTON_2 = 189,
|
||||
AKEYCODE_BUTTON_3 = 190,
|
||||
|
@ -81,7 +83,7 @@ enum {
|
|||
|
||||
#define LAST_KEYCODE AKEYCODE_ASSIST
|
||||
|
||||
void input_autodetect_setup (void *data, char *msg, size_t sizeof_msg, unsigned port, unsigned id, int source);
|
||||
void input_autodetect_setup(void *data, char *msg, size_t sizeof_msg, unsigned port, unsigned id, int source, bool *primary);
|
||||
|
||||
/* Xperia Play externs */
|
||||
extern unsigned zeus_port;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.retroarch"
|
||||
android:versionCode="17"
|
||||
android:versionName="0.9.9.3" >
|
||||
android:versionCode="23"
|
||||
android:versionName="0.9.9.6" >
|
||||
<uses-feature android:glEsVersion="0x00020000" />
|
||||
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
|
||||
<uses-sdk
|
||||
|
@ -13,29 +13,36 @@
|
|||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name" >
|
||||
<activity android:name="org.retroarch.browser.RetroArch">
|
||||
android:label="@string/app_name"
|
||||
android:hasCode="true">
|
||||
<activity android:name=".browser.CoreSelection"></activity>
|
||||
<activity android:name=".browser.HistorySelection"></activity>
|
||||
<activity android:name=".browser.DisplayRefreshRateTest"></activity>
|
||||
<activity android:name=".browser.RefreshRateSetOS"></activity>
|
||||
<activity android:name=".browser.MainMenuActivity" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</activity>
|
||||
<activity android:name=".browser.HoneycombPopupMenu"></activity>
|
||||
<activity android:name=".browser.LazyPopupMenu"></activity>
|
||||
<activity android:name=".browser.PopupMenuAbstract"></activity>
|
||||
<activity android:name=".browser.ReportIME"></activity>
|
||||
<activity android:name=".browser.HelpActivity"></activity>
|
||||
<activity android:name=".browser.FileWrapper"></activity>
|
||||
<activity android:name=".browser.DirectoryActivity"></activity>
|
||||
<activity android:name=".browser.ROMActivity"></activity>
|
||||
<activity android:name=".browser.RetroTVMode"></activity>
|
||||
|
||||
<activity android:name="org.retroarch.browser.DisplayRefreshRateTest"></activity>
|
||||
<activity android:name="org.retroarch.browser.RefreshRateSetOS"></activity>
|
||||
<activity android:name="org.retroarch.browser.SettingsActivity"></activity>
|
||||
<activity android:name="org.retroarch.browser.HelpActivity"></activity>
|
||||
<activity android:name="org.retroarch.browser.DirectoryActivity"></activity>
|
||||
<activity android:name="org.retroarch.browser.ROMActivity"></activity>
|
||||
<activity android:name=".browser.ShaderActivity"></activity>
|
||||
<activity android:name=".browser.OverlayActivity"></activity>
|
||||
<activity android:name=".browser.ROMDirActivity"></activity>
|
||||
<activity android:name=".browser.SRMDirActivity"></activity>
|
||||
<activity android:name=".browser.StateDirActivity"></activity>
|
||||
<activity android:name=".browser.SystemDirActivity"></activity>
|
||||
|
||||
<activity android:name="org.retroarch.browser.ShaderActivity"></activity>
|
||||
<activity android:name="org.retroarch.browser.OverlayActivity"></activity>
|
||||
<activity android:name="org.retroarch.browser.ROMDirActivity"></activity>
|
||||
<activity android:name="org.retroarch.browser.SRMDirActivity"></activity>
|
||||
<activity android:name="org.retroarch.browser.StateDirActivity"></activity>
|
||||
<activity android:name="org.retroarch.browser.SystemDirActivity"></activity>
|
||||
|
||||
<activity android:name="org.retroarch.browser.RetroActivity" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale">
|
||||
<activity android:name=".browser.RetroActivity" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
|
||||
<meta-data android:name="android.app.lib_name" android:value="retroarch-activity" />
|
||||
<meta-data android:name="android.app.func_name" android:value="ANativeActivity_onCreate" />
|
||||
</activity>
|
||||
|
|
|
@ -1,21 +1,81 @@
|
|||
libretro_mednafen_pce_fast = "Mednafen PCE-fast (PC Engine/PC Engine CD)"
|
||||
libretro_mednafen_wswan = "Mednafen WSwan (Wonderswan)"
|
||||
libretro_fceumm = "FCEUmm (Nintendo NES)"
|
||||
libretro_mednafen_vb = "Mednafen VB (Virtual Boy)"
|
||||
libretro_fba = "Final Burn Alpha (Arcade)"
|
||||
libretro_mednafen_ngp = "Mednafen NGP (Neo-Geo Pocket)"
|
||||
libretro_gambatte = "Gambatte (GameBoy/GameBoy Color)"
|
||||
libretro_genesis_plus_gx = "Genesis Plus GX (Sega Genesis/Sega CD/Master System)"
|
||||
libretro_picodrive = "Picodrive (Sega Genesis/Sega CD/Master System/32X)"
|
||||
libretro_vba_next = "VBA Next (GameBoy Advance)"
|
||||
libretro_prboom = "PrBoom (DOOM)"
|
||||
libretro_snes9x_next = "Snes9x-Next (Nintendo SNES)"
|
||||
libretro_nestopia = "Nestopia (Nintendo NES)"
|
||||
libretro_pcsx_rearmed-neon = "PCSX-reARMed (PlayStation1) [NEON]"
|
||||
libretro_pcsx_rearmed = "PCSX-reARMed (PlayStation1)"
|
||||
libretro_nxengine = "NXEngine (Cave Story/Doukutsu Monogatari)"
|
||||
libretro_quicknes = "QuickNES (Nintendo NES)"
|
||||
libretro_tyrquake = "TyrQuake (Quake 1)"
|
||||
libretro_scenewalker = "SceneWalker (Objects)"
|
||||
libretro_modelviewer = "ModelViewer (Objects)"
|
||||
libretro_mame078 = "MAME 2003 [0.78] (Arcade)"
|
||||
libretro_mednafen_pce_fast = "Mednafen PCE-fast"
|
||||
libretro_mednafen_pce_fast_system = "PC Engine/PC Engine CD"
|
||||
|
||||
libretro_mednafen_wswan = "Mednafen WSwan"
|
||||
libretro_mednafen_wswan_system = "Wonderswan"
|
||||
|
||||
libretro_fceumm = "FCEUmm"
|
||||
libretro_fceumm_system = "Nintendo NES"
|
||||
|
||||
libretro_mednafen_vb = "Mednafen VB"
|
||||
libretro_mednafen_vb_system = "Virtual Boy"
|
||||
|
||||
libretro_fba = "Final Burn Alpha"
|
||||
libretro_fba_system = "Arcade"
|
||||
|
||||
libretro_mednafen_ngp = "Mednafen NGP"
|
||||
libretro_mednafen_ngp_system = "Neo-Geo Pocket"
|
||||
|
||||
libretro_mednafen_psx = "Mednafen PSX"
|
||||
libretro_mednafen_psx_system = "PlayStation1"
|
||||
|
||||
libretro_gambatte = "Gambatte"
|
||||
libretro_gambatte_system = "GameBoy/GameBoy Color"
|
||||
|
||||
libretro_genesis_plus_gx = "Genesis Plus GX"
|
||||
libretro_genesis_plus_gx_system = "Sega Genesis/Sega CD/Master System"
|
||||
|
||||
libretro_picodrive = "Picodrive"
|
||||
libretro_picodrive_system = "Sega Genesis/Sega CD/Master System/32X"
|
||||
|
||||
libretro_vba_next = "VBA Next"
|
||||
libretro_vba_next_system = "GameBoy Advance"
|
||||
|
||||
libretro_prboom = "PrBoom"
|
||||
libretro_prboom_system = "DOOM"
|
||||
|
||||
libretro_snes9x = "SNES9x"
|
||||
libretro_snes9x_system = "Nintendo SNES"
|
||||
|
||||
libretro_snes9x_next = "SNES9x Next"
|
||||
libretro_snes9x_next_system = "Nintendo SNES"
|
||||
|
||||
libretro_nestopia = "Nestopia"
|
||||
libretro_nestopia_system = "Nintendo NES"
|
||||
|
||||
libretro_pcsx_rearmed-neon = "PCSX-reARMed [NEON]"
|
||||
libretro_pcsx_rearmed-neon_system = "PlayStation1"
|
||||
|
||||
libretro_pcsx_rearmed = "PCSX-reARMed"
|
||||
libretro_pcsx_rearmed_system = "PlayStation1"
|
||||
|
||||
libretro_nxengine = "NXEngine"
|
||||
libretro_nxengine_system = "Cave Story/Doukutsu Monogatari"
|
||||
|
||||
libretro_quicknes = "QuickNES"
|
||||
libretro_quicknes_system = "Nintendo NES"
|
||||
|
||||
libretro_tyrquake = "TyrQuake"
|
||||
libretro_tyrquake_system = "Quake 1"
|
||||
|
||||
libretro_instancingviewer = "InstancingViewer"
|
||||
libretro_instancingviewer_system = "Images"
|
||||
|
||||
libretro_desmume = "Desmume"
|
||||
libretro_desmume_system = "Nintendo DS"
|
||||
|
||||
libretro_stella = "Stella"
|
||||
libretro_stella_system = "Atari 2600"
|
||||
|
||||
libretro_scenewalker = "SceneWalker"
|
||||
libretro_scenewalker_system = "Objects"
|
||||
|
||||
libretro_modelviewer = "ModelViewer"
|
||||
libretro_modelviewer_system = "Objects"
|
||||
|
||||
libretro_mame078 = "MAME 2003 [0.78]"
|
||||
libretro_mame078_system = "Arcade"
|
||||
|
||||
libretro_bsnes_performance = "bsnes/higan Performance"
|
||||
libretro_bsnes_performance_system = "Nintendo SNES"
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/assets_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/extracting_assets_please_wait_" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/assets_progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
|
||||
</LinearLayout>
|
|
@ -9,5 +9,5 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="40px"
|
||||
android:text="There can be two reasons for this:\n\na) Either your device is not powerful enough to run the core you've selected at fullspeed.\n\nb) The refresh rate of the screen that your device reports is wrong. More on b) below.\n\n== REFRESH RATES AND RETROARCH ==\n\nUnlike other emulators, RetroArch does not use frameskipping. To get smooth gameplay and sound that are remotely close to the original hardware, RetroArch Android uses static synchronization. If you notice any skipping music or 'jerkiness' - rest assured it's not our code - it's likely that your device reports a wrong refreshrate to the OS (Android in this case). For instance, certain devices like the Note 2 have refresh rates below 60Hz.\n\nTo get any decent audio and video out of any application, you will have to synchronize the game's refresh rate with that of your screen - if the refresh rate cannot be properly synchronized, you will get bad audio pops and video glitchiness.\n\nThe problem is that a good many Android devices 'report' the wrong refresh rate to Android. The Samsung Galaxy S3 is known for doing this - it reports a 60Hz refresh rate when it isn't (the Note 2 for instance has a 58Hz screen but at least reports it correctly). So, because it 'reports' a wrong refresh rate, RetroArch will not yield good results.\n\nIf you experience any audio pops on cores that should be running fullspeed on your device, you should go with manual synchronization. To do this, you can start by calcuating your screens refresh rate with the 'Calibrate refresh rate' setting. This option can give a good guess, but for best results you should edit the value it returns in the 'Forced refresh rate (Hz)' option and set it manually - start at the value it returns and if it still audio pops/crackles, raise or lower the value (0.01 intervals is a good place to start) until you hit a sweet spot.\n\nIf you think your device reports the correct value, you can use that instead by selecting the 'Set OS-reported refresh rate' option instead.\n\nWith a bit of experimentation you can get this right easily - I am running games on a single-core Cortex A8 device (1.2GHz - Allwinner A10) and I get no sound pops or any video glitchiness at all in most cores. So this is entirely a refresh rate issue that you can overcome easily on most devices by doing what I state above." />
|
||||
android:text="There can be a couple of reasons for this:\n\na) Either your device is not powerful enough to run the core you've selected at fullspeed.\n\nb) The refresh rate of the screen that your device reports is wrong. More on b) below.\n\nc) Just turn on 'Threaded video' to save yourself all the trouble of trying to get static syncing to work right on your device.\n\n== REFRESH RATES AND RETROARCH ==\n\nUnlike other emulators, RetroArch does not use frameskipping. To get smooth gameplay and sound that are remotely close to the original hardware, RetroArch Android uses static synchronization. If you notice any skipping music or 'jerkiness' - rest assured it's not our code - it's likely that your device reports a wrong refreshrate to the OS (Android in this case). For instance, certain devices like the Note 2 have refresh rates below 60Hz.\n\nTo get any decent audio and video out of any application, you will have to synchronize the game's refresh rate with that of your screen - if the refresh rate cannot be properly synchronized, you will get bad audio pops and video glitchiness.\n\nThe problem is that a good many Android devices 'report' the wrong refresh rate to Android. The Samsung Galaxy S3 is known for doing this - it reports a 60Hz refresh rate when it isn't (the Note 2 for instance has a 58Hz screen but at least reports it correctly). So, because it 'reports' a wrong refresh rate, RetroArch will not yield good results.\n\nIf you experience any audio pops on cores that should be running fullspeed on your device, you should go with manual synchronization. To do this, you can start by calcuating your screens refresh rate with the 'Calibrate refresh rate' setting. This option can give a good guess, but for best results you should edit the value it returns in the 'Forced refresh rate (Hz)' option and set it manually - start at the value it returns and if it still audio pops/crackles, raise or lower the value (0.01 intervals is a good place to start) until you hit a sweet spot.\n\nIf you think your device reports the correct value, you can use that instead by selecting the 'Set OS-reported refresh rate' option instead.\n\nWith a bit of experimentation you can get this right easily - I am running games on a single-core Cortex A8 device (1.2GHz - Allwinner A10) and I get no sound pops or any video glitchiness at all in most cores. So this is entirely a refresh rate issue that you can overcome easily on most devices by doing what I state above." />
|
||||
</LinearLayout>
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="40px"
|
||||
android:text="The following pads have been added to the autodetection list:\n\n* Logitech/Logicool Rumblepad 2\n* Microsoft Sidewinder USB (ISSUE - diagonals not working).\n* Microsoft Xbox 360 Wired/Wireless (ISSUE - diagonals not working).\n* PS3 Sixaxis/DualShock 3 (using either USB or Dancingpixelstudios' IME app)\n* MOGA (using either 'root' gamepad mode or official IME app)\n* JXD S5110\n* Snakebyte idroid\n* Logitech Dual Action\n* Mayflash Super Joy Box 3 Pro\n* RetroUSB SNES RetroPort\n* RetroUSB NES RetroPad\n* Buffalo SNES Pad\n* Elecom PS1/PS2 to USB\n* Archos gamepad\n* Xbox 1 (Titanium X-Joy Converter) (ISSUE - diagonals not working).\n* Red Samurai (IME app Bluetooth or gamepad mode)\n* Xperia Play\n* Trust Raptor\n* Logitech F710\n* DragonRise USB\n* Madcatz PS3 fighting stick\n* iControlPad (HID joystick profile or SPP profile in tandem with Bluez IME)\n* iPega (gamepad mode, select it in iCade profile)\n* PC2JAMMA-USB (TODO - TEST)\n* Genius MaxFire G-08XU\n* Zeemote Steelseries\n* Saitek Rumblepad\n* Super Smart Joy\n* Groupwise PS2 to USB converter\n* Toodles 2008 Chimp\n* Sega Saturn USB pad\n* Mayflash Wii Classic\n* Mayflash PS2 to USB\n* Nintendo Wii (using ccpcreations.WiiUse IME app)\n* Nyko Playpad Pro" />
|
||||
android:text="The following pads have been added to the autodetection list:\n\n* Logitech/Logicool Rumblepad 2\n* Microsoft Sidewinder USB (ISSUE - diagonals not working).\n* Microsoft Xbox 360 Wired/Wireless.\n* PS3 Sixaxis/DualShock 3 (using either USB or Dancingpixelstudios' IME app)\n* MOGA (using either 'root' gamepad mode or official IME app)\n* JXD S5110\n* Snakebyte idroid\n* Logitech Dual Action\n* Mayflash Super Joy Box 3 Pro\n* RetroUSB SNES RetroPort\n* RetroUSB NES RetroPad\n* Buffalo SNES Pad\n* Elecom PS1/PS2 to USB\n* Archos gamepad\n* Xbox 1 (Titanium X-Joy Converter) (ISSUE - diagonals not working).\n* Red Samurai (IME app Bluetooth or gamepad mode)\n* Xperia Play\n* Trust Raptor\n* Logitech F710\n* DragonRise USB\n* Madcatz PS3 fighting stick\n* iControlPad (HID joystick profile or SPP profile in tandem with Bluez IME)\n* iPega (gamepad mode, select it in iCade profile)\n* PC2JAMMA-USB (TODO - TEST)\n* Genius MaxFire G-08XU\n* Zeemote Steelseries\n* Saitek Rumblepad\n* Super Smart Joy\n* Groupwise PS2 to USB converter\n* Toodles 2008 Chimp\n* Sega Saturn USB pad\n* Mayflash Wii Classic\n* Mayflash PS2 to USB\n* Nintendo Wii (using ccpcreations.WiiUse IME app)\n* Nyko Playpad Pro\n*Nvidia Shield" />
|
||||
</LinearLayout>
|
||||
|
|
|
@ -25,5 +25,6 @@
|
|||
* Mednafen Virtual Boy [Virtual Boy] : Dual-core ARM Cortex A9 CPU or higher.\n
|
||||
* Mednafen PC Engine [PC Engine] : Has been tested to run at fullspeed on an ARM Cortex A8 single-core CPU.\n
|
||||
* TyrQuake [Quake 1] : Has been tested to run around give or take 55-60fps at 320x240 resolution on an ARM Cortex A8 single-core CPU.\n
|
||||
* Picodrive : Has been tested to run at fullspeed with Knuckles Chaotix [a 32X game] on an ARM Cortex A8 single-core CPU.\n
|
||||
" />
|
||||
</LinearLayout>
|
||||
|
|
|
@ -10,6 +10,73 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_margin="40px"
|
||||
android:text="
|
||||
r21 (August 16, 2013)\n\n
|
||||
* [VBA Next] Fixes serious regressions - most evident in Golden Sun games -\n
|
||||
battle screens etc.\n
|
||||
* [VBA Next] Add a core option to change the control button layout from (left\n
|
||||
to right) B to A to (left to right) A to B.\n
|
||||
r19 (August 15, 2013)\n\n
|
||||
* [Android] Input autodetection fixes -\n
|
||||
- DualShock3 pad controls fixed\n
|
||||
* [Android] It should now be possible to map D-pad to analog on several gamepads, such as:\n
|
||||
- Xbox 360\n
|
||||
- PlayStation3\n
|
||||
- Shield\n
|
||||
* [Android] Threaded video is now the default due to positive user feedback. Purists and accuracy\n
|
||||
people can still go for static syncing for best results - although for PCSX ReARMed threaded\n
|
||||
video is essential. With the combination of threaded video and dynamic audio rate control,\n
|
||||
most of the audio pops and sync issues should be a thing of the past now. Yay.\n
|
||||
* [Android] UI has been reorganized and made less shitty (yes, we know). Still a long way to go.\n
|
||||
The entire menu should be gamepad-controllable now at least - handy for Shield/Ouya.\n
|
||||
* [Android] Shaders that were broken on Nexus 7/4/10 etc. should now work.\n
|
||||
* [Android] Added some additional autodetection rules:\n
|
||||
- Ouya: Input overlays are disabled by default\n
|
||||
* [Android] Added high-latency audio option for crappy/old Android devices that can't handle\n
|
||||
the lower-latency audio that is the default since 0.9.9.4. This should give you the same\n
|
||||
performance as 0.9.9.3 (r17). Turn this on if you get bad sound/performance (and it's not your\n
|
||||
device simply being slow). This might also apply for some of the newer devices - perhaps \n
|
||||
OpenSL driver has not been updated/optimized there.\n
|
||||
* [Android] Added a TV mode. This will launch you straight into RGUI mode. This mode
|
||||
is identical to what you get from the Wii and PC ports of RetroArch at startup. First
|
||||
you select a core, then you select a game to go with it.
|
||||
* [SNES9x] Fixes by Alcaro to libretro port
|
||||
* [SNES9x Next] Fixes savestates from not being able to be loaded.
|
||||
* (LIBRETRO) Added bsnes/higan performance core [v0.92] (Android).\n
|
||||
- bsnes/higan performance core will run all non-coprocessor games at fullspeed on an\n
|
||||
nVidia Shield.\n
|
||||
- Co-processor games (SuperFX/SA-1/DSP/Cx4/SA1) will run between ~40fps and 55-57fps\n
|
||||
on an nVidia Shield - depending on the specific co-processor. Note - you will need\n
|
||||
BIOS files for these games - see byuu boards for information on them.\n
|
||||
* [Mednafen NGP] Fixes input issues in a number of games, such as:\n
|
||||
- Card Fighters games\n
|
||||
- Etc.\n
|
||||
* [Picodrive] Updates/32X compatibility/accuracy improvements\n
|
||||
* [NEStopia] Updated to 1.46 WIP - added ability to load NstDatabase.xml, fixes Vs. System games\n
|
||||
and Startropics 1/2\n
|
||||
r18 (August 7, 2013)\n\n
|
||||
* [Android] ANR issues fixed - Google bug (as ever).\n
|
||||
* [Android] Input autodetection expanded -\n
|
||||
- NVidia Shield\n
|
||||
- iControlPad changes\n
|
||||
- Logitech Rumblepad 2 (added RETRO_DEVICE_ID_ANALOG support)\n
|
||||
- Xbox 360 (D-pad should be fixed, added RETRO_DEVICE_ID_ANALOG support, triggers should work)\n
|
||||
* [RGUI] Throttle with timers - no more irrational super-fast menu with threaded video.\n
|
||||
* [Android] Appeal to low-latency audio Android devices for OpenSL (Android 4.1 and up)\n
|
||||
* [Android] Look for the optimal sampling rate instead of assuming 48KHz as default - should fix Nexus 10\n
|
||||
* [Android] Added 'Optimal Device Settings' and added support for both Nexus 7 2013 and Nvidia Shield\n
|
||||
* [Android] Added adaptive jittering for threaded video option. Should now be much more tolerable.\n
|
||||
* [Android] Enable threaded video by default - leave static syncing for expert users.\n
|
||||
* (LIBRETRO) Added Picodrive (PC/Android/iOS/Blackberry)\n
|
||||
* (LIBRETRO) Added SNES9x mainline.\n
|
||||
* (LIBRETRO) Added Stella.\n
|
||||
* (LIBRETRO) Added Desmume.\n
|
||||
* [TyrQuake] Added dual analog core option.\n
|
||||
* [NEStopia] Add Core Options for blargg NTSC.\n
|
||||
* [FBA core] Prevent diagnostics at startup from being enabled to avoid crash.\n
|
||||
* [Stella] 2 players should work now.\n
|
||||
* [Genesis Plus GX] Updated to latest version.\n
|
||||
* [VBA Next] Start sanitizing some code back to VBA-M proper.\n
|
||||
* [NX Engine/Cave Story] Fixed big-endian bug on scrolling backgrounds.\n
|
||||
r17 (June 28, 2013)\n\n
|
||||
* [Android] Input autodetection expanded -\n
|
||||
- Xperia Play controls fixed once and for all (thanks to littleguy77)\n
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="48dp">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
|
@ -11,13 +11,27 @@
|
|||
android:layout_height="48dp"
|
||||
android:contentDescription="@string/file_type_icon"
|
||||
android:padding="8dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="0dp"
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="0.5"
|
||||
android:textSize="18sp" />
|
||||
android:layout_gravity="center_vertical"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sub_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:visibility="gone"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:id="@+id/rarch_settings" android:title="@string/rarch_settings" android:showAsAction="ifRoom" />
|
||||
<item android:id="@+id/help" android:title="@string/help"></item>
|
||||
<item android:id="@+id/input_method_select" android:title="@string/input_method" android:showAsAction="ifRoom" />
|
||||
<item android:id="@+id/report_ime" android:title="@string/report_ime"></item>
|
||||
<item android:id="@+id/report_refreshrate" android:title="@string/report_refreshrate"></item>
|
||||
<item android:id="@+id/retroarch_guide" android:title="@string/retroarch_guide"></item>
|
||||
<item android:id="@+id/cores_guide" android:title="@string/cores_guide"></item>
|
||||
<item android:id="@+id/overlay_guide" android:title="@string/overlay_guide"></item>
|
||||
</menu>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:id="@+id/settings"
|
||||
android:title="@string/settings"
|
||||
android:title="Options"
|
||||
android:icon="@drawable/ic_file"
|
||||
android:showAsAction="ifRoom" />
|
||||
</menu>
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
<string-array name="icade_profiles">
|
||||
<item>Red Samurai</item>
|
||||
<item>iPega PG-9017</item>
|
||||
<item>iPega PG-9017 (Mode 2)</item>
|
||||
<item>Gamestop Wireless</item>
|
||||
</string-array>
|
||||
|
||||
|
@ -40,6 +41,7 @@
|
|||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="key_bind_values">
|
||||
|
|
|
@ -3,20 +3,12 @@
|
|||
<string name="app_name">RetroArch</string>
|
||||
<string name="input_method">Input Method</string>
|
||||
<string name="file_type_icon">File type icon</string>
|
||||
<string name="video_settings">Video Settings</string>
|
||||
<string name="rarch_settings">Settings</string>
|
||||
<string name="audio_settings">Audio Settings</string>
|
||||
<string name="input_settings">Input Settings</string>
|
||||
<string name="general_settings">General Settings</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="retroarch_guide">RetroArch Guide</string>
|
||||
<string name="cores_guide">Cores Guide</string>
|
||||
<string name="overlay_guide">Overlay How-to Guide</string>
|
||||
<string name="key_bind_title">Select the button to use</string>
|
||||
<string name="key_bind_clear">Unbind</string>
|
||||
<string name="help">Help</string>
|
||||
<string name="report_ime">Report IME</string>
|
||||
<string name="report_refreshrate">Report Refresh Rate</string>
|
||||
<string name="key_bind_detect">Detect</string>
|
||||
<string name="optimal_settings_device">Optimal device settings</string>
|
||||
<string name="extracting_assets_please_wait_">Extracting assets, please wait ...</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,79 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:title="RetroArch Settings" >
|
||||
android:title="RetroArch - Main Menu" >
|
||||
|
||||
<PreferenceScreen android:title="Path Settings">
|
||||
<PreferenceCategory android:title="ROM paths">
|
||||
<Preference android:title="ROM directory"
|
||||
android:summary="Sets directory where ROM browser will first browse for ROM files.">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.ROMDirActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="Save files">
|
||||
<CheckBoxPreference android:title="Enable custom directory"
|
||||
android:summary="Enables use of custom save file folder. (.srm) save files will be saved and loaded to configured directory. If not enabled, save files will reside in ROM folder."
|
||||
android:key="savefile_directory_enable"
|
||||
android:defaultValue="false"/>
|
||||
<Preference android:title="Savefile directory"
|
||||
android:summary="Sets directory where to save and load game save files."
|
||||
android:dependency="savefile_directory_enable">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.SRMDirActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Save states">
|
||||
<CheckBoxPreference android:title="Enable custom directory"
|
||||
android:summary="Enables use of custom save state folder. (.state) save states will be saved and loaded to configured directory. If not enabled, save states will reside in ROM folder."
|
||||
android:key="savestate_directory_enable"
|
||||
android:defaultValue="false"/>
|
||||
<Preference android:title="Save state directory"
|
||||
android:summary="Sets directory where to save and load game save states."
|
||||
android:dependency="savestate_directory_enable">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.StateDirActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="System">
|
||||
<CheckBoxPreference android:title="Enable custom directory"
|
||||
android:summary="Enables use of custom system folder. Cores will look for system specific files, like BIOSes, in this folder. If not enabled, it will look in the ROM folder."
|
||||
android:key="system_directory_enable"
|
||||
android:defaultValue="false"/>
|
||||
<Preference android:title="System directory"
|
||||
android:summary="Sets directory where system files are loaded from."
|
||||
android:dependency="system_directory_enable">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.SystemDirActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
<PreferenceScreen android:title="TV Mode">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.RetroTVMode"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="System Settings" >
|
||||
<PreferenceCategory android:title="General" >
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="savestate_auto_load"
|
||||
android:summary="Loads an automatically created savestate (*.state.auto) at startup."
|
||||
android:title="Auto load state" />
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="savestate_auto_save"
|
||||
android:summary="Automatically saves state (*.state.auto) when exiting game."
|
||||
android:title="Auto save state" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Rewinding" >
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="rewind_enable"
|
||||
android:summary="Enable real-time rewinding of gameplay. (WARNING: Very CPU intensive - will decrease ingame performance by a lot - only use this option on a powerful device)."
|
||||
android:title="Enable" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceScreen android:title="Load Core">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.CoreSelection"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="Video Settings" >
|
||||
<PreferenceScreen android:title="Load Game">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.ROMActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="Load Game (History)">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.HistorySelection"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="Video Options" >
|
||||
<PreferenceCategory android:title="General" >
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
|
@ -100,7 +49,7 @@
|
|||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Synchronization" >
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:defaultValue="true"
|
||||
android:key="video_threaded"
|
||||
android:summary="Uses a multi-threaded video driver. Is likely to improve performance at the expense of slightly more latency and jitter. Use this if you have troubles getting good video and audio."
|
||||
android:title="Threaded video driver" />
|
||||
|
@ -124,21 +73,21 @@
|
|||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Shaders (1st pass)" >
|
||||
<PreferenceCategory android:title="Shaders" >
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="video_smooth"
|
||||
android:summary="Applies Bilinear filtering, smooths out edges (settings still apply even if no shader is selected)."
|
||||
android:title="Bilinear filter" />
|
||||
<CheckBoxPreference
|
||||
android:summary="Enable first pass shader (WARNING: recommended system requirements for these shaders is a Tegra 4/Exynos5 class GPU and/or higher)."
|
||||
android:summary="Enable first pass shader (WARNING: recommended system requirements for these shaders is a Tegra 4 / Exynos 5 class GPU and/or higher)."
|
||||
android:defaultValue="false"
|
||||
android:key="video_shader_enable"
|
||||
android:title="Enable" />
|
||||
|
||||
<Preference
|
||||
android:summary="Sets GLES2 style XML shader."
|
||||
android:title="XML shader"
|
||||
android:summary="Sets GLES2 style shader."
|
||||
android:title="GLSL shader"
|
||||
android:dependency="video_shader_enable" >
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.ShaderActivity"
|
||||
|
@ -152,7 +101,7 @@
|
|||
android:defaultValue="true"/>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="Audio Settings" >
|
||||
<PreferenceScreen android:title="Audio Options" >
|
||||
<PreferenceCategory android:title="Audio" >
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
|
@ -164,10 +113,20 @@
|
|||
android:summary="Enable dynamic rate control (recommended)."
|
||||
android:title="Dynamic Rate Control"
|
||||
android:dependency="audio_enable" />
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="audio_high_latency"
|
||||
android:summary="Use (very) high latency audio. Necessary for older Android devices with poor audio drivers."
|
||||
android:title="High latency audio"
|
||||
android:dependency="audio_enable" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="Input Settings" >
|
||||
<PreferenceScreen android:title="Input Options" >
|
||||
<PreferenceCategory android:title="General" >
|
||||
<CheckBoxPreference android:title="Enable global configuration"
|
||||
android:summary="Enable global settings for all cores. Leave disabled if you want per-core settings."
|
||||
android:key="global_config_enable"
|
||||
android:defaultValue="true"/>
|
||||
<ListPreference
|
||||
android:entries="@array/back_options"
|
||||
android:entryValues="@array/back_options_values"
|
||||
|
@ -449,5 +408,121 @@
|
|||
android:title="R3 Button" />
|
||||
</PreferenceScreen>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Diagnostics" >
|
||||
<Preference android:title="Report IME"
|
||||
android:summary="Reports the current IME (Input Method Editor) name.">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.ReportIME"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="Path Options">
|
||||
<PreferenceCategory android:title="ROM paths">
|
||||
<Preference android:title="ROM directory"
|
||||
android:summary="Sets directory where ROM browser will first browse for ROM files.">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.ROMDirActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="Save files">
|
||||
<CheckBoxPreference android:title="Enable custom directory"
|
||||
android:summary="Enables use of custom save file folder. (.srm) save files will be saved and loaded to configured directory. If not enabled, save files will reside in ROM folder."
|
||||
android:key="savefile_directory_enable"
|
||||
android:defaultValue="false"/>
|
||||
<Preference android:title="Savefile directory"
|
||||
android:summary="Sets directory where to save and load game save files."
|
||||
android:dependency="savefile_directory_enable">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.SRMDirActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Save states">
|
||||
<CheckBoxPreference android:title="Enable custom directory"
|
||||
android:summary="Enables use of custom save state folder. (.state) save states will be saved and loaded to configured directory. If not enabled, save states will reside in ROM folder."
|
||||
android:key="savestate_directory_enable"
|
||||
android:defaultValue="false"/>
|
||||
<Preference android:title="Save state directory"
|
||||
android:summary="Sets directory where to save and load game save states."
|
||||
android:dependency="savestate_directory_enable">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.StateDirActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="System">
|
||||
<CheckBoxPreference android:title="Enable custom directory"
|
||||
android:summary="Enables use of custom system folder. Cores will look for system specific files, like BIOSes, in this folder. If not enabled, it will look in the ROM folder."
|
||||
android:key="system_directory_enable"
|
||||
android:defaultValue="false"/>
|
||||
<Preference android:title="System directory"
|
||||
android:summary="Sets directory where system files are loaded from."
|
||||
android:dependency="system_directory_enable">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.SystemDirActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="Settings" >
|
||||
<PreferenceCategory android:title="General" >
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="savestate_auto_load"
|
||||
android:summary="Loads an automatically created savestate (*.state.auto) at startup."
|
||||
android:title="Auto load state" />
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="savestate_auto_save"
|
||||
android:summary="Automatically saves state (*.state.auto) when exiting game."
|
||||
android:title="Auto save state" />
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Rewinding" >
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="rewind_enable"
|
||||
android:summary="Enable real-time rewinding of gameplay. (WARNING: Very CPU intensive - will decrease ingame performance by a lot - only use this option on a powerful device)."
|
||||
android:title="Enable" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="Help">
|
||||
<intent
|
||||
android:targetClass="org.retroarch.browser.HelpActivity"
|
||||
android:targetPackage="org.retroarch" />
|
||||
</PreferenceScreen>
|
||||
<PreferenceScreen android:title="About">
|
||||
<PreferenceCategory android:title="Websites">
|
||||
<Preference android:title="RetroArch/libretro homepage"
|
||||
android:summary="The official homepage of the RetroArch/libretro project.">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="http://www.libretro.com" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Manuals">
|
||||
<Preference android:title="RetroArch Guide (PDF)"
|
||||
android:summary="The manual to RetroArch Android in PDF format.">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="http://www.libretro.com/documents/retroarch-manual.pdf" />
|
||||
</Preference>
|
||||
<Preference android:title="Cores Guide (PDF)"
|
||||
android:summary="The manual to most libretro cores in PDF format.">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="http://www.libretro.com/documents/retroarch-cores-manual.pdf" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="Development">
|
||||
<Preference android:title="Overlay Guide (PDF)"
|
||||
android:summary="Explains howto make your own overlays.">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="http://www.libretro.com/documents/overlay.pdf" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import org.retroarch.R;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import android.app.*;
|
||||
import android.media.AudioManager;
|
||||
import android.os.*;
|
||||
import android.widget.*;
|
||||
import android.util.Log;
|
||||
import android.view.*;
|
||||
|
||||
// JELLY_BEAN_MR1 = 17
|
||||
|
||||
public class CoreSelection extends Activity implements
|
||||
AdapterView.OnItemClickListener {
|
||||
private IconAdapter<ModuleWrapper> adapter;
|
||||
static private final String TAG = "CoreSelection";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
ConfigFile core_config;
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
core_config = new ConfigFile();
|
||||
try {
|
||||
core_config.append(getAssets().open("libretro_cores.cfg"));
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to load libretro_cores.cfg from assets.");
|
||||
}
|
||||
|
||||
String cpuInfo = MainMenuActivity.readCPUInfo();
|
||||
boolean cpuIsNeon = cpuInfo.contains("neon");
|
||||
|
||||
setContentView(R.layout.line_list);
|
||||
|
||||
// Setup the list
|
||||
adapter = new IconAdapter<ModuleWrapper>(this, R.layout.line_list_item);
|
||||
ListView list = (ListView) findViewById(R.id.list);
|
||||
list.setAdapter(adapter);
|
||||
list.setOnItemClickListener(this);
|
||||
|
||||
setTitle("Select Libretro core");
|
||||
|
||||
// Populate the list
|
||||
final String modulePath = MainMenuActivity.getInstance()
|
||||
.getApplicationInfo().nativeLibraryDir;
|
||||
final File[] libs = new File(modulePath).listFiles();
|
||||
for (final File lib : libs) {
|
||||
String libName = lib.getName();
|
||||
|
||||
// Never append a NEON lib if we don't have NEON.
|
||||
if (libName.contains("neon") && !cpuIsNeon)
|
||||
continue;
|
||||
|
||||
// If we have a NEON version with NEON capable CPU,
|
||||
// never append a non-NEON version.
|
||||
if (cpuIsNeon && !libName.contains("neon")) {
|
||||
boolean hasNeonVersion = false;
|
||||
for (final File lib_ : libs) {
|
||||
String otherName = lib_.getName();
|
||||
String baseName = libName.replace(".so", "");
|
||||
if (otherName.contains("neon")
|
||||
&& otherName.startsWith(baseName)) {
|
||||
hasNeonVersion = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNeonVersion)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allow both libretro-core.so and libretro_core.so.
|
||||
if (libName.startsWith("libretro")
|
||||
&& !libName.startsWith("libretroarch")) {
|
||||
try {
|
||||
adapter.add(new ModuleWrapper(this, lib, core_config));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> aListView, View aView,
|
||||
int aPosition, long aID) {
|
||||
final ModuleWrapper item = adapter.getItem(aPosition);
|
||||
MainMenuActivity.getInstance().setModule(item.file.getAbsolutePath(), item.getText());
|
||||
MainMenuActivity.getInstance().updateConfigFile();
|
||||
finish();
|
||||
}
|
||||
}
|
|
@ -12,75 +12,7 @@ import android.os.*;
|
|||
import android.preference.PreferenceManager;
|
||||
import android.widget.*;
|
||||
import android.view.*;
|
||||
import android.graphics.drawable.*;
|
||||
|
||||
class FileWrapper implements IconAdapterItem {
|
||||
public final File file;
|
||||
public final boolean parentItem;
|
||||
public final boolean dirSelectItem;
|
||||
|
||||
protected final boolean enabled;
|
||||
|
||||
public static final int DIRSELECT = 0;
|
||||
public static final int PARENT = 1;
|
||||
public static final int FILE = 2;
|
||||
|
||||
protected final int typeIndex;
|
||||
|
||||
public FileWrapper(File aFile, int type, boolean aIsEnabled) {
|
||||
file = aFile;
|
||||
|
||||
parentItem = type == PARENT;
|
||||
dirSelectItem = type == DIRSELECT;
|
||||
typeIndex = type == FILE ? (FILE + (file.isDirectory() ? 0 : 1)) : type;
|
||||
|
||||
enabled = parentItem || dirSelectItem || aIsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
if (dirSelectItem)
|
||||
return "[[Use this directory]]";
|
||||
else if (parentItem)
|
||||
return "[Parent Directory]";
|
||||
else
|
||||
return file.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconResourceId() {
|
||||
if (!parentItem && !dirSelectItem) {
|
||||
return file.isFile() ? R.drawable.ic_file : R.drawable.ic_dir;
|
||||
} else {
|
||||
return R.drawable.ic_dir;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIconDrawable() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int compareTo(FileWrapper aOther) {
|
||||
if (aOther != null) {
|
||||
// Who says ternary is hard to follow
|
||||
if (isEnabled() == aOther.isEnabled()) {
|
||||
return (typeIndex == aOther.typeIndex) ? file
|
||||
.compareTo(aOther.file)
|
||||
: ((typeIndex < aOther.typeIndex) ? -1 : 1);
|
||||
} else {
|
||||
return isEnabled() ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public class DirectoryActivity extends Activity implements
|
||||
AdapterView.OnItemClickListener {
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.retroarch.R;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
class FileWrapper implements IconAdapterItem {
|
||||
public final File file;
|
||||
public final boolean parentItem;
|
||||
public final boolean dirSelectItem;
|
||||
|
||||
protected final boolean enabled;
|
||||
|
||||
public static final int DIRSELECT = 0;
|
||||
public static final int PARENT = 1;
|
||||
public static final int FILE = 2;
|
||||
|
||||
protected final int typeIndex;
|
||||
|
||||
public FileWrapper(File aFile, int type, boolean aIsEnabled) {
|
||||
file = aFile;
|
||||
|
||||
parentItem = type == PARENT;
|
||||
dirSelectItem = type == DIRSELECT;
|
||||
typeIndex = type == FILE ? (FILE + (file.isDirectory() ? 0 : 1)) : type;
|
||||
|
||||
enabled = parentItem || dirSelectItem || aIsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
if (dirSelectItem)
|
||||
return "[[Use this directory]]";
|
||||
else if (parentItem)
|
||||
return "[Parent Directory]";
|
||||
else
|
||||
return file.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubText() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconResourceId() {
|
||||
if (!parentItem && !dirSelectItem) {
|
||||
return file.isFile() ? R.drawable.ic_file : R.drawable.ic_dir;
|
||||
} else {
|
||||
return R.drawable.ic_dir;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIconDrawable() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int compareTo(FileWrapper aOther) {
|
||||
if (aOther != null) {
|
||||
// Who says ternary is hard to follow
|
||||
if (isEnabled() == aOther.isEnabled()) {
|
||||
return (typeIndex == aOther.typeIndex) ? file
|
||||
.compareTo(aOther.file)
|
||||
: ((typeIndex < aOther.typeIndex) ? -1 : 1);
|
||||
} else {
|
||||
return isEnabled() ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import org.retroarch.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class HistorySelection extends Activity implements
|
||||
AdapterView.OnItemClickListener {
|
||||
|
||||
private IconAdapter<HistoryWrapper> adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.line_list);
|
||||
|
||||
// Setup the list
|
||||
adapter = new IconAdapter<HistoryWrapper>(this, R.layout.line_list_item);
|
||||
ListView list = (ListView) findViewById(R.id.list);
|
||||
list.setAdapter(adapter);
|
||||
list.setOnItemClickListener(this);
|
||||
|
||||
setTitle("Recently played games");
|
||||
|
||||
File history = new File(getApplicationInfo().dataDir, "retroarch-history.txt");
|
||||
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(
|
||||
new FileInputStream(history)));
|
||||
|
||||
for (;;) {
|
||||
String game = br.readLine();
|
||||
String core = br.readLine();
|
||||
String name = br.readLine();
|
||||
if (game == null || core == null || name == null)
|
||||
break;
|
||||
|
||||
adapter.add(new HistoryWrapper(game, core, name));
|
||||
}
|
||||
br.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> aListView, View aView,
|
||||
int aPosition, long aID) {
|
||||
final HistoryWrapper item = adapter.getItem(aPosition);
|
||||
final String gamePath = item.getGamePath();
|
||||
final String corePath = item.getCorePath();
|
||||
|
||||
MainMenuActivity.getInstance().setModule(corePath, item.getCoreName());
|
||||
|
||||
Intent myIntent;
|
||||
String current_ime = Settings.Secure.getString(getContentResolver(),
|
||||
Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
|
||||
MainMenuActivity.getInstance().updateConfigFile();
|
||||
|
||||
Toast.makeText(this, "Loading: [" + gamePath + "] ...",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
myIntent = new Intent(this, RetroActivity.class);
|
||||
myIntent.putExtra("ROM", gamePath);
|
||||
myIntent.putExtra("LIBRETRO", corePath);
|
||||
myIntent.putExtra("CONFIGFILE", MainMenuActivity.getDefaultConfigPath());
|
||||
myIntent.putExtra("IME", current_ime);
|
||||
startActivity(myIntent);
|
||||
finish();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
public class HistoryWrapper implements IconAdapterItem {
|
||||
|
||||
private String gamePath;
|
||||
private String gamePathShort;
|
||||
private String corePath;
|
||||
private String coreName;
|
||||
|
||||
public HistoryWrapper(String gamePath, String corePath, String coreName) {
|
||||
this.gamePath = gamePath;
|
||||
this.corePath = corePath;
|
||||
this.coreName = coreName;
|
||||
|
||||
File file = new File(gamePath);
|
||||
gamePathShort = file.getName();
|
||||
try {
|
||||
gamePathShort = gamePathShort.substring(0, gamePathShort.lastIndexOf('.'));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
public String getGamePath() {
|
||||
return gamePath;
|
||||
}
|
||||
|
||||
public String getCorePath() {
|
||||
return corePath;
|
||||
}
|
||||
|
||||
public String getCoreName() {
|
||||
return coreName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return gamePathShort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubText() {
|
||||
return coreName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconResourceId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIconDrawable() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -10,11 +10,9 @@ import android.widget.*;
|
|||
|
||||
interface IconAdapterItem {
|
||||
public abstract boolean isEnabled();
|
||||
|
||||
public abstract String getText();
|
||||
|
||||
public abstract String getSubText();
|
||||
public abstract int getIconResourceId();
|
||||
|
||||
public abstract Drawable getIconDrawable();
|
||||
}
|
||||
|
||||
|
@ -23,7 +21,6 @@ class IconAdapter<T extends IconAdapterItem> extends ArrayAdapter<T> {
|
|||
|
||||
public IconAdapter(Activity aContext, int aLayout) {
|
||||
super(aContext, aLayout);
|
||||
|
||||
layout = aLayout;
|
||||
}
|
||||
|
||||
|
@ -45,6 +42,16 @@ class IconAdapter<T extends IconAdapterItem> extends ArrayAdapter<T> {
|
|||
textView.setText(item.getText());
|
||||
textView.setEnabled(enabled);
|
||||
}
|
||||
|
||||
textView = (TextView) aConvertView.findViewById(R.id.sub_name);
|
||||
if (null != textView) {
|
||||
String subText = item.getSubText();
|
||||
if (null != subText) {
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
textView.setEnabled(item.isEnabled());
|
||||
textView.setText(subText);
|
||||
}
|
||||
}
|
||||
|
||||
ImageView imageView = (ImageView) aConvertView.findViewById(R.id.icon);
|
||||
if (null != imageView) {
|
||||
|
|
|
@ -0,0 +1,726 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.retroarch.R;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.AssetManager;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioTrack;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class MainMenuActivity extends PreferenceActivity {
|
||||
private static MainMenuActivity instance = null;
|
||||
static private final int ACTIVITY_LOAD_ROM = 0;
|
||||
static private final String TAG = "MainMenu";
|
||||
static private String libretro_path;
|
||||
static private String libretro_name;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
instance = this;
|
||||
|
||||
addPreferencesFromResource(R.xml.prefs);
|
||||
PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
|
||||
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(getBaseContext());
|
||||
|
||||
extractAssets();
|
||||
|
||||
if (!prefs.getBoolean("first_time_refreshrate_calculate", false)) {
|
||||
prefs.edit().putBoolean("first_time_refreshrate_calculate", true)
|
||||
.commit();
|
||||
|
||||
if (!detectDevice(false)) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this)
|
||||
.setTitle("Welcome to RetroArch")
|
||||
.setMessage(
|
||||
"This is your first time starting up RetroArch. RetroArch will now be preconfigured for the best possible gameplay experience.")
|
||||
.setPositiveButton("OK",
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog,
|
||||
int which) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(getBaseContext());
|
||||
SharedPreferences.Editor edit = prefs
|
||||
.edit();
|
||||
edit.putBoolean("video_threaded", true);
|
||||
edit.commit();
|
||||
}
|
||||
});
|
||||
alert.show();
|
||||
}
|
||||
}
|
||||
|
||||
if (prefs.getString("libretro_path", "").isEmpty() == false) {
|
||||
libretro_path = prefs.getString("libretro_path", "");
|
||||
setCoreTitle("No core");
|
||||
|
||||
if (prefs.getString("libretro_name", "").isEmpty() == false) {
|
||||
libretro_name = prefs.getString("libretro_name", "No core");
|
||||
setCoreTitle(libretro_name);
|
||||
}
|
||||
} else {
|
||||
libretro_path = MainMenuActivity.getInstance().getApplicationInfo().nativeLibraryDir;
|
||||
libretro_name = "No core";
|
||||
setCoreTitle("No core");
|
||||
}
|
||||
|
||||
Intent startedByIntent = getIntent();
|
||||
if (null != startedByIntent.getStringExtra("ROM")
|
||||
&& null != startedByIntent.getStringExtra("LIBRETRO")) {
|
||||
if (null == savedInstanceState
|
||||
|| !savedInstanceState.getBoolean("romexec"))
|
||||
loadRomExternal(startedByIntent.getStringExtra("ROM"),
|
||||
startedByIntent.getStringExtra("LIBRETRO"));
|
||||
else
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
public static MainMenuActivity getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final double getDisplayRefreshRate() {
|
||||
// Android is *very* likely to screw this up.
|
||||
// It is rarely a good value to use, so make sure it's not
|
||||
// completely wrong. Some phones return refresh rates that are
|
||||
// completely bogus
|
||||
// (like 0.3 Hz, etc), so try to be very conservative here.
|
||||
final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
||||
final Display display = wm.getDefaultDisplay();
|
||||
double rate = display.getRefreshRate();
|
||||
if (rate > 61.0 || rate < 58.0)
|
||||
rate = 59.95;
|
||||
return rate;
|
||||
}
|
||||
|
||||
public static final double getRefreshRate() {
|
||||
double rate = 0;
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(MainMenuActivity.getInstance()
|
||||
.getBaseContext());
|
||||
String refresh_rate = prefs.getString("video_refresh_rate", "");
|
||||
if (!refresh_rate.isEmpty()) {
|
||||
try {
|
||||
rate = Double.parseDouble(refresh_rate);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Cannot parse: " + refresh_rate + " as a double!");
|
||||
rate = MainMenuActivity.getInstance().getDisplayRefreshRate();
|
||||
}
|
||||
} else {
|
||||
rate = MainMenuActivity.getInstance().getDisplayRefreshRate();
|
||||
}
|
||||
|
||||
Log.i(TAG, "Using refresh rate: " + rate + " Hz.");
|
||||
return rate;
|
||||
}
|
||||
|
||||
public static String readCPUInfo() {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(
|
||||
new FileInputStream("/proc/cpuinfo")));
|
||||
|
||||
String line;
|
||||
while ((line = br.readLine()) != null)
|
||||
result += line + "\n";
|
||||
br.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@TargetApi(17)
|
||||
public static int getLowLatencyOptimalSamplingRate() {
|
||||
AudioManager manager = (AudioManager) MainMenuActivity.getInstance()
|
||||
.getApplicationContext()
|
||||
.getSystemService(Context.AUDIO_SERVICE);
|
||||
return Integer.parseInt(manager
|
||||
.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
|
||||
}
|
||||
|
||||
@TargetApi(17)
|
||||
public static int getLowLatencyBufferSize() {
|
||||
AudioManager manager = (AudioManager) MainMenuActivity.getInstance()
|
||||
.getApplicationContext()
|
||||
.getSystemService(Context.AUDIO_SERVICE);
|
||||
int buffersize = Integer.parseInt(manager
|
||||
.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER));
|
||||
|
||||
Log.i(TAG, "Queried ideal buffer size: " + buffersize);
|
||||
return buffersize;
|
||||
}
|
||||
|
||||
public static int getOptimalSamplingRate() {
|
||||
int ret;
|
||||
if (android.os.Build.VERSION.SDK_INT >= 17)
|
||||
ret = getLowLatencyOptimalSamplingRate();
|
||||
else
|
||||
ret = AudioTrack
|
||||
.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
|
||||
|
||||
Log.i(TAG, "Using sampling rate: " + ret + " Hz");
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static String getDefaultConfigPath() {
|
||||
String internal = System.getenv("INTERNAL_STORAGE");
|
||||
String external = System.getenv("EXTERNAL_STORAGE");
|
||||
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(MainMenuActivity.getInstance()
|
||||
.getBaseContext());
|
||||
|
||||
boolean global_config_enable = prefs.getBoolean("global_config_enable",
|
||||
true);
|
||||
boolean config_same_as_native_lib_dir = libretro_path
|
||||
.equals(MainMenuActivity.getInstance().getApplicationInfo().nativeLibraryDir);
|
||||
String append_path;
|
||||
if (!global_config_enable && (config_same_as_native_lib_dir == false)) {
|
||||
String sanitized_name = libretro_path.substring(
|
||||
libretro_path.lastIndexOf("/") + 1,
|
||||
libretro_path.lastIndexOf("."));
|
||||
sanitized_name = sanitized_name.replace("neon", "");
|
||||
sanitized_name = sanitized_name.replace("libretro_", "");
|
||||
append_path = File.separator + sanitized_name + "retroarch.cfg";
|
||||
} else {
|
||||
append_path = File.separator + "retroarch.cfg";
|
||||
}
|
||||
|
||||
if (external != null) {
|
||||
String confPath = external + append_path;
|
||||
if (new File(confPath).exists())
|
||||
return confPath;
|
||||
} else if (internal != null) {
|
||||
String confPath = internal + append_path;
|
||||
if (new File(confPath).exists())
|
||||
return confPath;
|
||||
} else {
|
||||
String confPath = "/mnt/extsd" + append_path;
|
||||
if (new File(confPath).exists())
|
||||
return confPath;
|
||||
}
|
||||
|
||||
if (internal != null && new File(internal + append_path).canWrite())
|
||||
return internal + append_path;
|
||||
else if (external != null
|
||||
&& new File(internal + append_path).canWrite())
|
||||
return external + append_path;
|
||||
else if ((MainMenuActivity.getInstance().getApplicationInfo().dataDir) != null)
|
||||
return (MainMenuActivity.getInstance().getApplicationInfo().dataDir)
|
||||
+ append_path;
|
||||
else
|
||||
// emergency fallback, all else failed
|
||||
return "/mnt/sd" + append_path;
|
||||
}
|
||||
|
||||
public void updateConfigFile() {
|
||||
ConfigFile config;
|
||||
try {
|
||||
config = new ConfigFile(new File(getDefaultConfigPath()));
|
||||
} catch (IOException e) {
|
||||
config = new ConfigFile();
|
||||
}
|
||||
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(MainMenuActivity.getInstance()
|
||||
.getBaseContext());
|
||||
|
||||
config.setString("libretro_path", libretro_path);
|
||||
config.setString("libretro_name", libretro_name);
|
||||
setCoreTitle(libretro_name);
|
||||
|
||||
config.setString("rgui_browser_directory",
|
||||
prefs.getString("rgui_browser_directory", ""));
|
||||
config.setBoolean("global_config_enable",
|
||||
prefs.getBoolean("global_config_enable", true));
|
||||
config.setBoolean("audio_rate_control",
|
||||
prefs.getBoolean("audio_rate_control", true));
|
||||
config.setInt("audio_out_rate",
|
||||
MainMenuActivity.getOptimalSamplingRate());
|
||||
|
||||
int buffersize = 0;
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= 17) {
|
||||
buffersize = getLowLatencyBufferSize();
|
||||
if (config.getBoolean("audio_high_latency") == false) {
|
||||
config.setInt("audio_latency", buffersize / 32);
|
||||
} else {
|
||||
config.setInt("audio_latency",
|
||||
prefs.getBoolean("audio_high_latency", false) ? 160 : 64);
|
||||
}
|
||||
}
|
||||
else {
|
||||
config.setInt("audio_latency",
|
||||
prefs.getBoolean("audio_high_latency", false) ? 160 : 64);
|
||||
}
|
||||
|
||||
config.setBoolean("audio_enable",
|
||||
prefs.getBoolean("audio_enable", true));
|
||||
config.setBoolean("video_smooth",
|
||||
prefs.getBoolean("video_smooth", true));
|
||||
config.setBoolean("video_allow_rotate",
|
||||
prefs.getBoolean("video_allow_rotate", true));
|
||||
config.setBoolean("savestate_auto_load",
|
||||
prefs.getBoolean("savestate_auto_load", true));
|
||||
config.setBoolean("savestate_auto_save",
|
||||
prefs.getBoolean("savestate_auto_save", false));
|
||||
config.setBoolean("rewind_enable",
|
||||
prefs.getBoolean("rewind_enable", false));
|
||||
config.setBoolean("video_vsync", prefs.getBoolean("video_vsync", true));
|
||||
config.setBoolean("input_autodetect_enable",
|
||||
prefs.getBoolean("input_autodetect_enable", true));
|
||||
config.setBoolean("input_debug_enable",
|
||||
prefs.getBoolean("input_debug_enable", false));
|
||||
config.setInt("input_back_behavior",
|
||||
Integer.valueOf(prefs.getString("input_back_behavior", "0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad1", Integer
|
||||
.valueOf(prefs.getString("input_autodetect_icade_profile_pad1",
|
||||
"0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad2", Integer
|
||||
.valueOf(prefs.getString("input_autodetect_icade_profile_pad2",
|
||||
"0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad3", Integer
|
||||
.valueOf(prefs.getString("input_autodetect_icade_profile_pad3",
|
||||
"0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad4", Integer
|
||||
.valueOf(prefs.getString("input_autodetect_icade_profile_pad4",
|
||||
"0")));
|
||||
|
||||
config.setDouble("video_refresh_rate",
|
||||
MainMenuActivity.getRefreshRate());
|
||||
config.setBoolean("video_threaded",
|
||||
prefs.getBoolean("video_threaded", true));
|
||||
|
||||
String aspect = prefs.getString("video_aspect_ratio", "auto");
|
||||
if (aspect.equals("full")) {
|
||||
config.setBoolean("video_force_aspect", false);
|
||||
} else if (aspect.equals("auto")) {
|
||||
config.setBoolean("video_force_aspect", true);
|
||||
config.setBoolean("video_force_aspect_auto", true);
|
||||
config.setDouble("video_aspect_ratio", -1.0);
|
||||
} else if (aspect.equals("square")) {
|
||||
config.setBoolean("video_force_aspect", true);
|
||||
config.setBoolean("video_force_aspect_auto", false);
|
||||
config.setDouble("video_aspect_ratio", -1.0);
|
||||
} else {
|
||||
double aspect_ratio = Double.parseDouble(aspect);
|
||||
config.setBoolean("video_force_aspect", true);
|
||||
config.setDouble("video_aspect_ratio", aspect_ratio);
|
||||
}
|
||||
|
||||
config.setBoolean("video_scale_integer",
|
||||
prefs.getBoolean("video_scale_integer", false));
|
||||
|
||||
String shaderPath = prefs.getString("video_shader", "");
|
||||
config.setString("video_shader", shaderPath);
|
||||
config.setBoolean("video_shader_enable",
|
||||
prefs.getBoolean("video_shader_enable", false)
|
||||
&& new File(shaderPath).exists());
|
||||
|
||||
boolean useOverlay = prefs.getBoolean("input_overlay_enable", true);
|
||||
if (useOverlay) {
|
||||
String overlayPath = prefs
|
||||
.getString("input_overlay", (MainMenuActivity.getInstance()
|
||||
.getApplicationInfo().dataDir)
|
||||
+ "/overlays/snes-landscape.cfg");
|
||||
config.setString("input_overlay", overlayPath);
|
||||
config.setDouble("input_overlay_opacity",
|
||||
prefs.getFloat("input_overlay_opacity", 1.0f));
|
||||
} else {
|
||||
config.setString("input_overlay", "");
|
||||
}
|
||||
|
||||
config.setString(
|
||||
"savefile_directory",
|
||||
prefs.getBoolean("savefile_directory_enable", false) ? prefs
|
||||
.getString("savefile_directory", "") : "");
|
||||
config.setString(
|
||||
"savestate_directory",
|
||||
prefs.getBoolean("savestate_directory_enable", false) ? prefs
|
||||
.getString("savestate_directory", "") : "");
|
||||
config.setString(
|
||||
"system_directory",
|
||||
prefs.getBoolean("system_directory_enable", false) ? prefs
|
||||
.getString("system_directory", "") : "");
|
||||
|
||||
config.setBoolean("video_font_enable",
|
||||
prefs.getBoolean("video_font_enable", true));
|
||||
|
||||
config.setString("game_history_path", MainMenuActivity.getInstance()
|
||||
.getApplicationInfo().dataDir + "/retroarch-history.txt");
|
||||
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
final String btns[] = { "up", "down", "left", "right", "a", "b",
|
||||
"x", "y", "start", "select", "l", "r", "l2", "r2", "l3",
|
||||
"r3" };
|
||||
for (String b : btns) {
|
||||
String p = "input_player" + String.valueOf(i) + "_" + b
|
||||
+ "_btn";
|
||||
config.setInt(p, prefs.getInt(p, 0));
|
||||
}
|
||||
}
|
||||
|
||||
String confPath = getDefaultConfigPath();
|
||||
try {
|
||||
config.write(new File(confPath));
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to save config file to: " + confPath);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] loadAsset(String asset) throws IOException {
|
||||
String path = asset;
|
||||
InputStream stream = getAssets().open(path);
|
||||
int len = stream.available();
|
||||
byte[] buf = new byte[len];
|
||||
stream.read(buf, 0, len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
private void extractAssets(AssetManager manager, String dataDir,
|
||||
String relativePath, int level) throws IOException {
|
||||
final String[] paths = manager.list(relativePath);
|
||||
if (paths != null && paths.length > 0) { // Directory
|
||||
// Log.d(TAG, "Extracting assets directory: " + relativePath);
|
||||
for (final String path : paths)
|
||||
extractAssets(manager, dataDir, relativePath
|
||||
+ (level > 0 ? File.separator : "") + path, level + 1);
|
||||
} else { // File, extract.
|
||||
// Log.d(TAG, "Extracting assets file: " + relativePath);
|
||||
|
||||
String parentPath = new File(relativePath).getParent();
|
||||
if (parentPath != null) {
|
||||
File parentFile = new File(dataDir, parentPath);
|
||||
parentFile.mkdirs(); // Doesn't throw.
|
||||
}
|
||||
|
||||
byte[] asset = loadAsset(relativePath);
|
||||
BufferedOutputStream writer = new BufferedOutputStream(
|
||||
new FileOutputStream(new File(dataDir, relativePath)));
|
||||
|
||||
writer.write(asset, 0, asset.length);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
|
||||
private int getVersionCode() {
|
||||
int version = 0;
|
||||
try {
|
||||
version = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
|
||||
} catch (NameNotFoundException e) {
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
private boolean areAssetsExtracted() {
|
||||
int version = getVersionCode();
|
||||
|
||||
try {
|
||||
String dataDir = getApplicationInfo().dataDir;
|
||||
File cacheVersion = new File(dataDir, ".cacheversion");
|
||||
if (cacheVersion != null && cacheVersion.isFile()
|
||||
&& cacheVersion.canRead() && cacheVersion.canWrite()) {
|
||||
DataInputStream cacheStream = new DataInputStream(
|
||||
new FileInputStream(cacheVersion));
|
||||
|
||||
int currentCacheVersion = 0;
|
||||
try {
|
||||
currentCacheVersion = cacheStream.readInt();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
cacheStream.close();
|
||||
|
||||
if (currentCacheVersion == version) {
|
||||
Log.i("ASSETS", "Assets already extracted, skipping...");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to extract assets to cache.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void extractAssetsThread() {
|
||||
try {
|
||||
AssetManager assets = getAssets();
|
||||
String dataDir = getApplicationInfo().dataDir;
|
||||
File cacheVersion = new File(dataDir, ".cacheversion");
|
||||
|
||||
// extractAssets(assets, cacheDir, "", 0);
|
||||
Log.i("ASSETS", "Extracting shader assets now ...");
|
||||
try {
|
||||
extractAssets(assets, dataDir, "shaders_glsl", 1);
|
||||
} catch (IOException e) {
|
||||
Log.i("ASSETS", "Failed to extract shaders ...");
|
||||
}
|
||||
|
||||
Log.i("ASSETS", "Extracting overlay assets now ...");
|
||||
try {
|
||||
extractAssets(assets, dataDir, "overlays", 1);
|
||||
} catch (IOException e) {
|
||||
Log.i("ASSETS", "Failed to extract overlays ...");
|
||||
}
|
||||
|
||||
DataOutputStream outputCacheVersion = new DataOutputStream(
|
||||
new FileOutputStream(cacheVersion, false));
|
||||
outputCacheVersion.writeInt(getVersionCode());
|
||||
outputCacheVersion.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to extract assets to cache.");
|
||||
}
|
||||
}
|
||||
|
||||
private void extractAssets() {
|
||||
if (areAssetsExtracted())
|
||||
return;
|
||||
|
||||
final Dialog dialog = new Dialog(this);
|
||||
final Handler handler = new Handler();
|
||||
dialog.setContentView(R.layout.assets);
|
||||
dialog.setCancelable(false);
|
||||
dialog.setTitle("Asset extraction");
|
||||
|
||||
// Java is fun :)
|
||||
Thread assetsThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
extractAssetsThread();
|
||||
handler.post(new Runnable() {
|
||||
public void run() {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
assetsThread.start();
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public void setModule(String core_path, String core_name) {
|
||||
libretro_path = core_path;
|
||||
libretro_name = core_name;
|
||||
File libretro_path_file = new File(core_path);
|
||||
setCoreTitle((libretro_path_file.isDirectory() == true) ? "No core"
|
||||
: core_name);
|
||||
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(getBaseContext());
|
||||
SharedPreferences.Editor edit = prefs.edit();
|
||||
edit.putString("libretro_path", libretro_path);
|
||||
edit.putString("libretro_name", libretro_name);
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
public void setCoreTitle(String core_name) {
|
||||
setTitle("RetroArch : " + core_name);
|
||||
}
|
||||
|
||||
boolean detectDevice(boolean show_dialog) {
|
||||
boolean retval = false;
|
||||
|
||||
boolean mentionPlayStore = !android.os.Build.MODEL
|
||||
.equals("OUYA Console");
|
||||
final String message = "The ideal configuration options for your device will now be preconfigured.\n\nNOTE: For optimal performance, turn off Google Account sync, "
|
||||
+ (mentionPlayStore ? "Google Play Store auto-updates, " : "")
|
||||
+ "GPS and Wi-Fi in your Android settings menu.";
|
||||
|
||||
Log.i("Device MODEL", android.os.Build.MODEL);
|
||||
if (android.os.Build.MODEL.equals("SHIELD")) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this)
|
||||
.setTitle("NVidia Shield detected")
|
||||
.setMessage(message)
|
||||
.setPositiveButton("OK",
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog,
|
||||
int which) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(getBaseContext());
|
||||
SharedPreferences.Editor edit = prefs
|
||||
.edit();
|
||||
edit.putString("video_refresh_rate", Double
|
||||
.valueOf(60.00d).toString());
|
||||
edit.putBoolean("input_overlay_enable",
|
||||
false);
|
||||
edit.putBoolean("input_autodetect_enable",
|
||||
true);
|
||||
edit.commit();
|
||||
}
|
||||
});
|
||||
alert.show();
|
||||
retval = true;
|
||||
} else if (android.os.Build.MODEL.equals("GAMEMID_BT")) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this)
|
||||
.setTitle("GameMID detected")
|
||||
.setMessage(message)
|
||||
.setPositiveButton("OK",
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog,
|
||||
int which) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(getBaseContext());
|
||||
SharedPreferences.Editor edit = prefs
|
||||
.edit();
|
||||
edit.putBoolean("input_overlay_enable",
|
||||
false);
|
||||
edit.putBoolean("input_autodetect_enable",
|
||||
true);
|
||||
edit.putBoolean("audio_high_latency", true);
|
||||
edit.commit();
|
||||
}
|
||||
});
|
||||
alert.show();
|
||||
retval = true;
|
||||
} else if (android.os.Build.MODEL.equals("OUYA Console")) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this)
|
||||
.setTitle("OUYA detected")
|
||||
.setMessage(message)
|
||||
.setPositiveButton("OK",
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog,
|
||||
int which) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(getBaseContext());
|
||||
SharedPreferences.Editor edit = prefs
|
||||
.edit();
|
||||
edit.putBoolean("input_overlay_enable",
|
||||
false);
|
||||
edit.putBoolean("input_autodetect_enable",
|
||||
true);
|
||||
edit.commit();
|
||||
}
|
||||
});
|
||||
alert.show();
|
||||
retval = true;
|
||||
} else if (android.os.Build.ID.equals("JSS15J")) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this)
|
||||
.setTitle("Nexus 7 2013 detected")
|
||||
.setMessage(message)
|
||||
.setPositiveButton("OK",
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog,
|
||||
int which) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(getBaseContext());
|
||||
SharedPreferences.Editor edit = prefs
|
||||
.edit();
|
||||
edit.putString("video_refresh_rate", Double
|
||||
.valueOf(59.65).toString());
|
||||
edit.commit();
|
||||
}
|
||||
});
|
||||
alert.show();
|
||||
retval = true;
|
||||
}
|
||||
|
||||
if (show_dialog) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"Device either not detected in list or doesn't have any optimal settings in our database.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startActivity(Intent intent) {
|
||||
if (intent.getComponent().getClassName()
|
||||
.equals("org.retroarch.browser.ROMActivity")) {
|
||||
if (new File(libretro_path).isDirectory() == false) {
|
||||
super.startActivityForResult(intent, ACTIVITY_LOAD_ROM);
|
||||
} else {
|
||||
Toast.makeText(this,
|
||||
"Go to 'Load Core' and select a core first.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
super.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int reqCode, int resCode, Intent data) {
|
||||
switch (reqCode) {
|
||||
case ACTIVITY_LOAD_ROM: {
|
||||
if (data.getStringExtra("PATH") != null) {
|
||||
updateConfigFile();
|
||||
Intent myIntent;
|
||||
String current_ime = Settings.Secure.getString(
|
||||
getContentResolver(),
|
||||
Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
Toast.makeText(this,
|
||||
"Loading: [" + data.getStringExtra("PATH") + "]...",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
myIntent = new Intent(this, RetroActivity.class);
|
||||
myIntent.putExtra("ROM", data.getStringExtra("PATH"));
|
||||
myIntent.putExtra("LIBRETRO", libretro_path);
|
||||
myIntent.putExtra("CONFIGFILE",
|
||||
MainMenuActivity.getDefaultConfigPath());
|
||||
myIntent.putExtra("IME", current_ime);
|
||||
startActivity(myIntent);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle data) {
|
||||
super.onSaveInstanceState(data);
|
||||
data.putBoolean("romexec", true);
|
||||
}
|
||||
|
||||
private void loadRomExternal(String rom, String core) {
|
||||
updateConfigFile();
|
||||
Intent myIntent = new Intent(this, RetroActivity.class);
|
||||
String current_ime = Settings.Secure.getString(getContentResolver(),
|
||||
Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
Toast.makeText(this, "Loading: [" + rom + "]...", Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
myIntent.putExtra("ROM", rom);
|
||||
myIntent.putExtra("LIBRETRO", core);
|
||||
myIntent.putExtra("CONFIGFILE", getDefaultConfigPath());
|
||||
myIntent.putExtra("IME", current_ime);
|
||||
startActivity(myIntent);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
class ModuleWrapper implements IconAdapterItem {
|
||||
public final File file;
|
||||
private ConfigFile config;
|
||||
|
||||
public ModuleWrapper(Context aContext, File aFile, ConfigFile config) throws IOException {
|
||||
file = aFile;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
String stripped = file.getName().replace(".so", "");
|
||||
if (config.keyExists(stripped)) {
|
||||
return config.getString(stripped);
|
||||
} else
|
||||
return stripped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubText() {
|
||||
String stripped = file.getName().replace(".so", "") + "_system";
|
||||
if (config.keyExists(stripped)) {
|
||||
return config.getString(stripped);
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconResourceId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIconDrawable() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import android.os.Bundle;
|
|||
public class OverlayActivity extends DirectoryActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
File overlayDir = new File(getCacheDir(), "Overlays");
|
||||
File overlayDir = new File(getBaseContext().getApplicationInfo().dataDir, "overlays");
|
||||
if (overlayDir.exists())
|
||||
super.setStartDirectory(overlayDir.getAbsolutePath());
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ public class ROMActivity extends DirectoryActivity {
|
|||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
|
||||
String startPath = prefs.getString("phoenix_rom_dir", "");
|
||||
String startPath = prefs.getString("rgui_browser_directory", "");
|
||||
if (!startPath.isEmpty() && new File(startPath).exists())
|
||||
super.setStartDirectory(startPath);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.os.Bundle;
|
|||
public class ROMDirActivity extends DirectoryActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.setPathSettingKey("phoenix_rom_dir");
|
||||
super.setPathSettingKey("rgui_browser_directory");
|
||||
super.setIsDirectoryTarget(true);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
|
||||
public class ReportIME extends Activity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
new AlertDialog.Builder(this).setMessage(current_ime).setNeutralButton("Close", null).show();
|
||||
}
|
||||
}
|
|
@ -4,21 +4,37 @@ import android.app.NativeActivity;
|
|||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class RetroActivity extends NativeActivity
|
||||
{
|
||||
public RetroActivity()
|
||||
{
|
||||
public class RetroActivity extends NativeActivity {
|
||||
public RetroActivity() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstance)
|
||||
{
|
||||
public void onCreate(Bundle savedInstance) {
|
||||
super.onCreate(savedInstance);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onLowMemory()
|
||||
{
|
||||
public void onLowMemory() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
}
|
||||
|
||||
// We call this function from native to display a toast string
|
||||
public void showToastAlert(String text)
|
||||
{
|
||||
// We need to use a runnable here to ensure that when the spawned
|
||||
// native_app_glue thread calls, we actually post the work to the UI
|
||||
// thread. Otherwise, we'll likely get exceptions because there's no
|
||||
// prepared Looper on the native_app_glue main thread.
|
||||
final String finalText = text;
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
Toast.makeText(getApplicationContext(), finalText, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,673 +0,0 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import org.retroarch.R;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import android.content.*;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.AssetManager;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.*;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioTrack;
|
||||
import android.net.Uri;
|
||||
import android.os.*;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.widget.*;
|
||||
import android.util.Log;
|
||||
import android.view.*;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.inputmethod.*;
|
||||
import android.graphics.drawable.*;
|
||||
|
||||
class ModuleWrapper implements IconAdapterItem {
|
||||
public final File file;
|
||||
private ConfigFile config;
|
||||
|
||||
public ModuleWrapper(Context aContext, File aFile, ConfigFile config) throws IOException {
|
||||
file = aFile;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
String stripped = file.getName().replace(".so", "");
|
||||
if (config.keyExists(stripped)) {
|
||||
return config.getString(stripped);
|
||||
} else
|
||||
return stripped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconResourceId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIconDrawable() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class RetroArch extends Activity implements
|
||||
AdapterView.OnItemClickListener {
|
||||
private IconAdapter<ModuleWrapper> adapter;
|
||||
static private final int ACTIVITY_LOAD_ROM = 0;
|
||||
static private String libretro_path;
|
||||
static private Double report_refreshrate;
|
||||
static private final String TAG = "RetroArch-Phoenix";
|
||||
private ConfigFile config;
|
||||
private ConfigFile core_config;
|
||||
|
||||
private final double getDisplayRefreshRate() {
|
||||
// Android is *very* likely to screw this up.
|
||||
// It is rarely a good value to use, so make sure it's not
|
||||
// completely wrong. Some phones return refresh rates that are completely bogus
|
||||
// (like 0.3 Hz, etc), so try to be very conservative here.
|
||||
final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
||||
final Display display = wm.getDefaultDisplay();
|
||||
double rate = display.getRefreshRate();
|
||||
if (rate > 61.0 || rate < 58.0)
|
||||
rate = 59.95;
|
||||
return rate;
|
||||
}
|
||||
|
||||
private final double getRefreshRate() {
|
||||
double rate = 0;
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(getBaseContext());
|
||||
String refresh_rate = prefs.getString("video_refresh_rate", "");
|
||||
if (!refresh_rate.isEmpty()) {
|
||||
try {
|
||||
rate = Double.parseDouble(refresh_rate);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Cannot parse: " + refresh_rate + " as a double!");
|
||||
rate = getDisplayRefreshRate();
|
||||
}
|
||||
} else {
|
||||
rate = getDisplayRefreshRate();
|
||||
}
|
||||
|
||||
Log.i(TAG, "Using refresh rate: " + rate + " Hz.");
|
||||
return rate;
|
||||
}
|
||||
|
||||
private String readCPUInfo() {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(
|
||||
new FileInputStream("/proc/cpuinfo")));
|
||||
|
||||
String line;
|
||||
while ((line = br.readLine()) != null)
|
||||
result += line + "\n";
|
||||
br.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean cpuInfoIsNeon(String info) {
|
||||
return info.contains("neon");
|
||||
}
|
||||
|
||||
private byte[] loadAsset(String asset) throws IOException {
|
||||
String path = asset;
|
||||
InputStream stream = getAssets().open(path);
|
||||
int len = stream.available();
|
||||
byte[] buf = new byte[len];
|
||||
stream.read(buf, 0, len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
private void extractAssets(AssetManager manager, String cacheDir, String relativePath, int level) throws IOException {
|
||||
final String[] paths = manager.list(relativePath);
|
||||
if (paths != null && paths.length > 0) { // Directory
|
||||
//Log.d(TAG, "Extracting assets directory: " + relativePath);
|
||||
for (final String path : paths)
|
||||
extractAssets(manager, cacheDir, relativePath + (level > 0 ? File.separator : "") + path, level + 1);
|
||||
} else { // File, extract.
|
||||
//Log.d(TAG, "Extracting assets file: " + relativePath);
|
||||
|
||||
String parentPath = new File(relativePath).getParent();
|
||||
if (parentPath != null) {
|
||||
File parentFile = new File(cacheDir, parentPath);
|
||||
parentFile.mkdirs(); // Doesn't throw.
|
||||
}
|
||||
|
||||
byte[] asset = loadAsset(relativePath);
|
||||
BufferedOutputStream writer = new BufferedOutputStream(
|
||||
new FileOutputStream(new File(cacheDir, relativePath)));
|
||||
|
||||
writer.write(asset, 0, asset.length);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void extractAssets() {
|
||||
int version = 0;
|
||||
try {
|
||||
version = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
|
||||
} catch(NameNotFoundException e) {
|
||||
// weird exception, shouldn't happen
|
||||
}
|
||||
|
||||
try {
|
||||
AssetManager assets = getAssets();
|
||||
String cacheDir = getCacheDir().getAbsolutePath();
|
||||
File cacheVersion = new File(cacheDir, ".cacheversion");
|
||||
if (cacheVersion != null && cacheVersion.isFile() && cacheVersion.canRead() && cacheVersion.canWrite())
|
||||
{
|
||||
DataInputStream cacheStream = new DataInputStream(new FileInputStream(cacheVersion));
|
||||
|
||||
int currentCacheVersion = 0;
|
||||
try {
|
||||
currentCacheVersion = cacheStream.readInt();
|
||||
} catch (IOException e) {}
|
||||
cacheStream.close();
|
||||
|
||||
if (currentCacheVersion == version)
|
||||
{
|
||||
Log.i("ASSETS", "Assets already extracted, skipping...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//extractAssets(assets, cacheDir, "", 0);
|
||||
Log.i("ASSETS", "Extracting shader assets now ...");
|
||||
try {
|
||||
extractAssets(assets, cacheDir, "Shaders", 1);
|
||||
} catch (IOException e) {
|
||||
Log.i("ASSETS", "Failed to extract shaders ...");
|
||||
}
|
||||
|
||||
Log.i("ASSETS", "Extracting overlay assets now ...");
|
||||
try {
|
||||
extractAssets(assets, cacheDir, "Overlays", 1);
|
||||
} catch (IOException e) {
|
||||
Log.i("ASSETS", "Failed to extract overlays ...");
|
||||
}
|
||||
|
||||
DataOutputStream outputCacheVersion = new DataOutputStream(new FileOutputStream(cacheVersion, false));
|
||||
outputCacheVersion.writeInt(version);
|
||||
outputCacheVersion.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to extract assets to cache.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
try {
|
||||
config = new ConfigFile(new File(getDefaultConfigPath()));
|
||||
} catch (IOException e) {
|
||||
config = new ConfigFile();
|
||||
}
|
||||
|
||||
core_config = new ConfigFile();
|
||||
try {
|
||||
core_config.append(getAssets().open("libretro_cores.cfg"));
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to load libretro_cores.cfg from assets.");
|
||||
}
|
||||
|
||||
String cpuInfo = readCPUInfo();
|
||||
boolean cpuIsNeon = cpuInfoIsNeon(cpuInfo);
|
||||
report_refreshrate = getDisplayRefreshRate();
|
||||
|
||||
// Extracting assets appears to take considerable amount of time, so
|
||||
// move extraction to a thread.
|
||||
Thread assetThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
extractAssets();
|
||||
}
|
||||
});
|
||||
assetThread.start();
|
||||
|
||||
setContentView(R.layout.line_list);
|
||||
|
||||
// Setup the list
|
||||
adapter = new IconAdapter<ModuleWrapper>(this, R.layout.line_list_item);
|
||||
ListView list = (ListView) findViewById(R.id.list);
|
||||
list.setAdapter(adapter);
|
||||
list.setOnItemClickListener(this);
|
||||
|
||||
setTitle("Select Libretro core");
|
||||
|
||||
// Populate the list
|
||||
final String modulePath = getApplicationInfo().nativeLibraryDir;
|
||||
final File[] libs = new File(modulePath).listFiles();
|
||||
for (final File lib : libs) {
|
||||
String libName = lib.getName();
|
||||
|
||||
// Never append a NEON lib if we don't have NEON.
|
||||
if (libName.contains("neon") && !cpuIsNeon)
|
||||
continue;
|
||||
|
||||
// If we have a NEON version with NEON capable CPU,
|
||||
// never append a non-NEON version.
|
||||
if (cpuIsNeon && !libName.contains("neon")) {
|
||||
boolean hasNeonVersion = false;
|
||||
for (final File lib_ : libs) {
|
||||
String otherName = lib_.getName();
|
||||
String baseName = libName.replace(".so", "");
|
||||
if (otherName.contains("neon") && otherName.startsWith(baseName)) {
|
||||
hasNeonVersion = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNeonVersion)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allow both libretro-core.so and libretro_core.so.
|
||||
if (libName.startsWith("libretro") && !libName.startsWith("libretroarch")) {
|
||||
try {
|
||||
adapter.add(new ModuleWrapper(this, lib, core_config));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
this.registerForContextMenu(findViewById(android.R.id.content));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
|
||||
|
||||
if (!prefs.getBoolean("first_time_refreshrate_calculate", false)) {
|
||||
prefs.edit().putBoolean("first_time_refreshrate_calculate", true).commit();
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this)
|
||||
.setTitle("Calculate Refresh Rate")
|
||||
.setMessage("It is highly recommended you run the refresh rate calibration test before you use RetroArch. Do you want to run it now?\n\nIf you choose No, you can run it at any time in the video preferences.\n\nIf you get performance problems even after calibration, please try threaded video driver in video preferences.")
|
||||
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent i = new Intent(getBaseContext(), DisplayRefreshRateTest.class);
|
||||
startActivity(i);
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", null);
|
||||
alert.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> aListView, View aView,
|
||||
int aPosition, long aID) {
|
||||
final ModuleWrapper item = adapter.getItem(aPosition);
|
||||
libretro_path = item.file.getAbsolutePath();
|
||||
|
||||
Intent myIntent;
|
||||
myIntent = new Intent(this, ROMActivity.class);
|
||||
startActivityForResult(myIntent, ACTIVITY_LOAD_ROM);
|
||||
}
|
||||
|
||||
private String getDefaultConfigPath() {
|
||||
String internal = System.getenv("INTERNAL_STORAGE");
|
||||
String external = System.getenv("EXTERNAL_STORAGE");
|
||||
|
||||
if (external != null) {
|
||||
String confPath = external + File.separator + "retroarch.cfg";
|
||||
if (new File(confPath).exists())
|
||||
return confPath;
|
||||
} else if (internal != null) {
|
||||
String confPath = internal + File.separator + "retroarch.cfg";
|
||||
if (new File(confPath).exists())
|
||||
return confPath;
|
||||
} else {
|
||||
String confPath = "/mnt/extsd/retroarch.cfg";
|
||||
if (new File(confPath).exists())
|
||||
return confPath;
|
||||
}
|
||||
|
||||
if (internal != null && new File(internal + File.separator + "retroarch.cfg").canWrite())
|
||||
return internal + File.separator + "retroarch.cfg";
|
||||
else if (external != null && new File(internal + File.separator + "retroarch.cfg").canWrite())
|
||||
return external + File.separator + "retroarch.cfg";
|
||||
else if (getCacheDir() != null && getCacheDir().getAbsolutePath() != null)
|
||||
return getCacheDir().getAbsolutePath() + File.separator + "retroarch.cfg";
|
||||
else // emergency fallback, all else failed
|
||||
return "/mnt/sd/retroarch.cfg";
|
||||
}
|
||||
|
||||
@TargetApi(android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
private int getLowLatencyOptimalSamplingRate() {
|
||||
AudioManager manager = (AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
|
||||
return Integer.parseInt(manager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
|
||||
}
|
||||
|
||||
private int getOptimalSamplingRate() {
|
||||
int ret;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
ret = getLowLatencyOptimalSamplingRate();
|
||||
else
|
||||
ret = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
|
||||
|
||||
Log.i(TAG, "Using sampling rate: " + ret + " Hz");
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void updateConfigFile() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
|
||||
config.setBoolean("audio_rate_control", prefs.getBoolean("audio_rate_control", true));
|
||||
config.setInt("audio_out_rate", getOptimalSamplingRate());
|
||||
config.setBoolean("audio_enable", prefs.getBoolean("audio_enable", true));
|
||||
config.setBoolean("video_smooth", prefs.getBoolean("video_smooth", true));
|
||||
config.setBoolean("video_allow_rotate", prefs.getBoolean("video_allow_rotate", true));
|
||||
config.setBoolean("savestate_auto_load", prefs.getBoolean("savestate_auto_load", true));
|
||||
config.setBoolean("savestate_auto_save", prefs.getBoolean("savestate_auto_save", false));
|
||||
config.setBoolean("rewind_enable", prefs.getBoolean("rewind_enable", false));
|
||||
config.setBoolean("video_vsync", prefs.getBoolean("video_vsync", true));
|
||||
config.setBoolean("input_autodetect_enable", prefs.getBoolean("input_autodetect_enable", true));
|
||||
config.setBoolean("input_debug_enable", prefs.getBoolean("input_debug_enable", false));
|
||||
config.setInt("input_back_behavior", Integer.valueOf(prefs.getString("input_back_behavior", "0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad1", Integer.valueOf(prefs.getString("input_autodetect_icade_profile_pad1", "0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad2", Integer.valueOf(prefs.getString("input_autodetect_icade_profile_pad2", "0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad3", Integer.valueOf(prefs.getString("input_autodetect_icade_profile_pad3", "0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad4", Integer.valueOf(prefs.getString("input_autodetect_icade_profile_pad4", "0")));
|
||||
|
||||
config.setDouble("video_refresh_rate", getRefreshRate());
|
||||
config.setBoolean("video_threaded", prefs.getBoolean("video_threaded", false));
|
||||
|
||||
String aspect = prefs.getString("video_aspect_ratio", "auto");
|
||||
if (aspect.equals("full")) {
|
||||
config.setBoolean("video_force_aspect", false);
|
||||
} else if (aspect.equals("auto")) {
|
||||
config.setBoolean("video_force_aspect", true);
|
||||
config.setBoolean("video_force_aspect_auto", true);
|
||||
config.setDouble("video_aspect_ratio", -1.0);
|
||||
} else if (aspect.equals("square")) {
|
||||
config.setBoolean("video_force_aspect", true);
|
||||
config.setBoolean("video_force_aspect_auto", false);
|
||||
config.setDouble("video_aspect_ratio", -1.0);
|
||||
} else {
|
||||
double aspect_ratio = Double.parseDouble(aspect);
|
||||
config.setBoolean("video_force_aspect", true);
|
||||
config.setDouble("video_aspect_ratio", aspect_ratio);
|
||||
}
|
||||
|
||||
config.setBoolean("video_scale_integer", prefs.getBoolean("video_scale_integer", false));
|
||||
|
||||
String shaderPath = prefs.getString("video_shader", "");
|
||||
config.setString("video_shader", shaderPath);
|
||||
config.setBoolean("video_shader_enable",
|
||||
prefs.getBoolean("video_shader_enable", false)
|
||||
&& new File(shaderPath).exists());
|
||||
|
||||
boolean useOverlay = prefs.getBoolean("input_overlay_enable", true);
|
||||
if (useOverlay) {
|
||||
String overlayPath = prefs.getString("input_overlay", getCacheDir() + "/Overlays/snes-landscape.cfg");
|
||||
config.setString("input_overlay", overlayPath);
|
||||
config.setDouble("input_overlay_opacity", prefs.getFloat("input_overlay_opacity", 1.0f));
|
||||
} else {
|
||||
config.setString("input_overlay", "");
|
||||
}
|
||||
|
||||
config.setString("savefile_directory", prefs.getBoolean("savefile_directory_enable", false) ?
|
||||
prefs.getString("savefile_directory", "") : "");
|
||||
config.setString("savestate_directory", prefs.getBoolean("savestate_directory_enable", false) ?
|
||||
prefs.getString("savestate_directory", "") : "");
|
||||
config.setString("system_directory", prefs.getBoolean("system_directory_enable", false) ?
|
||||
prefs.getString("system_directory", "") : "");
|
||||
|
||||
config.setBoolean("video_font_enable", prefs.getBoolean("video_font_enable", true));
|
||||
|
||||
for (int i = 1; i <= 4; i++)
|
||||
{
|
||||
final String btns[] = {"up", "down", "left", "right", "a", "b", "x", "y", "start", "select", "l", "r", "l2", "r2", "l3", "r3" };
|
||||
for (String b : btns)
|
||||
{
|
||||
String p = "input_player" + String.valueOf(i) + "_" + b + "_btn";
|
||||
config.setInt(p, prefs.getInt(p, 0));
|
||||
}
|
||||
}
|
||||
|
||||
String confPath = getDefaultConfigPath();
|
||||
try {
|
||||
config.write(new File(confPath));
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to save config file to: " + confPath);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
Intent myIntent;
|
||||
String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
|
||||
updateConfigFile();
|
||||
|
||||
switch (requestCode) {
|
||||
case ACTIVITY_LOAD_ROM:
|
||||
if (data.getStringExtra("PATH") != null) {
|
||||
Toast.makeText(this,
|
||||
"Loading: [" + data.getStringExtra("PATH") + "]...",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
myIntent = new Intent(this, RetroActivity.class);
|
||||
myIntent.putExtra("ROM", data.getStringExtra("PATH"));
|
||||
myIntent.putExtra("LIBRETRO", libretro_path);
|
||||
myIntent.putExtra("CONFIGFILE", getDefaultConfigPath());
|
||||
myIntent.putExtra("IME", current_ime);
|
||||
startActivity(myIntent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu aMenu) {
|
||||
super.onCreateOptionsMenu(aMenu);
|
||||
getMenuInflater().inflate(R.menu.directory_list, aMenu);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void showPopup(View v) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
||||
{
|
||||
PopupMenuAbstract menu = new PopupMenuAbstract(this, v);
|
||||
MenuInflater inflater = menu.getMenuInflater();
|
||||
inflater.inflate(R.menu.context_menu, menu.getMenu());
|
||||
menu.setOnMenuItemClickListener(new PopupMenuAbstract.OnMenuItemClickListener()
|
||||
{
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
return onContextItemSelected(item);
|
||||
}
|
||||
|
||||
});
|
||||
menu.show();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.openContextMenu(findViewById(android.R.id.content));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.context_menu, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem aItem) {
|
||||
switch (aItem.getItemId()) {
|
||||
case R.id.settings:
|
||||
showPopup(findViewById(R.id.settings));
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected(aItem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.input_method_select:
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.showInputMethodPicker();
|
||||
return true;
|
||||
|
||||
case R.id.rarch_settings:
|
||||
Intent rset = new Intent(this, SettingsActivity.class);
|
||||
startActivity(rset);
|
||||
return true;
|
||||
case R.id.help:
|
||||
Intent help = new Intent(this, HelpActivity.class);
|
||||
startActivity(help);
|
||||
return true;
|
||||
|
||||
case R.id.report_ime:
|
||||
String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
new AlertDialog.Builder(this).setMessage(current_ime).setNeutralButton("Close", null).show();
|
||||
return true;
|
||||
case R.id.report_refreshrate:
|
||||
String current_rate = "Screen Refresh Rate: " + Double.valueOf(report_refreshrate).toString();
|
||||
new AlertDialog.Builder(this).setMessage(current_rate).setNeutralButton("Close", null).show();
|
||||
return true;
|
||||
|
||||
case R.id.retroarch_guide:
|
||||
Intent rguide = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.libretro.org/documents/retroarch-manual.pdf"));
|
||||
startActivity(rguide);
|
||||
return true;
|
||||
|
||||
case R.id.cores_guide:
|
||||
Intent cguide = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.libretro.org/documents/retroarch-cores-manual.pdf"));
|
||||
startActivity(cguide);
|
||||
return true;
|
||||
|
||||
case R.id.overlay_guide:
|
||||
Intent mguide = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.libretro.org/documents/overlay.pdf"));
|
||||
startActivity(mguide);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class LazyPopupMenu {
|
||||
public abstract Menu getMenu();
|
||||
public abstract MenuInflater getMenuInflater();
|
||||
public abstract void setOnMenuItemClickListener(LazyPopupMenu.OnMenuItemClickListener listener);
|
||||
public abstract void show();
|
||||
public interface OnMenuItemClickListener {
|
||||
public abstract boolean onMenuItemClick(MenuItem item);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
class HoneycombPopupMenu extends LazyPopupMenu {
|
||||
private PopupMenu instance;
|
||||
HoneycombPopupMenu.OnMenuItemClickListener listen;
|
||||
|
||||
public HoneycombPopupMenu(Context context, View anchor)
|
||||
{
|
||||
instance = new PopupMenu(context, anchor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnMenuItemClickListener(HoneycombPopupMenu.OnMenuItemClickListener listener)
|
||||
{
|
||||
listen = listener;
|
||||
instance.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
return listen.onMenuItemClick(item);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Menu getMenu() {
|
||||
return instance.getMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuInflater getMenuInflater() {
|
||||
return instance.getMenuInflater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
instance.show();
|
||||
}
|
||||
}
|
||||
|
||||
class PopupMenuAbstract extends LazyPopupMenu
|
||||
{
|
||||
private LazyPopupMenu lazy;
|
||||
|
||||
public PopupMenuAbstract(Context context, View anchor)
|
||||
{
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
||||
{
|
||||
lazy = new HoneycombPopupMenu(context, anchor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Menu getMenu() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
||||
{
|
||||
return lazy.getMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuInflater getMenuInflater() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
||||
{
|
||||
return lazy.getMenuInflater();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnMenuItemClickListener(PopupMenuAbstract.OnMenuItemClickListener listener) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
||||
{
|
||||
lazy.setOnMenuItemClickListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
||||
{
|
||||
lazy.show();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
|
||||
public class RetroTVMode extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
MainMenuActivity.getInstance().updateConfigFile();
|
||||
|
||||
Intent myIntent = new Intent(this, RetroActivity.class);
|
||||
String current_ime = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
myIntent.putExtra("CONFIGFILE", MainMenuActivity.getDefaultConfigPath());
|
||||
myIntent.putExtra("IME", current_ime);
|
||||
startActivity(myIntent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package org.retroarch.browser;
|
||||
|
||||
import org.retroarch.R;
|
||||
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
public class SettingsActivity extends PreferenceActivity {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.prefs);
|
||||
PreferenceManager.setDefaultValues(this, R.xml.prefs, false);
|
||||
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import android.os.Bundle;
|
|||
public class ShaderActivity extends DirectoryActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
File shaderDir = new File(getCacheDir(), "Shaders");
|
||||
File shaderDir = new File(getBaseContext().getApplicationInfo().dataDir, "shaders_glsl");
|
||||
if (shaderDir.exists())
|
||||
super.setStartDirectory(shaderDir.getAbsolutePath());
|
||||
|
||||
|
|
|
@ -16,40 +16,67 @@
|
|||
#include <IOKit/hid/IOHIDManager.h>
|
||||
#include "../RetroArch/apple_input.h"
|
||||
|
||||
// NOTE: I pieced this together through trial and error, any corrections are welcome
|
||||
|
||||
static IOHIDManagerRef g_hid_manager;
|
||||
static uint32_t g_num_pads;
|
||||
|
||||
static void hid_input_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDValueRef inIOHIDValueRef)
|
||||
{
|
||||
IOHIDElementRef element = IOHIDValueGetElement(inIOHIDValueRef);
|
||||
|
||||
uint32_t slot = (uint32_t)inContext;
|
||||
if (slot >= 4)
|
||||
return;
|
||||
IOHIDDeviceRef device = IOHIDElementGetDevice(element);
|
||||
|
||||
uint32_t type = IOHIDElementGetType(element);
|
||||
uint32_t page = IOHIDElementGetUsagePage(element);
|
||||
uint32_t use = IOHIDElementGetUsage(element);
|
||||
|
||||
if (type == 2 && page == 9)
|
||||
// Mouse handler
|
||||
if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse))
|
||||
{
|
||||
CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef);
|
||||
|
||||
if (state) g_current_input_data.pad_buttons[slot] |= (1 << (use - 1));
|
||||
else g_current_input_data.pad_buttons[slot] &= ~(1 << (use - 1));
|
||||
}
|
||||
else if (page == 1)
|
||||
{
|
||||
static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 };
|
||||
for (int i = 0; i < 4; i ++)
|
||||
if (type == kIOHIDElementTypeInput_Button && page == kHIDPage_Button)
|
||||
{
|
||||
if (use == axis_use_ids[i])
|
||||
CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef);
|
||||
|
||||
if (state) g_current_input_data.mouse_buttons |= (1 << (use - 1));
|
||||
else g_current_input_data.mouse_buttons &= ~(1 << (use - 1));
|
||||
}
|
||||
else if (type == kIOHIDElementTypeInput_Misc && page == kHIDPage_GenericDesktop)
|
||||
{
|
||||
static const uint32_t axis_use_ids[2] = { 48, 49 };
|
||||
|
||||
for (int i = 0; i < 2; i ++)
|
||||
if (use == axis_use_ids[i])
|
||||
g_current_input_data.mouse_delta[i] += IOHIDValueGetIntegerValue(inIOHIDValueRef);
|
||||
}
|
||||
}
|
||||
// Joystick handler
|
||||
else if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick))
|
||||
{
|
||||
uint32_t slot = (uint32_t)inContext;
|
||||
if (slot >= 4)
|
||||
return;
|
||||
|
||||
if (type == kIOHIDElementTypeInput_Button && page == kHIDPage_Button)
|
||||
{
|
||||
CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef);
|
||||
|
||||
if (state) g_current_input_data.pad_buttons[slot] |= (1 << (use - 1));
|
||||
else g_current_input_data.pad_buttons[slot] &= ~(1 << (use - 1));
|
||||
}
|
||||
else if (type == kIOHIDElementTypeInput_Misc && page == kHIDPage_GenericDesktop)
|
||||
{
|
||||
static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 };
|
||||
for (int i = 0; i < 4; i ++)
|
||||
{
|
||||
CFIndex min = IOHIDElementGetPhysicalMin(element);
|
||||
CFIndex max = IOHIDElementGetPhysicalMax(element) - min;
|
||||
CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef) - min;
|
||||
if (use == axis_use_ids[i])
|
||||
{
|
||||
CFIndex min = IOHIDElementGetPhysicalMin(element);
|
||||
CFIndex max = IOHIDElementGetPhysicalMax(element) - min;
|
||||
CFIndex state = IOHIDValueGetIntegerValue(inIOHIDValueRef) - min;
|
||||
|
||||
float val = (float)state / (float)max;
|
||||
g_current_input_data.pad_axis[slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f;
|
||||
float val = (float)state / (float)max;
|
||||
g_current_input_data.pad_axis[slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +84,18 @@ static void hid_input_callback(void* inContext, IOReturn inResult, void* inSende
|
|||
|
||||
static void hid_device_attached(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inDevice)
|
||||
{
|
||||
void* context = 0;
|
||||
|
||||
if (IOHIDDeviceConformsTo(inDevice, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick))
|
||||
{
|
||||
if (g_num_pads > 4)
|
||||
return;
|
||||
context = (void*)(g_num_pads++);
|
||||
}
|
||||
|
||||
IOHIDDeviceOpen(inDevice, kIOHIDOptionsTypeNone);
|
||||
IOHIDDeviceScheduleWithRunLoop(inDevice, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
IOHIDDeviceRegisterInputValueCallback(inDevice, hid_input_callback, 0);
|
||||
IOHIDDeviceRegisterInputValueCallback(inDevice, hid_input_callback, context);
|
||||
}
|
||||
|
||||
static void hid_device_removed(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inDevice)
|
||||
|
@ -67,25 +103,38 @@ static void hid_device_removed(void* inContext, IOReturn inResult, void* inSende
|
|||
IOHIDDeviceClose(inDevice, kIOHIDOptionsTypeNone);
|
||||
}
|
||||
|
||||
static CFMutableDictionaryRef build_matching_dictionary(uint32_t page, uint32_t use)
|
||||
{
|
||||
CFMutableDictionaryRef matcher = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
CFNumberRef pagen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
|
||||
CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsagePageKey), pagen);
|
||||
CFRelease(pagen);
|
||||
|
||||
CFNumberRef usen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &use);
|
||||
CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsageKey), usen);
|
||||
CFRelease(usen);
|
||||
|
||||
return matcher;
|
||||
}
|
||||
|
||||
void osx_pad_init()
|
||||
{
|
||||
if (!g_hid_manager)
|
||||
{
|
||||
g_hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
||||
|
||||
CFMutableDictionaryRef matcher = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
uint32_t page = kHIDPage_GenericDesktop;
|
||||
uint32_t use = kHIDUsage_GD_Joystick;
|
||||
CFMutableArrayRef matcher = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||
|
||||
CFNumberRef pagen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
|
||||
CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsagePageKey), pagen);
|
||||
CFRelease(pagen);
|
||||
CFMutableDictionaryRef mouse = build_matching_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse);
|
||||
CFArrayAppendValue(matcher, mouse);
|
||||
CFRelease(mouse);
|
||||
|
||||
CFNumberRef usen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &use);
|
||||
CFDictionarySetValue(matcher, CFSTR(kIOHIDDeviceUsageKey), usen);
|
||||
CFRelease(usen);
|
||||
CFMutableDictionaryRef joystick = build_matching_dictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
|
||||
CFArrayAppendValue(matcher, joystick);
|
||||
CFRelease(joystick);
|
||||
|
||||
IOHIDManagerSetDeviceMatching(g_hid_manager, matcher);
|
||||
IOHIDManagerSetDeviceMatchingMultiple(g_hid_manager, matcher);
|
||||
CFRelease(matcher);
|
||||
|
||||
IOHIDManagerRegisterDeviceMatchingCallback(g_hid_manager, hid_device_attached, 0);
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013 - Jason Fetters
|
||||
* Copyright (C) 2011-2013 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_OSX_PLATFORM_H
|
||||
#define __RARCH_OSX_PLATFORM_H
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@interface RAGameView : NSView
|
||||
|
||||
+ (RAGameView*)get;
|
||||
- (void)display;
|
||||
|
||||
@end
|
||||
|
||||
@interface RetroArch_OSX : NSObject<RetroArch_Platform, NSApplicationDelegate>
|
||||
{
|
||||
@public
|
||||
NSWindow IBOutlet *window;
|
||||
}
|
||||
|
||||
+ (RetroArch_OSX*)get;
|
||||
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
- (void)unloadingCore:(RAModuleInfo*)core;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -0,0 +1,264 @@
|
|||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013 - Jason Fetters
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
#import "RetroArch_Apple.h"
|
||||
#include "rarch_wrapper.h"
|
||||
#include "../RetroArch/apple_input.h"
|
||||
|
||||
// If USE_XATTR is defined any loaded file will get a com.RetroArch.Core extended attribute
|
||||
// specifying which core was used to load.
|
||||
//#define USE_XATTR
|
||||
|
||||
#if defined(USE_XATTR)
|
||||
#include "sys/xattr.h"
|
||||
#endif
|
||||
|
||||
#include "file.h"
|
||||
|
||||
@interface RApplication : NSApplication
|
||||
@end
|
||||
|
||||
@implementation RApplication
|
||||
|
||||
- (void)sendEvent:(NSEvent *)event
|
||||
{
|
||||
[super sendEvent:event];
|
||||
|
||||
if (event.type == GSEVENT_TYPE_KEYDOWN || event.type == GSEVENT_TYPE_KEYUP)
|
||||
apple_input_handle_key_event(event.keyCode, event.type == GSEVENT_TYPE_KEYDOWN);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RetroArch_OSX
|
||||
{
|
||||
NSWindow IBOutlet* _coreSelectSheet;
|
||||
|
||||
bool _isTerminating;
|
||||
bool _loaded;
|
||||
bool _wantReload;
|
||||
NSString* _file;
|
||||
RAModuleInfo* _core;
|
||||
}
|
||||
|
||||
+ (RetroArch_OSX*)get
|
||||
{
|
||||
return (RetroArch_OSX*)[[NSApplication sharedApplication] delegate];
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
apple_platform = self;
|
||||
_loaded = true;
|
||||
|
||||
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
|
||||
RAGameView.get.frame = [window.contentView bounds];
|
||||
[window.contentView setAutoresizesSubviews:YES];
|
||||
[window.contentView addSubview:RAGameView.get];
|
||||
[window makeFirstResponder:RAGameView.get];
|
||||
|
||||
// Create core select list
|
||||
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
|
||||
|
||||
for (RAModuleInfo* i in RAModuleInfo.getModules)
|
||||
[cb addItemWithObjectValue:i];
|
||||
|
||||
if (cb.numberOfItems)
|
||||
[cb selectItemAtIndex:0];
|
||||
else
|
||||
apple_display_alert(@"No libretro cores were found.", @"RetroArch");
|
||||
|
||||
// Run RGUI if needed
|
||||
if (!_wantReload)
|
||||
apple_run_core(nil, 0);
|
||||
else
|
||||
[self chooseCore];
|
||||
|
||||
_wantReload = false;
|
||||
|
||||
extern void osx_pad_init();
|
||||
osx_pad_init();
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
_isTerminating = true;
|
||||
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(apple_event_basic_command, (void*)QUIT);
|
||||
|
||||
return apple_is_running ? NSTerminateCancel : NSTerminateNow;
|
||||
}
|
||||
|
||||
|
||||
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
|
||||
{
|
||||
if (filenames.count == 1 && filenames[0])
|
||||
{
|
||||
_file = filenames[0];
|
||||
|
||||
if (!_loaded)
|
||||
_wantReload = true;
|
||||
else
|
||||
[self chooseCore];
|
||||
|
||||
[sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
|
||||
}
|
||||
else
|
||||
{
|
||||
apple_display_alert(@"Cannot open multiple files", @"RetroArch");
|
||||
[sender replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openDocument:(id)sender
|
||||
{
|
||||
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||
[panel beginSheetModalForWindow:window completionHandler:^(NSInteger result)
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
|
||||
if (result == NSOKButton && panel.URL)
|
||||
{
|
||||
_file = panel.URL.path;
|
||||
[self performSelector:@selector(chooseCore) withObject:nil afterDelay:.5f];
|
||||
}
|
||||
}];
|
||||
[NSApplication.sharedApplication runModalForWindow:panel];
|
||||
}
|
||||
|
||||
// This utility function will queue the _core and _file instance values for running.
|
||||
// If the emulator thread is already running it will tell it to quit.
|
||||
- (void)runCore
|
||||
{
|
||||
_wantReload = apple_is_running;
|
||||
|
||||
if (!apple_is_running)
|
||||
apple_run_core(_core, _file.UTF8String);
|
||||
else
|
||||
apple_frontend_post_event(apple_event_basic_command, (void*)QUIT);
|
||||
}
|
||||
|
||||
- (void)chooseCore
|
||||
{
|
||||
#ifdef USE_XATTR
|
||||
char stored_name[PATH_MAX];
|
||||
if (getxattr(_file.UTF8String, "com.RetroArch.Core", stored_name, PATH_MAX, 0, 0) > 0)
|
||||
{
|
||||
for (RAModuleInfo* i in RAModuleInfo.getModules)
|
||||
{
|
||||
const char* core_name = i.path.lastPathComponent.UTF8String;
|
||||
if (strcmp(core_name, stored_name) == 0)
|
||||
{
|
||||
_core = i;
|
||||
[self runCore];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[NSApplication.sharedApplication beginSheet:_coreSelectSheet modalForWindow:window modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
||||
[NSApplication.sharedApplication runModalForWindow:_coreSelectSheet];
|
||||
}
|
||||
|
||||
- (IBAction)coreWasChosen:(id)sender
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
[NSApplication.sharedApplication endSheet:_coreSelectSheet returnCode:0];
|
||||
[_coreSelectSheet orderOut:self];
|
||||
|
||||
if (_isTerminating)
|
||||
return;
|
||||
|
||||
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
|
||||
_core = (RAModuleInfo*)cb.objectValueOfSelectedItem;
|
||||
|
||||
[self runCore];
|
||||
}
|
||||
|
||||
#pragma mark RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
|
||||
{
|
||||
if (file)
|
||||
{
|
||||
[NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:file]]];
|
||||
|
||||
#ifdef USE_XATTR
|
||||
const char* core_name = core.path.lastPathComponent.UTF8String;
|
||||
setxattr(file, "com.RetroArch.Core", core_name, strlen(core_name) + 1, 0, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unloadingCore:(RAModuleInfo*)core
|
||||
{
|
||||
if (_isTerminating)
|
||||
[NSApplication.sharedApplication terminate:nil];
|
||||
|
||||
if (_wantReload)
|
||||
apple_run_core(_core, _file.UTF8String);
|
||||
else if(apple_use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
else
|
||||
[NSApplication.sharedApplication terminate:nil];
|
||||
|
||||
_wantReload = false;
|
||||
}
|
||||
|
||||
- (NSString*)retroarchConfigPath
|
||||
{
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
return [paths[0] stringByAppendingPathComponent:@"RetroArch"];
|
||||
}
|
||||
|
||||
- (NSString*)corePath
|
||||
{
|
||||
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"Contents/Resources/modules"];
|
||||
}
|
||||
|
||||
#pragma mark Menus
|
||||
- (IBAction)showPreferences:(id)sender
|
||||
{
|
||||
[[[NSWindowController alloc] initWithWindowNibName:@"Settings"] window];
|
||||
}
|
||||
|
||||
- (IBAction)basicEvent:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&apple_event_basic_command, (void*)((NSMenuItem*)sender).tag);
|
||||
}
|
||||
|
||||
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return NSApplicationMain(argc, (const char **) argv);
|
||||
}
|
||||
|
|
@ -31,8 +31,11 @@ static UIView* g_pause_indicator_view;
|
|||
|
||||
#elif defined(OSX)
|
||||
|
||||
#include "apple_input.h"
|
||||
|
||||
static RAGameView* g_instance;
|
||||
static NSOpenGLContext* g_context;
|
||||
static NSOpenGLPixelFormat* g_format;
|
||||
|
||||
#define g_view g_instance // < RAGameView is a container on iOS; on OSX these are both the same object
|
||||
|
||||
|
@ -55,25 +58,22 @@ static float g_screen_scale = 1.0f;
|
|||
|
||||
- (id)init
|
||||
{
|
||||
static const NSOpenGLPixelFormatAttribute attributes [] = {
|
||||
NSOpenGLPFAWindow,
|
||||
NSOpenGLPFADoubleBuffer, // double buffered
|
||||
NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer
|
||||
(NSOpenGLPixelFormatAttribute)nil
|
||||
};
|
||||
|
||||
self = [super initWithFrame:CGRectMake(0, 0, 100, 100) pixelFormat:[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]];
|
||||
self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
|
||||
g_context = self.openGLContext;
|
||||
[g_context makeCurrentContext];
|
||||
|
||||
self = [super init];
|
||||
self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setFrame:(NSRect)frameRect
|
||||
{
|
||||
[super setFrame:frameRect];
|
||||
|
||||
if (g_view && g_context)
|
||||
[g_context update];
|
||||
}
|
||||
|
||||
- (void)display
|
||||
{
|
||||
[self.openGLContext flushBuffer];
|
||||
[g_context flushBuffer];
|
||||
}
|
||||
|
||||
- (void)bindDrawable
|
||||
|
@ -87,10 +87,33 @@ static float g_screen_scale = 1.0f;
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent*)theEvent
|
||||
{
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent*)theEvent
|
||||
{
|
||||
g_current_input_data.touch_count = 1;
|
||||
[self mouseDragged:theEvent];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(NSEvent*)theEvent
|
||||
{
|
||||
g_current_input_data.touch_count = 0;
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent*)theEvent
|
||||
{
|
||||
NSPoint pos = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
||||
g_current_input_data.touches[0].screen_x = pos.x;
|
||||
g_current_input_data.touches[0].screen_y = pos.y;
|
||||
}
|
||||
|
||||
#elif defined(IOS) // < iOS Pause menu and lifecycle
|
||||
- (id)init
|
||||
{
|
||||
|
@ -164,17 +187,6 @@ static float g_screen_scale = 1.0f;
|
|||
];
|
||||
}
|
||||
|
||||
- (void)suspend
|
||||
{
|
||||
g_view.context = nil;
|
||||
[EAGLContext setCurrentContext:nil];
|
||||
}
|
||||
|
||||
- (void)resume
|
||||
{
|
||||
g_view.context = g_context;
|
||||
[EAGLContext setCurrentContext:g_context];
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
@ -190,7 +202,7 @@ bool apple_init_game_view()
|
|||
g_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
|
||||
[EAGLContext setCurrentContext:g_context];
|
||||
g_view.context = g_context;
|
||||
|
||||
|
||||
// Show pause button for a few seconds, so people know it's there
|
||||
g_pause_indicator_view.alpha = 1.0f;
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:g_instance];
|
||||
|
@ -207,13 +219,6 @@ bool apple_init_game_view()
|
|||
void apple_destroy_game_view()
|
||||
{
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
// Clear the view, otherwise the last frame from this game will be displayed
|
||||
// briefly on the next game.
|
||||
[g_view bindDrawable];
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
[g_view display];
|
||||
|
||||
glFinish();
|
||||
|
||||
#ifdef IOS
|
||||
|
@ -230,6 +235,38 @@ void apple_destroy_game_view()
|
|||
#endif
|
||||
}
|
||||
|
||||
bool apple_create_gl_context(uint32_t version)
|
||||
{
|
||||
#ifdef OSX
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
[g_context clearDrawable];
|
||||
g_context = nil;
|
||||
g_format = nil;
|
||||
|
||||
NSOpenGLPixelFormatAttribute attributes [] = {
|
||||
NSOpenGLPFADoubleBuffer, // double buffered
|
||||
NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer
|
||||
version ? NSOpenGLPFAOpenGLProfile : 0, version,
|
||||
(NSOpenGLPixelFormatAttribute)nil
|
||||
};
|
||||
|
||||
g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
||||
g_context = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:nil];
|
||||
g_context.view = g_view;
|
||||
[g_context makeCurrentContext];
|
||||
});
|
||||
|
||||
[g_context makeCurrentContext];
|
||||
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void apple_flip_game_view()
|
||||
{
|
||||
if (--g_fast_forward_skips < 0)
|
||||
|
@ -248,7 +285,7 @@ void apple_set_game_view_sync(unsigned interval)
|
|||
g_fast_forward_skips = interval ? 0 : 3;
|
||||
#elif defined(OSX)
|
||||
GLint value = interval ? 1 : 0;
|
||||
[g_view.openGLContext setValues:&value forParameter:NSOpenGLCPSwapInterval];
|
||||
[g_context setValues:&value forParameter:NSOpenGLCPSwapInterval];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -261,6 +298,20 @@ void apple_get_game_view_size(unsigned *width, unsigned *height)
|
|||
*height = *height ? *height : 480;
|
||||
}
|
||||
|
||||
void *apple_get_proc_address(const char *symbol_name)
|
||||
{
|
||||
#ifdef IOS
|
||||
(void)symbol_name; // We don't need symbols above GLES2 on iOS.
|
||||
return NULL;
|
||||
#else
|
||||
CFStringRef symbol = CFStringCreateWithCString(kCFAllocatorDefault, symbol_name, kCFStringEncodingASCII);
|
||||
void *proc = CFBundleGetFunctionPointerForName(CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")),
|
||||
symbol);
|
||||
CFRelease(symbol);
|
||||
return proc;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IOS
|
||||
void apple_bind_game_view_fbo(void)
|
||||
{
|
||||
|
|
|
@ -27,10 +27,18 @@
|
|||
@property core_info_t* info;
|
||||
@property config_file_t* data;
|
||||
@property (strong) NSString* description;
|
||||
@property (strong) NSString* customConfigPath;
|
||||
|
||||
+ (NSArray*)getModules;
|
||||
- (bool)supportsFileAtPath:(NSString*)path;
|
||||
|
||||
+ (NSString*)globalConfigPath;
|
||||
|
||||
- (void)createCustomConfig;
|
||||
- (void)deleteCustomConfig;
|
||||
- (bool)hasCustomConfig;
|
||||
- (NSString*)configPath;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -44,6 +44,9 @@ static core_info_list_t* coreList;
|
|||
newInfo.data = core->data;
|
||||
newInfo.description = [NSString stringWithUTF8String:core->display_name];
|
||||
|
||||
NSString* baseName = newInfo.path.lastPathComponent.stringByDeletingPathExtension;
|
||||
newInfo.customConfigPath = [NSString stringWithFormat:@"%@/%@.cfg", apple_platform.retroarchConfigPath, baseName];
|
||||
|
||||
[moduleList addObject:newInfo];
|
||||
}
|
||||
|
||||
|
@ -70,6 +73,37 @@ static core_info_list_t* coreList;
|
|||
return does_core_support_file(self.info, path.UTF8String);
|
||||
}
|
||||
|
||||
+ (NSString*)globalConfigPath
|
||||
{
|
||||
static NSString* path;
|
||||
if (!path)
|
||||
path = [NSString stringWithFormat:@"%@/retroarch.cfg", apple_platform.retroarchConfigPath];
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
- (void)createCustomConfig
|
||||
{
|
||||
if (!self.hasCustomConfig)
|
||||
[NSFileManager.defaultManager copyItemAtPath:RAModuleInfo.globalConfigPath toPath:self.customConfigPath error:nil];
|
||||
}
|
||||
|
||||
- (void)deleteCustomConfig
|
||||
{
|
||||
if (self.hasCustomConfig)
|
||||
[NSFileManager.defaultManager removeItemAtPath:self.customConfigPath error:nil];
|
||||
}
|
||||
|
||||
- (bool)hasCustomConfig
|
||||
{
|
||||
return path_file_exists(self.customConfigPath.UTF8String);
|
||||
}
|
||||
|
||||
- (NSString*)configPath
|
||||
{
|
||||
return self.hasCustomConfig ? self.customConfigPath : RAModuleInfo.globalConfigPath;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#ifdef IOS
|
||||
|
|
|
@ -18,73 +18,43 @@
|
|||
#define __RARCH_APPLE_H
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import "RAModuleInfo.h"
|
||||
|
||||
void apple_run_core(RAModuleInfo* core, const char* file);
|
||||
#define GSEVENT_TYPE_KEYDOWN 10
|
||||
#define GSEVENT_TYPE_KEYUP 11
|
||||
|
||||
@protocol RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
- (void)unloadingCore:(RAModuleInfo*)core;
|
||||
- (NSString*)retroarchConfigPath;
|
||||
|
||||
- (NSString*)retroarchConfigPath; // < This returns the directory that contains retroarch.cfg and other custom configs
|
||||
- (NSString*)corePath;
|
||||
@end
|
||||
|
||||
#ifdef IOS
|
||||
#import "../iOS/platform.h"
|
||||
#elif defined(OSX)
|
||||
#import "../OSX/platform.h"
|
||||
#endif
|
||||
|
||||
extern bool apple_is_paused;
|
||||
extern bool apple_is_running;
|
||||
extern bool apple_use_tv_mode;
|
||||
extern RAModuleInfo* apple_core;
|
||||
|
||||
extern id<RetroArch_Platform> apple_platform;
|
||||
|
||||
#ifdef IOS
|
||||
// main.m
|
||||
enum basic_event_t { RESET = 1, LOAD_STATE = 2, SAVE_STATE = 3, QUIT = 4 };
|
||||
extern void apple_event_basic_command(void* userdata);
|
||||
extern void apple_event_set_state_slot(void* userdata);
|
||||
extern void apple_event_show_rgui(void* userdata);
|
||||
|
||||
// RAGameView.m
|
||||
@interface RAGameView : UIViewController
|
||||
+ (RAGameView*)get;
|
||||
- (void)openPauseMenu;
|
||||
- (void)closePauseMenu;
|
||||
|
||||
- (void)suspend;
|
||||
- (void)resume;
|
||||
@end
|
||||
|
||||
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate, RetroArch_Platform>
|
||||
|
||||
+ (RetroArch_iOS*)get;
|
||||
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
- (void)unloadingCore:(RAModuleInfo*)core;
|
||||
- (NSString*)retroarchConfigPath;
|
||||
|
||||
- (void)refreshConfig;
|
||||
- (void)refreshSystemConfig;
|
||||
|
||||
@property (strong, nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents
|
||||
@property (strong, nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch
|
||||
@property (strong, nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg
|
||||
|
||||
@end
|
||||
|
||||
#elif defined(OSX)
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@interface RAGameView : NSOpenGLView
|
||||
|
||||
+ (RAGameView*)get;
|
||||
- (void)display;
|
||||
|
||||
@end
|
||||
|
||||
@interface RetroArch_OSX : NSObject<RetroArch_Platform, NSApplicationDelegate>
|
||||
{
|
||||
@public
|
||||
NSWindow IBOutlet *window;
|
||||
}
|
||||
|
||||
+ (RetroArch_OSX*)get;
|
||||
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
- (void)unloadingCore:(RAModuleInfo*)core;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
extern void apple_refresh_config();
|
||||
extern void apple_enter_stasis();
|
||||
extern void apple_exit_stasis();
|
||||
extern void apple_run_core(RAModuleInfo* core, const char* file);
|
||||
|
||||
// utility.m
|
||||
extern void apple_display_alert(NSString* message, NSString* title);
|
||||
|
@ -92,4 +62,7 @@ extern void objc_clear_config_hack();
|
|||
extern bool path_make_and_check_directory(const char* path, mode_t mode, int amode);
|
||||
extern NSString* objc_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue);
|
||||
|
||||
// frontend/platform/platform_apple.c
|
||||
extern void apple_frontend_post_event(void (*fn)(void*), void* userdata);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -86,6 +86,11 @@ void apple_input_enable_icade(bool on)
|
|||
icade_buttons = 0;
|
||||
}
|
||||
|
||||
uint32_t apple_input_get_icade_buttons()
|
||||
{
|
||||
return icade_enabled ? icade_buttons : 0;
|
||||
}
|
||||
|
||||
void apple_input_handle_key_event(unsigned keycode, bool down)
|
||||
{
|
||||
keycode = HIDKEY(keycode);
|
||||
|
@ -131,7 +136,10 @@ static void apple_input_poll(void *data)
|
|||
}
|
||||
|
||||
input_joypad_poll(g_joydriver);
|
||||
g_polled_input_data.pad_buttons[0] |= icade_buttons;
|
||||
g_polled_input_data.pad_buttons[0] |= apple_input_get_icade_buttons();
|
||||
|
||||
g_current_input_data.mouse_delta[0] = 0;
|
||||
g_current_input_data.mouse_delta[1] = 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -147,6 +155,17 @@ static int16_t apple_input_state(void *data, const struct retro_keybind **binds,
|
|||
|
||||
case RETRO_DEVICE_KEYBOARD:
|
||||
return apple_key_pressed(id);
|
||||
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_MOUSE_X: return g_polled_input_data.mouse_delta[0];
|
||||
case RETRO_DEVICE_ID_MOUSE_Y: return g_polled_input_data.mouse_delta[1];
|
||||
case RETRO_DEVICE_ID_MOUSE_LEFT: return g_polled_input_data.mouse_buttons & 1;
|
||||
case RETRO_DEVICE_ID_MOUSE_RIGHT: return g_polled_input_data.mouse_buttons & 2;
|
||||
}
|
||||
}
|
||||
|
||||
case RETRO_DEVICE_POINTER:
|
||||
case RARCH_DEVICE_POINTER_SCREEN:
|
||||
|
|
|
@ -33,6 +33,9 @@ typedef struct
|
|||
apple_touch_data_t touches[MAX_TOUCHES];
|
||||
uint32_t touch_count;
|
||||
|
||||
uint32_t mouse_buttons;
|
||||
int16_t mouse_delta[2];
|
||||
|
||||
uint32_t keys[MAX_KEYS];
|
||||
|
||||
uint32_t pad_buttons[MAX_PADS];
|
||||
|
@ -44,6 +47,7 @@ extern apple_input_data_t g_polled_input_data; //< Game thread data
|
|||
|
||||
// Main thread only
|
||||
void apple_input_enable_icade(bool on);
|
||||
uint32_t apple_input_get_icade_buttons();
|
||||
void apple_input_handle_key_event(unsigned keycode, bool down);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -56,7 +56,7 @@ static bool apple_joypad_button(unsigned port, uint16_t joykey)
|
|||
|
||||
static int16_t apple_joypad_axis(unsigned port, uint32_t joyaxis)
|
||||
{
|
||||
if (joyaxis == AXIS_NONE || port != 0)
|
||||
if (joyaxis == AXIS_NONE)
|
||||
return 0;
|
||||
|
||||
int16_t val = 0;
|
||||
|
|
|
@ -21,37 +21,13 @@
|
|||
|
||||
#include "apple_input.h"
|
||||
|
||||
// If USE_XATTR is defined any loaded file will get a com.RetroArch.Core extended attribute
|
||||
// specifying which core was used to load.
|
||||
//#define USE_XATTR
|
||||
|
||||
#ifdef IOS
|
||||
#import "views.h"
|
||||
#include "../iOS/input/BTStack/btpad.h"
|
||||
#include "../iOS/input/BTStack/btdynamic.h"
|
||||
#include "../iOS/input/BTStack/btpad.h"
|
||||
#elif defined(USE_XATTR)
|
||||
#include "sys/xattr.h"
|
||||
#endif
|
||||
|
||||
#include "file.h"
|
||||
|
||||
#define GSEVENT_TYPE_KEYDOWN 10
|
||||
#define GSEVENT_TYPE_KEYUP 11
|
||||
|
||||
//#define HAVE_DEBUG_FILELOG
|
||||
static bool use_tv_mode;
|
||||
|
||||
id<RetroArch_Platform> apple_platform;
|
||||
|
||||
// From frontend/frontend_ios.c
|
||||
extern void* rarch_main(void* args);
|
||||
extern void apple_frontend_post_event(void (*fn)(void*), void* userdata);
|
||||
|
||||
|
||||
// These are based on the tag property of the button used to trigger the event
|
||||
enum basic_event_t { RESET = 1, LOAD_STATE = 2, SAVE_STATE = 3, QUIT = 4 };
|
||||
static void event_basic_command(void* userdata)
|
||||
void apple_event_basic_command(void* userdata)
|
||||
{
|
||||
switch ((enum basic_event_t)userdata)
|
||||
{
|
||||
|
@ -62,12 +38,12 @@ static void event_basic_command(void* userdata)
|
|||
}
|
||||
}
|
||||
|
||||
static void event_set_state_slot(void* userdata)
|
||||
void apple_event_set_state_slot(void* userdata)
|
||||
{
|
||||
g_extern.state_slot = (uint32_t)userdata;
|
||||
}
|
||||
|
||||
static void event_show_rgui(void* userdata)
|
||||
void apple_event_show_rgui(void* userdata)
|
||||
{
|
||||
const bool in_menu = g_extern.lifecycle_mode_state & (1 << MODE_MENU);
|
||||
g_extern.lifecycle_mode_state &= ~(1ULL << (in_menu ? MODE_MENU : MODE_GAME));
|
||||
|
@ -83,11 +59,63 @@ static void event_reload_config(void* userdata)
|
|||
init_drivers();
|
||||
}
|
||||
|
||||
void apple_refresh_config()
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&event_reload_config, 0);
|
||||
else
|
||||
objc_clear_config_hack();
|
||||
}
|
||||
|
||||
pthread_mutex_t stasis_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void event_stasis(void* userdata)
|
||||
{
|
||||
// HACK: uninit_drivers is the nuclear option; uninit_audio would be better but will
|
||||
// crash when resuming.
|
||||
uninit_drivers();
|
||||
pthread_mutex_lock(&stasis_mutex);
|
||||
pthread_mutex_unlock(&stasis_mutex);
|
||||
init_drivers();
|
||||
}
|
||||
|
||||
void apple_enter_stasis()
|
||||
{
|
||||
if (apple_is_running)
|
||||
{
|
||||
pthread_mutex_lock(&stasis_mutex);
|
||||
apple_frontend_post_event(event_stasis, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void apple_exit_stasis()
|
||||
{
|
||||
if (apple_is_running)
|
||||
pthread_mutex_unlock(&stasis_mutex);
|
||||
}
|
||||
|
||||
#pragma mark EMULATION
|
||||
static pthread_t apple_retro_thread;
|
||||
static bool apple_is_paused;
|
||||
static bool apple_is_running;
|
||||
static RAModuleInfo* apple_core;
|
||||
bool apple_is_paused;
|
||||
bool apple_is_running;
|
||||
bool apple_use_tv_mode;
|
||||
RAModuleInfo* apple_core;
|
||||
|
||||
void* rarch_main_spring(void* args)
|
||||
{
|
||||
char** argv = args;
|
||||
|
||||
uint32_t argc = 0;
|
||||
while (argv && argv[argc]) argc++;
|
||||
|
||||
if (rarch_main(argc, argv))
|
||||
{
|
||||
rarch_main_clear_state();
|
||||
dispatch_async_f(dispatch_get_main_queue(), (void*)1, apple_rarch_exited);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void apple_run_core(RAModuleInfo* core, const char* file)
|
||||
{
|
||||
|
@ -98,23 +126,31 @@ void apple_run_core(RAModuleInfo* core, const char* file)
|
|||
apple_core = core;
|
||||
apple_is_running = true;
|
||||
|
||||
struct rarch_main_wrap* load_data = malloc(sizeof(struct rarch_main_wrap));
|
||||
memset(load_data, 0, sizeof(struct rarch_main_wrap));
|
||||
|
||||
load_data->config_path = strdup(apple_platform.retroarchConfigPath.UTF8String);
|
||||
|
||||
#ifdef IOS
|
||||
load_data->sram_path = strdup(RetroArch_iOS.get.systemDirectory.UTF8String);
|
||||
load_data->state_path = strdup(RetroArch_iOS.get.systemDirectory.UTF8String);
|
||||
#endif
|
||||
static char config_path[PATH_MAX];
|
||||
static char core_path[PATH_MAX];
|
||||
static char file_path[PATH_MAX];
|
||||
|
||||
static const char* argv[] = { "retroarch", "-c", config_path, "-L", core_path, file_path, 0 };
|
||||
|
||||
if (apple_core)
|
||||
strlcpy(config_path, apple_core.configPath.UTF8String, sizeof(config_path));
|
||||
else
|
||||
strlcpy(config_path, RAModuleInfo.globalConfigPath.UTF8String, sizeof(config_path));
|
||||
|
||||
if (file && core)
|
||||
{
|
||||
load_data->libretro_path = strdup(apple_core.path.UTF8String);
|
||||
load_data->rom_path = strdup(file);
|
||||
argv[3] = "-L";
|
||||
argv[4] = core_path;
|
||||
strlcpy(core_path, apple_core.path.UTF8String, sizeof(core_path));
|
||||
strlcpy(file_path, file, sizeof(file_path));
|
||||
}
|
||||
else
|
||||
{
|
||||
argv[3] = "--menu";
|
||||
argv[4] = 0;
|
||||
}
|
||||
|
||||
if (pthread_create(&apple_retro_thread, 0, rarch_main, load_data))
|
||||
if (pthread_create(&apple_retro_thread, 0, rarch_main_spring, argv))
|
||||
{
|
||||
apple_rarch_exited((void*)1);
|
||||
return;
|
||||
|
@ -138,574 +174,6 @@ void apple_rarch_exited(void* result)
|
|||
[apple_platform unloadingCore:used_core];
|
||||
}
|
||||
|
||||
if (use_tv_mode)
|
||||
if (apple_use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// IOS
|
||||
//
|
||||
#pragma mark IOS
|
||||
#ifdef IOS
|
||||
// Input helpers: This is kept here because it needs objective-c
|
||||
static void handle_touch_event(NSArray* touches)
|
||||
{
|
||||
const int numTouches = [touches count];
|
||||
const float scale = [[UIScreen mainScreen] scale];
|
||||
|
||||
g_current_input_data.touch_count = 0;
|
||||
|
||||
for(int i = 0; i != numTouches && g_current_input_data.touch_count < MAX_TOUCHES; i ++)
|
||||
{
|
||||
UITouch* touch = [touches objectAtIndex:i];
|
||||
const CGPoint coord = [touch locationInView:touch.view];
|
||||
|
||||
if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
|
||||
{
|
||||
g_current_input_data.touches[g_current_input_data.touch_count ].screen_x = coord.x * scale;
|
||||
g_current_input_data.touches[g_current_input_data.touch_count ++].screen_y = coord.y * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@interface RApplication : UIApplication
|
||||
@end
|
||||
|
||||
@implementation RApplication
|
||||
|
||||
- (void)sendEvent:(UIEvent *)event
|
||||
{
|
||||
[super sendEvent:event];
|
||||
|
||||
if ([[event allTouches] count])
|
||||
handle_touch_event(event.allTouches.allObjects);
|
||||
else if ([event respondsToSelector:@selector(_gsEvent)])
|
||||
{
|
||||
// Stolen from: http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html
|
||||
uint8_t* eventMem = (uint8_t*)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]);
|
||||
int eventType = eventMem ? *(int*)&eventMem[8] : 0;
|
||||
|
||||
if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
|
||||
apple_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
|
||||
|
||||
CFBridgingRelease(eventMem);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@autoreleasepool {
|
||||
#if defined(HAVE_DEBUG_FILELOG) && (TARGET_IPHONE_SIMULATOR == 0)
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console_stdout.log"];
|
||||
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stdout);
|
||||
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stderr);
|
||||
#endif
|
||||
return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class]));
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RetroArch_iOS
|
||||
{
|
||||
UIWindow* _window;
|
||||
|
||||
bool _isGameTop, _isRomList;
|
||||
uint32_t _settingMenusInBackStack;
|
||||
uint32_t _enabledOrientations;
|
||||
|
||||
RAModuleInfo* _module;
|
||||
}
|
||||
|
||||
+ (RetroArch_iOS*)get
|
||||
{
|
||||
return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
|
||||
}
|
||||
|
||||
// UIApplicationDelegate
|
||||
- (void)applicationDidFinishLaunching:(UIApplication *)application
|
||||
{
|
||||
apple_platform = self;
|
||||
self.delegate = self;
|
||||
|
||||
// Setup window
|
||||
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
_window.rootViewController = self;
|
||||
[_window makeKeyAndVisible];
|
||||
|
||||
// Build system paths and test permissions
|
||||
self.documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
|
||||
self.systemDirectory = [self.documentsDirectory stringByAppendingPathComponent:@".RetroArch"];
|
||||
self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
|
||||
|
||||
if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
|
||||
apple_display_alert([NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory], 0);
|
||||
else if (!path_make_and_check_directory(self.systemDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
|
||||
apple_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0);
|
||||
else
|
||||
{
|
||||
[self pushViewController:[RADirectoryList directoryListAtBrowseRoot] animated:YES];
|
||||
[self refreshSystemConfig];
|
||||
|
||||
if (use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
}
|
||||
|
||||
// Warn if there are no cores present
|
||||
if ([RAModuleInfo getModules].count == 0)
|
||||
apple_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||
{
|
||||
[RAGameView.get resume];
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||
{
|
||||
[RAGameView.get suspend];
|
||||
}
|
||||
|
||||
// UINavigationControllerDelegate
|
||||
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
|
||||
{
|
||||
_isGameTop = [viewController isKindOfClass:[RAGameView class]];
|
||||
_isRomList = [viewController isKindOfClass:[RADirectoryList class]];
|
||||
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone];
|
||||
[[UIApplication sharedApplication] setIdleTimerDisabled:_isGameTop];
|
||||
|
||||
self.navigationBarHidden = _isGameTop;
|
||||
[self setToolbarHidden:!_isRomList animated:YES];
|
||||
self.topViewController.navigationItem.rightBarButtonItem = [self createSettingsButton];
|
||||
}
|
||||
|
||||
// UINavigationController: Never animate when pushing onto, or popping, an RAGameView
|
||||
- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated
|
||||
{
|
||||
if ([theView respondsToSelector:@selector(isSettingsView)] && [(id)theView isSettingsView])
|
||||
_settingMenusInBackStack ++;
|
||||
|
||||
[super pushViewController:theView animated:animated && !_isGameTop];
|
||||
}
|
||||
|
||||
- (UIViewController*)popViewControllerAnimated:(BOOL)animated
|
||||
{
|
||||
if ([self.topViewController respondsToSelector:@selector(isSettingsView)] && [(id)self.topViewController isSettingsView])
|
||||
_settingMenusInBackStack --;
|
||||
|
||||
return [super popViewControllerAnimated:animated && !_isGameTop];
|
||||
}
|
||||
|
||||
// NOTE: This version only runs on iOS6
|
||||
- (NSUInteger)supportedInterfaceOrientations
|
||||
{
|
||||
return _isGameTop ? _enabledOrientations
|
||||
: UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
|
||||
// NOTE: This version runs on iOS2-iOS5, but not iOS6
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
if (_isGameTop)
|
||||
switch (interfaceOrientation)
|
||||
{
|
||||
case UIInterfaceOrientationPortrait:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskPortrait);
|
||||
case UIInterfaceOrientationPortraitUpsideDown:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeLeft);
|
||||
case UIInterfaceOrientationLandscapeRight:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeRight);
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
|
||||
{
|
||||
[self pushViewController:RAGameView.get animated:NO];
|
||||
[RASettingsList refreshModuleConfig:core];
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
|
||||
[self refreshSystemConfig];
|
||||
}
|
||||
|
||||
- (void)unloadingCore:(RAModuleInfo*)core
|
||||
{
|
||||
[self popToViewController:[RAGameView get] animated:NO];
|
||||
[self popViewControllerAnimated:NO];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
|
||||
- (NSString*)retroarchConfigPath
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@/retroarch.cfg", self.systemDirectory];
|
||||
}
|
||||
|
||||
- (NSString*)corePath
|
||||
{
|
||||
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"];
|
||||
}
|
||||
|
||||
- (void)refreshConfig
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&event_reload_config, 0);
|
||||
else
|
||||
objc_clear_config_hack();
|
||||
}
|
||||
|
||||
- (void)refreshSystemConfig
|
||||
{
|
||||
// Read load time settings
|
||||
config_file_t* conf = config_file_new([self.systemConfigPath UTF8String]);
|
||||
|
||||
if (conf)
|
||||
{
|
||||
// Get enabled orientations
|
||||
static const struct { const char* setting; uint32_t orientation; } orientationSettings[4] =
|
||||
{
|
||||
{ "ios_allow_portrait", UIInterfaceOrientationMaskPortrait },
|
||||
{ "ios_allow_portrait_upside_down", UIInterfaceOrientationMaskPortraitUpsideDown },
|
||||
{ "ios_allow_landscape_left", UIInterfaceOrientationMaskLandscapeLeft },
|
||||
{ "ios_allow_landscape_right", UIInterfaceOrientationMaskLandscapeRight }
|
||||
};
|
||||
|
||||
_enabledOrientations = 0;
|
||||
|
||||
for (int i = 0; i < 4; i ++)
|
||||
{
|
||||
bool enabled = false;
|
||||
bool found = config_get_bool(conf, orientationSettings[i].setting, &enabled);
|
||||
|
||||
if (!found || enabled)
|
||||
_enabledOrientations |= orientationSettings[i].orientation;
|
||||
}
|
||||
|
||||
//
|
||||
bool val;
|
||||
apple_input_enable_icade(config_get_bool(conf, "ios_use_icade", &val) && val);
|
||||
btstack_set_poweron(config_get_bool(conf, "ios_use_btstack", &val) && val);
|
||||
use_tv_mode = config_get_bool(conf, "ios_tv_mode", & val) && val;
|
||||
|
||||
config_file_free(conf);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark PAUSE MENU
|
||||
- (UIBarButtonItem*)createSettingsButton
|
||||
{
|
||||
if (_settingMenusInBackStack == 0)
|
||||
return [[UIBarButtonItem alloc]
|
||||
initWithTitle:@"Settings"
|
||||
style:UIBarButtonItemStyleBordered
|
||||
target:[RetroArch_iOS get]
|
||||
action:@selector(showSystemSettings)];
|
||||
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (IBAction)showPauseMenu:(id)sender
|
||||
{
|
||||
if (apple_is_running && !apple_is_paused && _isGameTop)
|
||||
{
|
||||
apple_is_paused = true;
|
||||
[[RAGameView get] openPauseMenu];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)basicEvent:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&event_basic_command, ((UIView*)sender).tag);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)chooseState:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex);
|
||||
}
|
||||
|
||||
- (IBAction)showRGUI:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(event_show_rgui, 0);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)closePauseMenu:(id)sender
|
||||
{
|
||||
[[RAGameView get] closePauseMenu];
|
||||
apple_is_paused = false;
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
}
|
||||
|
||||
- (IBAction)showSettings
|
||||
{
|
||||
[self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)showSystemSettings
|
||||
{
|
||||
[self pushViewController:[RASystemSettingsList new] animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// OSX
|
||||
//
|
||||
#pragma mark OSX
|
||||
#ifdef OSX
|
||||
|
||||
@interface RApplication : NSApplication
|
||||
@end
|
||||
|
||||
@implementation RApplication
|
||||
|
||||
- (void)sendEvent:(NSEvent *)event
|
||||
{
|
||||
[super sendEvent:event];
|
||||
|
||||
if (event.type == GSEVENT_TYPE_KEYDOWN || event.type == GSEVENT_TYPE_KEYUP)
|
||||
apple_input_handle_key_event(event.keyCode, event.type == GSEVENT_TYPE_KEYDOWN);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RetroArch_OSX
|
||||
{
|
||||
NSWindow IBOutlet* _coreSelectSheet;
|
||||
|
||||
bool _isTerminating;
|
||||
bool _loaded;
|
||||
bool _wantReload;
|
||||
NSString* _file;
|
||||
RAModuleInfo* _core;
|
||||
}
|
||||
|
||||
+ (RetroArch_OSX*)get
|
||||
{
|
||||
return (RetroArch_OSX*)[[NSApplication sharedApplication] delegate];
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
apple_platform = self;
|
||||
_loaded = true;
|
||||
|
||||
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
|
||||
RAGameView.get.frame = [window.contentView bounds];
|
||||
[window.contentView setAutoresizesSubviews:YES];
|
||||
[window.contentView addSubview:RAGameView.get];
|
||||
[window makeFirstResponder:RAGameView.get];
|
||||
|
||||
// Create core select list
|
||||
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
|
||||
|
||||
for (RAModuleInfo* i in RAModuleInfo.getModules)
|
||||
[cb addItemWithObjectValue:i];
|
||||
|
||||
if (cb.numberOfItems)
|
||||
[cb selectItemAtIndex:0];
|
||||
else
|
||||
apple_display_alert(@"No libretro cores were found.", @"RetroArch");
|
||||
|
||||
// Run RGUI if needed
|
||||
if (!_wantReload)
|
||||
apple_run_core(nil, 0);
|
||||
else
|
||||
[self chooseCore];
|
||||
|
||||
_wantReload = false;
|
||||
|
||||
extern void osx_pad_init();
|
||||
osx_pad_init();
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
_isTerminating = true;
|
||||
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(event_basic_command, (void*)QUIT);
|
||||
|
||||
return apple_is_running ? NSTerminateCancel : NSTerminateNow;
|
||||
}
|
||||
|
||||
|
||||
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
|
||||
{
|
||||
if (filenames.count == 1 && filenames[0])
|
||||
{
|
||||
_file = filenames[0];
|
||||
|
||||
if (!_loaded)
|
||||
_wantReload = true;
|
||||
else
|
||||
[self chooseCore];
|
||||
|
||||
[sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
|
||||
}
|
||||
else
|
||||
{
|
||||
apple_display_alert(@"Cannot open multiple files", @"RetroArch");
|
||||
[sender replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)openDocument:(id)sender
|
||||
{
|
||||
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
||||
[panel beginSheetModalForWindow:window completionHandler:^(NSInteger result)
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
|
||||
if (result == NSOKButton && panel.URL)
|
||||
{
|
||||
_file = panel.URL.path;
|
||||
[self performSelector:@selector(chooseCore) withObject:nil afterDelay:.5f];
|
||||
}
|
||||
}];
|
||||
[NSApplication.sharedApplication runModalForWindow:panel];
|
||||
}
|
||||
|
||||
// This utility function will queue the _core and _file instance values for running.
|
||||
// If the emulator thread is already running it will tell it to quit.
|
||||
- (void)runCore
|
||||
{
|
||||
_wantReload = apple_is_running;
|
||||
|
||||
if (!apple_is_running)
|
||||
apple_run_core(_core, _file.UTF8String);
|
||||
else
|
||||
apple_frontend_post_event(event_basic_command, (void*)QUIT);
|
||||
}
|
||||
|
||||
- (void)chooseCore
|
||||
{
|
||||
#ifdef USE_XATTR
|
||||
char stored_name[PATH_MAX];
|
||||
if (getxattr(_file.UTF8String, "com.RetroArch.Core", stored_name, PATH_MAX, 0, 0) > 0)
|
||||
{
|
||||
for (RAModuleInfo* i in RAModuleInfo.getModules)
|
||||
{
|
||||
const char* core_name = i.path.lastPathComponent.UTF8String;
|
||||
if (strcmp(core_name, stored_name) == 0)
|
||||
{
|
||||
_core = i;
|
||||
[self runCore];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[NSApplication.sharedApplication beginSheet:_coreSelectSheet modalForWindow:window modalDelegate:nil didEndSelector:nil contextInfo:nil];
|
||||
[NSApplication.sharedApplication runModalForWindow:_coreSelectSheet];
|
||||
}
|
||||
|
||||
- (IBAction)coreWasChosen:(id)sender
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
[NSApplication.sharedApplication endSheet:_coreSelectSheet returnCode:0];
|
||||
[_coreSelectSheet orderOut:self];
|
||||
|
||||
if (_isTerminating)
|
||||
return;
|
||||
|
||||
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
|
||||
_core = (RAModuleInfo*)cb.objectValueOfSelectedItem;
|
||||
|
||||
[self runCore];
|
||||
}
|
||||
|
||||
#pragma mark RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
|
||||
{
|
||||
if (file)
|
||||
{
|
||||
[NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:file]]];
|
||||
|
||||
#ifdef USE_XATTR
|
||||
const char* core_name = core.path.lastPathComponent.UTF8String;
|
||||
setxattr(file, "com.RetroArch.Core", core_name, strlen(core_name) + 1, 0, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unloadingCore:(RAModuleInfo*)core
|
||||
{
|
||||
if (_isTerminating)
|
||||
[NSApplication.sharedApplication terminate:nil];
|
||||
|
||||
if (_wantReload)
|
||||
apple_run_core(_core, _file.UTF8String);
|
||||
else if(use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
else
|
||||
[NSApplication.sharedApplication terminate:nil];
|
||||
|
||||
_wantReload = false;
|
||||
}
|
||||
|
||||
- (NSString*)retroarchConfigPath
|
||||
{
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
return [paths[0] stringByAppendingPathComponent:@"RetroArch/retroarch.cfg"];
|
||||
}
|
||||
|
||||
- (NSString*)corePath
|
||||
{
|
||||
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"Contents/Resources/modules"];
|
||||
}
|
||||
|
||||
#pragma mark Menus
|
||||
- (IBAction)showPreferences:(id)sender
|
||||
{
|
||||
[[[NSWindowController alloc] initWithWindowNibName:@"Settings"] window];
|
||||
}
|
||||
|
||||
- (IBAction)basicEvent:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&event_basic_command, (void*)((NSMenuItem*)sender).tag);
|
||||
}
|
||||
|
||||
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
|
||||
{
|
||||
[NSApplication.sharedApplication stopModal];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return NSApplicationMain(argc, (const char **) argv);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,7 @@ void apple_destroy_game_view(void);
|
|||
void apple_flip_game_view(void);
|
||||
void apple_set_game_view_sync(unsigned interval);
|
||||
void apple_get_game_view_size(unsigned *width, unsigned *height);
|
||||
void *apple_get_proc_address(const char *symbol_name);
|
||||
|
||||
#ifdef IOS
|
||||
void apple_bind_game_view_fbo(void);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
9620F6651790004F001B3B81 /* Settings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9620F6641790004F001B3B81 /* Settings.xib */; };
|
||||
962EE0E2178B3DF6004224FF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 962EE0E1178B3DF6004224FF /* IOKit.framework */; };
|
||||
96355CE31788E72A0010DBFA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96355CE21788E72A0010DBFA /* Cocoa.framework */; };
|
||||
9646869817BBC14E00C5EA69 /* platform.m in Sources */ = {isa = PBXBuildFile; fileRef = 9646869617BBC14E00C5EA69 /* platform.m */; };
|
||||
967894931788ECDB00D6CA69 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9678948F1788ECDB00D6CA69 /* InfoPlist.strings */; };
|
||||
967894941788ECDB00D6CA69 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 967894911788ECDB00D6CA69 /* MainMenu.xib */; };
|
||||
967894961788ED1100D6CA69 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894951788ED1100D6CA69 /* main.m */; };
|
||||
|
@ -35,6 +36,8 @@
|
|||
96355CE51788E72A0010DBFA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||
96355CE61788E72A0010DBFA /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||
96355CE71788E72A0010DBFA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
9646869617BBC14E00C5EA69 /* platform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = platform.m; path = OSX/platform.m; sourceTree = SOURCE_ROOT; };
|
||||
9646869717BBC14E00C5EA69 /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform.h; path = OSX/platform.h; sourceTree = SOURCE_ROOT; };
|
||||
9678948D1788ECCA00D6CA69 /* RetroArch-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "RetroArch-Info.plist"; path = "OSX/RetroArch-Info.plist"; sourceTree = SOURCE_ROOT; };
|
||||
967894901788ECDB00D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = OSX/en.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; };
|
||||
967894921788ECDB00D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = OSX/en.lproj/MainMenu.xib; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -109,6 +112,8 @@
|
|||
96355CE81788E72A0010DBFA /* RetroArch */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9646869617BBC14E00C5EA69 /* platform.m */,
|
||||
9646869717BBC14E00C5EA69 /* platform.h */,
|
||||
9620F662178FD4D3001B3B81 /* settings.m */,
|
||||
967894A01788F07D00D6CA69 /* griffin.c */,
|
||||
967894971788F02600D6CA69 /* RAGameView.m */,
|
||||
|
@ -214,6 +219,7 @@
|
|||
9678949F1788F02600D6CA69 /* utility.m in Sources */,
|
||||
967894A11788F07D00D6CA69 /* griffin.c in Sources */,
|
||||
9620F663178FD4D3001B3B81 /* settings.m in Sources */,
|
||||
9646869817BBC14E00C5EA69 /* platform.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -354,7 +360,6 @@
|
|||
"-D__LIBRETRO__",
|
||||
"-DRARCH_PERFORMANCE_MODE",
|
||||
"-DRARCH_MOBILE",
|
||||
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
|
||||
"-DHAVE_COREAUDIO",
|
||||
"-DHAVE_DYNAMIC",
|
||||
"-DHAVE_OVERLAY",
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
96366C5516C9AC3300D64A22 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96366C5416C9AC3300D64A22 /* CoreAudio.framework */; };
|
||||
96366C5916C9ACF500D64A22 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96366C5816C9ACF500D64A22 /* AudioToolbox.framework */; };
|
||||
963F5AC816CC523B009BBD19 /* RAGameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 963F5AC516CC523B009BBD19 /* RAGameView.m */; };
|
||||
9646869517BBBEAE00C5EA69 /* platform.m in Sources */ = {isa = PBXBuildFile; fileRef = 9646869417BBBEAE00C5EA69 /* platform.m */; };
|
||||
966B9CBD16E41E7A005B61E1 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CB816E41E7A005B61E1 /* Default-568h@2x.png */; };
|
||||
966B9CBF16E41E7A005B61E1 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CB916E41E7A005B61E1 /* Default.png */; };
|
||||
966B9CC116E41E7A005B61E1 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CBA16E41E7A005B61E1 /* Default@2x.png */; };
|
||||
|
@ -49,6 +50,7 @@
|
|||
96366C5416C9AC3300D64A22 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
|
||||
96366C5816C9ACF500D64A22 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||
963F5AC516CC523B009BBD19 /* RAGameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAGameView.m; sourceTree = "<group>"; };
|
||||
9646869417BBBEAE00C5EA69 /* platform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = platform.m; path = iOS/platform.m; sourceTree = SOURCE_ROOT; };
|
||||
966B9CB816E41E7A005B61E1 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
|
||||
966B9CB916E41E7A005B61E1 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
|
||||
966B9CBA16E41E7A005B61E1 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = "<group>"; };
|
||||
|
@ -152,6 +154,7 @@
|
|||
96AFAE3316C1D4EA009DE44C /* RetroArch */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9646869417BBBEAE00C5EA69 /* platform.m */,
|
||||
967894571788EAAE00D6CA69 /* browser.m */,
|
||||
967894581788EAAE00D6CA69 /* RALogView.m */,
|
||||
967894591788EAAE00D6CA69 /* settings.m */,
|
||||
|
@ -305,6 +308,7 @@
|
|||
9678945B1788EAAE00D6CA69 /* browser.m in Sources */,
|
||||
9678945C1788EAAE00D6CA69 /* RALogView.m in Sources */,
|
||||
9678945D1788EAAE00D6CA69 /* settings.m in Sources */,
|
||||
9646869517BBBEAE00C5EA69 /* platform.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -365,7 +369,6 @@
|
|||
"-D__LIBRETRO__",
|
||||
"-DRARCH_PERFORMANCE_MODE",
|
||||
"-DRARCH_MOBILE",
|
||||
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
|
||||
"-std=gnu99",
|
||||
"-DHAVE_COREAUDIO",
|
||||
"-DHAVE_FBO",
|
||||
|
@ -416,7 +419,6 @@
|
|||
"-D__LIBRETRO__",
|
||||
"-DRARCH_PERFORMANCE_MODE",
|
||||
"-DRARCH_MOBILE",
|
||||
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
|
||||
"-std=gnu99",
|
||||
"-DHAVE_COREAUDIO",
|
||||
"-DHAVE_FBO",
|
||||
|
@ -458,7 +460,6 @@
|
|||
"-D__LIBRETRO__",
|
||||
"-DRARCH_PERFORMANCE_MODE",
|
||||
"-DRARCH_MOBILE",
|
||||
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
|
||||
"-DHAVE_COREAUDIO",
|
||||
"-DHAVE_DYNAMIC",
|
||||
"-DHAVE_OVERLAY",
|
||||
|
@ -502,7 +503,6 @@
|
|||
"-D__LIBRETRO__",
|
||||
"-DRARCH_PERFORMANCE_MODE",
|
||||
"-DRARCH_MOBILE",
|
||||
"-DPACKAGE_VERSION=\\\"0.9.9.3\\\"",
|
||||
"-DHAVE_COREAUDIO",
|
||||
"-DHAVE_DYNAMIC",
|
||||
"-DHAVE_OVERLAY",
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
NSString* rootPath = RetroArch_iOS.get.documentsDirectory;
|
||||
NSString* ragPath = [rootPath stringByAppendingPathComponent:@"RetroArchGames"];
|
||||
RADirectoryList* list = [RADirectoryList directoryListForPath:path_is_directory(ragPath.UTF8String) ? ragPath : rootPath];
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -156,7 +155,7 @@
|
|||
cell.imageView.image = [UIImage imageNamed:@"ic_dir"];
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
} else {
|
||||
cell.imageView.image = nil;
|
||||
cell.imageView.image = [UIImage imageNamed:@"ic_file"];
|
||||
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013 - Jason Fetters
|
||||
* Copyright (C) 2011-2013 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_IOS_PLATFORM_H
|
||||
#define __RARCH_IOS_PLATFORM_H
|
||||
|
||||
@interface RAGameView : UIViewController
|
||||
+ (RAGameView*)get;
|
||||
- (void)openPauseMenu;
|
||||
- (void)closePauseMenu;
|
||||
@end
|
||||
|
||||
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate, RetroArch_Platform>
|
||||
|
||||
+ (RetroArch_iOS*)get;
|
||||
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
|
||||
- (void)unloadingCore:(RAModuleInfo*)core;
|
||||
- (NSString*)retroarchConfigPath;
|
||||
|
||||
- (void)refreshSystemConfig;
|
||||
|
||||
@property (strong, nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents
|
||||
@property (strong, nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch
|
||||
@property (strong, nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg
|
||||
|
||||
@end
|
||||
|
||||
// modes are: keyboard, icade and btstack
|
||||
void ios_set_bluetooth_mode(NSString* mode);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,347 @@
|
|||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2013 - Jason Fetters
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
#import "RetroArch_Apple.h"
|
||||
#include "rarch_wrapper.h"
|
||||
|
||||
#include "../RetroArch/apple_input.h"
|
||||
|
||||
#import "views.h"
|
||||
#include "input/BTStack/btpad.h"
|
||||
#include "input/BTStack/btdynamic.h"
|
||||
#include "input/BTStack/btpad.h"
|
||||
|
||||
#include "file.h"
|
||||
|
||||
//#define HAVE_DEBUG_FILELOG
|
||||
void ios_set_bluetooth_mode(NSString* mode)
|
||||
{
|
||||
apple_input_enable_icade([mode isEqualToString:@"icade"]);
|
||||
btstack_set_poweron([mode isEqualToString:@"btstack"]);
|
||||
}
|
||||
|
||||
// Input helpers: This is kept here because it needs objective-c
|
||||
static void handle_touch_event(NSArray* touches)
|
||||
{
|
||||
const int numTouches = [touches count];
|
||||
const float scale = [[UIScreen mainScreen] scale];
|
||||
|
||||
g_current_input_data.touch_count = 0;
|
||||
|
||||
for(int i = 0; i != numTouches && g_current_input_data.touch_count < MAX_TOUCHES; i ++)
|
||||
{
|
||||
UITouch* touch = [touches objectAtIndex:i];
|
||||
const CGPoint coord = [touch locationInView:touch.view];
|
||||
|
||||
if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
|
||||
{
|
||||
g_current_input_data.touches[g_current_input_data.touch_count ].screen_x = coord.x * scale;
|
||||
g_current_input_data.touches[g_current_input_data.touch_count ++].screen_y = coord.y * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@interface RApplication : UIApplication
|
||||
@end
|
||||
|
||||
@implementation RApplication
|
||||
|
||||
- (void)sendEvent:(UIEvent *)event
|
||||
{
|
||||
[super sendEvent:event];
|
||||
|
||||
if ([[event allTouches] count])
|
||||
handle_touch_event(event.allTouches.allObjects);
|
||||
else if ([event respondsToSelector:@selector(_gsEvent)])
|
||||
{
|
||||
// Stolen from: http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html
|
||||
uint8_t* eventMem = (uint8_t*)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]);
|
||||
int eventType = eventMem ? *(int*)&eventMem[8] : 0;
|
||||
|
||||
if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
|
||||
apple_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
|
||||
|
||||
CFBridgingRelease(eventMem);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RetroArch_iOS
|
||||
{
|
||||
UIWindow* _window;
|
||||
|
||||
bool _isGameTop, _isRomList;
|
||||
uint32_t _settingMenusInBackStack;
|
||||
uint32_t _enabledOrientations;
|
||||
}
|
||||
|
||||
+ (RetroArch_iOS*)get
|
||||
{
|
||||
return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
|
||||
}
|
||||
|
||||
#pragma mark LIFECYCLE (UIApplicationDelegate)
|
||||
- (void)applicationDidFinishLaunching:(UIApplication *)application
|
||||
{
|
||||
apple_platform = self;
|
||||
self.delegate = self;
|
||||
|
||||
// Setup window
|
||||
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
_window.rootViewController = self;
|
||||
[_window makeKeyAndVisible];
|
||||
|
||||
// Build system paths and test permissions
|
||||
self.documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
|
||||
self.systemDirectory = [self.documentsDirectory stringByAppendingPathComponent:@".RetroArch"];
|
||||
self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
|
||||
|
||||
if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
|
||||
apple_display_alert([NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory], 0);
|
||||
else if (!path_make_and_check_directory(self.systemDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
|
||||
apple_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0);
|
||||
else
|
||||
{
|
||||
[self pushViewController:[RADirectoryList directoryListAtBrowseRoot] animated:YES];
|
||||
[self refreshSystemConfig];
|
||||
|
||||
if (apple_use_tv_mode)
|
||||
apple_run_core(nil, 0);
|
||||
}
|
||||
|
||||
// Warn if there are no cores present
|
||||
if ([RAModuleInfo getModules].count == 0)
|
||||
apple_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
apple_exit_stasis();
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application
|
||||
{
|
||||
apple_enter_stasis();
|
||||
}
|
||||
|
||||
// UINavigationControllerDelegate
|
||||
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
|
||||
{
|
||||
_isGameTop = [viewController isKindOfClass:[RAGameView class]];
|
||||
_isRomList = [viewController isKindOfClass:[RADirectoryList class]];
|
||||
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone];
|
||||
[[UIApplication sharedApplication] setIdleTimerDisabled:_isGameTop];
|
||||
|
||||
self.navigationBarHidden = _isGameTop;
|
||||
[self setToolbarHidden:!_isRomList animated:YES];
|
||||
self.topViewController.navigationItem.rightBarButtonItem = [self createSettingsButton];
|
||||
}
|
||||
|
||||
// UINavigationController: Never animate when pushing onto, or popping, an RAGameView
|
||||
- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated
|
||||
{
|
||||
if ([theView respondsToSelector:@selector(isSettingsView)] && [(id)theView isSettingsView])
|
||||
_settingMenusInBackStack ++;
|
||||
|
||||
[super pushViewController:theView animated:animated && !_isGameTop];
|
||||
}
|
||||
|
||||
- (UIViewController*)popViewControllerAnimated:(BOOL)animated
|
||||
{
|
||||
if ([self.topViewController respondsToSelector:@selector(isSettingsView)] && [(id)self.topViewController isSettingsView])
|
||||
_settingMenusInBackStack --;
|
||||
|
||||
return [super popViewControllerAnimated:animated && !_isGameTop];
|
||||
}
|
||||
|
||||
// NOTE: This version only runs on iOS6
|
||||
- (NSUInteger)supportedInterfaceOrientations
|
||||
{
|
||||
return _isGameTop ? _enabledOrientations
|
||||
: UIInterfaceOrientationMaskAll;
|
||||
}
|
||||
|
||||
// NOTE: This version runs on iOS2-iOS5, but not iOS6
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
if (_isGameTop)
|
||||
switch (interfaceOrientation)
|
||||
{
|
||||
case UIInterfaceOrientationPortrait:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskPortrait);
|
||||
case UIInterfaceOrientationPortraitUpsideDown:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeLeft);
|
||||
case UIInterfaceOrientationLandscapeRight:
|
||||
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeRight);
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark RetroArch_Platform
|
||||
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
|
||||
{
|
||||
[self pushViewController:RAGameView.get animated:NO];
|
||||
[RASettingsList refreshModuleConfig:core];
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
|
||||
[self refreshSystemConfig];
|
||||
}
|
||||
|
||||
- (void)unloadingCore:(RAModuleInfo*)core
|
||||
{
|
||||
[self popToViewController:[RAGameView get] animated:NO];
|
||||
[self popViewControllerAnimated:NO];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
|
||||
- (NSString*)retroarchConfigPath
|
||||
{
|
||||
return self.systemDirectory;
|
||||
}
|
||||
|
||||
- (NSString*)corePath
|
||||
{
|
||||
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"];
|
||||
}
|
||||
|
||||
#pragma mark FRONTEND CONFIG
|
||||
- (void)refreshSystemConfig
|
||||
{
|
||||
// Read load time settings
|
||||
config_file_t* conf = config_file_new([self.systemConfigPath UTF8String]);
|
||||
|
||||
if (conf)
|
||||
{
|
||||
// Get enabled orientations
|
||||
static const struct { const char* setting; uint32_t orientation; } orientationSettings[4] =
|
||||
{
|
||||
{ "ios_allow_portrait", UIInterfaceOrientationMaskPortrait },
|
||||
{ "ios_allow_portrait_upside_down", UIInterfaceOrientationMaskPortraitUpsideDown },
|
||||
{ "ios_allow_landscape_left", UIInterfaceOrientationMaskLandscapeLeft },
|
||||
{ "ios_allow_landscape_right", UIInterfaceOrientationMaskLandscapeRight }
|
||||
};
|
||||
|
||||
_enabledOrientations = 0;
|
||||
|
||||
for (int i = 0; i < 4; i ++)
|
||||
{
|
||||
bool enabled = false;
|
||||
bool found = config_get_bool(conf, orientationSettings[i].setting, &enabled);
|
||||
|
||||
if (!found || enabled)
|
||||
_enabledOrientations |= orientationSettings[i].orientation;
|
||||
}
|
||||
|
||||
// Setup bluetooth mode
|
||||
ios_set_bluetooth_mode(objc_get_value_from_config(conf, @"ios_btmode", @"keyboard"));
|
||||
|
||||
bool val;
|
||||
apple_use_tv_mode = config_get_bool(conf, "ios_tv_mode", & val) && val;
|
||||
|
||||
config_file_free(conf);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark PAUSE MENU
|
||||
- (UIBarButtonItem*)createSettingsButton
|
||||
{
|
||||
if (_settingMenusInBackStack == 0)
|
||||
return [[UIBarButtonItem alloc]
|
||||
initWithTitle:@"Settings"
|
||||
style:UIBarButtonItemStyleBordered
|
||||
target:[RetroArch_iOS get]
|
||||
action:@selector(showSystemSettings)];
|
||||
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (IBAction)showPauseMenu:(id)sender
|
||||
{
|
||||
if (apple_is_running && !apple_is_paused && _isGameTop)
|
||||
{
|
||||
apple_is_paused = true;
|
||||
[[RAGameView get] openPauseMenu];
|
||||
|
||||
btpad_set_inquiry_state(true);
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)basicEvent:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(&apple_event_basic_command, ((UIView*)sender).tag);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)chooseState:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(apple_event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex);
|
||||
}
|
||||
|
||||
- (IBAction)showRGUI:(id)sender
|
||||
{
|
||||
if (apple_is_running)
|
||||
apple_frontend_post_event(apple_event_show_rgui, 0);
|
||||
|
||||
[self closePauseMenu:sender];
|
||||
}
|
||||
|
||||
- (IBAction)closePauseMenu:(id)sender
|
||||
{
|
||||
[[RAGameView get] closePauseMenu];
|
||||
apple_is_paused = false;
|
||||
|
||||
btpad_set_inquiry_state(false);
|
||||
}
|
||||
|
||||
- (IBAction)showSettings
|
||||
{
|
||||
[self pushViewController:[[RASettingsList alloc] initWithModule:apple_core] animated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)showSystemSettings
|
||||
{
|
||||
[self pushViewController:[RASystemSettingsList new] animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@autoreleasepool {
|
||||
#if defined(HAVE_DEBUG_FILELOG) && (TARGET_IPHONE_SIMULATOR == 0)
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console_stdout.log"];
|
||||
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stdout);
|
||||
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stderr);
|
||||
#endif
|
||||
return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class]));
|
||||
}
|
||||
}
|
|
@ -28,34 +28,79 @@ enum SettingTypes
|
|||
};
|
||||
|
||||
@interface RASettingData : NSObject
|
||||
@property enum SettingTypes type;
|
||||
{
|
||||
@public
|
||||
enum SettingTypes type;
|
||||
|
||||
@property (strong) NSString* label;
|
||||
@property (strong) NSString* name;
|
||||
@property (strong) NSString* value;
|
||||
NSString* label; // < The label displayed in the settings menu
|
||||
NSString* name; // < The key name of the value in the config file
|
||||
NSString* value; // < The current state of the setting
|
||||
|
||||
@property (strong) NSString* path;
|
||||
@property (strong) NSArray* subValues;
|
||||
@property (strong) NSMutableArray* msubValues;
|
||||
uint32_t player; // < The player that a ButtonSetting represents
|
||||
NSString* button_bind; // < The Gamepad button binding string
|
||||
NSString* axis_bind; // < The Gamepad axis binding string
|
||||
|
||||
NSString* path; // < The base path for FileListSettings
|
||||
NSArray* subValues; // < The available options for EnumerationSettings and FileListSettings
|
||||
bool haveNoneOption; // < Determines if a 'None' option is added to an Enumeration or FileList
|
||||
bool haveDescriptions; // < Determines if subValues containts friendly descriptions for each value
|
||||
|
||||
double rangeMin; // < The mininum value of a range setting
|
||||
double rangeMax; // < The maximum value of a range setting
|
||||
|
||||
void (*changed)(RASettingData* action);
|
||||
void (*reload)(RASettingData* action, id userdata);
|
||||
}
|
||||
|
||||
@property double rangeMin;
|
||||
@property double rangeMax;
|
||||
- (void)setValue:(NSString*)aValue;
|
||||
|
||||
@property uint32_t player;
|
||||
|
||||
@property bool haveNoneOption;
|
||||
|
||||
- (id)initWithType:(enum SettingTypes)aType label:(NSString*)aLabel name:(NSString*)aName;
|
||||
@end
|
||||
|
||||
@implementation RASettingData
|
||||
- (id)initWithType:(enum SettingTypes)aType label:(NSString*)aLabel name:(NSString*)aName
|
||||
{
|
||||
self.type = aType;
|
||||
self.label = aLabel;
|
||||
self.name = aName;
|
||||
type = aType;
|
||||
label = aLabel;
|
||||
name = aName;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setValue:(NSString*)aValue;
|
||||
{
|
||||
value = aValue;
|
||||
|
||||
if (changed)
|
||||
changed(self);
|
||||
}
|
||||
|
||||
- (uint32_t)enumerationCount
|
||||
{
|
||||
return subValues.count / (haveDescriptions ? 2 : 1);
|
||||
}
|
||||
|
||||
- (NSString*)valueForEnumerationIndex:(uint32_t)index
|
||||
{
|
||||
return subValues[index * (haveDescriptions ? 2 : 1)];
|
||||
}
|
||||
|
||||
- (NSString*)labelForEnumerationIndex:(uint32_t)index
|
||||
{
|
||||
return subValues[index * (haveDescriptions ? 2 : 1) + (haveDescriptions ? 1 : 0)];
|
||||
}
|
||||
|
||||
- (NSString*)labelForEnumerationValue
|
||||
{
|
||||
const uint32_t count = self.enumerationCount;
|
||||
|
||||
for (int i = 0; haveDescriptions && i < count; i ++)
|
||||
{
|
||||
if ([value isEqualToString:subValues[i * 2]])
|
||||
return subValues[i * 2 + 1];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// Helper view definitions
|
||||
|
@ -71,7 +116,7 @@ enum SettingTypes
|
|||
static RASettingData* boolean_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue)
|
||||
{
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:BooleanSetting label:label name:name];
|
||||
result.value = objc_get_value_from_config(config, name, defaultValue);
|
||||
result->value = objc_get_value_from_config(config, name, defaultValue);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -80,27 +125,26 @@ static RASettingData* button_setting(config_file_t* config, uint32_t player, NSS
|
|||
NSString* realname = player ? [NSString stringWithFormat:@"input_player%d_%@", player, name] : name;
|
||||
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:ButtonSetting label:label name:realname];
|
||||
result.msubValues = [NSMutableArray arrayWithObjects:
|
||||
objc_get_value_from_config(config, realname, defaultValue),
|
||||
objc_get_value_from_config(config, [realname stringByAppendingString:@"_btn"], @"nul"),
|
||||
objc_get_value_from_config(config, [realname stringByAppendingString:@"_axis"], @"nul"),
|
||||
nil];
|
||||
result.player = player ? player - 1 : 0;
|
||||
result->player = player ? player - 1 : 0;
|
||||
result->value = objc_get_value_from_config(config, realname, defaultValue);
|
||||
result->button_bind = objc_get_value_from_config(config, [realname stringByAppendingString:@"_btn"], @"nul");
|
||||
result->axis_bind = objc_get_value_from_config(config, [realname stringByAppendingString:@"_axis"], @"nul");
|
||||
return result;
|
||||
}
|
||||
|
||||
static RASettingData* group_setting(NSString* label, NSArray* settings)
|
||||
{
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:GroupSetting label:label name:nil];
|
||||
result.subValues = settings;
|
||||
result->subValues = settings;
|
||||
return result;
|
||||
}
|
||||
|
||||
static RASettingData* enumeration_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, NSArray* values)
|
||||
static RASettingData* enumeration_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, NSArray* values, bool haveDescriptions)
|
||||
{
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:EnumerationSetting label:label name:name];
|
||||
result.value = objc_get_value_from_config(config, name, defaultValue);
|
||||
result.subValues = values;
|
||||
result->value = objc_get_value_from_config(config, name, defaultValue);
|
||||
result->subValues = values;
|
||||
result->haveDescriptions = haveDescriptions;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -113,19 +157,19 @@ static RASettingData* subpath_setting(config_file_t* config, NSString* name, NSS
|
|||
values = [values pathsMatchingExtensions:[NSArray arrayWithObject:extension]];
|
||||
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:FileListSetting label:label name:name];
|
||||
result.value = value;
|
||||
result.subValues = values;
|
||||
result.path = path;
|
||||
result.haveNoneOption = true;
|
||||
result->value = value;
|
||||
result->subValues = values;
|
||||
result->path = path;
|
||||
result->haveNoneOption = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
static RASettingData* range_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, double minValue, double maxValue)
|
||||
{
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:RangeSetting label:label name:name];
|
||||
result.value = objc_get_value_from_config(config, name, defaultValue);
|
||||
result.rangeMin = minValue;
|
||||
result.rangeMax = maxValue;
|
||||
result->value = objc_get_value_from_config(config, name, defaultValue);
|
||||
result->rangeMin = minValue;
|
||||
result->rangeMax = maxValue;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -133,8 +177,8 @@ static RASettingData* aspect_setting(config_file_t* config, NSString* label)
|
|||
{
|
||||
// Why does this need to be so difficult?
|
||||
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:AspectSetting label:label name:@"fram"];
|
||||
result.subValues = [NSArray arrayWithObjects:@"Fill Screen", @"Game Aspect", @"Pixel Aspect", @"4:3", @"16:9", nil];
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:AspectSetting label:label name:@""];
|
||||
result->subValues = [NSArray arrayWithObjects:@"Fill Screen", @"Game Aspect", @"Pixel Aspect", @"4:3", @"16:9", nil];
|
||||
|
||||
bool videoForceAspect = true;
|
||||
bool videoAspectAuto = false;
|
||||
|
@ -148,19 +192,20 @@ static RASettingData* aspect_setting(config_file_t* config, NSString* label)
|
|||
}
|
||||
|
||||
if (!videoForceAspect)
|
||||
result.value = @"Fill Screen";
|
||||
result->value = @"Fill Screen";
|
||||
else if (videoAspect < 0.0)
|
||||
result.value = videoAspectAuto ? @"Game Aspect" : @"Pixel Aspect";
|
||||
result->value = videoAspectAuto ? @"Game Aspect" : @"Pixel Aspect";
|
||||
else
|
||||
result.value = (videoAspect < 1.5) ? @"4:3" : @"16:9";
|
||||
result->value = (videoAspect < 1.5) ? @"4:3" : @"16:9";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
||||
static RASettingData* custom_action(NSString* action, NSString* value, id data, void (*reload_func)(RASettingData* action, id userdata))
|
||||
{
|
||||
RASettingData* result = [[RASettingData alloc] initWithType:CustomAction label:action name:nil];
|
||||
result.value = value;
|
||||
result->value = value;
|
||||
result->reload = reload_func;
|
||||
|
||||
if (data != nil)
|
||||
objc_setAssociatedObject(result, "USERDATA", data, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
|
@ -168,25 +213,36 @@ static RASettingData* custom_action(NSString* action, NSString* value, id data)
|
|||
return result;
|
||||
}
|
||||
|
||||
// This adds a change notify function to a setting and returns it; done this way so it can be used in NSArray
|
||||
// init lists.
|
||||
static RASettingData* change_notify(RASettingData* setting, void (*change_func)(RASettingData* setting))
|
||||
{
|
||||
setting->changed = change_func;
|
||||
return setting;
|
||||
}
|
||||
|
||||
static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
||||
{
|
||||
// Only player 1 should have default key bindings
|
||||
#define DEFKEY(val) (player == 1) ? val : @"nul"
|
||||
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSArray arrayWithObjects:[NSString stringWithFormat:@"Player %d", player],
|
||||
button_setting(config, player, @"up", @"Up", @"up"),
|
||||
button_setting(config, player, @"down", @"Down", @"down"),
|
||||
button_setting(config, player, @"left", @"Left", @"left"),
|
||||
button_setting(config, player, @"right", @"Right", @"right"),
|
||||
button_setting(config, player, @"up", @"Up", DEFKEY(@"up")),
|
||||
button_setting(config, player, @"down", @"Down", DEFKEY(@"down")),
|
||||
button_setting(config, player, @"left", @"Left", DEFKEY(@"left")),
|
||||
button_setting(config, player, @"right", @"Right", DEFKEY(@"right")),
|
||||
|
||||
button_setting(config, player, @"start", @"Start", @"enter"),
|
||||
button_setting(config, player, @"select", @"Select", @"rshift"),
|
||||
button_setting(config, player, @"start", @"Start", DEFKEY(@"enter")),
|
||||
button_setting(config, player, @"select", @"Select", DEFKEY(@"rshift")),
|
||||
|
||||
button_setting(config, player, @"b", @"B", @"z"),
|
||||
button_setting(config, player, @"a", @"A", @"x"),
|
||||
button_setting(config, player, @"x", @"X", @"s"),
|
||||
button_setting(config, player, @"y", @"Y", @"a"),
|
||||
button_setting(config, player, @"b", @"B", DEFKEY(@"z")),
|
||||
button_setting(config, player, @"a", @"A", DEFKEY(@"x")),
|
||||
button_setting(config, player, @"x", @"X", DEFKEY(@"s")),
|
||||
button_setting(config, player, @"y", @"Y", DEFKEY(@"a")),
|
||||
|
||||
button_setting(config, player, @"l", @"L", @"q"),
|
||||
button_setting(config, player, @"r", @"R", @"w"),
|
||||
button_setting(config, player, @"l", @"L", DEFKEY(@"q")),
|
||||
button_setting(config, player, @"r", @"R", DEFKEY(@"w")),
|
||||
button_setting(config, player, @"l2", @"L2", @"nul"),
|
||||
button_setting(config, player, @"r2", @"R2", @"nul"),
|
||||
button_setting(config, player, @"l3", @"L3", @"nul"),
|
||||
|
@ -219,7 +275,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
- (id)initWithModule:(RAModuleInfo*)module
|
||||
{
|
||||
_module = module;
|
||||
_configPath = RetroArch_iOS.get.retroarchConfigPath;
|
||||
_configPath = _module ? _module.configPath : RAModuleInfo.globalConfigPath;
|
||||
|
||||
config_file_t* config = config_file_new([_configPath UTF8String]);
|
||||
|
||||
|
@ -228,7 +284,8 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
|
||||
NSArray* settings = [NSArray arrayWithObjects:
|
||||
[NSArray arrayWithObjects:@"Core",
|
||||
custom_action(@"Core Info", nil, nil),
|
||||
custom_action(@"Core Info", nil, nil, 0),
|
||||
_module.hasCustomConfig ? custom_action(@"Delete Custom Config", nil, nil, 0) : nil,
|
||||
nil],
|
||||
|
||||
[NSArray arrayWithObjects:@"Video",
|
||||
|
@ -251,7 +308,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
|
||||
[NSArray arrayWithObjects:@"Input",
|
||||
subpath_setting(config, @"input_overlay", @"Input Overlay", @"", overlay_path, @"cfg"),
|
||||
range_setting(config, @"input_overlay_opacity", @"Overlay Opacity", @"1.0", 0.0, 1.0),
|
||||
range_setting(config, @"overlay_opacity", @"Overlay Opacity", @"1.0", 0.0, 1.0),
|
||||
group_setting(@"System Keys", [NSArray arrayWithObjects:
|
||||
// TODO: Many of these strings will be cut off on an iPhone
|
||||
[NSArray arrayWithObjects:@"System Keys",
|
||||
|
@ -305,37 +362,71 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
if (config)
|
||||
{
|
||||
config_set_string(config, "system_directory", [[RetroArch_iOS get].systemDirectory UTF8String]);
|
||||
config_set_string(config, "savefile_directory", [[RetroArch_iOS get].systemDirectory UTF8String]);
|
||||
config_set_string(config, "savestate_directory", [[RetroArch_iOS get].systemDirectory UTF8String]);
|
||||
[self writeSettings:nil toConfig:config];
|
||||
config_file_write(config, [_configPath UTF8String]);
|
||||
config_file_free(config);
|
||||
}
|
||||
|
||||
[[RetroArch_iOS get] refreshConfig];
|
||||
apple_refresh_config();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleCustomAction:(RASettingData*)setting
|
||||
{
|
||||
if ([@"Core Info" isEqualToString:setting.label])
|
||||
if ([@"Core Info" isEqualToString:setting->label])
|
||||
[[RetroArch_iOS get] pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:_module] animated:YES];
|
||||
else if([@"Delete Custom Config" isEqualToString:setting->label])
|
||||
{
|
||||
[_module deleteCustomConfig];
|
||||
_cancelSave = true;
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark System Settings
|
||||
|
||||
static void reload_core_config_state(RASettingData* action, RAModuleInfo* userdata)
|
||||
{
|
||||
[action setValue:userdata.hasCustomConfig ? @"[Custom]" : @"[Global]"];
|
||||
}
|
||||
|
||||
static void bluetooth_option_changed(RASettingData* setting)
|
||||
{
|
||||
ios_set_bluetooth_mode(setting->value);
|
||||
}
|
||||
|
||||
@implementation RASystemSettingsList
|
||||
- (id)init
|
||||
{
|
||||
config_file_t* config = config_file_new([[RetroArch_iOS get].systemConfigPath UTF8String]);
|
||||
|
||||
NSMutableArray* modules = [NSMutableArray array];
|
||||
[modules addObject:@"Cores"];
|
||||
[modules addObject:custom_action(@"Global Core Config", nil, nil, 0)];
|
||||
|
||||
NSArray* moduleList = [RAModuleInfo getModules];
|
||||
for (RAModuleInfo* i in moduleList)
|
||||
{
|
||||
[modules addObject:custom_action(i.description, nil, i, reload_core_config_state)];
|
||||
}
|
||||
|
||||
|
||||
NSArray* bluetoothOptions = [NSArray arrayWithObjects:@"keyboard", @"Keyboard",
|
||||
@"icade", @"iCade Device",
|
||||
btstack_try_load() ? @"btstack" : nil, @"WiiMote/SixAxis (BTstack)",
|
||||
nil];
|
||||
|
||||
NSArray* settings = [NSArray arrayWithObjects:
|
||||
[NSArray arrayWithObjects:@"Frontend",
|
||||
custom_action(@"Diagnostic Log", nil, nil),
|
||||
custom_action(@"Diagnostic Log", nil, nil, 0),
|
||||
boolean_setting(config, @"ios_tv_mode", @"TV Mode", @"false"),
|
||||
nil],
|
||||
[NSArray arrayWithObjects:@"Bluetooth",
|
||||
// TODO: Note that with this turned off the native bluetooth is expected to be a real keyboard
|
||||
boolean_setting(config, @"ios_use_icade", @"Native BT is iCade", @"false"),
|
||||
btstack_try_load() ? boolean_setting(config, @"ios_use_btstack", @"Enable BTstack", @"false") : nil,
|
||||
change_notify(enumeration_setting(config, @"ios_btmode", @"Mode", @"keyboard", bluetoothOptions, true), bluetooth_option_changed),
|
||||
nil],
|
||||
[NSArray arrayWithObjects:@"Orientations",
|
||||
boolean_setting(config, @"ios_allow_portrait", @"Portrait", @"true"),
|
||||
|
@ -343,9 +434,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
boolean_setting(config, @"ios_allow_landscape_left", @"Landscape Left", @"true"),
|
||||
boolean_setting(config, @"ios_allow_landscape_right", @"Landscape Right", @"true"),
|
||||
nil],
|
||||
[NSArray arrayWithObjects:@"Cores",
|
||||
custom_action(@"Core Configuration", nil, nil),
|
||||
nil],
|
||||
modules,
|
||||
nil
|
||||
];
|
||||
|
||||
|
@ -356,6 +445,12 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[self.tableView reloadData];
|
||||
[super viewDidAppear:animated];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
config_file_t* config = config_file_new([[RetroArch_iOS get].systemConfigPath UTF8String]);
|
||||
|
@ -375,12 +470,49 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
|
||||
- (void)handleCustomAction:(RASettingData*)setting
|
||||
{
|
||||
if ([@"Diagnostic Log" isEqualToString:setting.label])
|
||||
if ([@"Diagnostic Log" isEqualToString:setting->label])
|
||||
[[RetroArch_iOS get] pushViewController:[RALogView new] animated:YES];
|
||||
else if ([@"Enable BTstack" isEqualToString:setting.label])
|
||||
btstack_set_poweron([setting.value isEqualToString:@"true"]);
|
||||
else if([@"Core Configuration" isEqualToString:setting.label])
|
||||
else if ([@"Enable BTstack" isEqualToString:setting->label])
|
||||
btstack_set_poweron([setting->value isEqualToString:@"true"]);
|
||||
else if([@"Global Core Config" isEqualToString:setting->label])
|
||||
[RetroArch_iOS.get pushViewController:[[RASettingsList alloc] initWithModule:nil] animated:YES];
|
||||
else
|
||||
{
|
||||
RAModuleInfo* data = (RAModuleInfo*)objc_getAssociatedObject(setting, "USERDATA");
|
||||
if (data)
|
||||
{
|
||||
if (!data.hasCustomConfig)
|
||||
{
|
||||
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch"
|
||||
message:@"No custom configuration for this core exists, "
|
||||
"would you like to create one?"
|
||||
delegate:self
|
||||
cancelButtonTitle:@"No"
|
||||
otherButtonTitles:@"Yes", nil];
|
||||
objc_setAssociatedObject(alert, "MODULE", data, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
[alert show];
|
||||
}
|
||||
else
|
||||
[RetroArch_iOS.get pushViewController:[[RASettingsList alloc] initWithModule:data] animated:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)alertView:(UIAlertView*)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
RAModuleInfo* data = (RAModuleInfo*)objc_getAssociatedObject(alertView, "MODULE");
|
||||
|
||||
if (data)
|
||||
{
|
||||
if (buttonIndex == alertView.firstOtherButtonIndex)
|
||||
{
|
||||
[data createCustomConfig];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
[RetroArch_iOS.get pushViewController:[[RASettingsList alloc] initWithModule:data] animated:YES];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -420,35 +552,35 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
{
|
||||
RASettingData* setting = [group objectAtIndex:j];
|
||||
|
||||
switch (setting.type)
|
||||
switch (setting->type)
|
||||
{
|
||||
case GroupSetting:
|
||||
[self writeSettings:setting.subValues toConfig:config];
|
||||
[self writeSettings:setting->subValues toConfig:config];
|
||||
break;
|
||||
|
||||
case FileListSetting:
|
||||
if ([setting.value length] > 0)
|
||||
config_set_string(config, [setting.name UTF8String], [[setting.path stringByAppendingPathComponent:setting.value] UTF8String]);
|
||||
if ([setting->value length] > 0)
|
||||
config_set_string(config, [setting->name UTF8String], [[setting->path stringByAppendingPathComponent:setting->value] UTF8String]);
|
||||
else
|
||||
config_set_string(config, [setting.name UTF8String], "");
|
||||
config_set_string(config, [setting->name UTF8String], "");
|
||||
break;
|
||||
|
||||
case ButtonSetting:
|
||||
if (setting.msubValues[0])
|
||||
config_set_string(config, [setting.name UTF8String], [setting.msubValues[0] UTF8String]);
|
||||
if (setting.msubValues[1])
|
||||
config_set_string(config, [[setting.name stringByAppendingString:@"_btn"] UTF8String], [setting.msubValues[1] UTF8String]);
|
||||
if (setting.msubValues[2])
|
||||
config_set_string(config, [[setting.name stringByAppendingString:@"_axis"] UTF8String], [setting.msubValues[2] UTF8String]);
|
||||
if (setting->value)
|
||||
config_set_string(config, [setting->name UTF8String], [setting->value UTF8String]);
|
||||
if (setting->button_bind)
|
||||
config_set_string(config, [[setting->name stringByAppendingString:@"_btn"] UTF8String], [setting->button_bind UTF8String]);
|
||||
if (setting->axis_bind)
|
||||
config_set_string(config, [[setting->name stringByAppendingString:@"_axis"] UTF8String], [setting->axis_bind UTF8String]);
|
||||
break;
|
||||
|
||||
case AspectSetting:
|
||||
config_set_string(config, "video_force_aspect", [@"Fill Screen" isEqualToString:setting.value] ? "false" : "true");
|
||||
config_set_string(config, "video_aspect_ratio_auto", [@"Game Aspect" isEqualToString:setting.value] ? "true" : "false");
|
||||
config_set_string(config, "video_force_aspect", [@"Fill Screen" isEqualToString:setting->value] ? "false" : "true");
|
||||
config_set_string(config, "video_aspect_ratio_auto", [@"Game Aspect" isEqualToString:setting->value] ? "true" : "false");
|
||||
config_set_string(config, "video_aspect_ratio", "-1.0");
|
||||
if([@"4:3" isEqualToString:setting.value])
|
||||
if([@"4:3" isEqualToString:setting->value])
|
||||
config_set_string(config, "video_aspect_ratio", "1.33333333");
|
||||
else if([@"16:9" isEqualToString:setting.value])
|
||||
else if([@"16:9" isEqualToString:setting->value])
|
||||
config_set_string(config, "video_aspect_ratio", "1.77777777");
|
||||
break;
|
||||
|
||||
|
@ -456,7 +588,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
break;
|
||||
|
||||
default:
|
||||
config_set_string(config, [setting.name UTF8String], [setting.value UTF8String]);
|
||||
config_set_string(config, [setting->name UTF8String], [setting->value UTF8String]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -467,7 +599,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
{
|
||||
RASettingData* setting = (RASettingData*)[self itemForIndexPath:indexPath];
|
||||
|
||||
switch (setting.type)
|
||||
switch (setting->type)
|
||||
{
|
||||
case EnumerationSetting:
|
||||
case FileListSetting:
|
||||
|
@ -480,7 +612,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
break;
|
||||
|
||||
case GroupSetting:
|
||||
[[RetroArch_iOS get] pushViewController:[[RASettingsSubList alloc] initWithSettings:setting.subValues title:setting.label] animated:YES];
|
||||
[[RetroArch_iOS get] pushViewController:[[RASettingsSubList alloc] initWithSettings:setting->subValues title:setting->label] animated:YES];
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -493,7 +625,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
- (void)handleBooleanSwitch:(UISwitch*)swt
|
||||
{
|
||||
RASettingData* setting = objc_getAssociatedObject(swt, "SETTING");
|
||||
setting.value = (swt.on ? @"true" : @"false");
|
||||
[setting setValue:swt.on ? @"true" : @"false"];
|
||||
|
||||
[self handleCustomAction:setting];
|
||||
}
|
||||
|
@ -501,7 +633,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
- (void)handleSlider:(UISlider*)sld
|
||||
{
|
||||
RASettingData* setting = objc_getAssociatedObject(sld, "SETTING");
|
||||
setting.value = [NSString stringWithFormat:@"%f", sld.value];
|
||||
[setting setValue:[NSString stringWithFormat:@"%f", sld.value]];
|
||||
|
||||
[self handleCustomAction:setting];
|
||||
}
|
||||
|
@ -512,7 +644,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
|
||||
UITableViewCell* cell = nil;
|
||||
|
||||
switch (setting.type)
|
||||
switch (setting->type)
|
||||
{
|
||||
case BooleanSetting:
|
||||
{
|
||||
|
@ -529,10 +661,10 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
}
|
||||
|
||||
cell.textLabel.text = setting.label;
|
||||
cell.textLabel.text = setting->label;
|
||||
|
||||
UISwitch* swt = (UISwitch*)cell.accessoryView;
|
||||
swt.on = [setting.value isEqualToString:@"true"];
|
||||
swt.on = [setting->value isEqualToString:@"true"];
|
||||
objc_setAssociatedObject(swt, "SETTING", setting, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
|
||||
return cell;
|
||||
|
@ -554,12 +686,12 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
}
|
||||
|
||||
cell.textLabel.text = setting.label;
|
||||
cell.textLabel.text = setting->label;
|
||||
|
||||
UISlider* sld = (UISlider*)cell.accessoryView;
|
||||
sld.minimumValue = setting.rangeMin;
|
||||
sld.maximumValue = setting.rangeMax;
|
||||
sld.value = [setting.value doubleValue];
|
||||
sld.minimumValue = setting->rangeMin;
|
||||
sld.maximumValue = setting->rangeMax;
|
||||
sld.value = [setting->value doubleValue];
|
||||
objc_setAssociatedObject(sld, "SETTING", setting, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
|
||||
return cell;
|
||||
|
@ -575,16 +707,21 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"default"];
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
|
||||
cell.textLabel.text = setting.label;
|
||||
|
||||
if (setting->reload)
|
||||
setting->reload(setting, objc_getAssociatedObject(setting, "USERDATA"));
|
||||
|
||||
cell.textLabel.text = setting->label;
|
||||
|
||||
if (setting.type != ButtonSetting)
|
||||
cell.detailTextLabel.text = setting.value;
|
||||
else
|
||||
if (setting->type == ButtonSetting)
|
||||
cell.detailTextLabel.text = [NSString stringWithFormat:@"[KB:%@] [JS:%@] [AX:%@]",
|
||||
[setting.msubValues[0] length] ? setting.msubValues[0] : @"nul",
|
||||
[setting.msubValues[1] length] ? setting.msubValues[1] : @"nul",
|
||||
[setting.msubValues[2] length] ? setting.msubValues[2] : @"nul"];
|
||||
[setting->value length] ? setting->value : @"nul",
|
||||
[setting->button_bind length] ? setting->button_bind : @"nul",
|
||||
[setting->axis_bind length] ? setting->axis_bind : @"nul"];
|
||||
else if(setting->type == EnumerationSetting)
|
||||
cell.detailTextLabel.text = setting.labelForEnumerationValue;
|
||||
else
|
||||
cell.detailTextLabel.text = setting->value;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
@ -606,20 +743,20 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
|
||||
_value = setting;
|
||||
_view = table;
|
||||
_mainSection = _value.haveNoneOption ? 1 : 0;
|
||||
_mainSection = _value->haveNoneOption ? 1 : 0;
|
||||
|
||||
[self setTitle: _value.label];
|
||||
[self setTitle: _value->label];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
|
||||
{
|
||||
return _value.haveNoneOption ? 2 : 1;
|
||||
return _value->haveNoneOption ? 2 : 1;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return (section == _mainSection) ? _value.subValues.count : 1;
|
||||
return (section == _mainSection) ? _value.enumerationCount : 1;
|
||||
}
|
||||
|
||||
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
|
@ -627,14 +764,17 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"option"];
|
||||
cell = cell ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"option"];
|
||||
|
||||
cell.textLabel.text = (indexPath.section == _mainSection) ? _value.subValues[indexPath.row] : @"None";
|
||||
if (indexPath.section == _mainSection)
|
||||
cell.textLabel.text = [_value labelForEnumerationIndex:indexPath.row];
|
||||
else
|
||||
cell.textLabel.text = @"None";
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
_value.value = (indexPath.section == _mainSection) ? _value.subValues[indexPath.row] : @"";
|
||||
[_value setValue: (indexPath.section == _mainSection) ? [_value valueForEnumerationIndex:indexPath.row] : @""];
|
||||
|
||||
[_view reloadData];
|
||||
[[RetroArch_iOS get] popViewControllerAnimated:YES];
|
||||
|
@ -661,7 +801,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
_me = self;
|
||||
|
||||
_alert = [[UIAlertView alloc] initWithTitle:@"RetroArch"
|
||||
message:_value.label
|
||||
message:_value->label
|
||||
delegate:self
|
||||
cancelButtonTitle:@"Cancel"
|
||||
otherButtonTitles:@"Clear Keyboard", @"Clear Joystick", @"Clear Axis", nil];
|
||||
|
@ -689,11 +829,11 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
- (void)alertView:(UIAlertView*)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
if (buttonIndex == _alert.firstOtherButtonIndex)
|
||||
_value.msubValues[0] = @"nul";
|
||||
_value->value = @"nul";
|
||||
else if(buttonIndex == _alert.firstOtherButtonIndex + 1)
|
||||
_value.msubValues[1] = @"nul";
|
||||
_value->button_bind = @"nul";
|
||||
else if(buttonIndex == _alert.firstOtherButtonIndex + 2)
|
||||
_value.msubValues[2] = @"nul";
|
||||
_value->axis_bind = @"nul";
|
||||
|
||||
[self finish];
|
||||
}
|
||||
|
@ -755,23 +895,25 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
{ "nul", 0x00},
|
||||
};
|
||||
|
||||
|
||||
for (int i = 0; ios_key_name_map[i].hid_id; i++)
|
||||
{
|
||||
if (g_current_input_data.keys[ios_key_name_map[i].hid_id])
|
||||
{
|
||||
_value.msubValues[0] = [NSString stringWithUTF8String:ios_key_name_map[i].keyname];
|
||||
_value->value = [NSString stringWithUTF8String:ios_key_name_map[i].keyname];
|
||||
[self finish];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad Buttons
|
||||
for (int i = 0; g_current_input_data.pad_buttons[_value.player] && i < sizeof(g_current_input_data.pad_buttons[_value.player]) * 8; i++)
|
||||
uint32_t buttons = g_current_input_data.pad_buttons[_value->player] |
|
||||
((_value->player == 0) ? apple_input_get_icade_buttons() : 0);
|
||||
|
||||
for (int i = 0; buttons && i < sizeof(buttons) * 8; i++)
|
||||
{
|
||||
if (g_current_input_data.pad_buttons[_value.player] & (1 << i))
|
||||
if (buttons & (1 << i))
|
||||
{
|
||||
_value.msubValues[1] = [NSString stringWithFormat:@"%d", i];
|
||||
_value->button_bind = [NSString stringWithFormat:@"%d", i];
|
||||
[self finish];
|
||||
return;
|
||||
}
|
||||
|
@ -780,11 +922,11 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
|
|||
// Pad Axis
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int16_t value = g_current_input_data.pad_axis[_value.player][i];
|
||||
int16_t value = g_current_input_data.pad_axis[_value->player][i];
|
||||
|
||||
if (abs(value) > 0x1000)
|
||||
{
|
||||
_value.msubValues[2] = [NSString stringWithFormat:@"%s%d", (value > 0x1000) ? "+" : "-", i];
|
||||
_value->axis_bind = [NSString stringWithFormat:@"%s%d", (value > 0x1000) ? "+" : "-", i];
|
||||
[self finish];
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
display_name = "SNES / Super Famicom (SNES9x Next)"
|
||||
supported_extensions = "smc|sfc"
|
||||
corename = "bsnes/higan Performance"
|
||||
manufacturer = "Nintendo"
|
||||
systemname = "Super Nintendo Entertainment System"
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "Nintendo DS"
|
||||
display_name = "Nintendo DS (DeSmuME)"
|
||||
supported_extensions = "nds"
|
||||
corename = "DeSmuME"
|
||||
manufacturer = "Nintendo"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "Game Boy / Game Boy Color"
|
||||
display_name = "Game Boy / Game Boy Color (Gambatte)"
|
||||
supported_extensions = "gb|gbc|dmg"
|
||||
corename = "gambatte"
|
||||
manufacturer = "Nintendo"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "Sega (MS/GG/MD/CD)"
|
||||
display_name = "Sega MS/GG/MD/CD (Genesis Plus GX)"
|
||||
supported_extensions = "md|smd|gen|sms|gg|sg|bin|cue|ios"
|
||||
corename = "Genesis Plus GX"
|
||||
manufacturer = "Sega"
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
display_name = "PNG Images (InstancingViewer)"
|
||||
recommended_extensions = "png"
|
||||
corename = "InstancingViewer"
|
||||
manufacturer = "Various"
|
||||
systemname = "Instantiation of objects"
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "Neo Geo Pocket (Color)"
|
||||
display_name = "Neo Geo Pocket/Color (Mednafen Neopop)"
|
||||
supported_extensions = "ngp|ngc"
|
||||
corename = "Mednafen Neopop"
|
||||
manufacturer = "SNK"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "PC Engine/TurboGrafx-16"
|
||||
display_name = "PC Engine/TurboGrafx-16 (Mednafen PCE Fast)"
|
||||
supported_extensions = "pce|sgx|cue"
|
||||
corename = "Mednafen PCE Fast"
|
||||
manufacturer = "NEC"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "Virtual Boy"
|
||||
display_name = "Virtual Boy (Mednafen VB)"
|
||||
supported_extensions = "vb|vboy|bin"
|
||||
corename = "Mednafen VB"
|
||||
manufacturer = "Nintendo"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
display_name = "WonderSwan (Color)"
|
||||
display_name = "WonderSwan/Color (Mednafen Cygne)"
|
||||
supported_extensions = "ws|wsc"
|
||||
corename = "Mednafen WonderSwan"
|
||||
manufacturer = "Bandai"
|
||||
systemname = "WonderSwan (Color)"
|
||||
systemname = "WonderSwan/Color"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "Modelviewer"
|
||||
display_name = "3D Models (Modelviewer)"
|
||||
recommended_extensions = "obj"
|
||||
corename = "Modelviewer"
|
||||
manufacturer = "Various"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
display_name = "NXEngine (Cave Story)"
|
||||
display_name = "Cave Story (NXEngine)"
|
||||
supported_extensions = "exe"
|
||||
corename = "NXEngine"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "Sega (MS/GG/MD/CD/32X)"
|
||||
display_name = "Sega MS/GG/MD/CD/32X (Picodrive)"
|
||||
supported_extensions = "md|smd|gen|sms|gg|sg|bin|cue|ios|32x"
|
||||
corename = "Picodrive"
|
||||
manufacturer = "Sega"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
display_name = "PrBoom (DOOM)"
|
||||
display_name = "Doom (PrBoom)"
|
||||
supported_extensions = "wad|iwad"
|
||||
corename = "prboom"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "SceneWalker"
|
||||
display_name = "3D Models (SceneWalker)"
|
||||
recommended_extensions = "obj"
|
||||
corename = "SceneWalker"
|
||||
manufacturer = "Various"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
display_name = "Atari 2600"
|
||||
display_name = "Atari 2600 (Stella)"
|
||||
supported_extensions = "a26|bin"
|
||||
corename = "Stella"
|
||||
manufacturer = "Atari"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
display_name = "TyrQuake"
|
||||
display_name = "Quake 1 (TyrQuake)"
|
||||
supported_extensions = "pak"
|
||||
corename = "prboom"
|
||||
|
|
|
@ -23,7 +23,7 @@ if [ -z "$NOCODESIGN" ] ; then
|
|||
|
||||
xcrun -sdk iphoneos PackageApplication "$BUILD_PATH/RetroArch.app" -o "$BUILD_PATH/RetroArch.ipa" --sign "$CODE_SIGN_IDENTITY" --embed "$BUILD_PATH/RetroArch.app/embedded.mobileprovision"
|
||||
else
|
||||
xcodebuild -verbose -sdk iphoneos -configuration Release
|
||||
xcodebuild -verbose -sdk iphoneos -configuration Release -project $PROJECT_NAME
|
||||
echo "Building for Jailbroken system"
|
||||
fi
|
||||
|
||||
|
|
|
@ -33,13 +33,10 @@
|
|||
|
||||
#define SLPlayItf_SetPlayState(a, ...) ((*(a))->SetPlayState(a, __VA_ARGS__))
|
||||
|
||||
// TODO: Are these sane?
|
||||
#define BUFFER_SIZE (2 * 1024)
|
||||
#define BUFFER_COUNT 16
|
||||
|
||||
typedef struct sl
|
||||
{
|
||||
uint8_t buffer[BUFFER_COUNT][BUFFER_SIZE];
|
||||
uint8_t **buffer;
|
||||
uint8_t *buffer_chunk;
|
||||
unsigned buffer_index;
|
||||
unsigned buffer_ptr;
|
||||
volatile unsigned buffered_blocks;
|
||||
|
@ -55,6 +52,7 @@ typedef struct sl
|
|||
slock_t *lock;
|
||||
scond_t *cond;
|
||||
bool nonblock;
|
||||
unsigned buf_size;
|
||||
unsigned buf_count;
|
||||
} sl_t;
|
||||
|
||||
|
@ -93,6 +91,8 @@ static void sl_free(void *data)
|
|||
if (sl->cond)
|
||||
scond_free(sl->cond);
|
||||
|
||||
free(sl->buffer);
|
||||
free(sl->buffer_chunk);
|
||||
free(sl);
|
||||
}
|
||||
|
||||
|
@ -115,6 +115,8 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
|
|||
if (!sl)
|
||||
goto error;
|
||||
|
||||
RARCH_LOG("[SLES ] : Requested audio latency: %dms...", latency);
|
||||
|
||||
GOTO_IF_FAIL(slCreateEngine(&sl->engine_object, 0, NULL, 0, NULL, NULL));
|
||||
GOTO_IF_FAIL(SLObjectItf_Realize(sl->engine_object, SL_BOOLEAN_FALSE));
|
||||
GOTO_IF_FAIL(SLObjectItf_GetInterface(sl->engine_object, SL_IID_ENGINE, &sl->engine));
|
||||
|
@ -122,11 +124,23 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
|
|||
GOTO_IF_FAIL(SLEngineItf_CreateOutputMix(sl->engine, &sl->output_mix, 0, NULL, NULL));
|
||||
GOTO_IF_FAIL(SLObjectItf_Realize(sl->output_mix, SL_BOOLEAN_FALSE));
|
||||
|
||||
sl->buf_size = next_pow2(32 * latency);
|
||||
sl->buf_count = (latency * 4 * out_rate + 500) / 1000;
|
||||
sl->buf_count = (sl->buf_count + BUFFER_SIZE / 2) / BUFFER_SIZE;
|
||||
sl->buf_count = min(sl->buf_count, BUFFER_COUNT);
|
||||
sl->buf_count = (sl->buf_count + sl->buf_size / 2) / sl->buf_size;
|
||||
|
||||
RARCH_LOG("[SLES] : Setting audio latency (buffer size: [%d]) ...\n", sl->buf_count * BUFFER_SIZE);
|
||||
sl->buffer = (uint8_t**)calloc(sizeof(uint8_t*), sl->buf_count);
|
||||
if (!sl->buffer)
|
||||
goto error;
|
||||
|
||||
sl->buffer_chunk = (uint8_t*)calloc(sl->buf_count, sl->buf_size);
|
||||
if (!sl->buffer_chunk)
|
||||
goto error;
|
||||
|
||||
for (unsigned i = 0; i < sl->buf_count; i++)
|
||||
sl->buffer[i] = sl->buffer_chunk + i * sl->buf_size;
|
||||
|
||||
RARCH_LOG("[SLES] : Setting audio latency: Block size = %u, Blocks = %u, Total = %u ...\n",
|
||||
sl->buf_size, sl->buf_count, sl->buf_size * sl->buf_count);
|
||||
|
||||
fmt_pcm.formatType = SL_DATAFORMAT_PCM;
|
||||
fmt_pcm.numChannels = 2;
|
||||
|
@ -164,7 +178,7 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency)
|
|||
sl->buffered_blocks = sl->buf_count;
|
||||
sl->buffer_index = 0;
|
||||
for (unsigned i = 0; i < sl->buf_count; i++)
|
||||
(*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[i], BUFFER_SIZE);
|
||||
(*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[i], sl->buf_size);
|
||||
|
||||
GOTO_IF_FAIL(SLObjectItf_GetInterface(sl->buffer_queue_object, SL_IID_PLAY, &sl->player));
|
||||
GOTO_IF_FAIL(SLPlayItf_SetPlayState(sl->player, SL_PLAYSTATE_PLAYING));
|
||||
|
@ -218,7 +232,7 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
|||
slock_unlock(sl->lock);
|
||||
}
|
||||
|
||||
size_t avail_write = min(BUFFER_SIZE - sl->buffer_ptr, size);
|
||||
size_t avail_write = min(sl->buf_size - sl->buffer_ptr, size);
|
||||
if (avail_write)
|
||||
{
|
||||
memcpy(sl->buffer[sl->buffer_index] + sl->buffer_ptr, buf, avail_write);
|
||||
|
@ -228,9 +242,9 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
|||
written += avail_write;
|
||||
}
|
||||
|
||||
if (sl->buffer_ptr >= BUFFER_SIZE)
|
||||
if (sl->buffer_ptr >= sl->buf_size)
|
||||
{
|
||||
SLresult res = (*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[sl->buffer_index], BUFFER_SIZE);
|
||||
SLresult res = (*sl->buffer_queue)->Enqueue(sl->buffer_queue, sl->buffer[sl->buffer_index], sl->buf_size);
|
||||
sl->buffer_index = (sl->buffer_index + 1) % sl->buf_count;
|
||||
__sync_fetch_and_add(&sl->buffered_blocks, 1);
|
||||
sl->buffer_ptr = 0;
|
||||
|
@ -243,22 +257,26 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
|||
}
|
||||
}
|
||||
|
||||
//RARCH_LOG("Blocks: %u\n", sl->buffered_blocks);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
static size_t sl_write_avail(void *data)
|
||||
{
|
||||
sl_t *sl = (sl_t*)data;
|
||||
size_t avail = (sl->buf_count - (int)sl->buffered_blocks - 1) * BUFFER_SIZE + (BUFFER_SIZE - (int)sl->buffer_ptr);
|
||||
size_t avail = (sl->buf_count - (int)sl->buffered_blocks - 1) * sl->buf_size + (sl->buf_size - (int)sl->buffer_ptr);
|
||||
return avail;
|
||||
}
|
||||
|
||||
static size_t sl_buffer_size(void *data)
|
||||
{
|
||||
sl_t *sl = (sl_t*)data;
|
||||
return BUFFER_SIZE * sl->buf_count;
|
||||
return sl->buf_size * sl->buf_count;
|
||||
}
|
||||
|
||||
static bool sl_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return false;
|
||||
}
|
||||
|
||||
const audio_driver_t audio_opensl = {
|
||||
|
@ -268,7 +286,7 @@ const audio_driver_t audio_opensl = {
|
|||
sl_start,
|
||||
sl_set_nonblock_state,
|
||||
sl_free,
|
||||
NULL,
|
||||
sl_use_float,
|
||||
"opensl",
|
||||
sl_write_avail,
|
||||
sl_buffer_size,
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "thread_wrapper.h"
|
||||
#include "../thread.h"
|
||||
#include "../general.h"
|
||||
#include "../performance.h"
|
||||
#include "../fifo_buffer.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct audio_thread
|
||||
{
|
||||
const audio_driver_t *driver;
|
||||
void *driver_data;
|
||||
|
||||
sthread_t *thread;
|
||||
slock_t *lock;
|
||||
scond_t *cond;
|
||||
bool alive;
|
||||
bool stopped;
|
||||
} audio_thread_t;
|
||||
|
||||
static void audio_thread_loop(void *data)
|
||||
{
|
||||
audio_thread_t *thr = (audio_thread_t*)data;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
slock_lock(thr->lock);
|
||||
|
||||
if (!thr->alive)
|
||||
{
|
||||
scond_signal(thr->cond);
|
||||
slock_unlock(thr->lock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (thr->stopped)
|
||||
{
|
||||
thr->driver->stop(thr->driver_data);
|
||||
while (thr->stopped)
|
||||
scond_wait(thr->cond, thr->lock);
|
||||
thr->driver->start(thr->driver_data);
|
||||
}
|
||||
|
||||
slock_unlock(thr->lock);
|
||||
g_extern.system.audio_callback();
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_thread_block(audio_thread_t *thr)
|
||||
{
|
||||
slock_lock(thr->lock);
|
||||
thr->stopped = true;
|
||||
scond_signal(thr->cond);
|
||||
slock_unlock(thr->lock);
|
||||
}
|
||||
|
||||
static void audio_thread_unblock(audio_thread_t *thr)
|
||||
{
|
||||
slock_lock(thr->lock);
|
||||
thr->stopped = false;
|
||||
scond_signal(thr->cond);
|
||||
slock_unlock(thr->lock);
|
||||
}
|
||||
|
||||
static void audio_thread_free(void *data)
|
||||
{
|
||||
audio_thread_t *thr = (audio_thread_t*)data;
|
||||
slock_lock(thr->lock);
|
||||
thr->stopped = false;
|
||||
thr->alive = false;
|
||||
scond_signal(thr->cond);
|
||||
slock_unlock(thr->lock);
|
||||
|
||||
sthread_join(thr->thread);
|
||||
|
||||
thr->driver->free(thr->driver_data);
|
||||
slock_free(thr->lock);
|
||||
scond_free(thr->cond);
|
||||
free(thr);
|
||||
}
|
||||
|
||||
static bool audio_thread_stop(void *data)
|
||||
{
|
||||
audio_thread_t *thr = (audio_thread_t*)data;
|
||||
audio_thread_block(thr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool audio_thread_start(void *data)
|
||||
{
|
||||
audio_thread_t *thr = (audio_thread_t*)data;
|
||||
audio_thread_unblock(thr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void audio_thread_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
(void)data;
|
||||
(void)state;
|
||||
}
|
||||
|
||||
static bool audio_thread_use_float(void *data)
|
||||
{
|
||||
audio_thread_t *thr = (audio_thread_t*)data;
|
||||
return thr->driver->use_float && thr->driver->use_float(thr->driver_data);
|
||||
}
|
||||
|
||||
static ssize_t audio_thread_write(void *data, const void *buf, size_t size)
|
||||
{
|
||||
audio_thread_t *thr = (audio_thread_t*)data;
|
||||
ssize_t ret = thr->driver->write(thr->driver_data, buf, size);
|
||||
if (ret < 0)
|
||||
{
|
||||
slock_lock(thr->lock);
|
||||
thr->alive = false;
|
||||
scond_signal(thr->cond);
|
||||
slock_unlock(thr->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const audio_driver_t audio_thread = {
|
||||
NULL,
|
||||
audio_thread_write,
|
||||
audio_thread_stop,
|
||||
audio_thread_start,
|
||||
audio_thread_set_nonblock_state,
|
||||
audio_thread_free,
|
||||
audio_thread_use_float,
|
||||
"audio-thread",
|
||||
NULL, // No point in using rate control with threaded audio.
|
||||
NULL,
|
||||
};
|
||||
|
||||
bool rarch_threaded_audio_init(const audio_driver_t **out_driver, void **out_data,
|
||||
const char *device, unsigned out_rate, unsigned latency,
|
||||
const audio_driver_t *driver)
|
||||
{
|
||||
void *audio_handle = driver->init(device, out_rate, latency);
|
||||
if (!audio_handle)
|
||||
return false;
|
||||
|
||||
audio_thread_t *thr = (audio_thread_t*)calloc(1, sizeof(*thr));
|
||||
if (!thr)
|
||||
{
|
||||
driver->free(audio_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
thr->driver = driver;
|
||||
thr->driver_data = audio_handle;
|
||||
|
||||
thr->cond = scond_new();
|
||||
thr->lock = slock_new();
|
||||
thr->alive = true;
|
||||
thr->stopped = true;
|
||||
|
||||
thr->thread = sthread_create(audio_thread_loop, thr);
|
||||
|
||||
*out_driver = &audio_thread;
|
||||
*out_data = thr;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch 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 Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch 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 RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RARCH_AUDIO_THREAD_H__
|
||||
#define RARCH_AUDIO_THREAD_H__
|
||||
|
||||
#include "../driver.h"
|
||||
#include "../boolean.h"
|
||||
|
||||
// Starts a audio driver in a new thread.
|
||||
// Access to audio driver will be mediated through this driver.
|
||||
// This driver interfaces with audio callback and is only used in that case.
|
||||
bool rarch_threaded_audio_init(const audio_driver_t **out_driver, void **out_data,
|
||||
const char *device, unsigned out_rate, unsigned latency,
|
||||
const audio_driver_t *driver);
|
||||
|
||||
#endif
|
||||
|
|
@ -77,7 +77,7 @@ static void autosave_thread(void *data)
|
|||
|
||||
slock_lock(save->cond_lock);
|
||||
if (!save->quit)
|
||||
scond_wait_timeout(save->cond, save->cond_lock, save->interval * 1000);
|
||||
scond_wait_timeout(save->cond, save->cond_lock, save->interval * 1000000LL);
|
||||
slock_unlock(save->cond_lock);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ DEFINES += HAVE_RGUI HAVE_NEON RARCH_MOBILE \
|
|||
SINC_LOWER_QUALITY HAVE_RARCH_MAIN_IMPLEMENTATION \
|
||||
HAVE_VID_CONTEXT HAVE_FBO HAVE_GRIFFIN __LIBRETRO__ \
|
||||
HAVE_DYNAMIC HAVE_ZLIB __BLACKBERRY_QNX__ HAVE_OPENGLES \
|
||||
PACKAGE_VERSION=\"0.9.9\" HAVE_OPENGLES2 HAVE_NULLINPUT \
|
||||
HAVE_OPENGLES2 HAVE_NULLINPUT \
|
||||
HAVE_AL HAVE_THREADS WANT_MINIZ HAVE_OVERLAY HAVE_GLSL \
|
||||
USING_GL20 HAVE_OPENGL __STDC_CONSTANT_MACROS HAVE_BB10
|
||||
|
||||
|
|
|
@ -28,6 +28,11 @@ Page
|
|||
value: 3
|
||||
}
|
||||
]
|
||||
|
||||
onSelectedValueChanged:
|
||||
{
|
||||
ButtonMap.refreshButtonMap(selectedValue)
|
||||
}
|
||||
}
|
||||
|
||||
actions: [
|
||||
|
@ -36,7 +41,7 @@ Page
|
|||
ActionBar.placement: ActionBarPlacement.OnBar
|
||||
imageSource: "asset:///images/search.png"
|
||||
onTriggered: {
|
||||
RetroArch.discoverController();
|
||||
RetroArch.discoverController(players.selectedValue);
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -48,17 +53,39 @@ Page
|
|||
preferredWidth: 650
|
||||
horizontalAlignment: HorizontalAlignment.Center
|
||||
|
||||
DropDown
|
||||
Container
|
||||
{
|
||||
objectName: "dropdown_devices"
|
||||
title: "Device"
|
||||
horizontalAlignment: HorizontalAlignment.Center
|
||||
layout: StackLayout
|
||||
{
|
||||
orientation: LayoutOrientation.LeftToRight
|
||||
}
|
||||
|
||||
DropDown
|
||||
{
|
||||
horizontalAlignment: HorizontalAlignment.Left
|
||||
id: dropdown_device
|
||||
objectName: "dropdown_devices"
|
||||
title: "Device"
|
||||
}
|
||||
|
||||
Button
|
||||
{
|
||||
horizontalAlignment: HorizontalAlignment.Right
|
||||
text: "Set"
|
||||
|
||||
onClicked:
|
||||
{
|
||||
ButtonMap.mapDevice(dropdown_device.selectedValue, players.selectedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView
|
||||
{
|
||||
id: buttonMapList
|
||||
objectName: "buttonMapList"
|
||||
|
||||
|
||||
listItemComponents: [
|
||||
ListItemComponent
|
||||
{
|
||||
|
@ -109,14 +136,13 @@ Page
|
|||
}
|
||||
}
|
||||
]
|
||||
|
||||
//TODO: Map specific devices instead of 0.
|
||||
|
||||
onTriggered:
|
||||
{
|
||||
var sym, data;
|
||||
data = dataModel.data(indexPath);
|
||||
sym = RetroArch.mapButton(0, players.selectedValue, data["index"]);
|
||||
data["button"] = RetroArch.buttonToString(0, sym);
|
||||
sym = ButtonMap.mapButton(0, players.selectedValue, data["index"]);
|
||||
data["button"] = ButtonMap.buttonToString(players.selectedValue, sym);
|
||||
dataModel.replace(indexPath, data);
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
<asset path="../../media/overlays">overlays</asset>
|
||||
<asset path="assets">assets</asset>
|
||||
<asset path="assets/images/icon.png">icon.png</asset>
|
||||
<asset path="../../ios/modules">lib</asset>
|
||||
<asset path="../../apple/modules">lib</asset>
|
||||
|
||||
|
||||
<!-- Bright theme is used for this application. -->
|
||||
|
|
|
@ -65,7 +65,7 @@ ButtonMap::ButtonMap(screen_context_t screen_ctx, QString groupId, int coid)
|
|||
|
||||
buttonDataModel = new ArrayDataModel();
|
||||
|
||||
refreshButtonMap();
|
||||
refreshButtonMap(0);
|
||||
}
|
||||
|
||||
ButtonMap::~ButtonMap()
|
||||
|
@ -78,100 +78,75 @@ QString ButtonMap::getLabel(int button)
|
|||
return QString((uint)platform_keys[button].joykey);
|
||||
}
|
||||
|
||||
//pass in RARCH button enum for button, map to g_setting
|
||||
int ButtonMap::mapNextButtonPressed()
|
||||
{
|
||||
bps_event_t *event = NULL;
|
||||
int sym;
|
||||
int ButtonMap::mapNextButtonPressed()
|
||||
{
|
||||
bps_event_t *event = NULL;
|
||||
int sym;
|
||||
|
||||
//use in frontend run loop, get key pressed back, and map
|
||||
int z = 10;
|
||||
if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &z) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
//use in frontend run loop, get key pressed back, and map
|
||||
int z = 10;
|
||||
if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &z) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
screen_post_window(screen_win, screen_buf, 1, screen_resolution, 0);
|
||||
screen_post_window(screen_win, screen_buf, 1, screen_resolution, 0);
|
||||
|
||||
while(1){
|
||||
if (BPS_SUCCESS != bps_get_event(&event, -1))
|
||||
{
|
||||
fprintf(stderr, "bps_get_event failed\n");
|
||||
break;
|
||||
}
|
||||
while(1)
|
||||
{
|
||||
if (BPS_SUCCESS != bps_get_event(&event, -1))
|
||||
{
|
||||
fprintf(stderr, "bps_get_event failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (event)
|
||||
{
|
||||
int domain = bps_event_get_domain(event);
|
||||
if (event)
|
||||
{
|
||||
int domain = bps_event_get_domain(event);
|
||||
|
||||
if (domain == screen_get_domain())
|
||||
{
|
||||
screen_event_t screen_event = screen_event_get_event(event);
|
||||
int screen_val;
|
||||
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &screen_val);
|
||||
if (domain == screen_get_domain())
|
||||
{
|
||||
screen_event_t screen_event = screen_event_get_event(event);
|
||||
int screen_val;
|
||||
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &screen_val);
|
||||
|
||||
//TODO: Should we only let the buttons through that we are trying to map?
|
||||
if(screen_val == SCREEN_EVENT_MTOUCH_TOUCH)
|
||||
{
|
||||
//This is touch screen event
|
||||
sym = -1;
|
||||
break;
|
||||
}
|
||||
else if(screen_val == SCREEN_EVENT_KEYBOARD)
|
||||
{
|
||||
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &sym);
|
||||
sym &= 0xFF;
|
||||
break;
|
||||
}
|
||||
else if( (screen_val == SCREEN_EVENT_GAMEPAD) || (screen_val == SCREEN_EVENT_JOYSTICK) )
|
||||
{
|
||||
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &sym);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO: Should we only let the buttons through that we are trying to map?
|
||||
if(screen_val == SCREEN_EVENT_MTOUCH_TOUCH)
|
||||
{
|
||||
//This is touch screen event
|
||||
sym = NO_BTN;
|
||||
break;
|
||||
}
|
||||
else if(screen_val == SCREEN_EVENT_KEYBOARD)
|
||||
{
|
||||
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &sym);
|
||||
sym &= 0xFF;
|
||||
break;
|
||||
}
|
||||
else if( (screen_val == SCREEN_EVENT_GAMEPAD) || (screen_val == SCREEN_EVENT_JOYSTICK) )
|
||||
{
|
||||
screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &sym);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
z = -10;
|
||||
if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &z) != 0) {
|
||||
return -1;
|
||||
}
|
||||
z = -10;
|
||||
if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &z) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
screen_post_window(screen_win, screen_buf, 1, screen_resolution, 0);
|
||||
screen_post_window(screen_win, screen_buf, 1, screen_resolution, 0);
|
||||
|
||||
return (g_settings.input.binds[player][button].joykey = sym);
|
||||
}
|
||||
return (g_settings.input.binds[player][button].joykey = sym);
|
||||
}
|
||||
|
||||
int ButtonMap::getButtonMapping(int player, int button)
|
||||
{
|
||||
return g_settings.input.binds[player][button].joykey;
|
||||
}
|
||||
|
||||
QString ButtonMap::buttonToString(int button)
|
||||
{
|
||||
for(int i=0;i<20;++i)
|
||||
{
|
||||
if(platform_keys[i].joykey == (uint)button)
|
||||
{
|
||||
return QString(platform_keys[i].desc);
|
||||
}
|
||||
}
|
||||
|
||||
return (button!=NO_BTN) ? QString(button) : QString("Not Mapped");
|
||||
}
|
||||
|
||||
int ButtonMap::requestButtonMapping(screen_device_t device, int player, int button)
|
||||
{
|
||||
//Send message to run thread to start mapping, wait for reply.
|
||||
recv_msg msg;
|
||||
msg.code = RETROARCH_BUTTON_MAP;
|
||||
|
||||
this->device = device;
|
||||
this->player = player;
|
||||
this->button = button;
|
||||
|
||||
return MsgSend(coid, (void*)&msg, sizeof(msg), (void*)NULL, 0);
|
||||
}
|
||||
int ButtonMap::getButtonMapping(int player, int button)
|
||||
{
|
||||
return g_settings.input.binds[player][button].joykey;
|
||||
}
|
||||
|
||||
void ButtonMap::mapDevice(int index, int player)
|
||||
{
|
||||
|
@ -179,16 +154,16 @@ void ButtonMap::mapDevice(int index, int player)
|
|||
input_qnx.set_keybinds((void*)&devices[index], devices[index].device, player, 0,
|
||||
(1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS));
|
||||
|
||||
refreshButtonMap();
|
||||
refreshButtonMap(player);
|
||||
}
|
||||
|
||||
void ButtonMap::refreshButtonMap()
|
||||
{
|
||||
void ButtonMap::refreshButtonMap(int player)
|
||||
{
|
||||
QVariantMap map;
|
||||
|
||||
buttonDataModel->clear();
|
||||
|
||||
for(int i=0; i<16; ++i)
|
||||
for (int i=0; i<16; ++i)
|
||||
{
|
||||
QString desc = QString(input_config_bind_map[i].desc);
|
||||
int index = desc.indexOf("(");
|
||||
|
@ -198,15 +173,56 @@ void ButtonMap::mapDevice(int index, int player)
|
|||
}
|
||||
|
||||
map.insert("label",QVariant(desc));
|
||||
map.insert("button", buttonToString(g_settings.input.binds[0][i].joykey));
|
||||
map.insert("button", buttonToString(player, g_settings.input.binds[player][i].joykey));
|
||||
map.insert("type", QVariant("item"));
|
||||
map.insert("index", QVariant(i));
|
||||
buttonDataModel->append(map);
|
||||
}
|
||||
|
||||
map.insert("label",QVariant("RetroArch Menu"));
|
||||
map.insert("button", buttonToString(g_settings.input.binds[0][RARCH_MENU_TOGGLE].joykey));
|
||||
map.insert("button", buttonToString(player, g_settings.input.binds[player][RARCH_MENU_TOGGLE].joykey));
|
||||
map.insert("type", QVariant("item"));
|
||||
map.insert("index", QVariant(RARCH_MENU_TOGGLE));
|
||||
buttonDataModel->append(map);
|
||||
}
|
||||
|
||||
//Update device dropdown
|
||||
if (deviceSelection)
|
||||
{
|
||||
if(port_device[player])
|
||||
deviceSelection->setSelectedIndex(port_device[player]->index);
|
||||
else
|
||||
deviceSelection->resetSelectedIndex();
|
||||
}
|
||||
}
|
||||
|
||||
//Button map
|
||||
int ButtonMap::mapButton(int player, int button)
|
||||
{
|
||||
recv_msg msg;
|
||||
msg.code = RETROARCH_BUTTON_MAP;
|
||||
|
||||
this->player = player;
|
||||
this->button = button;
|
||||
|
||||
return MsgSend(coid, (void*)&msg, sizeof(msg), (void*)NULL, 0);
|
||||
}
|
||||
|
||||
QString ButtonMap::buttonToString(int player, int button)
|
||||
{
|
||||
if(g_settings.input.device[player] == DEVICE_KEYPAD || g_settings.input.device[player] == DEVICE_KEYBOARD)
|
||||
{
|
||||
return QString(button);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i=0;i<20;++i)
|
||||
{
|
||||
if(platform_keys[i].joykey == (uint)button)
|
||||
{
|
||||
return QString(platform_keys[i].desc);
|
||||
}
|
||||
}
|
||||
|
||||
return (button!=NO_BTN) ? QString(button) : QString("Not Mapped");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <bb/cascades/Application>
|
||||
#include <bb/cascades/ArrayDataModel>
|
||||
#include <bb/cascades/DropDown>
|
||||
|
||||
#include <screen/screen.h>
|
||||
#include <sys/neutrino.h>
|
||||
|
@ -19,8 +20,9 @@ typedef struct {
|
|||
|
||||
using namespace bb::cascades;
|
||||
|
||||
class ButtonMap
|
||||
class ButtonMap: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ButtonMap(screen_context_t screen_cxt, QString groupId, int coid);
|
||||
|
@ -33,12 +35,15 @@ public:
|
|||
int getButtonMapping(int player, int button);
|
||||
//Call from frontend
|
||||
int requestButtonMapping(screen_device_t device, int player, int button);
|
||||
void refreshButtonMap();
|
||||
void mapDevice(int index, int player);
|
||||
|
||||
QString buttonToString(int button);
|
||||
|
||||
Q_INVOKABLE int mapButton(int player, int button);
|
||||
Q_INVOKABLE QString buttonToString(int player, int button);
|
||||
Q_INVOKABLE void refreshButtonMap(int player);
|
||||
Q_INVOKABLE void mapDevice(int index, int player);
|
||||
|
||||
ArrayDataModel *buttonDataModel;
|
||||
DropDown *deviceSelection;
|
||||
|
||||
private:
|
||||
screen_context_t screen_cxt;
|
||||
|
|
|
@ -95,9 +95,10 @@ RetroArch::RetroArch()
|
|||
screen_create_context(&screen_ctx, 0);
|
||||
input_qnx.init();
|
||||
buttonMap = new ButtonMap(screen_ctx, (const char*)Application::instance()->mainWindow()->groupId().toAscii().constData(), coid);
|
||||
qml->setContextProperty("ButtonMap", buttonMap);
|
||||
|
||||
deviceSelection = mAppPane->findChild<DropDown*>("dropdown_devices");
|
||||
connect(deviceSelection, SIGNAL(selectedValueChanged(QVariant)), this, SLOT(onDeviceSelected(QVariant)));
|
||||
buttonMap->deviceSelection = deviceSelection;
|
||||
findDevices();
|
||||
|
||||
//Setup the datamodel for button mapping.
|
||||
|
@ -257,13 +258,6 @@ void RetroArch::onCoreSelected(QVariant value)
|
|||
qDebug() << "Supported Extensions: " << romExtensions;
|
||||
}
|
||||
|
||||
void RetroArch::onDeviceSelected(QVariant value)
|
||||
{
|
||||
//Change the binds for current player to device[value]
|
||||
//TODO: Don't hardcode player 0
|
||||
buttonMap->mapDevice(value.toInt(), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
@ -327,6 +321,16 @@ void RetroArch::findDevices()
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" void discoverControllers();
|
||||
void RetroArch::discoverController(int player)
|
||||
{
|
||||
//TODO: Check device, gamepad/keyboard and return accordingly.
|
||||
discoverControllers();
|
||||
findDevices();
|
||||
buttonMap->refreshButtonMap(player);
|
||||
return;
|
||||
}
|
||||
|
||||
void RetroArch::initRASettings()
|
||||
{
|
||||
strlcpy(g_settings.libretro,(char *)core.toAscii().constData(), sizeof(g_settings.libretro));
|
||||
|
@ -339,28 +343,3 @@ void RetroArch::initRASettings()
|
|||
if(hwInfo->isPhysicalKeyboardDevice() || port_device[0])
|
||||
*g_settings.input.overlay = '\0';
|
||||
}
|
||||
|
||||
int RetroArch::mapButton(void* deviceVp, int player, int button)
|
||||
{
|
||||
screen_device_t device = (screen_device_t)deviceVp;
|
||||
return buttonMap->requestButtonMapping(device, player, button);
|
||||
}
|
||||
|
||||
QString RetroArch::buttonToString(void* deviceVp, int button)
|
||||
{
|
||||
//TODO: Check deviceVp, gamepad/keyboard and return accordingly.
|
||||
if(g_settings.input.device[0] == DEVICE_KEYPAD || g_settings.input.device[0] == DEVICE_KEYBOARD)
|
||||
return QString(button);
|
||||
else
|
||||
return buttonMap->buttonToString(button);
|
||||
}
|
||||
|
||||
extern "C" void discoverControllers();
|
||||
void RetroArch::discoverController()
|
||||
{
|
||||
//TODO: Check device, gamepad/keyboard and return accordingly.
|
||||
discoverControllers();
|
||||
findDevices();
|
||||
buttonMap->refreshButtonMap();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -35,9 +35,7 @@ public:
|
|||
|
||||
Q_INVOKABLE void startEmulator();
|
||||
Q_INVOKABLE void findDevices();
|
||||
Q_INVOKABLE int mapButton(void* device, int player, int button);
|
||||
Q_INVOKABLE QString buttonToString(void* deviceVp, int button);
|
||||
Q_INVOKABLE void discoverController();
|
||||
Q_INVOKABLE void discoverController(int player);
|
||||
void populateCores(core_info_list_t * info);
|
||||
|
||||
signals:
|
||||
|
@ -49,7 +47,6 @@ public slots:
|
|||
void aboutToQuit();
|
||||
void onRotationCompleted();
|
||||
void onCoreSelected(QVariant);
|
||||
void onDeviceSelected(QVariant);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
|
|
@ -19,6 +19,7 @@ typedef struct {
|
|||
char device_name[64];
|
||||
int device;
|
||||
int port;
|
||||
int index;
|
||||
|
||||
// Current state.
|
||||
int buttons;
|
||||
|
|
|
@ -168,7 +168,7 @@
|
|||
<listOptionValue builtIn="false" value="HAVE_OPENGLES"/>
|
||||
<listOptionValue builtIn="false" value="HAVE_OPENGLES2"/>
|
||||
<listOptionValue builtIn="false" value="HAVE_NULLINPUT"/>
|
||||
<listOptionValue builtIn="false" value="HAVE_ALSA"/>
|
||||
<listOptionValue builtIn="false" value="HAVE_AL"/>
|
||||
<listOptionValue builtIn="false" value="HAVE_THREADS"/>
|
||||
<listOptionValue builtIn="false" value="WANT_MINIZ"/>
|
||||
<listOptionValue builtIn="false" value="HAVE_OVERLAY"/>
|
||||
|
|
|
@ -131,6 +131,8 @@ void discoverControllers()
|
|||
{
|
||||
// Get an array of all available devices.
|
||||
int deviceCount;
|
||||
screen_event_t *event;
|
||||
|
||||
screen_get_context_property_iv(screen_ctx, SCREEN_PROPERTY_DEVICE_COUNT, &deviceCount);
|
||||
screen_device_t* devices_found = (screen_device_t*)calloc(deviceCount, sizeof(screen_device_t));
|
||||
screen_get_context_property_pv(screen_ctx, SCREEN_PROPERTY_DEVICES, (void**)devices_found);
|
||||
|
@ -151,9 +153,9 @@ void discoverControllers()
|
|||
if (type == SCREEN_EVENT_GAMEPAD || type == SCREEN_EVENT_JOYSTICK || type == SCREEN_EVENT_KEYBOARD)
|
||||
{
|
||||
devices[pads_connected].handle = devices_found[i];
|
||||
devices[pads_connected].index = pads_connected;
|
||||
loadController(&devices[pads_connected]);
|
||||
|
||||
pads_connected++;
|
||||
if (pads_connected == MAX_PADS)
|
||||
break;
|
||||
}
|
||||
|
@ -184,6 +186,7 @@ static void initController(input_device_t* controller)
|
|||
controller->analog1[0] = controller->analog1[1] = controller->analog1[2] = 0;
|
||||
controller->port = -1;
|
||||
controller->device = -1;
|
||||
controller->index = -1;
|
||||
memset(controller->id, 0, sizeof(controller->id));
|
||||
}
|
||||
|
||||
|
@ -225,9 +228,12 @@ static void qnx_input_autodetect_gamepad(input_device_t* controller)
|
|||
strlcpy(controller->device_name, "None", sizeof(controller->device_name));
|
||||
}
|
||||
|
||||
if (input_qnx.set_keybinds)
|
||||
if (input_qnx.set_keybinds && (controller->device != DEVICE_NONE))
|
||||
{
|
||||
input_qnx.set_keybinds((void*)controller, controller->device, pads_connected, 0,
|
||||
(1ULL << KEYBINDS_ACTION_SET_DEFAULT_BINDS));
|
||||
pads_connected++;
|
||||
}
|
||||
}
|
||||
|
||||
static void process_keyboard_event(screen_event_t event, int type)
|
||||
|
@ -730,10 +736,10 @@ static void qnx_input_set_keybinds(void *data, unsigned device, unsigned port,
|
|||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].def_joykey = KEYCODE_K & 0xFF;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].def_joykey = KEYCODE_U & 0xFF;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].def_joykey = KEYCODE_I & 0xFF;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = KEYCODE_P & 0xFF;
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
controller->port = port;
|
||||
|
@ -756,10 +762,10 @@ static void qnx_input_set_keybinds(void *data, unsigned device, unsigned port,
|
|||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].def_joykey = KEYCODE_S & 0xFF;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].def_joykey = KEYCODE_Q & 0xFF;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].def_joykey = KEYCODE_W & 0xFF;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = KEYCODE_TILDE;
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
controller->port = port;
|
||||
|
@ -811,7 +817,7 @@ static void qnx_input_set_keybinds(void *data, unsigned device, unsigned port,
|
|||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = SCREEN_R2_GAME_BUTTON;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = SCREEN_L3_GAME_BUTTON;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = SCREEN_R3_GAME_BUTTON;
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = 0; //TODO: Find a good mappnig
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = NO_BTN; //TODO: Find a good mappnig
|
||||
g_settings.input.dpad_emulation[port] = ANALOG_DPAD_NONE;
|
||||
controller->port = port;
|
||||
port_device[port] = controller;
|
||||
|
@ -821,23 +827,23 @@ static void qnx_input_set_keybinds(void *data, unsigned device, unsigned port,
|
|||
strlcpy(g_settings.input.device_names[port], "None",
|
||||
sizeof(g_settings.input.device_names[port]));
|
||||
g_settings.input.device[port] = device;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = 0;
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = 0;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_B].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_Y].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_SELECT].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_START].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_UP].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_DOWN].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_LEFT].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_RIGHT].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_A].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_X].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L2].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R2].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_L3].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RETRO_DEVICE_ID_JOYPAD_R3].def_joykey = NO_BTN;
|
||||
g_settings.input.binds[port][RARCH_MENU_TOGGLE].def_joykey = NO_BTN;
|
||||
controller->port = -1;
|
||||
port_device[port] = 0;
|
||||
break;
|
||||
|
|
|
@ -44,6 +44,7 @@ enum
|
|||
VIDEO_D3D9,
|
||||
VIDEO_VG,
|
||||
VIDEO_NULL,
|
||||
VIDEO_OMAP,
|
||||
|
||||
AUDIO_RSOUND,
|
||||
AUDIO_OSS,
|
||||
|
@ -380,6 +381,9 @@ static const bool savestate_auto_load = true;
|
|||
// Slowmotion ratio.
|
||||
static const float slowmotion_ratio = 3.0;
|
||||
|
||||
// Maximum fast forward ratio (Negative => no limit).
|
||||
static const float fastforward_ratio = -1.0;
|
||||
|
||||
// Enable stdin/network command interface
|
||||
static const bool network_cmd_enable = false;
|
||||
static const uint16_t network_cmd_port = 55355;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
PACKAGE_NAME=retroarch
|
||||
PACKAGE_VERSION=0.9.9
|
||||
|
||||
cat /dev/null > config.log
|
||||
|
||||
|
|
|
@ -706,7 +706,7 @@ struct mz_zip_internal_state_tag
|
|||
#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size
|
||||
#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]
|
||||
|
||||
static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
|
||||
static void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
|
||||
{
|
||||
def_free_func(pZip->m_pAlloc_opaque, pArray->m_p);
|
||||
memset(pArray, 0, sizeof(mz_zip_array));
|
||||
|
@ -721,7 +721,7 @@ static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *
|
|||
return MZ_TRUE;
|
||||
}
|
||||
|
||||
static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
|
||||
static mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
|
||||
{
|
||||
if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; }
|
||||
pArray->m_size = new_size;
|
||||
|
@ -748,7 +748,7 @@ static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags
|
|||
return MZ_TRUE;
|
||||
}
|
||||
|
||||
static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)
|
||||
static mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)
|
||||
{
|
||||
const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
|
||||
const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
|
||||
|
|
|
@ -1,3 +1,61 @@
|
|||
------------------------------------------------------------------------------
|
||||
v0.9.9.6
|
||||
------------------------------------------------------------------------------
|
||||
* [VBA Next] Fixes serious regressions - most evident in Golden Sun games -
|
||||
battle screens etc.
|
||||
* [VBA Next] Add a core option to change the control button layout from (left
|
||||
to right) B to A to (left to right) A to B.
|
||||
* [Android] Added Load Game History to Android Java UI
|
||||
* [Android] Will show a progressbar dialog during asset extraction so that the
|
||||
user knows what is happening.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
v0.9.9.5
|
||||
------------------------------------------------------------------------------
|
||||
* [Android] Input autodetection fixes -
|
||||
- DualShock3 pad controls fixed
|
||||
* [Android] It should now be possible to map D-pad to analog on several gamepads, such as:
|
||||
- Xbox 360
|
||||
- PlayStation3
|
||||
- Shield
|
||||
* [Android] Threaded video is now the default due to positive user feedback. Purists and accuracy
|
||||
people can still go for static syncing for best results - although for PCSX ReARMed threaded
|
||||
video is essential. With the combination of threaded video and dynamic audio rate control,
|
||||
most of the audio pops and sync issues should be a thing of the past now. Yay.
|
||||
* [Android] UI has been reorganized and made less shitty (yes, we know). Still a long
|
||||
way to go there. The entire menu should be gamepad-controllable now at least.
|
||||
* [Android] Shaders that were broken on Nexus 7/4/10 etc. should now work
|
||||
* [Android] Added some additional autodetection rules:
|
||||
- Ouya: Input overlays are disabled by default
|
||||
* [Android] Added high-latency audio option for crappy/old Android devices that
|
||||
can't handle the lower-latency audio that is the default since 0.9.9.4. This should
|
||||
give you the same performance as 0.9.9.3 (r17). Turn this on if you get bad sound/performance
|
||||
(and it's not your device simply being slow). This might also apply for some of the newer
|
||||
devices - perhaps OpenSL driver has not been updated/optimized there.
|
||||
* [Android] Added a TV mode. This will launch you straight into RGUI mode. This mode
|
||||
is identical to what you get from the Wii and PC ports of RetroArch at startup. First
|
||||
you select a core, then you select a game to go with it.
|
||||
* [SNES9x] Fixes by Alcaro to libretro port
|
||||
* [SNES9x Next] Fixes savestates from not being able to be loaded.
|
||||
* (LIBRETRO) Added bsnes/higan performance core [v0.92] (Android).
|
||||
- bsnes/higan performance core will run all non-coprocessor games at fullspeed on an
|
||||
nVidia Shield.
|
||||
- Co-processor games (SuperFX/SA-1/DSP/Cx4/SA1) will run between ~40fps and 55-57fps
|
||||
on an nVidia Shield - depending on the specific co-processor. Note - you will need
|
||||
BIOS files for these games - see byuu boards for information on them.
|
||||
* [Mednafen NGP] Fixes input issues in a number of games, such as:
|
||||
- Card Fighters games
|
||||
- Etc.
|
||||
* [Picodrive] Updates/32X compatibility/accuracy improvements
|
||||
* [NEStopia] Updated to 1.46 WIP - added ability to load NstDatabase.xml, fixes Vs. System games
|
||||
and Startropics 1/2
|
||||
* [iOS] Only player 1 gets default keyboard bindings
|
||||
* [iOS] Fixes PS3 gamepad bindings in RGUI
|
||||
* [iOS] Fixes iCade button mappings
|
||||
* [iOS] UI additions - Refresh / New Folder / Move options.
|
||||
* [iOS] Some lifecycle management fixes - should deal better now with phone calls
|
||||
received and then returning back to RA, etc.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
v0.9.9.3
|
||||
------------------------------------------------------------------------------
|
||||
|
|
58
driver.c
58
driver.c
|
@ -24,6 +24,7 @@
|
|||
#include "audio/utils.h"
|
||||
#include "audio/resampler.h"
|
||||
#include "gfx/thread_wrapper.h"
|
||||
#include "audio/thread_wrapper.h"
|
||||
#include "gfx/gfx_common.h"
|
||||
|
||||
#ifdef HAVE_X11
|
||||
|
@ -122,6 +123,9 @@ static const video_driver_t *video_drivers[] = {
|
|||
#ifdef HAVE_NULLVIDEO
|
||||
&video_null,
|
||||
#endif
|
||||
#ifdef HAVE_OMAP
|
||||
&video_omap,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const input_driver_t *input_drivers[] = {
|
||||
|
@ -354,7 +358,7 @@ void global_uninit_drivers(void)
|
|||
|
||||
if (driver.input_data)
|
||||
{
|
||||
driver.input->free(NULL);
|
||||
driver.input->free(driver.input_data);
|
||||
driver.input_data = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -370,19 +374,26 @@ void init_drivers(void)
|
|||
g_extern.frame_count = 0;
|
||||
init_video_input();
|
||||
|
||||
if (g_extern.system.hw_render_callback.context_reset)
|
||||
if (!driver.video_cache_context_ack && g_extern.system.hw_render_callback.context_reset)
|
||||
g_extern.system.hw_render_callback.context_reset();
|
||||
driver.video_cache_context_ack = false;
|
||||
|
||||
init_audio();
|
||||
|
||||
// Keep non-throttled state as good as possible.
|
||||
if (driver.nonblock_state)
|
||||
driver_set_nonblock_state(driver.nonblock_state);
|
||||
|
||||
g_extern.system.frame_time_last = 0;
|
||||
}
|
||||
|
||||
void uninit_drivers(void)
|
||||
{
|
||||
uninit_audio();
|
||||
|
||||
if (g_extern.system.hw_render_callback.context_destroy && !driver.video_cache_context)
|
||||
g_extern.system.hw_render_callback.context_destroy();
|
||||
|
||||
uninit_video_input();
|
||||
|
||||
if (driver.video_data_own)
|
||||
|
@ -493,8 +504,26 @@ void init_audio(void)
|
|||
return;
|
||||
}
|
||||
|
||||
driver.audio_data = audio_init_func(*g_settings.audio.device ? g_settings.audio.device : NULL,
|
||||
g_settings.audio.out_rate, g_settings.audio.latency);
|
||||
#ifdef HAVE_THREADS
|
||||
find_audio_driver();
|
||||
if (g_extern.system.audio_callback)
|
||||
{
|
||||
RARCH_LOG("Starting threaded audio driver ...\n");
|
||||
if (!rarch_threaded_audio_init(&driver.audio, &driver.audio_data,
|
||||
*g_settings.audio.device ? g_settings.audio.device : NULL,
|
||||
g_settings.audio.out_rate, g_settings.audio.latency,
|
||||
driver.audio))
|
||||
{
|
||||
RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n");
|
||||
rarch_fail(1, "init_audio()");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
driver.audio_data = audio_init_func(*g_settings.audio.device ? g_settings.audio.device : NULL,
|
||||
g_settings.audio.out_rate, g_settings.audio.latency);
|
||||
}
|
||||
|
||||
if (!driver.audio_data)
|
||||
{
|
||||
|
@ -530,7 +559,8 @@ void init_audio(void)
|
|||
rarch_assert(g_settings.audio.out_rate < g_settings.audio.in_rate * AUDIO_MAX_RATIO);
|
||||
rarch_assert(g_extern.audio_data.outsamples = (float*)malloc(outsamples_max * sizeof(float)));
|
||||
|
||||
if (g_extern.audio_active && g_settings.audio.rate_control)
|
||||
g_extern.audio_data.rate_control = false;
|
||||
if (!g_extern.system.audio_callback && g_extern.audio_active && g_settings.audio.rate_control)
|
||||
{
|
||||
if (driver.audio->buffer_size && driver.audio->write_avail)
|
||||
{
|
||||
|
@ -549,6 +579,9 @@ void init_audio(void)
|
|||
#endif
|
||||
|
||||
g_extern.measure_data.buffer_free_samples_count = 0;
|
||||
|
||||
if (g_extern.audio_active && !g_extern.audio_data.mute && g_extern.system.audio_callback) // Threaded driver is initially stopped.
|
||||
audio_start_func();
|
||||
}
|
||||
|
||||
static void compute_audio_buffer_statistics(void)
|
||||
|
@ -598,10 +631,7 @@ static void compute_audio_buffer_statistics(void)
|
|||
bool driver_monitor_fps_statistics(double *refresh_rate, double *deviation, unsigned *sample_points)
|
||||
{
|
||||
if (g_settings.video.threaded)
|
||||
{
|
||||
RARCH_LOG("Monitor FPS estimation is disabled for threaded video.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned samples = min(MEASURE_FRAME_TIME_SAMPLES_COUNT, g_extern.measure_data.frame_time_samples_count);
|
||||
if (samples < 2)
|
||||
|
@ -637,6 +667,12 @@ bool driver_monitor_fps_statistics(double *refresh_rate, double *deviation, unsi
|
|||
|
||||
static void compute_monitor_fps_statistics(void)
|
||||
{
|
||||
if (g_settings.video.threaded)
|
||||
{
|
||||
RARCH_LOG("Monitor FPS estimation is disabled for threaded video.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_extern.measure_data.frame_time_samples_count < 2 * MEASURE_FRAME_TIME_SAMPLES_COUNT)
|
||||
{
|
||||
RARCH_LOG("Does not have enough samples for monitor refresh rate estimation. Requires to run for at least %u frames.\n",
|
||||
|
@ -656,6 +692,9 @@ static void compute_monitor_fps_statistics(void)
|
|||
|
||||
void uninit_audio(void)
|
||||
{
|
||||
if (driver.audio_data && driver.audio)
|
||||
driver.audio->free(driver.audio_data);
|
||||
|
||||
free(g_extern.audio_data.conv_outsamples);
|
||||
g_extern.audio_data.conv_outsamples = NULL;
|
||||
g_extern.audio_data.data_ptr = 0;
|
||||
|
@ -669,9 +708,6 @@ void uninit_audio(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (driver.audio_data && driver.audio)
|
||||
driver.audio->free(driver.audio_data);
|
||||
|
||||
rarch_resampler_freep(&g_extern.audio_data.resampler, &g_extern.audio_data.resampler_data);
|
||||
|
||||
free(g_extern.audio_data.data);
|
||||
|
|
8
driver.h
8
driver.h
|
@ -270,6 +270,7 @@ enum input_devices
|
|||
DEVICE_GAMEMID,
|
||||
DEVICE_DEFENDER_GAME_RACER_CLASSIC,
|
||||
DEVICE_HOLTEK_JC_U912F,
|
||||
DEVICE_NVIDIA_SHIELD,
|
||||
#elif defined(GEKKO)
|
||||
DEVICE_GAMECUBE = 0,
|
||||
#ifdef HW_RVL
|
||||
|
@ -301,6 +302,7 @@ enum analog_dpad_bind_enums
|
|||
ANALOG_DPAD_NONE = 0,
|
||||
ANALOG_DPAD_LSTICK,
|
||||
ANALOG_DPAD_RSTICK,
|
||||
ANALOG_DPAD_DUALANALOG,
|
||||
ANALOG_DPAD_LAST
|
||||
};
|
||||
|
||||
|
@ -417,6 +419,11 @@ typedef struct driver
|
|||
|
||||
bool threaded_video;
|
||||
|
||||
// If set during context deinit, the driver should keep
|
||||
// graphics context alive to avoid having to reset all context state.
|
||||
bool video_cache_context;
|
||||
bool video_cache_context_ack; // Set to true by driver if context caching succeeded.
|
||||
|
||||
// Set if the respective handles are owned by RetroArch driver core.
|
||||
// Consoles upper logic will generally intialize the drivers before
|
||||
// the driver core initializes. It will then be up to upper logic
|
||||
|
@ -516,6 +523,7 @@ extern const video_driver_t video_xdk_d3d;
|
|||
extern const video_driver_t video_sdl;
|
||||
extern const video_driver_t video_vg;
|
||||
extern const video_driver_t video_null;
|
||||
extern const video_driver_t video_omap;
|
||||
extern const input_driver_t input_android;
|
||||
extern const input_driver_t input_sdl;
|
||||
extern const input_driver_t input_dinput;
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
#define audio_write_avail_func() driver.audio->write_avail(driver.audio_data)
|
||||
#define audio_buffer_size_func() driver.audio->buffer_size(driver.audio_data)
|
||||
|
||||
#if !defined(RARCH_CONSOLE) /* Normal */
|
||||
|
||||
#define video_init_func(video_info, input, input_data) \
|
||||
driver.video->init(video_info, input, input_data)
|
||||
#define video_frame_func(data, width, height, pitch, msg) \
|
||||
|
@ -69,93 +67,4 @@ static inline bool input_key_pressed_func(int key)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*============================================================
|
||||
VIDEO
|
||||
============================================================ */
|
||||
|
||||
#define CONCAT2(A, B) A##B
|
||||
|
||||
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) /* GL */
|
||||
#define MAKENAME_VIDEO(A) CONCAT2(gl, A)
|
||||
|
||||
#define video_set_aspect_ratio_func(aspectratio_idx) gfx_ctx_set_aspect_ratio(driver.video_data, aspectratio_idx)
|
||||
|
||||
#define gfx_ctx_window_has_focus() (true)
|
||||
|
||||
#elif defined(_XBOX) && (defined(HAVE_D3D8) || defined(HAVE_D3D9)) /* D3D */
|
||||
#define MAKENAME_VIDEO(A) CONCAT2(xdk_d3d, A)
|
||||
|
||||
#elif defined(XENON) /* XENON */
|
||||
#define MAKENAME_VIDEO(A) CONCAT2(xenon360_gfx, A)
|
||||
|
||||
#define video_set_aspect_ratio_func(aspectratio_idx) gfx_ctx_set_aspect_ratio(driver.video_data, aspectratio_idx)
|
||||
|
||||
#define gfx_ctx_window_has_focus() (true)
|
||||
|
||||
#elif defined(GEKKO) /* Gamecube, Wii */
|
||||
#define MAKENAME_VIDEO(A) CONCAT2(gx, A)
|
||||
|
||||
#define video_set_aspect_ratio_func(aspectratio_idx) gx_set_aspect_ratio(driver.video_data, aspectratio_idx)
|
||||
#define video_viewport_size_func(width, height) ((void)0)
|
||||
#define video_read_viewport_func(buffer) (false)
|
||||
|
||||
//#elif defined(PSP) /* PSP1 */
|
||||
//#define MAKENAME_VIDEO(A) CONCAT2(psp, A)
|
||||
//#define video_set_aspect_ratio_func(aspectratio_idx) (true)
|
||||
|
||||
#else /* NULL */
|
||||
#define MAKENAME_VIDEO(A) CONCAT2(nullvideo, A)
|
||||
|
||||
#define video_set_aspect_ratio_func(aspectratio_idx) (true)
|
||||
|
||||
#endif
|
||||
|
||||
#define video_viewport_info_func(info) driver.video->viewport_info(driver.video_data, info)
|
||||
|
||||
#define video_init_func(video_info, input, input_data) MAKENAME_VIDEO(_init)(video_info, input, input_data)
|
||||
#define video_frame_func(data, width, height, pitch, msg) \
|
||||
MAKENAME_VIDEO(_frame)(driver.video_data, data, width, height, pitch, msg)
|
||||
#define video_alive_func() MAKENAME_VIDEO(_alive)(driver.video_data)
|
||||
#define video_focus_func() MAKENAME_VIDEO(_focus)(driver.video_data)
|
||||
#define video_free_func() MAKENAME_VIDEO(_free)(driver.video_data)
|
||||
#define video_set_nonblock_state_func(state) MAKENAME_VIDEO(_set_nonblock_state)(driver.video_data, state)
|
||||
#define video_set_rotation_func(rotation) MAKENAME_VIDEO(_set_rotation)(driver.video_data, rotation)
|
||||
#define video_start_func() MAKENAME_VIDEO(_start)()
|
||||
#define video_set_shader_func(type, path) MAKENAME_VIDEO(_set_shader)(driver.video_data, type, path)
|
||||
#define video_xml_shader_func(path) driver.video->xml_shader(driver.video_data, path)
|
||||
|
||||
/*============================================================
|
||||
INPUT
|
||||
============================================================ */
|
||||
|
||||
#if defined(_XBOX) && (defined(HAVE_D3D8) || defined(HAVE_D3D9)) /* D3D */
|
||||
#define MAKENAME_INPUT(A) CONCAT2(xdk, A)
|
||||
#elif defined(GEKKO) /* Gamecube, Wii */
|
||||
#define MAKENAME_INPUT(A) CONCAT2(gx, A)
|
||||
#define gfx_ctx_window_has_focus() (true)
|
||||
#elif defined(__CELLOS_LV2__) /* PS3 */
|
||||
#define MAKENAME_INPUT(A) CONCAT2(ps3, A)
|
||||
#elif defined(ANDROID) /* ANDROID */
|
||||
#define MAKENAME_INPUT(A) CONCAT2(android, A)
|
||||
#elif defined(XENON) /* XENON */
|
||||
#define MAKENAME_INPUT(A) CONCAT2(xenon360, A)
|
||||
#else
|
||||
#define MAKENAME_INPUT(A) CONCAT2(nullinput, A)
|
||||
#endif
|
||||
|
||||
#define gfx_ctx_window_has_focus() (true)
|
||||
|
||||
#define input_init_func() MAKENAME_INPUT(_input_init)()
|
||||
#define input_poll_func() MAKENAME_INPUT(_input_poll)(driver.input_data)
|
||||
#define input_input_state_func(retro_keybinds, port, device, index, id) \
|
||||
MAKENAME_INPUT(_input_state)(driver.input_data, retro_keybinds, port, device, index, id)
|
||||
#define input_key_pressed_func(key) MAKENAME_INPUT(_input_key_pressed)(driver.input_data, key)
|
||||
#define input_free_func() MAKENAME_INPUT(_input_free_input)(driver.input_data)
|
||||
|
||||
#define video_overlay_interface_func(iface) driver.video->overlay_interface(driver.video_data, iface)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _RARCH_DRIVER_FUNCS_H */
|
||||
|
|
49
dynamic.c
49
dynamic.c
|
@ -42,6 +42,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef HAVE_DYNAMIC
|
||||
#undef SYM
|
||||
#define SYM(x) do { \
|
||||
function_t func = dylib_proc(lib_handle, #x); \
|
||||
memcpy(&p##x, &func, sizeof(func)); \
|
||||
|
@ -653,6 +654,7 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
break;
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_HW_RENDER:
|
||||
case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL: // ABI compat
|
||||
{
|
||||
RARCH_LOG("Environ SET_HW_RENDER.\n");
|
||||
struct retro_hw_render_callback *cb = (struct retro_hw_render_callback*)data;
|
||||
|
@ -669,6 +671,7 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
break;
|
||||
|
||||
case RETRO_HW_CONTEXT_OPENGL:
|
||||
case RETRO_HW_CONTEXT_OPENGL_CORE:
|
||||
RARCH_ERR("Requesting OpenGL context, but RetroArch is compiled against OpenGLES2. Cannot use HW context.\n");
|
||||
return false;
|
||||
#elif defined(HAVE_OPENGL)
|
||||
|
@ -680,6 +683,11 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
RARCH_LOG("Requesting OpenGL context.\n");
|
||||
driver.video = &video_gl;
|
||||
break;
|
||||
|
||||
case RETRO_HW_CONTEXT_OPENGL_CORE:
|
||||
RARCH_LOG("Requesting core OpenGL context (%u.%u).\n", cb->version_major, cb->version_minor);
|
||||
driver.video = &video_gl;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
|
@ -688,7 +696,11 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
}
|
||||
cb->get_current_framebuffer = driver_get_current_framebuffer;
|
||||
cb->get_proc_address = driver_get_proc_address;
|
||||
memcpy(&g_extern.system.hw_render_callback, cb, sizeof(*cb));
|
||||
|
||||
if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL) // Old ABI. Don't copy garbage.
|
||||
memcpy(&g_extern.system.hw_render_callback, cb, offsetof(struct retro_hw_render_callback, stencil));
|
||||
else
|
||||
memcpy(&g_extern.system.hw_render_callback, cb, sizeof(*cb));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -711,6 +723,41 @@ static bool environment_cb(unsigned cmd, void *data)
|
|||
break;
|
||||
}
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK:
|
||||
{
|
||||
RARCH_LOG("Environ SET_AUDIO_CALLBACK.\n");
|
||||
const struct retro_audio_callback *info = (const struct retro_audio_callback*)data;
|
||||
|
||||
#ifdef HAVE_FFMPEG
|
||||
if (g_extern.recording) // A/V sync is a must.
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETPLAY
|
||||
if (g_extern.netplay_enable)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
g_extern.system.audio_callback = info->callback;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK:
|
||||
{
|
||||
RARCH_LOG("Environ SET_FRAME_TIME_CALLBACK.\n");
|
||||
|
||||
#ifdef HAVE_NETPLAY
|
||||
if (g_extern.netplay_enable) // retro_run() will be called in very strange and mysterious ways, have to disable it.
|
||||
return false;
|
||||
#endif
|
||||
|
||||
const struct retro_frame_time_callback *info = (const struct retro_frame_time_callback*)data;
|
||||
g_extern.system.frame_time = *info;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd);
|
||||
return false;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue