diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..8e597bd2 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +fceux.com \ No newline at end of file diff --git a/INSTALL b/INSTALL index f1f2a562..249461e2 100644 --- a/INSTALL +++ b/INSTALL @@ -1,7 +1,9 @@ To compile and install FCEUX for SDL, follow the instructions in the README-SDL.md file. -Users of Microsoft Visual Studio can use the solution files within the vc directory. +Users of Microsoft Visual Studio can use the solution files within the vc directory. The Windows XP toolset is required to open and build this solution. If it +is not installed, go to "Tools" > "Get Tools and Features". Select "Individual Components" and then install "C++ Windows XP Support for VS 2017 (v141) tools". These solution files will compile FCEUX and some included libraries for full functionality. -CMake has been depreciated in favor of scons. However, if you wish to use it you can find the old cmake build files in the attic. +The SDL port build tool of choice has come full circle back to Cmake. The cmake build tool will compile the new Qt version of the SDL GUI. +The scons build tool will build the older GTK based GUI which currently only builds on Linux. diff --git a/README b/README index 53c559fc..e75719a6 100644 --- a/README +++ b/README @@ -24,7 +24,7 @@ Table of Contents ---------------- * sdl2 - Version >= 2.0 * cmake - Required to build fceux. -* qt5 - version >= 5.11 recommended +* qt5 OR gtk3 - (qt version >= 5.11 recommended) (gtk3 >= 3.22 recommended) * liblua5.1 (optional) - Will statically link internally if the system cannot provide this. * minizip * zlib @@ -33,6 +33,7 @@ Table of Contents 2 - Installation ---------------- +The old scons build system is no longer supported. Fceux can be compiled and built using the cmake build system. To compile, run: mkdir build; cd build; @@ -41,6 +42,11 @@ Fceux can be compiled and built using the cmake build system. To compile, run: To build a binary with debug information included in it: cmake -DCMAKE_BUILD_TYPE=Debug .. +The Qt version of the GUI builds by default and this is the preferred GUI for use. +For those who must have GTK/Gnome style, +the GTK version of the GUI can be selected to build with: + cmake -DCMAKE_BUILD_TYPE=Release -DGTK=1 .. # Release build using GTK GUI + To do the actual compiling: make @@ -75,7 +81,12 @@ Look in the src/CMakeList.txt file to tweak options. 4 - GUI ------- -The Qt GUI is required and automatically builds as part of the build. +The Qt (or GTK) GUI is required and automatically builds as part of the build. The Qt GUI is the default. +When invoking cmake, the GTK GUI can be built (instead of Qt) by specifying a -DGTK=1 on the command line. +See above build instructions. +OpenGL options: +For Linux builds, the OpenGL library preference can be either GLVND or LEGACY (default). +To use GLVND OpenGL, add a -DGLVND=1 on the cmake command line. 5 - LUA Scripting ----------------- @@ -107,7 +118,7 @@ The latest version of iup (3.5 at the time of writing) is recommended. ------- * Q. Im having issues with my sound! -* A. First of all, for the best sound quality be sure you are using SDL 1.2.14 or later. Versions 1.2.13 and earlier are known to have problems with fceux! Next, try different SDL audio drivers to see if this makes any difference. You can do this by using this command before running fceux: +* A. Try different SDL audio drivers to see if this makes any difference. You can do this by using this command before running fceux: export SDL_AUDIODRIVER=driver diff --git a/SConstruct b/SConstruct index 97b30bce..5d97b46c 100644 --- a/SConstruct +++ b/SConstruct @@ -98,16 +98,16 @@ else: conf.env.Append(CCFLAGS = "-DHAVE_ASPRINTF") if env['SYSTEM_MINIZIP']: assert env.ParseConfig('pkg-config minizip --cflags --libs'), "please install: libminizip" - assert conf.CheckLibWithHeader('z', 'zlib.h', 'c', 'inflate;', 1), "please install: zlib" + assert env.ParseConfig('pkg-config zlib --cflags --libs'), "please install: zlib" + #assert conf.CheckLibWithHeader('z', 'zlib.h', 'c', 'inflate;', 1), "please install: zlib" env.Append(CPPDEFINES=["_SYSTEM_MINIZIP"]) else: - assert conf.CheckLibWithHeader('z', 'zlib.h', 'c', 'inflate;', 1), "please install: zlib" + assert env.ParseConfig('pkg-config zlib --cflags --libs'), "please install: zlib" + #assert conf.CheckLibWithHeader('z', 'zlib.h', 'c', 'inflate;', 1), "please install: zlib" if env['SDL2']: - if not conf.CheckLib('SDL2'): - print('Did not find libSDL2 or SDL2.lib, exiting!') - Exit(1) + assert env.ParseConfig('pkg-config sdl2 --cflags --libs'), "please install: sdl2" env.Append(CPPDEFINES=["_SDL2"]) - env.ParseConfig('pkg-config sdl2 --cflags --libs') + #env.ParseConfig('pkg-config sdl2 --cflags --libs') else: if not conf.CheckLib('SDL'): print('Did not find libSDL or SDL.lib, exiting!') diff --git a/TODO-SDL b/TODO-SDL index 67111867..90a21899 100644 --- a/TODO-SDL +++ b/TODO-SDL @@ -1,21 +1,66 @@ Priorities ========== * Clean out old unused files - scons build system is dead, cmake is the way to go. - * GTK GUI was not cross-platform. Has been replaced in favor of Qt5. Need to clean out dead code. - * Cheat Editor will be a high priority. - * Code cleanup. Lots of compiler warning with newer GCC. Maybe I'm OCD... but these warnings bother me. + * GTK GUI was not cross-platform. A Qt5 version of the GUI has been created to meet this need. + I will keep the GTK GUI around for Linux users who prefer it, but when it comes to adding new features + the Qt GUI is where I plan to add them first (if at all). + * Code cleanup. Lots of compiler warnings with newer GCC. Maybe I'm OCD... but these warnings bother me. Features ======== * Emulator no runs as a separate thread from the GUI. Much improved performance. - * Cross platform QT GUI is fully functional minus Debug Tools and Cheat Menu. + * Cross platform QT GUI is fully functional minus Debug Tools. +---------------------------------------------------------------------------------| +---------------------- GUI Capability Matrix -----------------------------------| +---------------------------------------------------------------------------------| +Feature | Qt5 | GTK3 | +-----------------------------------------------------|-------------|-------------| +Basic game ROM open/run and close via menu functions | YES | YES | +Load/save game states | YES | YES | +Select and execute Lua script via file browser | YES | YES | +Lua Console/Control Window | YES | NO | +Screenshot snap/save functionality | YES | YES | +Virtual game pad button mapping window | YES | YES | +Other input device type button mapping window | NO | NO | +Audio mixer / config window | YES | YES | +Video config window | YES | YES | +OpenGL graphics | YES | YES | +Hot key config window | YES | YES | +Palette config window | YES | YES | +Multi-thread (GUI and emulation on separate threads) | YES | NO | +Emulation speed control via menu | NO | NO | +Emulation speed control via hotkeys | YES | YES | +Fullscreen functionality | YES | YES | +AVI Record Functionality | NO | NO | +NES Emulation Power/Reset/Pause functionality | YES | YES | +Game genie load/enable capability | YES | YES | +Movie record/save/play functionality | YES | YES | +Cheat search window | YES | YES | +Active Cheat window | YES | YES | +RAM Search Window | NO | NO | +RAM Watch Window | NO | YES | +Memory Watch Window | NO | NO | +TAS Editor | NO | NO | +6502 Debugger Window | NO | YES | +PPU Viewer | NO | NO | +Name Table Viewer | NO | NO | +Memory Hex Editor | NO | YES | +Trace Logger | NO | NO | +Code/Data Logger | NO | NO | +Game Genie Encoder/Decoder | NO | NO | +iNES Header Editor | NO | NO | +Built in help pages | NO | NO | +Network play (who actually uses this???) | NO | NO | +-----------------------------------------------------|-------------|-------------| +---------------------------------------------------------------------------------| +---------------------------------------------------------------------------------| + QT === * Clean out rest of old GTK comments and #ifdefs - * GUI Cheat editor TODO * GUI Debug Tools TODO - * GUI should compile in windows as well.... but testing is not a priority since the windows gui has a totally separate backend. + * GUI should compile in windows as well.... but testing is not a priority since the windows gui already has a totally separate backend. BUGS ==== diff --git a/pipelines/debpkg.pl b/pipelines/debpkg.pl index e0960679..ba27b62b 100755 --- a/pipelines/debpkg.pl +++ b/pipelines/debpkg.pl @@ -10,7 +10,9 @@ my $PKG_OUTPUT_FILE="fceux-$VERSION-$ARCH.deb"; # Start by auto figuring out dependencies of the executable. # the rest of the package creation is trival. -my $SO_LIST=`objdump -x $INSTALL_PREFIX/usr/bin/fceux`; +my $SO_LIST=""; +$SO_LIST=`objdump -x $INSTALL_PREFIX/usr/bin/fceux`; +$SO_LIST= $SO_LIST . `objdump -x $INSTALL_PREFIX/usr/bin/fceux-gtk`; #print "$SO_LIST"; diff --git a/pipelines/linux_build.sh b/pipelines/linux_build.sh index 8da0b4e4..edb7c49d 100755 --- a/pipelines/linux_build.sh +++ b/pipelines/linux_build.sh @@ -60,8 +60,8 @@ pkg-config --cflags --libs minizip #echo '****************************************' #echo 'Install Dependency libgtk-3-dev' #echo '****************************************' -#sudo apt-get --assume-yes install libgtk-3-dev -#pkg-config --cflags --libs gtk+-3.0 +sudo apt-get --assume-yes install libgtk-3-dev +pkg-config --cflags --libs gtk+-3.0 # ## Install GTK+-3 Sourceview #sudo apt-get --assume-yes install libgtksourceview-3.0-dev @@ -92,14 +92,24 @@ mkdir -p $INSTALL_PREFIX/usr; #scons --clean #scons GTK3=1 SYSTEM_LUA=1 SYSTEM_MINIZIP=1 CREATE_AVI=1 install --prefix=$INSTALL_PREFIX/usr echo "Num CPU: `nproc`"; -mkdir build; cd build; -#qmake PREFIX=$INSTALL_PREFIX/usr .. +mkdir buildQT; cd buildQT; cmake \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX/usr \ -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ .. -make -j `nproc` +make -j `nproc` +make install + +cd ..; +mkdir buildGTK; cd buildGTK; +cmake \ + -DGTK=1 \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX/usr \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + .. +make -j `nproc` make install # Install Files @@ -134,6 +144,16 @@ else exit 1; fi +if [ -e $INSTALL_PREFIX/usr/bin/fceux-gtk ]; then + echo '**************************************************************' + echo 'Printing Shared Object Dependencies for fceux-gtk Executable' + echo '**************************************************************' + ldd $INSTALL_PREFIX/usr/bin/fceux-gtk +else + echo "Error: Executable Failed to build: $INSTALL_PREFIX/usr/bin/fceux-gtk"; + exit 1; +fi + echo '**************************************************************' echo 'Printing To Be Packaged Files ' echo '**************************************************************' diff --git a/readme.md b/readme.md index da142c09..5719756b 100644 --- a/readme.md +++ b/readme.md @@ -8,6 +8,7 @@ Interim builds: * Win32: [fceux.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux.zip?branch=master&job=Windows%2032) * Win64: [fceux64.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux64.zip?branch=master&job=Windows%2064) * Ubuntu: [fceux-2.2.3-amd64.deb](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.2.3-amd64.deb?branch=master&job=Ubuntu) +* MacOSX: [fceux-2.2.3-Darwin.dmg](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.2.3-Darwin.dmg?branch=master&job=MacOS) * Status: [Appveyor](https://ci.appveyor.com/project/zeromus/fceux/) But you might like mesen more: https://github.com/SourMesen/Mesen diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c1063f0c..4ef224bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,14 @@ +if ( ${GTK} ) +message( STATUS "GUI backend: GTK") +set( APP_NAME fceux-gtk) +else() +message( STATUS "GUI backend: QT") +set( APP_NAME fceux) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) - -set( APP_NAME fceux) +endif() if(WIN32) set(SOURCES ${SRC_CORE} ${SRC_DRIVERS_COMMON} ${SRC_DRIVERS_WIN}) @@ -21,20 +26,34 @@ else(WIN32) # Non Windows System # UNIX (Linux or Mac OSX) - #set (OpenGL_GL_PREFERENCE GLVND) - set (OpenGL_GL_PREFERENCE LEGACY) + if ( ${GLVND} ) + message( STATUS "OpenGL preference: GLVND") + set (OpenGL_GL_PREFERENCE GLVND) + else() + message( STATUS "OpenGL preference: LEGACY") + set (OpenGL_GL_PREFERENCE LEGACY) + endif() # Use the built-in cmake find_package functions to find dependencies # Use package PkgConfig to detect headers/library what find_package cannot find. find_package(PkgConfig REQUIRED) - find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED) find_package(OpenGL REQUIRED) find_package(ZLIB REQUIRED) - add_definitions( ${Qt5Widgets_DEFINITIONS} ) - include_directories( ${Qt5Widgets_INCLUDE_DIRS} ) + add_definitions( -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs -fPIC ) + add_definitions( -DFCEUDEF_DEBUGGER ) - add_definitions( -D__QT_DRIVER__ -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs -fPIC -DQT_DEPRECATED_WARNINGS ) + if ( ${GTK} ) + pkg_check_modules( GTK3 REQUIRED gtk+-3.0) + pkg_check_modules( X11 REQUIRED x11) + add_definitions( ${GTK3_CFLAGS} ${X11_CFLAGS} ) + add_definitions( -D_GTK -DOPENGL ) + else(${GTK}) + find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED) + add_definitions( ${Qt5Widgets_DEFINITIONS} ) + include_directories( ${Qt5Widgets_INCLUDE_DIRS} ) + add_definitions( -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS ) + endif() # Check for libminizip pkg_check_modules( MINIZIP REQUIRED minizip) @@ -376,11 +395,31 @@ set(SRC_DRIVERS_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scale3x.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scalebit.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/vidblit.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/os_utils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/nes_ntsc.c ${CMAKE_CURRENT_SOURCE_DIR}/drivers/videolog/nesvideos-piece.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/videolog/rgbtorgb.cpp ) +if ( ${GTK} ) +set(SRC_DRIVERS_SDL + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/cheat.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/config.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/debugger.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/glxwin.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/gui.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/GamePadConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/input.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/memview.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/ramwatch.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/sdl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/sdl-joystick.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/sdl-sound.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/sdl-throttle.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/sdl-video.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/sdl/unix-netplay.cpp +) +else() set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleWindow.cpp @@ -388,6 +427,12 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerSDL.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GamePadConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HotKeyConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GuiConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/LuaControl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CheatsConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HexEditor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AboutWindow.cpp @@ -402,6 +447,7 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-throttle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/unix-netplay.cpp ) +endif() set(SOURCES ${SRC_CORE} ${SRC_DRIVERS_COMMON} ${SRC_DRIVERS_SDL}) @@ -422,11 +468,27 @@ add_executable( ${APP_NAME} MACOSX_BUNDLE ${APP_ICON} ${SOURCES} ../resources. ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp) else() -add_executable( ${APP_NAME} ${SOURCES} ../resources.qrc - ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp) + + if ( ${GTK} ) + add_executable( ${APP_NAME} ${SOURCES} + ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp) + else() + add_executable( ${APP_NAME} ${SOURCES} ../resources.qrc + ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp) + endif() endif() -target_link_libraries( fceux +if ( ${GTK} ) + target_link_libraries( ${APP_NAME} + ${GTK3_LDFLAGS} ${X11_LDFLAGS} + ${OPENGL_LDFLAGS} + ${SDL2_LDFLAGS} + ${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES} + ${LUA_LDFLAGS} + ${SYS_LIBS} +) +else() +target_link_libraries( ${APP_NAME} ${Qt5Widgets_LIBRARIES} ${Qt5OpenGL_LIBRARIES} ${OPENGL_LDFLAGS} @@ -435,6 +497,7 @@ target_link_libraries( fceux ${LUA_LDFLAGS} ${SYS_LIBS} ) +endif() if (APPLE) diff --git a/src/boards/bandai.cpp b/src/boards/bandai.cpp index 24043a99..770e02db 100644 --- a/src/boards/bandai.cpp +++ b/src/boards/bandai.cpp @@ -48,120 +48,205 @@ static SFORMAT StateRegs[] = #define X24C0X_READ 3 #define X24C0X_WRITE 4 -static uint8 x24c0x_data[256], x24c0x_state; -static uint8 x24c0x_addr, x24c0x_word, x24c0x_latch, x24c0x_bitcount; -static uint8 x24c0x_sda, x24c0x_scl, x24c0x_out, x24c0x_oe; +static uint8 x24c0x_data[512]; -static SFORMAT x24c0xStateRegs[] = +static uint8 x24c01_state; +static uint8 x24c01_addr, x24c01_word, x24c01_latch, x24c01_bitcount; +static uint8 x24c01_sda, x24c01_scl, x24c01_out; + +static uint8 x24c02_state; +static uint8 x24c02_addr, x24c02_word, x24c02_latch, x24c02_bitcount; +static uint8 x24c02_sda, x24c02_scl, x24c02_out; + +static SFORMAT x24c01StateRegs[] = { - { &x24c0x_addr, 1, "ADDR" }, - { &x24c0x_word, 1, "WORD" }, - { &x24c0x_latch, 1, "LATC" }, - { &x24c0x_bitcount, 1, "BITC" }, - { &x24c0x_sda, 1, "SDA" }, - { &x24c0x_scl, 1, "SCL" }, - { &x24c0x_out, 1, "OUT" }, - { &x24c0x_oe, 1, "OE" }, - { &x24c0x_state, 1, "STAT" }, + { &x24c01_addr, 1, "ADDR" }, + { &x24c01_word, 1, "WORD" }, + { &x24c01_latch, 1, "LATC" }, + { &x24c01_bitcount, 1, "BITC" }, + { &x24c01_sda, 1, "SDA" }, + { &x24c01_scl, 1, "SCL" }, + { &x24c01_out, 1, "OUT" }, + { &x24c01_state, 1, "STAT" }, { 0 } }; -static void x24c0x_init() { - x24c0x_addr = x24c0x_word = x24c0x_latch = x24c0x_bitcount = x24c0x_sda = x24c0x_scl = x24c0x_oe = 0; - x24c0x_state = X24C0X_STANDBY; +static SFORMAT x24c02StateRegs[] = +{ + { &x24c02_addr, 1, "ADDR" }, + { &x24c02_word, 1, "WORD" }, + { &x24c02_latch, 1, "LATC" }, + { &x24c02_bitcount, 1, "BITC" }, + { &x24c02_sda, 1, "SDA" }, + { &x24c02_scl, 1, "SCL" }, + { &x24c02_out, 1, "OUT" }, + { &x24c02_state, 1, "STAT" }, + { 0 } +}; + +static void x24c01_init() { + x24c01_addr = x24c01_word = x24c01_latch = x24c01_bitcount = x24c01_sda = x24c01_scl = 0; + x24c01_state = X24C0X_STANDBY; } -static void x24c0x_write(uint8 data) { - uint8 sda = (data >> 6) & 1; - uint8 scl = (data >> 5) & 1; - x24c0x_oe = (data >> 7); +static void x24c02_init() { + x24c02_addr = x24c02_word = x24c02_latch = x24c02_bitcount = x24c02_sda = x24c02_scl = 0; + x24c02_state = X24C0X_STANDBY; +} - if(x24c0x_scl && scl) { - if(x24c0x_sda && !sda) { // START - x24c0x_state = X24C0X_ADDRESS; - x24c0x_bitcount = 0; - x24c0x_addr = 0; - } else if(!x24c0x_sda && sda) { //STOP - x24c0x_state = X24C0X_STANDBY; +static void x24c01_write(uint8 data) { + uint8 scl = (data >> 5) & 1; + uint8 sda = (data >> 6) & 1; + + if(x24c01_scl && scl) { + if(x24c01_sda && !sda) { // START + x24c01_state = X24C0X_ADDRESS; + x24c01_bitcount = 0; + x24c01_addr = 0; + } else if(!x24c01_sda && sda) { //STOP + x24c01_state = X24C0X_STANDBY; } - } else if(!x24c0x_scl && scl) { // RISING EDGE - switch(x24c0x_state) { + } else if(!x24c01_scl && scl) { // RISING EDGE + switch(x24c01_state) { case X24C0X_ADDRESS: - if(x24c0x_bitcount < 7) { - x24c0x_addr <<= 1; - x24c0x_addr |= sda; + if(x24c01_bitcount < 7) { + x24c01_addr <<= 1; + x24c01_addr |= sda; } else { - if(!x24c02) // X24C01 mode - x24c0x_word = x24c0x_addr; - if(sda) { // READ COMMAND - x24c0x_state = X24C0X_READ; - } else { // WRITE COMMAND - if(x24c02) // X24C02 mode - x24c0x_state = X24C0X_WORD; - else - x24c0x_state = X24C0X_WRITE; - } + x24c01_word = x24c01_addr; + if(sda) // READ COMMAND + x24c01_state = X24C0X_READ; + else // WRITE COMMAND + x24c01_state = X24C0X_WRITE; } - x24c0x_bitcount++; - break; - case X24C0X_WORD: - if(x24c0x_bitcount == 8) { // ACK - x24c0x_word = 0; - x24c0x_out = 0; - } else { // WORD ADDRESS INPUT - x24c0x_word <<= 1; - x24c0x_word |= sda; - if(x24c0x_bitcount == 16) { // END OF ADDRESS INPUT - x24c0x_bitcount = 7; - x24c0x_state = X24C0X_WRITE; - } - } - x24c0x_bitcount++; + x24c01_bitcount++; break; case X24C0X_READ: - if (x24c0x_bitcount == 8) { // ACK - x24c0x_out = 0; - x24c0x_latch = x24c0x_data[x24c0x_word]; - x24c0x_bitcount = 0; - } else { // REAL OUTPUT - x24c0x_out = x24c0x_latch >> 7; - x24c0x_latch <<= 1; - x24c0x_bitcount++; - if(x24c0x_bitcount == 8) { - x24c0x_word++; - x24c0x_word &= 0xff; + if (x24c01_bitcount == 8) { // ACK + x24c01_out = 0; + x24c01_latch = x24c0x_data[x24c01_word]; + x24c01_bitcount = 0; + } else { // REAL OUTPUT + x24c01_out = x24c01_latch >> 7; + x24c01_latch <<= 1; + x24c01_bitcount++; + if(x24c01_bitcount == 8) { + x24c01_word++; + x24c01_word &= 0xff; } } break; case X24C0X_WRITE: - if (x24c0x_bitcount == 8) { // ACK - x24c0x_out = 0; - x24c0x_latch = 0; - x24c0x_bitcount = 0; - } else { // REAL INPUT - x24c0x_latch <<= 1; - x24c0x_latch |= sda; - x24c0x_bitcount++; - if(x24c0x_bitcount == 8) { - x24c0x_data[x24c0x_word] = x24c0x_latch; - x24c0x_word++; - x24c0x_word &= 0xff; + if (x24c01_bitcount == 8) { // ACK + x24c01_out = 0; + x24c01_latch = 0; + x24c01_bitcount = 0; + } else { // REAL INPUT + x24c01_latch <<= 1; + x24c01_latch |= sda; + x24c01_bitcount++; + if(x24c01_bitcount == 8) { + x24c0x_data[x24c01_word] = x24c01_latch; + x24c01_word++; + x24c01_word &= 0xff; } } break; } } - x24c0x_sda = sda; - x24c0x_scl = scl; + x24c01_sda = sda; + x24c01_scl = scl; } -static uint8 x24c0x_read() { - return x24c0x_out << 4; +static void x24c02_write(uint8 data) { + uint8 scl = (data >> 5) & 1; + uint8 sda = (data >> 6) & 1; + + if (x24c02_scl && scl) { + if (x24c02_sda && !sda) { // START + x24c02_state = X24C0X_ADDRESS; + x24c02_bitcount = 0; + x24c02_addr = 0; + } else if (!x24c02_sda && sda) { //STOP + x24c02_state = X24C0X_STANDBY; + } + } else if (!x24c02_scl && scl) { // RISING EDGE + switch (x24c02_state) { + case X24C0X_ADDRESS: + if (x24c02_bitcount < 7) { + x24c02_addr <<= 1; + x24c02_addr |= sda; + } else { + if (sda) // READ COMMAND + x24c02_state = X24C0X_READ; + else // WRITE COMMAND + x24c02_state = X24C0X_WORD; + } + x24c02_bitcount++; + break; + case X24C0X_WORD: + if (x24c02_bitcount == 8) { // ACK + x24c02_word = 0; + x24c02_out = 0; + } else { // WORD ADDRESS INPUT + x24c02_word <<= 1; + x24c02_word |= sda; + if (x24c02_bitcount == 16) {// END OF ADDRESS INPUT + x24c02_bitcount = 7; + x24c02_state = X24C0X_WRITE; + } + } + x24c02_bitcount++; + break; + case X24C0X_READ: + if (x24c02_bitcount == 8) { // ACK + x24c02_out = 0; + x24c02_latch = x24c0x_data[x24c02_word|0x100]; + x24c02_bitcount = 0; + } else { // REAL OUTPUT + x24c02_out = x24c02_latch >> 7; + x24c02_latch <<= 1; + x24c02_bitcount++; + if (x24c02_bitcount == 8) { + x24c02_word++; + x24c02_word &= 0xff; + } + } + break; + case X24C0X_WRITE: + if (x24c02_bitcount == 8) { // ACK + x24c02_out = 0; + x24c02_latch = 0; + x24c02_bitcount = 0; + } else { // REAL INPUT + x24c02_latch <<= 1; + x24c02_latch |= sda; + x24c02_bitcount++; + if (x24c02_bitcount == 8) { + x24c0x_data[x24c02_word|0x100] = x24c02_latch; + x24c02_word++; + x24c02_word &= 0xff; + } + } + break; + } + } + x24c02_sda = sda; + x24c02_scl = scl; } // +static void SyncMirror(void) { + switch (reg[9] & 3) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + static void Sync(void) { if (is153) { int base = (reg[0] & 1) << 4; @@ -174,12 +259,7 @@ static void Sync(void) { setprg16(0x8000, reg[8]); setprg16(0xC000, ~0); } - switch (reg[9] & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } + SyncMirror(); } static DECLFW(BandaiWrite) { @@ -192,12 +272,15 @@ static DECLFW(BandaiWrite) { case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break; case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break; case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break; - case 0x0D: x24c0x_write(V); break; + case 0x0D: if(x24c02) x24c02_write(V); else x24c01_write(V); break; } } static DECLFR(BandaiRead) { - return (X.DB & 0xEF) | x24c0x_read(); + if(x24c02) + return (X.DB & 0xEF) | (x24c02_out << 4); + else + return (X.DB & 0xEF) | (x24c01_out << 4); } static void BandaiIRQHook(int a) { @@ -213,11 +296,14 @@ static void BandaiIRQHook(int a) { static void BandaiPower(void) { IRQa = 0; - x24c0x_init(); + if(x24c02) + x24c02_init(); + else + x24c01_init(); Sync(); SetReadHandler(0x6000, 0x7FFF, BandaiRead); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0xFFFF, BandaiWrite); + SetWriteHandler(0x8000, 0xFFFF, BandaiWrite); } static void StateRestore(int version) { @@ -231,12 +317,12 @@ void Mapper16_Init(CartInfo *info) { MapIRQHook = BandaiIRQHook; info->battery = 1; - info->SaveGame[0] = x24c0x_data; + info->SaveGame[0] = x24c0x_data + 256; info->SaveGameLen[0] = 256; AddExState(x24c0x_data, 256, 0, "DATA"); + AddExState(&x24c02StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; - AddExState(&x24c0xStateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); } @@ -250,9 +336,9 @@ void Mapper159_Init(CartInfo *info) { info->SaveGame[0] = x24c0x_data; info->SaveGameLen[0] = 128; AddExState(x24c0x_data, 128, 0, "DATA"); + AddExState(&x24c01StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; - AddExState(&x24c0xStateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); } @@ -307,7 +393,9 @@ static int BarcodeReadPos; static int BarcodeCycleCount; static uint32 BarcodeOut; -int FCEUI_DatachSet(const uint8 *rcode) { +// #define INTERL2OF5 + +int FCEUI_DatachSet(uint8 *rcode) { int prefix_parity_type[10][6] = { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1 }, { 0, 0, 1, 1, 0, 1 }, { 0, 0, 1, 1, 1, 0 }, { 0, 1, 0, 0, 1, 1 }, { 0, 1, 1, 0, 0, 1 }, { 0, 1, 1, 1, 0, 0 }, { 0, 1, 0, 1, 0, 1 }, @@ -330,6 +418,7 @@ int FCEUI_DatachSet(const uint8 *rcode) { }; uint8 code[13 + 1]; uint32 tmp_p = 0; + uint32 csum = 0; int i, j; int len; @@ -341,18 +430,46 @@ int FCEUI_DatachSet(const uint8 *rcode) { } if (len != 13 && len != 12 && len != 8 && len != 7) return(0); - #define BS(x) BarcodeData[tmp_p] = x; tmp_p++ +#define BS(x) BarcodeData[tmp_p] = x; tmp_p++ - for (j = 0; j < 32; j++) { + for (j = 0; j < 32; j++) { // delay before sending a code BS(0x00); } - /* Left guard bars */ +#ifdef INTERL2OF5 + + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 cs + BS(1); BS(1); BS(0); BS(0); // 1 + +#else + // Left guard bars BS(1); BS(0); BS(1); - if (len == 13 || len == 12) { - uint32 csum; - for (i = 0; i < 6; i++) if (prefix_parity_type[code[0]][i]) { for (j = 0; j < 7; j++) { @@ -362,53 +479,53 @@ int FCEUI_DatachSet(const uint8 *rcode) { for (j = 0; j < 7; j++) { BS(data_left_odd[code[i + 1]][j]); } - - /* Center guard bars */ + // Center guard bars BS(0); BS(1); BS(0); BS(1); BS(0); - for (i = 7; i < 12; i++) for (j = 0; j < 7; j++) { BS(data_right[code[i]][j]); } - csum = 0; - for (i = 0; i < 12; i++) csum += code[i] * ((i & 1) ? 3 : 1); - csum = (10 - (csum % 10)) % 10; + // Calc and write down the control code if not assigned, instead, send code as is + // Battle Rush uses modified type of codes with different control code calculation + if (len == 12) { + for (i = 0; i < 12; i++) + csum += code[i] * ((i & 1) ? 3 : 1); + csum = (10 - (csum % 10)) % 10; + rcode[12] = csum + 0x30; // update check code to the input string as well + rcode[13] = 0; + code[12] = csum; + } for (j = 0; j < 7; j++) { - BS(data_right[csum][j]); + BS(data_right[code[12]][j]); } } else if (len == 8 || len == 7) { - uint32 csum = 0; - - for (i = 0; i < 7; i++) csum += (i & 1) ? code[i] : (code[i] * 3); - - csum = (10 - (csum % 10)) % 10; - for (i = 0; i < 4; i++) for (j = 0; j < 7; j++) { BS(data_left_odd[code[i]][j]); } - - - /* Center guard bars */ + // Center guard bars BS(0); BS(1); BS(0); BS(1); BS(0); - for (i = 4; i < 7; i++) for (j = 0; j < 7; j++) { BS(data_right[code[i]][j]); } - + csum = 0; + for (i = 0; i < 7; i++) + csum += (i & 1) ? code[i] : (code[i] * 3); + csum = (10 - (csum % 10)) % 10; + rcode[7] = csum + 0x30; // update check code to the input string as well + rcode[8] = 0; for (j = 0; j < 7; j++) { BS(data_right[csum][j]); } } - - /* Right guard bars */ + // Right guard bars BS(1); BS(0); BS(1); +#endif for (j = 0; j < 32; j++) { BS(0x00); } - BS(0xFF); #undef BS @@ -419,6 +536,26 @@ int FCEUI_DatachSet(const uint8 *rcode) { return(1); } +static void BarcodeSync(void) { + setchr8(0); + setprg16(0x8000, (reg[8] & 0x0F)); + setprg16(0xC000, 0x0F); + SyncMirror(); +} + +static DECLFW(BarcodeWrite) { + A &= 0x0F; + switch (A) { + case 0x00: reg[0] = (V & 8) << 2; x24c01_write(reg[0xD] | reg[0]); break; // extra EEPROM x24C01 used in Battle Rush mini-cart + case 0x08: + case 0x09: reg[A] = V; BarcodeSync(); break; + case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break; + case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break; + case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break; + case 0x0D: reg[0xD] = V & (~0x20); x24c01_write(reg[0xD] | reg[0]); x24c02_write(V); break; + } +} + static void BarcodeIRQHook(int a) { BandaiIRQHook(a); @@ -436,7 +573,7 @@ static void BarcodeIRQHook(int a) { } static DECLFR(BarcodeRead) { - return BarcodeOut; + return (X.DB & 0xE7) | ((x24c02_out | x24c01_out) << 4) | BarcodeOut; } static void M157Power(void) { @@ -446,20 +583,29 @@ static void M157Power(void) { BarcodeOut = 0; BarcodeCycleCount = 0; - Sync(); + x24c01_init(); + x24c02_init(); + BarcodeSync(); - SetWriteHandler(0x6000, 0xFFFF, BandaiWrite); SetReadHandler(0x6000, 0x7FFF, BarcodeRead); SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, BarcodeWrite); } void Mapper157_Init(CartInfo *info) { - is153 = 1; + x24c02 = 1; info->Power = M157Power; MapIRQHook = BarcodeIRQHook; GameInfo->cspecial = SIS_DATACH; + info->battery = 1; + info->SaveGame[0] = x24c0x_data; + info->SaveGameLen[0] = 512; + AddExState(x24c0x_data, 512, 0, "DATA"); + AddExState(&x24c01StateRegs, ~0, 0, 0); + AddExState(&x24c02StateRegs, ~0, 0, 0); + GameStateRestore = StateRestore; GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/boards/emu2413.c b/src/boards/emu2413.c index 5c8e7042..8b6035c8 100644 --- a/src/boards/emu2413.c +++ b/src/boards/emu2413.c @@ -604,8 +604,8 @@ void OPLL_reset(OPLL * opll) { for (i = 0; i < 0x40; i++) OPLL_writeReg(opll, i, 0); - opll->realstep = (uint32)((1 << 31) / rate); - opll->opllstep = (uint32)((1 << 31) / (clk / 72)); + opll->realstep = (uint32)((1u << 31) / rate); + opll->opllstep = (uint32)((1u << 31) / (clk / 72)); opll->oplltime = 0; } diff --git a/src/boards/fk23c.cpp b/src/boards/fk23c.cpp index d7b3889f..e0df71d2 100644 --- a/src/boards/fk23c.cpp +++ b/src/boards/fk23c.cpp @@ -82,10 +82,10 @@ static int prg_mask; //PRG wrapper static void BMCFK23CPW(uint32 A, uint8 V) { - uint32 bank = (EXPREGS[1] & 0x1F); - uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0); - uint32 block = (EXPREGS[1] & 0x60) | hiblock; - uint32 extra = (EXPREGS[3] & 2); + //uint32 bank = (EXPREGS[1] & 0x1F); + //uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0); + //uint32 block = (EXPREGS[1] & 0x60) | hiblock; + //uint32 extra = (EXPREGS[3] & 2); // FCEU_printf("0:%04X:%02X\n",A,V); if((EXPREGS[0]&7)==4) @@ -161,7 +161,7 @@ static DECLFW(BMCFK23CWrite) EXPREGS[A&3]=V; // BUT WHY is there any rom that need it actually? - bool remap = false; +// bool remap = false; // FCEU_printf("K3:(exp0=%02x)\n",EXPREGS[0]); // FCEU_printf("WH0:%04X:%02X\n",A,V); @@ -199,7 +199,7 @@ static void BMCFK23CReset(void) //this little hack makes sure that we try all the dip switch settings eventually, if we reset enough dipswitch++; dipswitch&=7; - printf("BMCFK23C dipswitch set to %d\n",dipswitch); + printf("BMCFK23C dipswitch set to %u\n",dipswitch); EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0; EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF; diff --git a/src/boards/fns.cpp b/src/boards/fns.cpp index facb3c5e..08bbe24e 100644 --- a/src/boards/fns.cpp +++ b/src/boards/fns.cpp @@ -52,7 +52,9 @@ static void MMC1CHR(void) { static void MMC1PRG(void) { uint8 offs_16banks = DRegs[1] & 0x10; uint8 prg_reg = DRegs[3] & 0xF; + setprg8r(0x10, 0x6000, DRegs[1] & 3); + switch (DRegs[0] & 0xC) { case 0xC: setprg16(0x8000, (prg_reg + offs_16banks)); @@ -96,13 +98,13 @@ static DECLFW(MMC1_write) { Buffer |= (V & 1) << (BufferShift++); if (BufferShift == 5) { + FCEU_printf("MMC1 REG%d:%02x (PC %04x)\n", n, Buffer, X.PC); DRegs[n] = Buffer; - // FCEU_printf("MMC1 REG%d:%02x\n", n, Buffer); BufferShift = Buffer = 0; switch (n) { - case 0: MMC1MIRROR(); // break; - case 1: // break; -// case 2: MMC1CHR(); break; + case 0: MMC1MIRROR(); + case 1: + case 2: case 3: MMC1PRG(); break; } } @@ -151,13 +153,13 @@ static DECLFW(FNC_cmd_write) { break; } case 0x40C0: { -// FCEU_printf("FNS W %04x:%02x\n", A, V); + FCEU_printf("FNS W %04x:%02x (PC %04x)\n", A, V, X.PC); r40C0 = V; MMC1CHR(); break; } -// default: -// FCEU_printf("FNS W %04x:%02x\n", A, V); + default: + FCEU_printf("FNS W %04x:%02x (PC %04x)\n", A, V, X.PC); } } @@ -169,23 +171,32 @@ static DECLFR(FNC_stat_read) { IRQa = 0; return ret; } + case 0x40AC: { // NMI/IRQ state reset (lookalike) + return 0; + } case 0x40B0: { kanji_pos = 0; return 0; } case 0x40C0: { -// FCEU_printf("FNS R %04x\n", A); + FCEU_printf("FNS R %04x (PC %04x)\n", A, X.PC); int ret = r40C0; r40C0 &= 0; return ret; } default: { -// FCEU_printf("FNS R %04x\n", A); + FCEU_printf("FNS R %04x (PC %04x)\n", A, X.PC); return 0xff; } } } +static DECLFR(FNC_cart_i2c_read) { + FCEU_printf("I2C R %04x (PC %04x)\n", A, X.PC); + return 0; +} + + static DECLFR(FNC_kanji_read) { int32 ofs = ((A & 0xFFF) << 5) + kanji_pos; kanji_pos++; @@ -217,8 +228,9 @@ static void FNS_Power(void) { SetReadHandler(0x4080, 0x40FF, FNC_stat_read); SetReadHandler(0x5000, 0x5FFF, FNC_kanji_read); - SetReadHandler(0x6000, 0x7FFF, MAWRAM); - SetWriteHandler(0x6000, 0x7FFF, MBWRAM); + SetReadHandler(0x6000, 0x6000, FNC_cart_i2c_read); + SetReadHandler(0x6001, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); FCEU_CheatAddRAM(8, 0x6000, WRAM); MMC1CMReset(); diff --git a/src/cheat.cpp b/src/cheat.cpp index 10ee4105..fe2db821 100644 --- a/src/cheat.cpp +++ b/src/cheat.cpp @@ -569,7 +569,7 @@ int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c) int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type) { - int boo[4]; + unsigned int boo[4]; if(strlen(str)!=8) return(0); sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3); @@ -921,7 +921,7 @@ inline void FCEUI_CreateCheatMap() inline void FCEUI_RefreshCheatMap() { memset(cheatMap, 0, CHEATMAP_SIZE); - for (int i = 0; i < numsubcheats; ++i) + for (uint32 i = 0; i < numsubcheats; ++i) FCEUI_SetCheatMapByte(SubCheats[i].addr, true); } @@ -932,4 +932,4 @@ inline void FCEUI_ReleaseCheatMap() free(cheatMap); cheatMap = NULL; } -} \ No newline at end of file +} diff --git a/src/conddebug.cpp b/src/conddebug.cpp index 915fcfde..c08519c8 100644 --- a/src/conddebug.cpp +++ b/src/conddebug.cpp @@ -194,10 +194,10 @@ Condition* Parentheses(const char** str, Condition* c, char openPar, char closeP { scan(str); - c->lhs = Connect(str); - if (!c) return 0; + c->lhs = Connect(str); + if (next == closePar) { scan(str); diff --git a/src/debug.cpp b/src/debug.cpp index c88e581a..47e873ed 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -22,7 +22,7 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer) { int offset = -1; - if (sscanf(offsetBuffer,"%4X",&offset) == EOF) + if (sscanf(offsetBuffer,"%4X",(unsigned int *)&offset) == EOF) { return -1; } diff --git a/src/driver.h b/src/driver.h index d3f1f020..561af40a 100644 --- a/src/driver.h +++ b/src/driver.h @@ -142,7 +142,9 @@ void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall); //Sets the base directory(save states, snapshots, etc. are saved in directories below this directory. void FCEUI_SetBaseDirectory(std::string const & dir); +const char *FCEUI_GetBaseDirectory(void); +bool FCEUI_GetUserPaletteAvail(void); void FCEUI_SetUserPalette(uint8 *pal, int nEntries); //Sets up sound code to render sound at the specified rate, in samples @@ -250,7 +252,7 @@ void FCEUI_FDSInsert(void); //mbg merge 7/17/06 changed to void fn(void) to make //int FCEUI_FDSEject(void); void FCEUI_FDSSelect(void); -int FCEUI_DatachSet(const uint8 *rcode); +int FCEUI_DatachSet(uint8 *rcode); ///returns a flag indicating whether emulation is paused int FCEUI_EmulationPaused(); @@ -340,7 +342,7 @@ enum EFCEUI FCEUI_STOPMOVIE, FCEUI_RECORDMOVIE, FCEUI_PLAYMOVIE, FCEUI_OPENGAME, FCEUI_CLOSEGAME, FCEUI_TASEDITOR, - FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN, + FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN, FCEUI_INPUT_BARCODE, FCEUI_TOGGLERECORDINGMOVIE, FCEUI_TRUNCATEMOVIE, FCEUI_INSERT1FRAME, FCEUI_DELETE1FRAME }; diff --git a/src/drivers/Qt/AboutWindow.cpp b/src/drivers/Qt/AboutWindow.cpp index 4d67090d..b79f0315 100644 --- a/src/drivers/Qt/AboutWindow.cpp +++ b/src/drivers/Qt/AboutWindow.cpp @@ -16,6 +16,7 @@ static const char *Authors[] = { "Linux/SDL Developers:", + "\t mjbudd77", "\t Lukas Sabota //punkrockguy318", "\t Soules", "\t Bryan Cain", "\t radsaq", "\t Shinydoofy", "FceuX 2.0 Developers:", diff --git a/src/drivers/Qt/CheatsConf.cpp b/src/drivers/Qt/CheatsConf.cpp new file mode 100644 index 00000000..1f53e556 --- /dev/null +++ b/src/drivers/Qt/CheatsConf.cpp @@ -0,0 +1,1014 @@ +// HotKeyConf.cpp +// +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "../../fceu.h" +#include "../../cheat.h" +#include "../../debug.h" +#include "../../driver.h" +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/CheatsConf.h" +#include "Qt/ConsoleUtilities.h" + +static GuiCheatsDialog_t *win = NULL; +//---------------------------------------------------------------------------- +GuiCheatsDialog_t::GuiCheatsDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QHBoxLayout *mainLayout, *hbox, *hbox1; + QVBoxLayout *vbox, *vbox1, *vbox2, *vbox3; + QTreeWidgetItem *item; + QLabel *lbl; + QGroupBox *groupBox; + QFrame *frame; + QScreen *screen = QGuiApplication::primaryScreen(); + double devPixRatio = 1.0f; + + if ( screen != NULL ) + { + devPixRatio = (int)( screen->devicePixelRatio() + 0.50f); + //printf("Pix Ratio: %f \n", devPixRatio ); + } + + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + + QFontMetrics fm(font); + + //fontCharWidth = fm.boundingRect('X').width() * devPixRatio; + fontCharWidth = 2.00 * fm.averageCharWidth() * devPixRatio; + + setWindowTitle("Cheat Search"); + + pauseWhileActive = false; + wasPausedByCheats = false; + + //resize( 512, 512 ); + + // Window Layout Box + mainLayout = new QHBoxLayout(); + + //------------------------------------------------------- + // Left Side Active Cheats Frame + actCheatFrame = new QGroupBox( tr("Active Cheats") ); + + vbox1 = new QVBoxLayout(); + + mainLayout->addWidget( actCheatFrame ); + + actvCheatList = new QTreeWidget(); + + actvCheatList->setColumnCount(2); + + item = new QTreeWidgetItem(); + item->setFont( 0, font ); + item->setFont( 1, font ); + item->setText( 0, QString::fromStdString( "Code" ) ); + item->setText( 1, QString::fromStdString( "Name" ) ); + item->setTextAlignment( 0, Qt::AlignCenter); + item->setTextAlignment( 1, Qt::AlignCenter); + + actvCheatList->setHeaderItem( item ); + + actvCheatList->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + + connect( actvCheatList, SIGNAL(itemClicked(QTreeWidgetItem*, int)), + this, SLOT(actvCheatItemClicked( QTreeWidgetItem*, int)) ); + + hbox = new QHBoxLayout(); + + enaCheats = new QCheckBox( tr("Enable Cheats") ); + autoSave = new QCheckBox( tr("Auto Load / Save with Game") ); + + enaCheats->setChecked( !globalCheatDisabled ); + autoSave->setChecked( !disableAutoLSCheats ); + + hbox->addWidget( enaCheats ); + hbox->addWidget( autoSave ); + + vbox1->addLayout( hbox ); + + vbox1->addWidget( actvCheatList ); + + hbox = new QHBoxLayout(); + + lbl = new QLabel( tr("Name:") ); + cheatNameEntry = new QLineEdit(); + cheatNameEntry->setFont( font ); + //cheatNameEntry->setMaxLength(64); + + hbox->addWidget( lbl ); + hbox->addWidget( cheatNameEntry ); + + vbox1->addLayout( hbox ); + + hbox = new QHBoxLayout(); + + lbl = new QLabel( tr("Address:") ); + cheatAddrEntry = new QLineEdit(); + cheatAddrEntry->setMaxLength(4); + cheatAddrEntry->setInputMask( ">HHHH;0" ); + cheatAddrEntry->setFont( font ); + cheatAddrEntry->setCursorPosition(0); + cheatAddrEntry->setAlignment(Qt::AlignCenter); + cheatAddrEntry->setMaximumWidth( 5 * fontCharWidth ); + + hbox->addWidget( lbl ); + hbox->addWidget( cheatAddrEntry ); + + lbl = new QLabel( tr("Value:") ); + cheatValEntry = new QLineEdit(); + cheatValEntry->setMaxLength(2); + cheatValEntry->setInputMask( ">HH;0" ); + cheatValEntry->setFont( font ); + cheatValEntry->setCursorPosition(0); + cheatValEntry->setAlignment(Qt::AlignCenter); + cheatValEntry->setMaximumWidth( 3 * fontCharWidth ); + + hbox->addWidget( lbl ); + hbox->addWidget( cheatValEntry ); + + lbl = new QLabel( tr("Compare:") ); + cheatCmpEntry = new QLineEdit(); + cheatCmpEntry->setMaxLength(2); + cheatCmpEntry->setInputMask( ">HH;X" ); + cheatCmpEntry->setFont( font ); + cheatCmpEntry->setCursorPosition(0); + cheatCmpEntry->setAlignment(Qt::AlignCenter); + cheatCmpEntry->setMaximumWidth( 3 * fontCharWidth ); + + hbox->addWidget( lbl ); + hbox->addWidget( cheatCmpEntry ); + + vbox1->addLayout( hbox ); + + hbox = new QHBoxLayout(); + + addCheatBtn = new QPushButton( tr("Add") ); + delCheatBtn = new QPushButton( tr("Delete") ); + modCheatBtn = new QPushButton( tr("Update") ); + + hbox->addWidget( addCheatBtn ); + hbox->addWidget( delCheatBtn ); + hbox->addWidget( modCheatBtn ); + + vbox1->addLayout( hbox ); + + hbox = new QHBoxLayout(); + + importCheatFileBtn = new QPushButton( tr("Import") ); + exportCheatFileBtn = new QPushButton( tr("Export") ); + importCheatFileBtn->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + exportCheatFileBtn->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + + hbox->addWidget( importCheatFileBtn ); + hbox->addWidget( exportCheatFileBtn ); + + vbox1->addLayout( hbox ); + + actCheatFrame->setLayout( vbox1 ); + + cheatSearchFrame = new QGroupBox( tr("Cheat Search") ); + cheatResultFrame = new QGroupBox( tr("Possibilities") ); + + srchResults = new QTreeWidget(); + srchResults->setColumnCount(3); + + item = new QTreeWidgetItem(); + item->setFont( 0, font ); + item->setFont( 1, font ); + item->setFont( 2, font ); + item->setText( 0, QString::fromStdString( "Addr" ) ); + item->setText( 1, QString::fromStdString( "Pre" ) ); + item->setText( 2, QString::fromStdString( "Cur" ) ); + item->setTextAlignment( 0, Qt::AlignCenter); + item->setTextAlignment( 1, Qt::AlignCenter); + item->setTextAlignment( 2, Qt::AlignCenter); + + srchResults->setHeaderItem( item ); + + //srchResults->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + srchResults->header()->setSectionResizeMode( QHeaderView::Interactive ); + //srchResults->header()->setSectionResizeMode( QHeaderView::Fixed ); + srchResults->header()->resizeSection( 0, 10 * fontCharWidth ); + srchResults->header()->resizeSection( 1, 6 * fontCharWidth ); + srchResults->header()->resizeSection( 2, 6 * fontCharWidth ); + //srchResults->header()->setSectionResizeMode( QHeaderView::Stretch ); + //srchResults->header()->setDefaultSectionSize( 200 ); + //srchResults->header()->setDefaultSectionSize( 200 ); + //srchResults->setReadOnly(true); + + vbox = new QVBoxLayout(); + vbox->addWidget( srchResults ); + cheatResultFrame->setLayout( vbox ); + + hbox1 = new QHBoxLayout(); + + vbox2 = new QVBoxLayout(); + + hbox1->addLayout( vbox2 ); + hbox1->addWidget( cheatResultFrame ); + + cheatSearchFrame->setLayout( hbox1 ); + + srchResetBtn = new QPushButton( tr("Reset") ); + srchResetBtn->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + + vbox2->addWidget( srchResetBtn ); + + frame = new QFrame(); + frame->setFrameShape( QFrame::Box ); + frame->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + vbox2->addWidget( frame ); + vbox = new QVBoxLayout(); + + frame->setLayout( vbox ); + + knownValBtn = new QPushButton( tr("Known Value:") ); + knownValBtn->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + knownValBtn->setEnabled(false); + + vbox->addWidget( knownValBtn ); + + hbox1 = new QHBoxLayout(); + vbox->addLayout( hbox1 ); + + lbl = new QLabel( tr("0x") ); + lbl->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + knownValEntry = new QLineEdit(); + knownValEntry->setMaxLength(2); + knownValEntry->setInputMask( ">HH;0" ); + knownValEntry->setFont( font ); + knownValEntry->setCursorPosition(0); + knownValEntry->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + knownValEntry->setMaximumWidth( 3 * fontCharWidth ); + knownValEntry->setAlignment(Qt::AlignCenter); + knownValEntry->setEnabled(false); + hbox1->addWidget( lbl, 0, Qt::AlignRight ); + hbox1->addWidget( knownValEntry, 0, Qt::AlignLeft ); + + groupBox = new QGroupBox( tr("Previous Compare") ); + vbox2->addWidget( groupBox ); + groupBox->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + + vbox3 = new QVBoxLayout(); + + frame = new QFrame(); + frame->setFrameShape( QFrame::Box ); + frame->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + vbox3->addWidget( frame ); + vbox = new QVBoxLayout(); + + eqValBtn = new QPushButton( tr("Equal") ); + eqValBtn->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + eqValBtn->setEnabled(false); + vbox->addWidget( eqValBtn ); + + frame->setLayout( vbox ); + + frame = new QFrame(); + frame->setFrameShape( QFrame::Box ); + frame->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + vbox3->addWidget( frame ); + vbox = new QVBoxLayout(); + + neValBtn = new QPushButton( tr("Not Equal") ); + neValBtn->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + neValBtn->setEnabled(false); + + hbox = new QHBoxLayout(); + useNeVal = new QCheckBox( tr("By:") ); + useNeVal->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + useNeVal->setEnabled(false); + neValEntry = new QLineEdit(); + neValEntry->setMaxLength(2); + neValEntry->setInputMask( ">HH;0" ); + neValEntry->setFont( font ); + neValEntry->setCursorPosition(0); + neValEntry->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + neValEntry->setMaximumWidth( 3 * fontCharWidth ); + neValEntry->setAlignment(Qt::AlignCenter); + neValEntry->setEnabled(false); + + hbox->addWidget( useNeVal, 0, Qt::AlignRight ); + hbox->addWidget( neValEntry, 0, Qt::AlignLeft ); + + vbox->addWidget( neValBtn ); + vbox->addLayout( hbox ); + frame->setLayout( vbox ); + + frame = new QFrame(); + frame->setFrameShape( QFrame::Box ); + frame->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + vbox3->addWidget( frame ); + vbox = new QVBoxLayout(); + + grValBtn = new QPushButton( tr("Greater Than") ); + grValBtn->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + grValBtn->setEnabled(false); + + hbox = new QHBoxLayout(); + useGrVal = new QCheckBox( tr("By:") ); + useGrVal->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + useGrVal->setEnabled(false); + grValEntry = new QLineEdit(); + grValEntry->setMaxLength(2); + grValEntry->setInputMask( ">HH;0" ); + grValEntry->setFont( font ); + grValEntry->setCursorPosition(0); + grValEntry->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + grValEntry->setMaximumWidth( 3 * fontCharWidth ); + grValEntry->setAlignment(Qt::AlignCenter); + grValEntry->setEnabled(false); + + hbox->addWidget( useGrVal, 0, Qt::AlignRight ); + hbox->addWidget( grValEntry, 0, Qt::AlignLeft ); + + vbox->addWidget( grValBtn ); + vbox->addLayout( hbox ); + frame->setLayout( vbox ); + + frame = new QFrame(); + frame->setFrameShape( QFrame::Box ); + frame->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + vbox3->addWidget( frame ); + vbox = new QVBoxLayout(); + + ltValBtn = new QPushButton( tr("Less Than") ); + ltValBtn->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + ltValBtn->setEnabled(false); + + hbox = new QHBoxLayout(); + useLtVal = new QCheckBox( tr("By:") ); + useLtVal->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + useLtVal->setEnabled(false); + ltValEntry = new QLineEdit(); + ltValEntry->setMaxLength(2); + ltValEntry->setInputMask( ">HH;0" ); + ltValEntry->setFont( font ); + ltValEntry->setCursorPosition(0); + ltValEntry->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ); + ltValEntry->setMaximumWidth( 3 * fontCharWidth ); + ltValEntry->setAlignment(Qt::AlignCenter); + ltValEntry->setEnabled(false); + + hbox->addWidget( useLtVal, 0, Qt::AlignRight ); + hbox->addWidget( ltValEntry, 0, Qt::AlignLeft ); + + vbox->addWidget( ltValBtn ); + vbox->addLayout( hbox ); + frame->setLayout( vbox ); + + groupBox->setLayout( vbox3 ); + + vbox = new QVBoxLayout(); + + pauseBox = new QCheckBox( tr("Pause emulation when this window is active") ); + + vbox->addWidget( cheatSearchFrame ); + vbox->addWidget( pauseBox ); + + mainLayout->addLayout( vbox ); + + setLayout( mainLayout ); + + connect( srchResetBtn, SIGNAL(clicked(void)), this, SLOT(resetSearchCallback(void)) ); + connect( knownValBtn , SIGNAL(clicked(void)), this, SLOT(knownValueCallback(void)) ); + connect( eqValBtn , SIGNAL(clicked(void)), this, SLOT(equalValueCallback(void)) ); + connect( neValBtn , SIGNAL(clicked(void)), this, SLOT(notEqualValueCallback(void)) ); + connect( ltValBtn , SIGNAL(clicked(void)), this, SLOT(lessThanValueCallback(void)) ); + connect( grValBtn , SIGNAL(clicked(void)), this, SLOT(greaterThanValueCallback(void)) ); + connect( addCheatBtn , SIGNAL(clicked(void)), this, SLOT(addActvCheat(void)) ); + connect( delCheatBtn , SIGNAL(clicked(void)), this, SLOT(deleteActvCheat(void)) ); + connect( modCheatBtn , SIGNAL(clicked(void)), this, SLOT(updateCheatParameters(void)) ); + + connect( enaCheats, SIGNAL(stateChanged(int)), this, SLOT(globalEnableCheats(int)) ); + connect( autoSave , SIGNAL(stateChanged(int)), this, SLOT(autoLoadSaveCheats(int)) ); + connect( pauseBox , SIGNAL(stateChanged(int)), this, SLOT(pauseWindowState(int)) ); + + connect( importCheatFileBtn, SIGNAL(clicked(void)), this, SLOT(openCheatFile(void)) ); + connect( exportCheatFileBtn, SIGNAL(clicked(void)), this, SLOT(saveCheatFile(void)) ); + + showActiveCheatList(true); +} +//---------------------------------------------------------------------------- +GuiCheatsDialog_t::~GuiCheatsDialog_t(void) +{ + if (EmulationPaused && wasPausedByCheats) + { + EmulationPaused = 0; + FCEU_printf ("Emulation paused: %d\n", EmulationPaused); + } + wasPausedByCheats = false; + + printf("Destroy Cheat Window Event\n"); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Cheat Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------------------------------- +int GuiCheatsDialog_t::addSearchResult (uint32_t a, uint8_t last, uint8_t current) +{ + QTreeWidgetItem *item; + char addrStr[8], lastStr[8], curStr[8]; + + item = new QTreeWidgetItem(); + + sprintf (addrStr, "$%04X", a); + sprintf (lastStr, "%02X", last); + sprintf (curStr , "%02X", current); + + //item->setFont( 0, font ); + //item->setFont( 1, font ); + //item->setFont( 2, font ); + + item->setText( 0, tr(addrStr) ); + item->setText( 1, tr(lastStr) ); + item->setText( 2, tr(curStr) ); + + item->setTextAlignment( 0, Qt::AlignCenter); + item->setTextAlignment( 1, Qt::AlignCenter); + item->setTextAlignment( 2, Qt::AlignCenter); + + srchResults->addTopLevelItem( item ); + + return 1; +} +//---------------------------------------------------------------------------- +static int ShowCheatSearchResultsCallB (uint32 a, uint8 last, uint8 current) +{ + return win->addSearchResult( a, last, current ); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::showCheatSearchResults(void) +{ + int total_matches; + + win = this; + + srchResults->clear(); + + total_matches = FCEUI_CheatSearchGetCount (); + + FCEUI_CheatSearchGetRange (0, total_matches, + ShowCheatSearchResultsCallB); + + printf("Num Matches: %i \n", total_matches ); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::resetSearchCallback(void) +{ + fceuWrapperLock(); + + FCEUI_CheatSearchBegin (); + + showCheatSearchResults(); + + fceuWrapperUnLock(); + + knownValBtn->setEnabled(true); + eqValBtn->setEnabled(true); + neValBtn->setEnabled(true); + grValBtn->setEnabled(true); + ltValBtn->setEnabled(true); + + useNeVal->setEnabled(true); + useGrVal->setEnabled(true); + useLtVal->setEnabled(true); + + knownValEntry->setEnabled(true); + neValEntry->setEnabled(true); + grValEntry->setEnabled(true); + ltValEntry->setEnabled(true); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::knownValueCallback(void) +{ + int value; + //printf("Cheat Search Known!\n"); + fceuWrapperLock(); + + //printf("%s\n", knownValEntry->text().toStdString().c_str() ); + + value = strtol( knownValEntry->text().toStdString().c_str(), NULL, 16 ); + + FCEUI_CheatSearchEnd (FCEU_SEARCH_NEWVAL_KNOWN, value, 0); + + showCheatSearchResults(); + + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::equalValueCallback(void) +{ + //printf("Cheat Search Equal!\n"); + fceuWrapperLock(); + + FCEUI_CheatSearchEnd (FCEU_SEARCH_PUERLY_RELATIVE_CHANGE, 0, 0); + + showCheatSearchResults(); + + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::notEqualValueCallback(void) +{ + //printf("Cheat Search Not Equal!\n"); + int value; + int checked = useNeVal->checkState() != Qt::Unchecked; + + fceuWrapperLock(); + + if (checked) + { + value = strtol( neValEntry->text().toStdString().c_str(), NULL, 16 ); + + FCEUI_CheatSearchEnd (FCEU_SEARCH_PUERLY_RELATIVE_CHANGE, 0, value); + } + else + { + FCEUI_CheatSearchEnd (FCEU_SEARCH_ANY_CHANGE, 0, 0); + } + + showCheatSearchResults(); + + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::greaterThanValueCallback(void) +{ + //printf("Cheat Search Greater Than!\n"); + int value; + int checked = useGrVal->checkState() != Qt::Unchecked; + + fceuWrapperLock(); + + if (checked) + { + value = strtol( grValEntry->text().toStdString().c_str(), NULL, 16 ); + + FCEUI_CheatSearchEnd (FCEU_SEARCH_NEWVAL_GT_KNOWN, 0, value); + } + else + { + FCEUI_CheatSearchEnd (FCEU_SEARCH_NEWVAL_GT, 0, 0); + } + + showCheatSearchResults(); + + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::lessThanValueCallback(void) +{ + //printf("Cheat Search Less Than!\n"); + int value; + int checked = useLtVal->checkState() != Qt::Unchecked; + + fceuWrapperLock(); + + if (checked) + { + value = strtol( ltValEntry->text().toStdString().c_str(), NULL, 16 ); + + FCEUI_CheatSearchEnd (FCEU_SEARCH_NEWVAL_LT_KNOWN, 0, value); + } + else + { + FCEUI_CheatSearchEnd (FCEU_SEARCH_NEWVAL_LT, 0, 0); + } + + showCheatSearchResults(); + + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- +int GuiCheatsDialog_t::activeCheatListCB (char *name, uint32 a, uint8 v, int c, int s, int type, void *data) +{ + QTreeWidgetItem *item; + char codeStr[32]; + + if (c >= 0) + { + sprintf (codeStr, "$%04X:%02X:%02X", a,v,c); + } + else + { + sprintf (codeStr, "$%04X:%02X ", a,v); + } + + item = actvCheatList->topLevelItem(actvCheatIdx); + + if ( item == NULL ) + { + item = new QTreeWidgetItem(); + + actvCheatList->addTopLevelItem( item ); + } + + //item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable ); + item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren ); + + item->setCheckState( 0, s ? Qt::Checked : Qt::Unchecked ); + + item->setText( 0, tr(codeStr)); + item->setText( 1, tr(name) ); + + item->setTextAlignment( 0, Qt::AlignLeft); + item->setTextAlignment( 1, Qt::AlignLeft); + + actvCheatIdx++; + + return 1; +} +//---------------------------------------------------------------------------- +static int activeCheatListCB (char *name, uint32 a, uint8 v, int c, int s, int type, void *data) +{ + return win->activeCheatListCB( name, a, v, c, s, type, data ); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::showActiveCheatList(bool redraw) +{ + win = this; + + actvCheatRedraw = redraw; + + if ( redraw ) + { + actvCheatList->clear(); + } + actvCheatIdx = 0; + + FCEUI_ListCheats (::activeCheatListCB, (void *) this); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::openCheatFile(void) +{ + FILE *fp; + int ret, useNativeFileDialogVal; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Open Cheat File") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("Cheat files (*.cht *.CHT) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Open") ); + + g_config->getOption ("SDL.LastOpenFile", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + g_config->setOption ("SDL.LastOpenFile", filename.toStdString().c_str() ); + + fceuWrapperLock(); + + fp = fopen (filename.toStdString().c_str(), "r"); + + if (fp != NULL) + { + FCEU_LoadGameCheats (fp, 0); + fclose (fp); + } + fceuWrapperUnLock(); + + showActiveCheatList(true); + + return; +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::saveCheatFile(void) +{ + FILE *fp; + int ret, useNativeFileDialogVal; + QString filename; + char dir[512]; + QFileDialog dialog(this, tr("Save Cheat File") ); + + dialog.setFileMode(QFileDialog::AnyFile); + + dialog.setNameFilter(tr("Cheat files (*.cht *.CHT) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Save") ); + + if ( GameInfo ) + { + getFileBaseName( GameInfo->filename, dir ); + + strcat( dir, ".cht"); + + dialog.selectFile( dir ); + } + + sprintf( dir, "%s/cheats", FCEUI_GetBaseDirectory() ); + + dialog.setDirectory( tr(dir) ); + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + //g_config->setOption ("SDL.LastOpenFile", filename.toStdString().c_str() ); + + fceuWrapperLock(); + + fp = FCEUD_UTF8fopen (filename.toStdString().c_str(), "wb"); + + if (fp != NULL) + { + FCEU_SaveGameCheats (fp); + fclose (fp); + } + fceuWrapperUnLock(); + + showActiveCheatList(true); + + return; +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::addActvCheat(void) +{ + uint32 a = 0; + uint8 v = 0; + int c = -1; + std::string name, cmpStr; + + a = strtoul( cheatAddrEntry->text().toStdString().c_str(), NULL, 16 ); + + v = strtoul( cheatValEntry->text().toStdString().c_str(), NULL, 16 ); + + cmpStr = cheatCmpEntry->text().toStdString(); + + if ( isdigit( cmpStr[0] ) ) + { + c = strtoul( cmpStr.c_str(), NULL, 16 ); + } + else + { + c = -1; + } + + name = cheatNameEntry->text().toStdString(); + + fceuWrapperLock(); + FCEUI_AddCheat( name.c_str(), a, v, c, 1 ); + fceuWrapperUnLock(); + + showActiveCheatList(true); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::deleteActvCheat(void) +{ + QTreeWidgetItem *item; + + item = actvCheatList->currentItem(); + + if ( item == NULL ) + { + printf( "No Item Selected\n"); + return; + } + + int row = actvCheatList->indexOfTopLevelItem(item); + + fceuWrapperLock(); + FCEUI_DelCheat (row); + fceuWrapperUnLock(); + + showActiveCheatList(true); + + cheatNameEntry->setText( tr("") ); + cheatAddrEntry->setText( tr("") ); + cheatValEntry->setText( tr("") ); + cheatCmpEntry->setText( tr("") ); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::updateCheatParameters(void) +{ + uint32 a = 0; + uint8 v = 0; + int c = -1, s = 0, type = 0; + std::string name, cmpStr; + QTreeWidgetItem *item; + + item = actvCheatList->currentItem(); + + if ( item == NULL ) + { + printf( "No Item Selected\n"); + return; + } + + int row = actvCheatList->indexOfTopLevelItem(item); + + if ( FCEUI_GetCheat( row, NULL, &a, &v, &c, &s, &type) == 0 ) + { + return; + } + //printf("Row: %i \n", row ); + + a = strtoul( cheatAddrEntry->text().toStdString().c_str(), NULL, 16 ); + + v = strtoul( cheatValEntry->text().toStdString().c_str(), NULL, 16 ); + + cmpStr = cheatCmpEntry->text().toStdString(); + + if ( isdigit( cmpStr[0] ) ) + { + c = strtoul( cmpStr.c_str(), NULL, 16 ); + } + else + { + c = -1; + } + + name = cheatNameEntry->text().toStdString(); + + //printf("Name: %s \n", name.c_str() ); + + fceuWrapperLock(); + + FCEUI_SetCheat( row, name.c_str(), a, v, c, s, type); + + fceuWrapperUnLock(); + + showActiveCheatList(false); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::actvCheatItemClicked( QTreeWidgetItem *item, int column) +{ + uint32 a = 0; + uint8 v = 0; + int c = -1, s = 0, type = 0; + char *name = NULL; + char stmp[64]; + + int row = actvCheatList->indexOfTopLevelItem(item); + + //printf("Row: %i Column: %i \n", row, column ); + + if ( FCEUI_GetCheat( row, &name, &a, &v, &c, &s, &type) == 0 ) + { + return; + } + + if ( column == 0 ) + { + int isChecked = item->checkState( column ) != Qt::Unchecked; + + if ( isChecked != s ) + { + //printf("Toggle Cheat: %i\n", isChecked); + FCEUI_ToggleCheat( row ); + } + } + sprintf( stmp, "%04X", a ); + cheatAddrEntry->setText( tr(stmp) ); + + sprintf( stmp, "%02X", v ); + cheatValEntry->setText( tr(stmp) ); + + if ( c >= 0 ) + { + sprintf( stmp, "%02X", c ); + cheatCmpEntry->setText( tr(stmp) ); + } + else + { + cheatCmpEntry->setText( tr("") ); + } + + if ( name != NULL ) + { + cheatNameEntry->setText( tr(name) ); + } + else + { + cheatNameEntry->setText( tr("") ); + } +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::globalEnableCheats(int state) +{ + fceuWrapperLock(); + FCEUI_GlobalToggleCheat( state != Qt::Unchecked ); + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::autoLoadSaveCheats(int state) +{ + if ( state == Qt::Unchecked ) + { + printf("If this option is unchecked, you must manually save the cheats by yourself, or all the changes you made to the cheat list would be discarded silently without any asking once you close the game!\nDo you really want to do it in this way?"); + disableAutoLSCheats = 2; + } + else + { + disableAutoLSCheats = 0; + } +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::pauseWindowState(int state) +{ + pauseWhileActive = (state != Qt::Unchecked); + + if (pauseWhileActive) + { + if (EmulationPaused == 0) + { + EmulationPaused = 1; + wasPausedByCheats = true; + } + } + else + { + if (EmulationPaused && wasPausedByCheats) + { + EmulationPaused = 0; + } + wasPausedByCheats = false; + } + FCEU_printf ("Emulation paused: %d\n", EmulationPaused); +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/CheatsConf.h b/src/drivers/Qt/CheatsConf.h new file mode 100644 index 00000000..fbc46a24 --- /dev/null +++ b/src/drivers/Qt/CheatsConf.h @@ -0,0 +1,99 @@ +// GamePadConf.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class GuiCheatsDialog_t : public QDialog +{ + Q_OBJECT + + public: + GuiCheatsDialog_t(QWidget *parent = 0); + ~GuiCheatsDialog_t(void); + + int addSearchResult( uint32_t a, uint8_t last, uint8_t current ); + + int activeCheatListCB (char *name, uint32 a, uint8 v, int c, int s, int type, void *data); + + protected: + void closeEvent(QCloseEvent *event); + + QGroupBox *actCheatFrame; + QGroupBox *cheatSearchFrame; + QGroupBox *cheatResultFrame; + QPushButton *addCheatBtn; + QPushButton *delCheatBtn; + QPushButton *modCheatBtn; + QPushButton *importCheatFileBtn; + QPushButton *exportCheatFileBtn; + QPushButton *srchResetBtn; + QPushButton *knownValBtn; + QPushButton *eqValBtn; + QPushButton *neValBtn; + QPushButton *grValBtn; + QPushButton *ltValBtn; + QCheckBox *useNeVal; + QCheckBox *useGrVal; + QCheckBox *useLtVal; + QCheckBox *enaCheats; + QCheckBox *autoSave; + QCheckBox *pauseBox; + QTreeWidget *actvCheatList; + QTreeWidget *srchResults; + QLineEdit *cheatNameEntry; + QLineEdit *cheatAddrEntry; + QLineEdit *cheatValEntry; + QLineEdit *cheatCmpEntry; + QLineEdit *knownValEntry; + QLineEdit *neValEntry; + QLineEdit *grValEntry; + QLineEdit *ltValEntry; + QFont font; + + int fontCharWidth; + int actvCheatIdx; + bool actvCheatRedraw; + bool pauseWhileActive; + bool wasPausedByCheats; + + private: + void showCheatSearchResults(void); + void showActiveCheatList(bool redraw); + + public slots: + void closeWindow(void); + private slots: + void resetSearchCallback(void); + void knownValueCallback(void); + void equalValueCallback(void); + void notEqualValueCallback(void); + void lessThanValueCallback(void); + void greaterThanValueCallback(void); + void openCheatFile(void); + void saveCheatFile(void); + void addActvCheat(void); + void deleteActvCheat(void); + void updateCheatParameters(void); + void autoLoadSaveCheats(int state); + void globalEnableCheats(int state); + void pauseWindowState(int state); + void actvCheatItemClicked( QTreeWidgetItem *item, int column); + +}; diff --git a/src/drivers/Qt/ConsoleSoundConf.cpp b/src/drivers/Qt/ConsoleSoundConf.cpp index 4d716f3b..b02c2253 100644 --- a/src/drivers/Qt/ConsoleSoundConf.cpp +++ b/src/drivers/Qt/ConsoleSoundConf.cpp @@ -1,5 +1,7 @@ // ConsoleSoundConf.cpp // +#include + #include "../../fceu.h" #include "../../driver.h" #include "Qt/ConsoleSoundConf.h" @@ -217,7 +219,22 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent) //---------------------------------------------------- ConsoleSndConfDialog_t::~ConsoleSndConfDialog_t(void) { - + printf("Destroy Sound Config Window\n"); +} +//---------------------------------------------------------------------------- +void ConsoleSndConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Sound Config Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void ConsoleSndConfDialog_t::closeWindow(void) +{ + //printf("Sound Close Window\n"); + done(0); + deleteLater(); } //---------------------------------------------------- void ConsoleSndConfDialog_t::setCheckBoxFromProperty( QCheckBox *cbx, const char *property ) @@ -262,10 +279,12 @@ void ConsoleSndConfDialog_t::bufSizeChanged(int value) g_config->setOption ("SDL.Sound.BufSize", value); // reset sound subsystem for changes to take effect - fceuWrapperLock(); - KillSound (); - InitSound (); - fceuWrapperUnLock(); + if ( fceuWrapperTryLock() ) + { + KillSound (); + InitSound (); + fceuWrapperUnLock(); + } } //---------------------------------------------------- void ConsoleSndConfDialog_t::volumeChanged(int value) @@ -278,9 +297,11 @@ void ConsoleSndConfDialog_t::volumeChanged(int value) g_config->setOption ("SDL.Sound.Volume", value); - fceuWrapperLock(); - FCEUI_SetSoundVolume (value); - fceuWrapperUnLock(); + if ( fceuWrapperTryLock() ) + { + FCEUI_SetSoundVolume (value); + fceuWrapperUnLock(); + } } //---------------------------------------------------- void ConsoleSndConfDialog_t::triangleChanged(int value) @@ -293,9 +314,11 @@ void ConsoleSndConfDialog_t::triangleChanged(int value) g_config->setOption ("SDL.Sound.TriangleVolume", value); - fceuWrapperLock(); - FCEUI_SetTriangleVolume (value); - fceuWrapperUnLock(); + if ( fceuWrapperTryLock() ) + { + FCEUI_SetTriangleVolume (value); + fceuWrapperUnLock(); + } } //---------------------------------------------------- void ConsoleSndConfDialog_t::square1Changed(int value) @@ -308,9 +331,11 @@ void ConsoleSndConfDialog_t::square1Changed(int value) g_config->setOption ("SDL.Sound.Square1Volume", value); - fceuWrapperLock(); - FCEUI_SetSquare1Volume (value); - fceuWrapperUnLock(); + if ( fceuWrapperTryLock() ) + { + FCEUI_SetSquare1Volume (value); + fceuWrapperUnLock(); + } } //---------------------------------------------------- void ConsoleSndConfDialog_t::square2Changed(int value) @@ -323,9 +348,11 @@ void ConsoleSndConfDialog_t::square2Changed(int value) g_config->setOption ("SDL.Sound.Square2Volume", value); - fceuWrapperLock(); - FCEUI_SetSquare2Volume (value); - fceuWrapperUnLock(); + if ( fceuWrapperTryLock() ) + { + FCEUI_SetSquare2Volume (value); + fceuWrapperUnLock(); + } } //---------------------------------------------------- void ConsoleSndConfDialog_t::noiseChanged(int value) @@ -338,9 +365,11 @@ void ConsoleSndConfDialog_t::noiseChanged(int value) g_config->setOption ("SDL.Sound.NoiseVolume", value); - fceuWrapperLock(); - FCEUI_SetNoiseVolume (value); - fceuWrapperUnLock(); + if ( fceuWrapperTryLock() ) + { + FCEUI_SetNoiseVolume (value); + fceuWrapperUnLock(); + } } //---------------------------------------------------- void ConsoleSndConfDialog_t::pcmChanged(int value) @@ -353,9 +382,11 @@ void ConsoleSndConfDialog_t::pcmChanged(int value) g_config->setOption ("SDL.Sound.PCMVolume", value); - fceuWrapperLock(); - FCEUI_SetPCMVolume (value); - fceuWrapperUnLock(); + if ( fceuWrapperTryLock() ) + { + FCEUI_SetPCMVolume (value); + fceuWrapperUnLock(); + } } //---------------------------------------------------- void ConsoleSndConfDialog_t::enaSoundStateChange(int value) @@ -427,10 +458,12 @@ void ConsoleSndConfDialog_t::soundQualityChanged(int index) g_config->setOption ("SDL.Sound.Quality", qualitySelect->itemData(index).toInt() ); // reset sound subsystem for changes to take effect - fceuWrapperLock(); - KillSound (); - InitSound (); - fceuWrapperUnLock(); + if ( fceuWrapperTryLock() ) + { + KillSound (); + InitSound (); + fceuWrapperUnLock(); + } g_config->save (); } //---------------------------------------------------- @@ -440,10 +473,12 @@ void ConsoleSndConfDialog_t::soundRateChanged(int index) g_config->setOption ("SDL.Sound.Rate", rateSelect->itemData(index).toInt() ); // reset sound subsystem for changes to take effect - fceuWrapperLock(); - KillSound (); - InitSound (); - fceuWrapperUnLock(); + if ( fceuWrapperTryLock() ) + { + KillSound (); + InitSound (); + fceuWrapperUnLock(); + } g_config->save (); } //---------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleSoundConf.h b/src/drivers/Qt/ConsoleSoundConf.h index 40e86d2a..40f8de1f 100644 --- a/src/drivers/Qt/ConsoleSoundConf.h +++ b/src/drivers/Qt/ConsoleSoundConf.h @@ -25,6 +25,8 @@ class ConsoleSndConfDialog_t : public QDialog ~ConsoleSndConfDialog_t(void); protected: + void closeEvent(QCloseEvent *event); + QCheckBox *enaChkbox; QCheckBox *enaLowPass; QCheckBox *swapDutyChkbox; @@ -44,6 +46,7 @@ class ConsoleSndConfDialog_t : public QDialog void setSliderFromProperty( QSlider *slider, QLabel *lbl, const char *property ); private slots: + void closeWindow(void); void bufSizeChanged(int value); void volumeChanged(int value); void triangleChanged(int value); diff --git a/src/drivers/Qt/ConsoleUtilities.cpp b/src/drivers/Qt/ConsoleUtilities.cpp new file mode 100644 index 00000000..d118dd7d --- /dev/null +++ b/src/drivers/Qt/ConsoleUtilities.cpp @@ -0,0 +1,85 @@ +// ConsoleUtilities.cpp +#include +#include + +#include "../../fceu.h" +#include "Qt/ConsoleUtilities.h" + +//--------------------------------------------------------------------------- +int getDirFromFile( const char *path, char *dir ) +{ + int i, lastSlash = -1, lastPeriod = -1; + + i=0; + while ( path[i] != 0 ) + { + if ( path[i] == '/' ) + { + lastSlash = i; + } + else if ( path[i] == '.' ) + { + lastPeriod = i; + } + dir[i] = path[i]; i++; + } + dir[i] = 0; + + if ( lastPeriod >= 0 ) + { + if ( lastPeriod > lastSlash ) + { + dir[lastSlash] = 0; + } + } + + return 0; +} +//--------------------------------------------------------------------------- +const char *getRomFile( void ) +{ + if ( GameInfo ) + { + return GameInfo->filename; + } + return NULL; +} +//--------------------------------------------------------------------------- +// Return file base name stripping out preceding path and trailing suffix. +int getFileBaseName( const char *filepath, char *base ) +{ + int i=0,j=0,end=0; + if ( filepath == NULL ) + { + base[0] = 0; + return 0; + } + i=0; j=0; + while ( filepath[i] != 0 ) + { + if ( (filepath[i] == '/') || (filepath[i] == '\\') ) + { + j = i+1; + } + i++; + } + i = j; + + j=0; + while ( filepath[i] != 0 ) + { + base[j] = filepath[i]; i++; j++; + } + base[j] = 0; end=j; + + while ( j > 1 ) + { + j--; + if ( base[j] == '.' ) + { + end=j; base[j] = 0; break; + } + } + return end; +} +//--------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleUtilities.h b/src/drivers/Qt/ConsoleUtilities.h new file mode 100644 index 00000000..e55e0361 --- /dev/null +++ b/src/drivers/Qt/ConsoleUtilities.h @@ -0,0 +1,7 @@ +// ConsoleUtilities.h + +int getDirFromFile( const char *path, char *dir ); + +const char *getRomFile( void ); + +int getFileBaseName( const char *filepath, char *base ); diff --git a/src/drivers/Qt/ConsoleVideoConf.cpp b/src/drivers/Qt/ConsoleVideoConf.cpp index 05104e20..1da2f639 100644 --- a/src/drivers/Qt/ConsoleVideoConf.cpp +++ b/src/drivers/Qt/ConsoleVideoConf.cpp @@ -1,5 +1,7 @@ // ConsoleVideoConf.cpp // +#include + #include "../../fceu.h" #include "Qt/main.h" #include "Qt/dface.h" @@ -26,7 +28,7 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent) driverSelect = new QComboBox(); driverSelect->addItem( tr("OpenGL"), 0 ); - //driverSelect->addItem( tr("SDL"), 1 ); + driverSelect->addItem( tr("SDL"), 1 ); hbox1 = new QHBoxLayout(); @@ -52,8 +54,10 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent) regionSelect->addItem( tr("Dendy"), 2 ); setComboBoxFromProperty( regionSelect, "SDL.PAL"); + setComboBoxFromProperty( driverSelect, "SDL.VideoDriver"); connect(regionSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(regionChanged(int)) ); + connect(driverSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(driverChanged(int)) ); hbox1 = new QHBoxLayout(); @@ -103,7 +107,7 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent) button = new QPushButton( tr("Close") ); hbox1->addWidget( button ); - connect(button, SIGNAL(clicked()), this, SLOT(closewindow(void)) ); + connect(button, SIGNAL(clicked()), this, SLOT(closeWindow(void)) ); main_vbox->addLayout( hbox1 ); @@ -113,8 +117,24 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent) //---------------------------------------------------- ConsoleVideoConfDialog_t::~ConsoleVideoConfDialog_t(void) { + printf("Destroy Video Config Window\n"); } +//---------------------------------------------------------------------------- +void ConsoleVideoConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Video Config Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void ConsoleVideoConfDialog_t::closeWindow(void) +{ + //printf("Video Config Close Window\n"); + done(0); + deleteLater(); +} //---------------------------------------------------- void ConsoleVideoConfDialog_t::resetVideo(void) { @@ -199,6 +219,20 @@ void ConsoleVideoConfDialog_t::showFPSChanged( int value ) fceuWrapperUnLock(); } //---------------------------------------------------- +void ConsoleVideoConfDialog_t::driverChanged(int index) +{ + int driver; + //printf("Driver: %i : %i \n", index, driverSelect->itemData(index).toInt() ); + + driver = driverSelect->itemData(index).toInt(); + + g_config->setOption ("SDL.VideoDriver", driver); + + g_config->save (); + + printf("Note: A restart of the application is needed for video driver change to take effect...\n"); +} +//---------------------------------------------------- void ConsoleVideoConfDialog_t::regionChanged(int index) { int region; @@ -221,8 +255,3 @@ void ConsoleVideoConfDialog_t::applyChanges( void ) resetVideo(); } //---------------------------------------------------- -void ConsoleVideoConfDialog_t::closewindow( void ) -{ - done(0); -} -//---------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleVideoConf.h b/src/drivers/Qt/ConsoleVideoConf.h index e27d59c0..73d86e76 100644 --- a/src/drivers/Qt/ConsoleVideoConf.h +++ b/src/drivers/Qt/ConsoleVideoConf.h @@ -25,6 +25,8 @@ class ConsoleVideoConfDialog_t : public QDialog ~ConsoleVideoConfDialog_t(void); protected: + void closeEvent(QCloseEvent *bar); + QComboBox *driverSelect; QComboBox *regionSelect; QCheckBox *gl_LF_chkBox; @@ -40,6 +42,9 @@ class ConsoleVideoConfDialog_t : public QDialog void resetVideo(void); + public slots: + void closeWindow(void); + private slots: void use_new_PPU_changed( int value ); void frameskip_changed( int value ); @@ -47,8 +52,8 @@ class ConsoleVideoConfDialog_t : public QDialog void clipSidesChanged( int value ); void showFPSChanged( int value ); void regionChanged(int index); + void driverChanged(int index); void applyChanges( void ); - void closewindow( void ); }; diff --git a/src/drivers/Qt/ConsoleViewerSDL.cpp b/src/drivers/Qt/ConsoleViewerSDL.cpp index 18867777..4f96346e 100644 --- a/src/drivers/Qt/ConsoleViewerSDL.cpp +++ b/src/drivers/Qt/ConsoleViewerSDL.cpp @@ -15,6 +15,12 @@ extern unsigned int gui_draw_area_height; ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent) : QWidget( parent ) { + QPalette pal = palette(); + + pal.setColor(QPalette::Background, Qt::black); + setAutoFillBackground(true); + setPalette(pal); + view_width = GL_NES_WIDTH; view_height = GL_NES_HEIGHT; @@ -30,11 +36,29 @@ ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent) sdlTexture = NULL; vsyncEnabled = false; + + localBufSize = GL_NES_WIDTH * GL_NES_HEIGHT * sizeof(uint32_t); + + localBuf = (uint32_t*)malloc( localBufSize ); + + if ( localBuf ) + { + memset( localBuf, 0, localBufSize ); + } + } ConsoleViewSDL_t::~ConsoleViewSDL_t(void) { + if ( localBuf ) + { + free( localBuf ); localBuf = NULL; + } +} +void ConsoleViewSDL_t::transfer2LocalBuffer(void) +{ + memcpy( localBuf, nes_shm->pixbuf, localBufSize ); } int ConsoleViewSDL_t::init(void) @@ -46,10 +70,16 @@ int ConsoleViewSDL_t::init(void) printf("[SDL] Failed to initialize video subsystem.\n"); return -1; } - //else - //{ - // printf("Initialized SDL Video Subsystem\n"); - //} + else + { + printf("Initialized SDL Video Subsystem\n"); + } + + for (int i=0; iwinId(); @@ -132,17 +162,18 @@ void ConsoleViewSDL_t::resizeEvent(QResizeEvent *event) s = event->size(); view_width = s.width(); view_height = s.height(); - //printf("SDL Resize: %i x %i \n", view_width, view_height); + printf("SDL Resize: %i x %i \n", view_width, view_height); reset(); - sdlViewport.x = sdlRendW - view_width; - sdlViewport.y = sdlRendH - view_height; - sdlViewport.w = view_width; - sdlViewport.h = view_height; + //sdlViewport.x = sdlRendW - view_width; + //sdlViewport.y = sdlRendH - view_height; + //sdlViewport.w = view_width; + //sdlViewport.h = view_height; } -void ConsoleViewSDL_t::paintEvent( QPaintEvent *event ) +//void ConsoleViewSDL_t::paintEvent( QPaintEvent *event ) +void ConsoleViewSDL_t::render(void) { int nesWidth = GL_NES_WIDTH; int nesHeight = GL_NES_HEIGHT; @@ -167,8 +198,10 @@ void ConsoleViewSDL_t::paintEvent( QPaintEvent *event ) rw=(int)(nesWidth*xscale); rh=(int)(nesHeight*yscale); - sx=sdlViewport.x + (view_width-rw)/2; - sy=sdlViewport.y + (view_height-rh)/2; + //sx=sdlViewport.x + (view_width-rw)/2; + //sy=sdlViewport.y + (view_height-rh)/2; + sx=(view_width-rw)/2; + sy=(view_height-rh)/2; if ( (sdlRenderer == NULL) || (sdlTexture == NULL) ) { @@ -183,13 +216,13 @@ void ConsoleViewSDL_t::paintEvent( QPaintEvent *event ) int rowPitch; SDL_LockTexture( sdlTexture, nullptr, (void**)&textureBuffer, &rowPitch); { - memcpy( textureBuffer, nes_shm->pixbuf, GL_NES_HEIGHT*GL_NES_WIDTH*sizeof(uint32_t) ); + memcpy( textureBuffer, localBuf, GL_NES_HEIGHT*GL_NES_WIDTH*sizeof(uint32_t) ); } SDL_UnlockTexture(sdlTexture); - SDL_RenderSetViewport( sdlRenderer, &sdlViewport ); + //SDL_RenderSetViewport( sdlRenderer, &sdlViewport ); - SDL_Rect source = {0, 0, GL_NES_WIDTH, GL_NES_HEIGHT }; + SDL_Rect source = {0, 0, nesWidth, nesHeight }; SDL_Rect dest = { sx, sy, rw, rh }; SDL_RenderCopy(sdlRenderer, sdlTexture, &source, &dest); diff --git a/src/drivers/Qt/ConsoleViewerSDL.h b/src/drivers/Qt/ConsoleViewerSDL.h index 386d148a..45de62e7 100644 --- a/src/drivers/Qt/ConsoleViewerSDL.h +++ b/src/drivers/Qt/ConsoleViewerSDL.h @@ -19,10 +19,13 @@ class ConsoleViewSDL_t : public QWidget int init(void); void reset(void); void cleanup(void); + void render(void); + + void transfer2LocalBuffer(void); protected: - void paintEvent(QPaintEvent *event); + //void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); int view_width; int view_height; @@ -37,10 +40,13 @@ class ConsoleViewSDL_t : public QWidget bool vsyncEnabled; + uint32_t *localBuf; + uint32_t localBufSize; + SDL_Window *sdlWindow; SDL_Renderer *sdlRenderer; SDL_Texture *sdlTexture; - SDL_Rect sdlViewport; + //SDL_Rect sdlViewport; private slots: }; diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index c9bc21db..57102e8e 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../../fceu.h" #include "../../fds.h" @@ -19,6 +20,12 @@ #include "Qt/ConsoleWindow.h" #include "Qt/GamePadConf.h" #include "Qt/HotKeyConf.h" +#include "Qt/PaletteConf.h" +#include "Qt/GuiConf.h" +#include "Qt/LuaControl.h" +#include "Qt/CheatsConf.h" +#include "Qt/HexEditor.h" +#include "Qt/ConsoleUtilities.h" #include "Qt/ConsoleSoundConf.h" #include "Qt/ConsoleVideoConf.h" #include "Qt/AboutWindow.h" @@ -29,17 +36,33 @@ consoleWin_t::consoleWin_t(QWidget *parent) : QMainWindow( parent ) { + int use_SDL_video = false; createMainMenu(); - viewport = new ConsoleViewGL_t(this); - //viewport = new ConsoleViewSDL_t(this); + g_config->getOption( "SDL.VideoDriver", &use_SDL_video ); + + errorMsgValid = false; + viewport_GL = NULL; + viewport_SDL = NULL; + + if ( use_SDL_video ) + { + viewport_SDL = new ConsoleViewSDL_t(this); + + setCentralWidget(viewport_SDL); + } + else + { + viewport_GL = new ConsoleViewGL_t(this); + + setCentralWidget(viewport_GL); + } - setCentralWidget(viewport); setWindowIcon(QIcon(":fceux1.png")); gameTimer = new QTimer( this ); - mutex = new QMutex( QMutex::NonRecursive ); + mutex = new QMutex( QMutex::Recursive ); emulatorThread = new emulatorThread_t(); connect(emulatorThread, &QThread::finished, emulatorThread, &QObject::deleteLater); @@ -52,17 +75,16 @@ consoleWin_t::consoleWin_t(QWidget *parent) emulatorThread->start(); - gamePadConfWin = NULL; } consoleWin_t::~consoleWin_t(void) { nes_shm->runEmulator = 0; - if ( gamePadConfWin != NULL ) - { - gamePadConfWin->closeWindow(); - } + gameTimer->stop(); + + closeGamePadConfWindow(); + fceuWrapperLock(); fceuWrapperClose(); fceuWrapperUnLock(); @@ -71,7 +93,14 @@ consoleWin_t::~consoleWin_t(void) emulatorThread->quit(); emulatorThread->wait(); - delete viewport; + if ( viewport_GL != NULL ) + { + delete viewport_GL; viewport_GL = NULL; + } + if ( viewport_SDL != NULL ) + { + delete viewport_SDL; viewport_SDL = NULL; + } delete mutex; // LoadGame() checks for an IP and if it finds one begins a network session @@ -88,14 +117,31 @@ void consoleWin_t::setCyclePeriodms( int ms ) //printf("Period Set to: %i ms \n", ms ); } +void consoleWin_t::showErrorMsgWindow() +{ + QMessageBox msgBox(this); + + fceuWrapperLock(); + msgBox.setIcon( QMessageBox::Critical ); + msgBox.setText( tr(errorMsg.c_str()) ); + errorMsg.clear(); + fceuWrapperUnLock(); + msgBox.show(); + msgBox.exec(); +} + +void consoleWin_t::QueueErrorMsgWindow( const char *msg ) +{ + errorMsg.append( msg ); + errorMsg.append("\n"); + errorMsgValid = true; +} + void consoleWin_t::closeEvent(QCloseEvent *event) { //printf("Main Window Close Event\n"); - if ( gamePadConfWin != NULL ) - { - //printf("Command Game Pad Close\n"); - gamePadConfWin->closeWindow(); - } + closeGamePadConfWindow(); + event->accept(); closeApp(); @@ -118,9 +164,12 @@ void consoleWin_t::createMainMenu(void) { QMenu *subMenu; QActionGroup *group; + int useNativeMenuBar; - // This is needed for menu bar to show up on MacOS - menuBar()->setNativeMenuBar(false); + // This is needed for menu bar to show up on MacOS + g_config->getOption( "SDL.UseNativeMenuBar", &useNativeMenuBar ); + + menuBar()->setNativeMenuBar( useNativeMenuBar ? true : false ); //----------------------------------------------------------------------- // File @@ -285,6 +334,22 @@ void consoleWin_t::createMainMenu(void) optMenu->addAction(hotkeyConfig); + // Options -> Palette Config + paletteConfig = new QAction(tr("Palette Config"), this); + //paletteConfig->setShortcut( QKeySequence(tr("Ctrl+C"))); + paletteConfig->setStatusTip(tr("Palette Configure")); + connect(paletteConfig, SIGNAL(triggered()), this, SLOT(openPaletteConfWin(void)) ); + + optMenu->addAction(paletteConfig); + + // Options -> GUI Config + guiConfig = new QAction(tr("GUI Config"), this); + //guiConfig->setShortcut( QKeySequence(tr("Ctrl+C"))); + guiConfig->setStatusTip(tr("GUI Configure")); + connect(guiConfig, SIGNAL(triggered()), this, SLOT(openGuiConfWin(void)) ); + + optMenu->addAction(guiConfig); + // Options -> Auto-Resume autoResume = new QAction(tr("Auto-Resume Play"), this); //autoResume->setShortcut( QKeySequence(tr("Ctrl+C"))); @@ -401,6 +466,30 @@ void consoleWin_t::createMainMenu(void) subMenu->addAction(fdsLoadBiosAct); + //----------------------------------------------------------------------- + // Tools + toolsMenu = menuBar()->addMenu(tr("Tools")); + + // Tools -> Cheats + cheatsAct = new QAction(tr("Cheats..."), this); + //cheatsAct->setShortcut( QKeySequence(tr("Shift+F7"))); + cheatsAct->setStatusTip(tr("Open Cheat Window")); + connect(cheatsAct, SIGNAL(triggered()), this, SLOT(openCheats(void)) ); + + toolsMenu->addAction(cheatsAct); + + //----------------------------------------------------------------------- + // Debug + debugMenu = menuBar()->addMenu(tr("Debug")); + + // Debug -> Hex Editor + hexEditAct = new QAction(tr("Hex Editor..."), this); + //hexEditAct->setShortcut( QKeySequence(tr("Shift+F7"))); + hexEditAct->setStatusTip(tr("Open Memory Hex Editor")); + connect(hexEditAct, SIGNAL(triggered()), this, SLOT(openHexEditor(void)) ); + + debugMenu->addAction(hexEditAct); + //----------------------------------------------------------------------- // Movie movieMenu = menuBar()->addMenu(tr("Movie")); @@ -442,12 +531,20 @@ void consoleWin_t::createMainMenu(void) //----------------------------------------------------------------------- // Help helpMenu = menuBar()->addMenu(tr("Help")); - - aboutAct = new QAction(tr("About"), this); + + // Help -> About FCEUX + aboutAct = new QAction(tr("About FCEUX"), this); aboutAct->setStatusTip(tr("About FCEUX")); connect(aboutAct, SIGNAL(triggered()), this, SLOT(aboutFCEUX(void)) ); helpMenu->addAction(aboutAct); + + // Help -> About Qt + aboutActQt = new QAction(tr("About Qt"), this); + aboutActQt->setStatusTip(tr("About Qt")); + connect(aboutActQt, SIGNAL(triggered()), this, SLOT(aboutQt(void)) ); + + helpMenu->addAction(aboutActQt); }; //--------------------------------------------------------------------------- void consoleWin_t::closeApp(void) @@ -468,40 +565,10 @@ void consoleWin_t::closeApp(void) qApp->quit(); } //--------------------------------------------------------------------------- -int consoleWin_t::getDirFromFile( const char *path, char *dir ) -{ - int i, lastSlash = -1, lastPeriod = -1; - - i=0; - while ( path[i] != 0 ) - { - if ( path[i] == '/' ) - { - lastSlash = i; - } - else if ( path[i] == '.' ) - { - lastPeriod = i; - } - dir[i] = path[i]; i++; - } - dir[i] = 0; - - if ( lastPeriod >= 0 ) - { - if ( lastPeriod > lastSlash ) - { - dir[lastSlash] = 0; - } - } - - return 0; -} -//--------------------------------------------------------------------------- void consoleWin_t::openROMFile(void) { - int ret; + int ret, useNativeFileDialogVal; QString filename; std::string last; char dir[512]; @@ -509,9 +576,11 @@ void consoleWin_t::openROMFile(void) dialog.setFileMode(QFileDialog::ExistingFile); - dialog.setNameFilter(tr("NES files (*.nes)(*.NES) ;; All files (*)")); + dialog.setNameFilter(tr("NES files (*.nes *.NES) ;; All files (*)")); dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Open") ); g_config->getOption ("SDL.LastOpenFile", &last ); @@ -519,9 +588,10 @@ void consoleWin_t::openROMFile(void) dialog.setDirectory( tr(dir) ); - // the gnome default file dialog is not playing nice with QT. - // TODO make this a config option to use native file dialog. - dialog.setOption(QFileDialog::DontUseNativeDialog, true); + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); dialog.show(); ret = dialog.exec(); @@ -562,7 +632,7 @@ void consoleWin_t::closeROMCB(void) void consoleWin_t::loadNSF(void) { - int ret; + int ret, useNativeFileDialogVal; QString filename; std::string last; char dir[512]; @@ -570,9 +640,11 @@ void consoleWin_t::loadNSF(void) dialog.setFileMode(QFileDialog::ExistingFile); - dialog.setNameFilter(tr("NSF Sound Files (*.nsf)(*.NSF) ;; Zip Files (*.zip)(*.ZIP) ;; All files (*)")); + dialog.setNameFilter(tr("NSF Sound Files (*.nsf *.NSF) ;; Zip Files (*.zip *.ZIP) ;; All files (*)")); dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Load") ); g_config->getOption ("SDL.LastOpenNSF", &last ); @@ -580,9 +652,10 @@ void consoleWin_t::loadNSF(void) dialog.setDirectory( tr(dir) ); - // the gnome default file dialog is not playing nice with QT. - // TODO make this a config option to use native file dialog. - dialog.setOption(QFileDialog::DontUseNativeDialog, true); + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); dialog.show(); ret = dialog.exec(); @@ -613,7 +686,7 @@ void consoleWin_t::loadNSF(void) void consoleWin_t::loadStateFrom(void) { - int ret; + int ret, useNativeFileDialogVal; QString filename; std::string last; char dir[512]; @@ -621,9 +694,11 @@ void consoleWin_t::loadStateFrom(void) dialog.setFileMode(QFileDialog::ExistingFile); - dialog.setNameFilter(tr("FCS Files (*.fc?)(*.FC?) ;; SAV Files (*.sav)(*.SAV) ;; All files (*)")); + dialog.setNameFilter(tr("FCS & SAV Files (*.sav *.SAV *.fc? *.FC?) ;; All files (*)")); dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Load") ); g_config->getOption ("SDL.LastLoadStateFrom", &last ); @@ -631,9 +706,10 @@ void consoleWin_t::loadStateFrom(void) dialog.setDirectory( tr(dir) ); - // the gnome default file dialog is not playing nice with QT. - // TODO make this a config option to use native file dialog. - dialog.setOption(QFileDialog::DontUseNativeDialog, true); + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); dialog.show(); ret = dialog.exec(); @@ -664,7 +740,7 @@ void consoleWin_t::loadStateFrom(void) void consoleWin_t::saveStateAs(void) { - int ret; + int ret, useNativeFileDialogVal; QString filename; std::string last; char dir[512]; @@ -672,9 +748,12 @@ void consoleWin_t::saveStateAs(void) dialog.setFileMode(QFileDialog::AnyFile); - dialog.setNameFilter(tr("FCS Files (*.fc?)(*.FC?) ;; SAV Files (*.sav)(*.SAV) ;; All files (*)")); + dialog.setNameFilter(tr("SAV Files (*.sav *.SAV) ;; All files (*)")); dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Save") ); + dialog.setDefaultSuffix( tr(".sav") ); g_config->getOption ("SDL.LastSaveStateAs", &last ); @@ -682,9 +761,10 @@ void consoleWin_t::saveStateAs(void) dialog.setDirectory( tr(dir) ); - // the gnome default file dialog is not playing nice with QT. - // TODO make this a config option to use native file dialog. - dialog.setOption(QFileDialog::DontUseNativeDialog, true); + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); dialog.show(); ret = dialog.exec(); @@ -807,80 +887,21 @@ void consoleWin_t::takeScreenShot(void) void consoleWin_t::loadLua(void) { #ifdef _S9XLUA_H - int ret; - QString filename; - std::string last; - char dir[512]; - QFileDialog dialog(this, tr("Open LUA Script") ); + LuaControlDialog_t *luaCtrlWin; - dialog.setFileMode(QFileDialog::ExistingFile); - - dialog.setNameFilter(tr("LUA Scripts (*.lua)(*.LUA) ;; All files (*)")); - - dialog.setViewMode(QFileDialog::List); - - g_config->getOption ("SDL.LastLoadLua", &last ); - - if ( last.size() == 0 ) - { - last.assign( "/usr/share/fceux/luaScripts" ); - } - - getDirFromFile( last.c_str(), dir ); - - dialog.setDirectory( tr(dir) ); - - // the gnome default file dialog is not playing nice with QT. - // TODO make this a config option to use native file dialog. - dialog.setOption(QFileDialog::DontUseNativeDialog, true); - - dialog.show(); - ret = dialog.exec(); - - if ( ret ) - { - QStringList fileList; - fileList = dialog.selectedFiles(); - - if ( fileList.size() > 0 ) - { - filename = fileList[0]; - } - } - - if ( filename.isNull() ) - { - return; - } - qDebug() << "selected file path : " << filename.toUtf8(); - - g_config->setOption ("SDL.LastLoadLua", filename.toStdString().c_str() ); - - fceuWrapperLock(); - if ( 0 == FCEU_LoadLuaCode( filename.toStdString().c_str() ) ) - { - printf("Error: Could not open the selected lua script: '%s'\n", filename.toStdString().c_str() ); - } - fceuWrapperUnLock(); + //printf("Open Lua Control Window\n"); + + luaCtrlWin = new LuaControlDialog_t(this); + + luaCtrlWin->show(); #endif } void consoleWin_t::openGamePadConfWin(void) { - if ( gamePadConfWin != NULL ) - { - printf("GamePad Config Window Already Open\n"); - return; - } //printf("Open GamePad Config Window\n"); - gamePadConfWin = new GamePadConfDialog_t(this); - gamePadConfWin->show(); - gamePadConfWin->exec(); - - delete gamePadConfWin; - gamePadConfWin = NULL; - //printf("GamePad Config Window Destroyed\n"); + openGamePadConfWindow(this); } void consoleWin_t::openGameSndConfWin(void) @@ -892,11 +913,6 @@ void consoleWin_t::openGameSndConfWin(void) sndConfWin = new ConsoleSndConfDialog_t(this); sndConfWin->show(); - sndConfWin->exec(); - - delete sndConfWin; - - //printf("Sound Config Window Destroyed\n"); } void consoleWin_t::openGameVideoConfWin(void) @@ -908,11 +924,6 @@ void consoleWin_t::openGameVideoConfWin(void) vidConfWin = new ConsoleVideoConfDialog_t(this); vidConfWin->show(); - vidConfWin->exec(); - - delete vidConfWin; - - //printf("Video Config Window Destroyed\n"); } void consoleWin_t::openHotkeyConfWin(void) @@ -924,11 +935,50 @@ void consoleWin_t::openHotkeyConfWin(void) hkConfWin = new HotKeyConfDialog_t(this); hkConfWin->show(); - hkConfWin->exec(); +} - delete hkConfWin; +void consoleWin_t::openPaletteConfWin(void) +{ + PaletteConfDialog_t *paletteConfWin; - //printf("Hotkey Config Window Destroyed\n"); + //printf("Open Palette Config Window\n"); + + paletteConfWin = new PaletteConfDialog_t(this); + + paletteConfWin->show(); +} + +void consoleWin_t::openGuiConfWin(void) +{ + GuiConfDialog_t *guiConfWin; + + //printf("Open GUI Config Window\n"); + + guiConfWin = new GuiConfDialog_t(this); + + guiConfWin->show(); +} + +void consoleWin_t::openCheats(void) +{ + GuiCheatsDialog_t *cheatWin; + + //printf("Open GUI Cheat Window\n"); + + cheatWin = new GuiCheatsDialog_t(this); + + cheatWin->show(); +} + +void consoleWin_t::openHexEditor(void) +{ + HexEditorDialog_t *hexEditWin; + + //printf("Open GUI Hex Editor Window\n"); + + hexEditWin = new HexEditorDialog_t(this); + + hexEditWin->show(); } void consoleWin_t::toggleAutoResume(void) @@ -999,7 +1049,7 @@ void consoleWin_t::toggleGameGenie(bool checked) void consoleWin_t::loadGameGenieROM(void) { - int ret; + int ret, useNativeFileDialogVal; QString filename; std::string last; char dir[512]; @@ -1007,9 +1057,11 @@ void consoleWin_t::loadGameGenieROM(void) dialog.setFileMode(QFileDialog::ExistingFile); - dialog.setNameFilter(tr("GG ROM File (gg.rom)(*Genie*.nes) ;; All files (*)")); + dialog.setNameFilter(tr("GG ROM File (gg.rom *Genie*.nes) ;; All files (*)")); dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Load") ); g_config->getOption ("SDL.LastOpenFile", &last ); @@ -1017,9 +1069,10 @@ void consoleWin_t::loadGameGenieROM(void) dialog.setDirectory( tr(dir) ); - // the gnome default file dialog is not playing nice with QT. - // TODO make this a config option to use native file dialog. - dialog.setOption(QFileDialog::DontUseNativeDialog, true); + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); dialog.show(); ret = dialog.exec(); @@ -1079,7 +1132,7 @@ void consoleWin_t::fdsEjectDisk(void) void consoleWin_t::fdsLoadBiosFile(void) { - int ret; + int ret, useNativeFileDialogVal; QString filename; std::string last; char dir[512]; @@ -1087,9 +1140,11 @@ void consoleWin_t::fdsLoadBiosFile(void) dialog.setFileMode(QFileDialog::ExistingFile); - dialog.setNameFilter(tr("ROM files (*.rom)(*.ROM) ;; All files (*)")); + dialog.setNameFilter(tr("ROM files (*.rom *.ROM) ;; All files (*)")); dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Load") ); g_config->getOption ("SDL.LastOpenFile", &last ); @@ -1097,9 +1152,10 @@ void consoleWin_t::fdsLoadBiosFile(void) dialog.setDirectory( tr(dir) ); - // the gnome default file dialog is not playing nice with QT. - // TODO make this a config option to use native file dialog. - dialog.setOption(QFileDialog::DontUseNativeDialog, true); + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); dialog.show(); ret = dialog.exec(); @@ -1143,7 +1199,7 @@ void consoleWin_t::fdsLoadBiosFile(void) void consoleWin_t::openMovie(void) { - int ret; + int ret, useNativeFileDialogVal; QString filename; std::string last; char dir[512]; @@ -1154,6 +1210,8 @@ void consoleWin_t::openMovie(void) dialog.setNameFilter(tr("FM2 Movies (*.fm2) ;; All files (*)")); dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Open") ); g_config->getOption ("SDL.LastOpenFile", &last ); @@ -1161,9 +1219,10 @@ void consoleWin_t::openMovie(void) dialog.setDirectory( tr(dir) ); - // the gnome default file dialog is not playing nice with QT. - // TODO make this a config option to use native file dialog. - dialog.setOption(QFileDialog::DontUseNativeDialog, true); + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); dialog.show(); ret = dialog.exec(); @@ -1225,7 +1284,7 @@ void consoleWin_t::recordMovie(void) void consoleWin_t::recordMovieAs(void) { - int ret; + int ret, useNativeFileDialogVal; QString filename; std::string last; char dir[512]; @@ -1236,6 +1295,8 @@ void consoleWin_t::recordMovieAs(void) dialog.setNameFilter(tr("FM2 Movies (*.fm2) ;; All files (*)")); dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Save") ); g_config->getOption ("SDL.LastOpenFile", &last ); @@ -1243,9 +1304,10 @@ void consoleWin_t::recordMovieAs(void) dialog.setDirectory( tr(dir) ); - // the gnome default file dialog is not playing nice with QT. - // TODO make this a config option to use native file dialog. - dialog.setOption(QFileDialog::DontUseNativeDialog, true); + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); dialog.show(); ret = dialog.exec(); @@ -1292,11 +1354,16 @@ void consoleWin_t::aboutFCEUX(void) aboutWin = new AboutWindow(this); aboutWin->show(); - aboutWin->exec(); + return; +} - delete aboutWin; +void consoleWin_t::aboutQt(void) +{ + //printf("About Qt Window\n"); + + QMessageBox::aboutQt(this); - //printf("About Window Destroyed\n"); + //printf("About Qt Destroyed\n"); return; } @@ -1329,10 +1396,23 @@ void consoleWin_t::updatePeriodic(void) { nes_shm->blitUpdated = 0; - viewport->transfer2LocalBuffer(); + if ( viewport_SDL ) + { + viewport_SDL->transfer2LocalBuffer(); + viewport_SDL->render(); + } + else + { + viewport_GL->transfer2LocalBuffer(); + //viewport_GL->repaint(); + viewport_GL->update(); + } + } - //viewport->repaint(); - viewport->update(); + if ( errorMsgValid ) + { + showErrorMsgWindow(); + errorMsgValid = false; } return; diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index 59bb43f5..eb5fdddb 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -39,17 +39,21 @@ class consoleWin_t : public QMainWindow consoleWin_t(QWidget *parent = 0); ~consoleWin_t(void); - ConsoleViewGL_t *viewport; - //ConsoleViewSDL_t *viewport; + ConsoleViewGL_t *viewport_GL; + ConsoleViewSDL_t *viewport_SDL; void setCyclePeriodms( int ms ); QMutex *mutex; + void QueueErrorMsgWindow( const char *msg ); + protected: QMenu *fileMenu; QMenu *optMenu; QMenu *emuMenu; + QMenu *toolsMenu; + QMenu *debugMenu; QMenu *movieMenu; QMenu *helpMenu; @@ -67,9 +71,12 @@ class consoleWin_t : public QMainWindow QAction *gameSoundConfig; QAction *gameVideoConfig; QAction *hotkeyConfig; + QAction *paletteConfig; + QAction *guiConfig; QAction *autoResume; QAction *fullscreen; QAction *aboutAct; + QAction *aboutActQt; QAction *state[10]; QAction *powerAct; QAction *resetAct; @@ -81,23 +88,26 @@ class consoleWin_t : public QMainWindow QAction *fdsSwitchAct; QAction *fdsEjectAct; QAction *fdsLoadBiosAct; + QAction *cheatsAct; + QAction *hexEditAct; QAction *openMovAct; QAction *stopMovAct; QAction *recMovAct; QAction *recAsMovAct; QTimer *gameTimer; + emulatorThread_t *emulatorThread; - GamePadConfDialog_t *gamePadConfWin; + std::string errorMsg; + bool errorMsgValid; protected: void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void syncActionConfig( QAction *act, const char *property ); - - int getDirFromFile( const char *path, char *dir ); + void showErrorMsgWindow(void); private: void createMainMenu(void); @@ -112,10 +122,13 @@ class consoleWin_t : public QMainWindow void quickSave(void); void closeROMCB(void); void aboutFCEUX(void); + void aboutQt(void); void openGamePadConfWin(void); void openGameSndConfWin(void); void openGameVideoConfWin(void); void openHotkeyConfWin(void); + void openPaletteConfWin(void); + void openGuiConfWin(void); void toggleAutoResume(void); void toggleFullscreen(void); void updatePeriodic(void); @@ -141,6 +154,8 @@ class consoleWin_t : public QMainWindow void fdsSwitchDisk(void); void fdsEjectDisk(void); void fdsLoadBiosFile(void); + void openCheats(void); + void openHexEditor(void); void openMovie(void); void stopMovie(void); void recordMovie(void); diff --git a/src/drivers/Qt/GamePadConf.cpp b/src/drivers/Qt/GamePadConf.cpp index 24cfb88c..2847a01c 100644 --- a/src/drivers/Qt/GamePadConf.cpp +++ b/src/drivers/Qt/GamePadConf.cpp @@ -1,35 +1,105 @@ // GamePadConf.cpp // +#include +#include +#include + #include "Qt/GamePadConf.h" #include "Qt/main.h" +#include "Qt/dface.h" #include "Qt/input.h" #include "Qt/config.h" #include "Qt/keyscan.h" +#include "Qt/sdl-joystick.h" #include "Qt/fceuWrapper.h" +struct GamePadConfigLocalData_t +{ + std::string guid; + std::string profile; + + struct { + + char needsSave; + + } btn[GAMEPAD_NUM_BUTTONS]; + + GamePadConfigLocalData_t(void) + { + for (int i=0; ishow(); + + return 0; +} +//---------------------------------------------------- +int closeGamePadConfWindow(void) +{ + if ( gamePadConfWin != NULL ) + { + gamePadConfWin->closeWindow(); + } + return 0; +} //---------------------------------------------------- GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent) : QDialog( parent ) { - QHBoxLayout *hbox1, *hbox2; + QHBoxLayout *hbox, *hbox1, *hbox2, *hbox3, *hbox4; + QVBoxLayout *vbox; QGridLayout *grid; QCheckBox *efs_chkbox, *udlr_chkbox; - QGroupBox *frame; - QPushButton *loadDefaultButton; + QGroupBox *frame1, *frame2; + QLabel *label; + QPushButton *newProfileButton; + QPushButton *saveProfileButton; + QPushButton *applyProfileButton; + QPushButton *removeProfileButton; QPushButton *clearAllButton; QPushButton *closebutton; QPushButton *clearButton[GAMEPAD_NUM_BUTTONS]; + std::string prefix; + char stmp[256]; + + gamePadConfWin = this; + + // Ensure that joysticks are enabled, no harm calling init again. + InitJoysticks(); portNum = 0; - configNo = 0; buttonConfigStatus = 1; + inputTimer = new QTimer( this ); + + connect( inputTimer, &QTimer::timeout, this, &GamePadConfDialog_t::updatePeriodic ); + setWindowTitle( tr("GamePad Config") ); hbox1 = new QHBoxLayout(); hbox2 = new QHBoxLayout(); + hbox3 = new QHBoxLayout(); + hbox4 = new QHBoxLayout(); - QLabel *label = new QLabel(tr("Port:")); + label = new QLabel(tr("Console Port:")); portSel = new QComboBox(); hbox1->addWidget( label ); hbox1->addWidget( portSel ); @@ -39,6 +109,83 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent) portSel->addItem( tr("3"), 2 ); portSel->addItem( tr("4"), 3 ); + label = new QLabel(tr("Device:")); + devSel = new QComboBox(); + hbox2->addWidget( label ); + hbox2->addWidget( devSel ); + + devSel->addItem( tr("Keyboard"), -1 ); + + for (int i=0; iisConnected() ) + { + sprintf( stmp, "%i: %s", i, js->getName() ); + devSel->addItem( tr(stmp), i ); + } + } + } + for (int i=0; icount(); i++) + { + if ( devSel->itemData(i).toInt() == GamePad[portNum].getDeviceIndex() ) + { + devSel->setCurrentIndex( i ); + } + } + + label = new QLabel(tr("GUID:")); + guidLbl = new QLabel(); + + hbox3->addWidget( label ); + hbox3->addWidget( guidLbl ); + + guidLbl->setText( GamePad[portNum].getGUID() ); + + frame1 = new QGroupBox(tr("Mapping Profile:")); + //grid = new QGridLayout(); + vbox = new QVBoxLayout(); + + //frame1->setLayout( grid ); + frame1->setLayout( vbox ); + + hbox = new QHBoxLayout(); + vbox->addLayout( hbox ); + + mapSel = new QComboBox(); + hbox->addWidget( mapSel ); + + mapSel->setWhatsThis( tr("Combo box for selection of a saved button mapping profile for the selected device")); + mapSel->addItem( tr("default"), 0 ); + + hbox = new QHBoxLayout(); + vbox->addLayout( hbox ); + + applyProfileButton = new QPushButton( tr("Load") ); + applyProfileButton->setWhatsThis(tr("Sets Current Active Map to the Selected Profile")); + hbox->addWidget( applyProfileButton ); + + saveProfileButton = new QPushButton( tr("Save") ); + saveProfileButton->setWhatsThis(tr("Stores Current Active Map to the Selected Profile")); + hbox->addWidget( saveProfileButton ); + + hbox = new QHBoxLayout(); + vbox->addLayout( hbox ); + + newProfileButton = new QPushButton( tr("New") ); + newProfileButton->setWhatsThis(tr("Create a New Map Profile")); + hbox->addWidget( newProfileButton ); + + removeProfileButton = new QPushButton( tr("Delete") ); + removeProfileButton->setWhatsThis(tr("Deletes the Selected Map Profile")); + hbox->addWidget( removeProfileButton ); + + mapMsg = new QLabel(); + vbox->addWidget(mapMsg); + efs_chkbox = new QCheckBox( tr("Enable Four Score") ); udlr_chkbox = new QCheckBox( tr("Allow Up+Down/Left+Right") ); @@ -50,13 +197,12 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent) g_config->getOption("SDL.Input.EnableOppositeDirectionals", &opposite_dirs); udlr_chkbox->setChecked( opposite_dirs ); - frame = new QGroupBox(tr("Buttons:")); - grid = new QGridLayout(); + frame2 = new QGroupBox(tr("Current Active Button Mappings:")); + grid = new QGridLayout(); grid-> setHorizontalSpacing(50); - //frame->setFrameStyle( QFrame::Box ); - frame->setLayout( grid ); + frame2->setLayout( grid ); for (int i=0; iaddWidget( buttonName , i, 0, Qt::AlignCenter ); grid->addWidget( keyName[i] , i, 1, Qt::AlignCenter ); - grid->addWidget( button[i] , i, 2, Qt::AlignCenter ); - grid->addWidget( clearButton[i], i, 3, Qt::AlignCenter ); + grid->addWidget( label , i, 2, Qt::AlignCenter ); + grid->addWidget( keyState[i] , i, 3, Qt::AlignCenter ); + grid->addWidget( button[i] , i, 4, Qt::AlignCenter ); + grid->addWidget( clearButton[i], i, 5, Qt::AlignCenter ); } updateCntrlrDpy(); - loadDefaultButton = new QPushButton(tr("Load Defaults")); clearAllButton = new QPushButton(tr("Clear All")); closebutton = new QPushButton(tr("Close")); - hbox2->addWidget( loadDefaultButton ); - hbox2->addWidget( clearAllButton ); - hbox2->addWidget( closebutton ); + hbox4->addWidget( clearAllButton ); + hbox4->addWidget( closebutton ); connect(button[0], SIGNAL(clicked()), this, SLOT(changeButton0(void)) ); connect(button[1], SIGNAL(clicked()), this, SLOT(changeButton1(void)) ); @@ -111,30 +259,55 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent) connect(clearButton[8], SIGNAL(clicked()), this, SLOT(clearButton8(void)) ); connect(clearButton[9], SIGNAL(clicked()), this, SLOT(clearButton9(void)) ); - connect(loadDefaultButton, SIGNAL(clicked()), this, SLOT(loadDefaults(void)) ); + connect(newProfileButton , SIGNAL(clicked()), this, SLOT(newProfileCallback(void)) ); + connect(applyProfileButton , SIGNAL(clicked()), this, SLOT(loadProfileCallback(void)) ); + connect(saveProfileButton , SIGNAL(clicked()), this, SLOT(saveProfileCallback(void)) ); + connect(removeProfileButton, SIGNAL(clicked()), this, SLOT(deleteProfileCallback(void)) ); + connect(clearAllButton , SIGNAL(clicked()), this, SLOT(clearAllCallback(void)) ); connect(closebutton , SIGNAL(clicked()), this, SLOT(closeWindow(void)) ); - connect(portSel , SIGNAL(activated(int)), this, SLOT(controllerSelect(int)) ); + connect(portSel , SIGNAL(activated(int)), this, SLOT(portSelect(int)) ); + connect(devSel , SIGNAL(activated(int)), this, SLOT(deviceSelect(int)) ); connect(efs_chkbox , SIGNAL(stateChanged(int)), this, SLOT(ena4score(int)) ); connect(udlr_chkbox, SIGNAL(stateChanged(int)), this, SLOT(oppDirEna(int)) ); QVBoxLayout *mainLayout = new QVBoxLayout(); mainLayout->addLayout( hbox1 ); + mainLayout->addLayout( hbox2 ); + mainLayout->addLayout( hbox3 ); + mainLayout->addWidget( frame1 ); mainLayout->addWidget( efs_chkbox ); mainLayout->addWidget( udlr_chkbox ); - mainLayout->addWidget( frame ); - mainLayout->addLayout( hbox2 ); + mainLayout->addWidget( frame2 ); + mainLayout->addLayout( hbox4 ); setLayout( mainLayout ); + inputTimer->start( 33 ); // 30hz + + for (int i=0; igetOption(prefix + "Profile", &lcl[i].profile ); + + lcl[i].guid.assign( GamePad[i].getGUID() ); + } + + loadMapList(); } //---------------------------------------------------- GamePadConfDialog_t::~GamePadConfDialog_t(void) { + inputTimer->stop(); buttonConfigStatus = 0; + gamePadConfWin = NULL; + + printf("GamePad Window Deleted\n"); } void GamePadConfDialog_t::keyPressEvent(QKeyEvent *event) { @@ -148,30 +321,152 @@ void GamePadConfDialog_t::keyReleaseEvent(QKeyEvent *event) pushKeyEvent( event, 0 ); } //---------------------------------------------------- +void GamePadConfDialog_t::loadMapList(void) +{ + QDir dir; + QStringList filters, fileList; + const char *baseDir = FCEUI_GetBaseDirectory(); + const char *guid; + std::string path; + std::string prefix, mapName; + int index, devIdx; + jsDev_t *js; + size_t n=0; + char stmp[256]; + + index = devSel->currentIndex(); + devIdx = devSel->itemData(index).toInt(); + + if ( devIdx < 0 ) + { + guid = "keyboard"; + } + else + { + js = getJoystickDevice( devIdx ); + + guid = js->getGUID(); + } + + if ( guid == NULL ) + { + return; + } + + path = std::string(baseDir) + "/input/" + std::string(guid); + + dir.setPath( QString::fromStdString(path) ); + + filters << "*.txt"; + dir.setNameFilters(filters); + + fileList = dir.entryList( filters, QDir::Files, QDir::NoSort ); + + sprintf( stmp, "SDL.Input.GamePad.%u.", portNum ); + prefix = stmp; + + g_config->getOption(prefix + "Profile", &mapName ); + + mapSel->clear(); + mapSel->addItem( tr("default"), 0 ); n=1; + + for (size_t i=0; i < fileList.size(); i++) + { + size_t suffixIdx; + std::string fileName = fileList[i].toStdString(); + + suffixIdx = fileName.find_last_of('.'); + + fileName.erase( suffixIdx ); + + //printf("File: %s \n", fileName.c_str() ); + // + + if ( fileName.compare("default") == 0 ) continue; + + mapSel->addItem( tr(fileName.c_str()), (int)i+1 ); + + if ( mapName.compare( fileName ) == 0 ) + { + mapSel->setCurrentIndex(n); + } + n++; + } +} +//---------------------------------------------------- void GamePadConfDialog_t::updateCntrlrDpy(void) { char keyNameStr[128]; for (int i=0; isetText( tr(keyNameStr) ); + + //if ( lcl[portNum].btn[i].needsSave ) + //{ + // keyName[i]->setStyleSheet("color: red;"); + //} + //else + //{ + // keyName[i]->setStyleSheet("color: black;"); + //} } } //---------------------------------------------------- -void GamePadConfDialog_t::controllerSelect(int index) +void GamePadConfDialog_t::portSelect(int index) { //printf("Port Number:%i \n", index); portNum = index; updateCntrlrDpy(); + + for (int i=0; icount(); i++) + { + if ( devSel->itemData(i).toInt() == GamePad[portNum].getDeviceIndex() ) + { + devSel->setCurrentIndex( i ); + } + } + guidLbl->setText( GamePad[portNum].getGUID() ); + + loadMapList(); +} +//---------------------------------------------------- +void GamePadConfDialog_t::deviceSelect(int index) +{ + jsDev_t *js; + int devIdx = devSel->itemData(index).toInt(); + + js = getJoystickDevice( devIdx ); + + if ( js != NULL ) + { + if ( js->isConnected() ) + { + guidLbl->setText( js->getGUID() ); + } + } + else + { + guidLbl->setText(""); + } + GamePad[portNum].setDeviceIndex( devIdx ); + + lcl[portNum].guid.assign( GamePad[portNum].getGUID() ); + lcl[portNum].profile.assign("default"); + + loadMapList(); + + updateCntrlrDpy(); } //---------------------------------------------------- void GamePadConfDialog_t::ena4score(int state) @@ -190,8 +485,8 @@ void GamePadConfDialog_t::oppDirEna(int state) //---------------------------------------------------- void GamePadConfDialog_t::changeButton(int padNo, int x) { - char buf[256]; - std::string prefix; + //char buf[256]; + //std::string prefix; const char *keyNameStr; if ( buttonConfigStatus == 2 ) @@ -205,32 +500,13 @@ void GamePadConfDialog_t::changeButton(int padNo, int x) button[x]->setText("Waiting" ); - snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%d.", padNo); - prefix = buf; - DWaitButton (NULL, &GamePadConfig[padNo][x], configNo, &buttonConfigStatus ); + DWaitButton (NULL, &GamePad[padNo].bmap[x], &buttonConfigStatus ); - g_config->setOption (prefix + GamePadNames[x], - GamePadConfig[padNo][x].ButtonNum[configNo]); - - if (GamePadConfig[padNo][x].ButtType[configNo] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (GamePadConfig[padNo][x].ButtType[configNo] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - GamePadConfig[padNo][x].DeviceNum[configNo]); - - keyNameStr = ButtonName( &GamePadConfig[padNo][x], configNo ); + keyNameStr = ButtonName( &GamePad[padNo].bmap[x] ); keyName[x]->setText( keyNameStr ); button[x]->setText("Change"); + lcl[padNo].btn[x].needsSave = 1; ButtonConfigEnd (); @@ -239,34 +515,32 @@ void GamePadConfDialog_t::changeButton(int padNo, int x) //---------------------------------------------------- void GamePadConfDialog_t::clearButton( int padNo, int x ) { - char buf[256]; - std::string prefix; - - GamePadConfig[padNo][x].ButtonNum[configNo] = -1; + GamePad[padNo].bmap[x].ButtonNum = -1; keyName[x]->setText(""); - snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%d.", padNo); - prefix = buf; - - g_config->setOption (prefix + GamePadNames[x], - GamePadConfig[padNo][x].ButtonNum[configNo]); - + lcl[padNo].btn[x].needsSave = 1; } //---------------------------------------------------- void GamePadConfDialog_t::closeEvent(QCloseEvent *event) { - //printf("GamePad Close Window Event\n"); + promptToSave(); + + printf("GamePad Close Window Event\n"); buttonConfigStatus = 0; done(0); + deleteLater(); event->accept(); } //---------------------------------------------------- void GamePadConfDialog_t::closeWindow(void) { - //printf("Close Window\n"); + promptToSave(); + + printf("Close Window\n"); buttonConfigStatus = 0; done(0); + deleteLater(); } //---------------------------------------------------- void GamePadConfDialog_t::changeButton0(void) @@ -377,46 +651,236 @@ void GamePadConfDialog_t::clearAllCallback(void) } } //---------------------------------------------------- -void GamePadConfDialog_t::loadDefaults(void) +void GamePadConfDialog_t::saveConfig(void) { - char buf[256]; - std::string prefix; + int i; + char stmp[256]; + std::string prefix, mapName; - if ( portNum > 0 ) + sprintf( stmp, "SDL.Input.GamePad.%u.", portNum ); + prefix = stmp; + + mapName = mapSel->currentText().toStdString(); + + g_config->setOption(prefix + "DeviceGUID", GamePad[portNum].getGUID() ); + g_config->setOption(prefix + "Profile" , mapName.c_str() ); + + for (i=0; isave(); +} +//---------------------------------------------------- +void GamePadConfDialog_t::createNewProfile( const char *name ) +{ + char stmp[256]; + //printf("Creating: %s \n", name ); + + GamePad[portNum].createProfile(name); + + mapSel->addItem( tr(name) ); + + mapSel->setCurrentIndex( mapSel->count() - 1 ); + saveConfig(); + + sprintf( stmp, "Mapping Created: %s/%s \n", GamePad[portNum].getGUID(), name ); + mapMsg->setText( tr(stmp) ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::newProfileCallback(void) +{ + int ret; + QInputDialog dialog(this); + + dialog.setWindowTitle( tr("New Profile") ); + dialog.setLabelText( tr("Specify New Profile Name") ); + dialog.setOkButtonText( tr("Create") ); + + dialog.show(); + ret = dialog.exec(); + + if ( QDialog::Accepted == ret ) + { + createNewProfile( dialog.textValue().toStdString().c_str() ); + } +} +//---------------------------------------------------- +void GamePadConfDialog_t::loadProfileCallback(void) +{ + char stmp[256]; + int index, devIdx, ret; + std::string mapName; + + index = devSel->currentIndex(); + devIdx = devSel->itemData(index).toInt(); + + mapName = mapSel->currentText().toStdString(); + + GamePad[portNum].setDeviceIndex( devIdx ); + + if ( mapName.compare("default") == 0 ) + { + ret =GamePad[portNum].loadDefaults(); + } + else + { + ret = GamePad[portNum].loadProfile( mapName.c_str() ); + } + if ( ret == 0 ) + { + saveConfig(); + + sprintf( stmp, "Mapping Loaded: %s/%s \n", GamePad[portNum].getGUID(), mapName.c_str() ); + } + else + { + sprintf( stmp, "Error: Failed to Load Mapping: %s/%s \n", GamePad[portNum].getGUID(), mapName.c_str() ); + } + mapMsg->setText( tr(stmp) ); + + updateCntrlrDpy(); +} +//---------------------------------------------------- +void GamePadConfDialog_t::saveProfileCallback(void) +{ + int ret; + std::string mapName; + char stmp[256]; + + mapName = mapSel->currentText().toStdString(); + + ret = GamePad[portNum].saveCurrentMapToFile( mapName.c_str() ); + + if ( ret == 0 ) + { + saveConfig(); + + sprintf( stmp, "Mapping Saved: %s/%s \n", GamePad[portNum].getGUID(), mapName.c_str() ); + } + else + { + sprintf( stmp, "Error: Failed to Save Mapping: %s \n", mapName.c_str() ); + } + mapMsg->setText( tr(stmp) ); + +} +//---------------------------------------------------- +void GamePadConfDialog_t::deleteProfileCallback(void) +{ + int ret; + std::string mapName; + char stmp[256]; + + mapName = mapSel->currentText().toStdString(); + + ret = GamePad[portNum].deleteMapping( mapName.c_str() ); + + if ( ret == 0 ) + { + sprintf( stmp, "Mapping Deleted: %s/%s \n", GamePad[portNum].getGUID(), mapName.c_str() ); + } + else + { + sprintf( stmp, "Error: Failed to Delete Mapping: %s \n", mapName.c_str() ); + } + mapMsg->setText( tr(stmp) ); + + loadMapList(); +} +//---------------------------------------------------- +void GamePadConfDialog_t::promptToSave(void) +{ + int i,j,n; + std::string msg; + QMessageBox msgBox(this); + char saveRequired = 0; + char padNeedsSave[GAMEPAD_NUM_DEVICES]; + char stmp[256]; + + n=0; + for (i=0; i 1) ? 's':' '); - g_config->setOption (prefix + GamePadNames[x], - GamePadConfig[portNum][x].ButtonNum[configNo]); + msg.assign( stmp ); - if (GamePadConfig[portNum][x].ButtType[configNo] == BUTTC_KEYBOARD) + j=n; + for (i=0; isetOption (prefix + "DeviceType", "Keyboard"); + sprintf( stmp, "%i", i+1 ); + + msg.append(stmp); + + j--; + + if ( j > 1 ) + { + msg.append(", "); + } + else if ( j == 1 ) + { + msg.append(" and "); + } } - else if (GamePadConfig[portNum][x].ButtType[configNo] == BUTTC_JOYSTICK) + } + msg.append("."); + + msgBox.setIcon( QMessageBox::Warning ); + msgBox.setText( tr(msg.c_str()) ); + + msgBox.show(); + //msgBox.resize( 512, 128 ); + msgBox.exec(); +} +//---------------------------------------------------- +void GamePadConfDialog_t::updatePeriodic(void) +{ + for (int i=0; isetText( tr(txt) ); + keyState[i]->setStyleSheet( style ); + + if ( lcl[portNum].btn[i].needsSave ) { - g_config->setOption (prefix + "DeviceType", "Joystick"); + keyName[i]->setStyleSheet("color: red;"); } else { - g_config->setOption (prefix + "DeviceType", "Unknown"); + keyName[i]->setStyleSheet("color: black;"); } - g_config->setOption (prefix + "DeviceNum", - GamePadConfig[portNum][x].DeviceNum[configNo]); - } - updateCntrlrDpy(); + } } //---------------------------------------------------- GamePadConfigButton_t::GamePadConfigButton_t(int i) diff --git a/src/drivers/Qt/GamePadConf.h b/src/drivers/Qt/GamePadConf.h index 0f83000c..7d5fabe2 100644 --- a/src/drivers/Qt/GamePadConf.h +++ b/src/drivers/Qt/GamePadConf.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "Qt/main.h" @@ -37,12 +38,18 @@ class GamePadConfDialog_t : public QDialog ~GamePadConfDialog_t(void); protected: + QTimer *inputTimer; QComboBox *portSel; + QComboBox *devSel; + QComboBox *mapSel; + QComboBox *profSel; + QLabel *guidLbl; + QLabel *mapMsg; QLabel *keyName[GAMEPAD_NUM_BUTTONS]; + QLabel *keyState[GAMEPAD_NUM_BUTTONS]; GamePadConfigButton_t *button[GAMEPAD_NUM_BUTTONS]; int portNum; - int configNo; int buttonConfigStatus; void changeButton( int port, int button ); @@ -52,6 +59,10 @@ class GamePadConfDialog_t : public QDialog void closeEvent(QCloseEvent *bar); private: void updateCntrlrDpy(void); + void createNewProfile( const char *name ); + void loadMapList(void); + void saveConfig(void); + void promptToSave(void); public slots: void closeWindow(void); @@ -77,9 +88,18 @@ class GamePadConfDialog_t : public QDialog void clearButton8(void); void clearButton9(void); void clearAllCallback(void); - void loadDefaults(void); void ena4score(int state); void oppDirEna(int state); - void controllerSelect(int index); + void portSelect(int index); + void deviceSelect(int index); + void newProfileCallback(void); + void loadProfileCallback(void); + void saveProfileCallback(void); + void deleteProfileCallback(void); + void updatePeriodic(void); }; + +int openGamePadConfWindow( QWidget *parent ); + +int closeGamePadConfWindow(void); diff --git a/src/drivers/Qt/GuiConf.cpp b/src/drivers/Qt/GuiConf.cpp new file mode 100644 index 00000000..0eab340b --- /dev/null +++ b/src/drivers/Qt/GuiConf.cpp @@ -0,0 +1,82 @@ +// PaletteConf.cpp +// +#include + +#include "Qt/GuiConf.h" +#include "Qt/main.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/ConsoleWindow.h" + +//---------------------------------------------------- +GuiConfDialog_t::GuiConfDialog_t(QWidget *parent) + : QDialog( parent ) +{ + int useNativeFileDialogVal; + int useNativeMenuBarVal; + QVBoxLayout *mainLayout; + + //resize( 512, 600 ); + + // sync with config + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + g_config->getOption ("SDL.UseNativeMenuBar", &useNativeMenuBarVal); + + setWindowTitle( tr("GUI Config") ); + + mainLayout = new QVBoxLayout(); + + useNativeFileDialog = new QCheckBox( tr("Use Native OS File Dialog") ); + useNativeMenuBar = new QCheckBox( tr("Use Native OS Menu Bar") ); + + useNativeFileDialog->setChecked( useNativeFileDialogVal ); + useNativeMenuBar->setChecked( useNativeMenuBarVal ); + + connect(useNativeFileDialog , SIGNAL(stateChanged(int)), this, SLOT(useNativeFileDialogChanged(int)) ); + connect(useNativeMenuBar , SIGNAL(stateChanged(int)), this, SLOT(useNativeMenuBarChanged(int)) ); + + mainLayout->addWidget( useNativeFileDialog ); + mainLayout->addWidget( useNativeMenuBar ); + + setLayout( mainLayout ); +} + +//---------------------------------------------------- +GuiConfDialog_t::~GuiConfDialog_t(void) +{ + printf("Destroy GUI Config Close Window\n"); +} +//---------------------------------------------------------------------------- +void GuiConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("GUI Config Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------- +void GuiConfDialog_t::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------- +void GuiConfDialog_t::useNativeFileDialogChanged(int state) +{ + int value = (state == Qt::Unchecked) ? 0 : 1; + + g_config->setOption ("SDL.UseNativeFileDialog", value); +} +//---------------------------------------------------- +void GuiConfDialog_t::useNativeMenuBarChanged(int state) +{ + int value = (state == Qt::Unchecked) ? 0 : 1; + + g_config->setOption ("SDL.UseNativeMenuBar", value); + + consoleWindow->menuBar()->setNativeMenuBar( value ); +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/GuiConf.h b/src/drivers/Qt/GuiConf.h new file mode 100644 index 00000000..aa0bcc84 --- /dev/null +++ b/src/drivers/Qt/GuiConf.h @@ -0,0 +1,41 @@ +// GuiConf.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class GuiConfDialog_t : public QDialog +{ + Q_OBJECT + + public: + GuiConfDialog_t(QWidget *parent = 0); + ~GuiConfDialog_t(void); + + protected: + void closeEvent(QCloseEvent *event); + + QCheckBox *useNativeFileDialog; + QCheckBox *useNativeMenuBar; + private: + + public slots: + void closeWindow(void); + private slots: + void useNativeFileDialogChanged(int v); + void useNativeMenuBarChanged(int v); + +}; diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp new file mode 100644 index 00000000..f822b40c --- /dev/null +++ b/src/drivers/Qt/HexEditor.cpp @@ -0,0 +1,1921 @@ +// HotKeyConf.cpp +// +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../types.h" +#include "../../fceu.h" +#include "../../cheat.h" +#include "../../debug.h" +#include "../../driver.h" +#include "../../version.h" +#include "../../movie.h" +#include "../../palette.h" +#include "../../fds.h" +#include "../../cart.h" +#include "../../ines.h" +#include "../common/configSys.h" + +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/HexEditor.h" +#include "Qt/ConsoleUtilities.h" + +static HexBookMarkManager_t hbm; +static std::list winList; +static const char *memViewNames[] = { "RAM", "PPU", "OAM", "ROM", NULL }; +//---------------------------------------------------------------------------- +static int getRAM( unsigned int i ) +{ + return GetMem(i); +} +//---------------------------------------------------------------------------- +static int getPPU( unsigned int i ) +{ + i &= 0x3FFF; + if (i < 0x2000)return VPage[(i) >> 10][(i)]; + //NSF PPU Viewer crash here (UGETAB) (Also disabled by 'MaxSize = 0x2000') + if (GameInfo->type == GIT_NSF) + return 0; + else + { + if (i < 0x3F00) + return vnapage[(i >> 10) & 0x3][i & 0x3FF]; + return READPAL_MOTHEROFALL(i & 0x1F); + } + return 0; +} +//---------------------------------------------------------------------------- +static int getOAM( unsigned int i ) +{ + return SPRAM[i & 0xFF]; +} +//---------------------------------------------------------------------------- +static int getROM( unsigned int offset) +{ + if (offset < 16) + { + return *((unsigned char *)&head+offset); + } + else if (offset < (16+PRGsize[0]) ) + { + return PRGptr[0][offset-16]; + } + else if (offset < (16+PRGsize[0]+CHRsize[0]) ) + { + return CHRptr[0][offset-16-PRGsize[0]]; + } + return -1; +} +//---------------------------------------------------------------------------- +static void PalettePoke(uint32 addr, uint8 data) +{ + data = data & 0x3F; + addr = addr & 0x1F; + if ((addr & 3) == 0) + { + addr = (addr & 0xC) >> 2; + if (addr == 0) + { + PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = data; + } + else + { + UPALRAM[addr-1] = UPALRAM[0x10|(addr-1)] = data; + } + } + else + { + PALRAM[addr] = data; + } +} +//---------------------------------------------------------------------------- +static int writeMem( int mode, unsigned int addr, int value ) +{ + value = value & 0x000000ff; + + switch ( mode ) + { + default: + case QHexEdit::MODE_NES_RAM: + { + if ( addr < 0x8000 ) + { + writefunc wfunc; + + wfunc = GetWriteHandler (addr); + + if (wfunc) + { + wfunc ((uint32) addr, + (uint8) (value & 0x000000ff)); + } + } + else + { + fprintf( stdout, "Error: Writing into RAM addresses >= 0x8000 is unsafe. Operation Denied.\n"); + } + } + break; + case QHexEdit::MODE_NES_PPU: + { + addr &= 0x3FFF; + if (addr < 0x2000) + { + VPage[addr >> 10][addr] = value; //todo: detect if this is vrom and turn it red if so + } + if ((addr >= 0x2000) && (addr < 0x3F00)) + { + vnapage[(addr >> 10) & 0x3][addr & 0x3FF] = value; //todo: this causes 0x3000-0x3f00 to mirror 0x2000-0x2f00, is this correct? + } + if ((addr >= 0x3F00) && (addr < 0x3FFF)) + { + PalettePoke(addr, value); + } + } + break; + case QHexEdit::MODE_NES_OAM: + { + addr &= 0xFF; + SPRAM[addr] = value; + } + break; + case QHexEdit::MODE_NES_ROM: + { + if (addr < 16) + { + fprintf( stdout, "You can't edit ROM header here, however you can use iNES Header Editor to edit the header if it's an iNES format file."); + } + else if ( (addr >= 16) && (addr < PRGsize[0]+16) ) + { + *(uint8 *)(GetNesPRGPointer(addr-16)) = value; + } + else if ( (addr >= PRGsize[0]+16) && (addr < CHRsize[0]+PRGsize[0]+16) ) + { + *(uint8 *)(GetNesCHRPointer(addr-16-PRGsize[0])) = value; + } + } + break; + } + return 0; +} +//---------------------------------------------------------------------------- + +static int convToXchar( int i ) +{ + int c = 0; + + if ( (i >= 0) && (i < 10) ) + { + c = i + '0'; + } + else if ( i < 16 ) + { + c = (i - 10) + 'A'; + } + return c; +} +//---------------------------------------------------------------------------- + +static int convFromXchar( int i ) +{ + int c = 0; + + i = ::toupper(i); + + if ( (i >= '0') && (i <= '9') ) + { + c = i - '0'; + } + else if ( (i >= 'A') && (i <= 'F') ) + { + c = (i - 'A') + 10; + } + return c; +} + +//---------------------------------------------------------------------------- +memBlock_t::memBlock_t( void ) +{ + buf = NULL; + _size = 0; + _maxLines = 0; + memAccessFunc = NULL; +} +//---------------------------------------------------------------------------- + +memBlock_t::~memBlock_t(void) +{ + if ( buf != NULL ) + { + ::free( buf ); buf = NULL; + } + _size = 0; + _maxLines = 0; +} + +//---------------------------------------------------------------------------- +int memBlock_t::reAlloc( int newSize ) +{ + if ( newSize == 0 ) + { + return 0; + } + if ( _size == newSize ) + { + return 0; + } + + if ( buf != NULL ) + { + ::free( buf ); buf = NULL; + } + _size = 0; + _maxLines = 0; + + buf = (struct memByte_t *)malloc( newSize * sizeof(struct memByte_t) ); + + if ( buf != NULL ) + { + _size = newSize; + init(); + + if ( (_size % 16) ) + { + _maxLines = (_size / 16) + 1; + } + else + { + _maxLines = (_size / 16); + } + } + return (buf == NULL); +} +//---------------------------------------------------------------------------- +void memBlock_t::setAccessFunc( int (*newMemAccessFunc)( unsigned int offset) ) +{ + memAccessFunc = newMemAccessFunc; +} +//---------------------------------------------------------------------------- +void memBlock_t::init(void) +{ + for (int i=0; i<_size; i++) + { + buf[i].data = memAccessFunc(i); + buf[i].color = 0; + buf[i].actv = 0; + //buf[i].draw = 1; + } +} +//---------------------------------------------------------------------------- +HexBookMark::HexBookMark(void) +{ + addr = 0; + mode = 0; + desc[0] = 0; +} +//---------------------------------------------------------------------------- +HexBookMark::~HexBookMark(void) +{ + +} +//---------------------------------------------------------------------------- +HexBookMarkManager_t::HexBookMarkManager_t(void) +{ + +} +//---------------------------------------------------------------------------- +HexBookMarkManager_t::~HexBookMarkManager_t(void) +{ + removeAll(); +} +//---------------------------------------------------------------------------- +void HexBookMarkManager_t::removeAll(void) +{ + HexBookMark *b; + + while ( !ls.empty() ) + { + b = ls.front(); + + delete b; + + ls.pop_front(); + } + v.clear(); +} +//---------------------------------------------------------------------------- +int HexBookMarkManager_t::addBookMark( int addr, int mode, const char *desc ) +{ + HexBookMark *b; + + b = new HexBookMark(); + b->addr = addr; + b->mode = mode; + + if ( desc ) + { + strncpy( b->desc, desc, 63 ); + } + + b->desc[63] = 0; + + ls.push_back(b); + + updateVector(); + + return 0; +} +//---------------------------------------------------------------------------- +void HexBookMarkManager_t::updateVector(void) +{ + std::list ::iterator it; + + v.clear(); + + for (it=ls.begin(); it!=ls.end(); it++) + { + v.push_back( *it ); + } + + return; +} +//---------------------------------------------------------------------------- +int HexBookMarkManager_t::size(void) +{ + return ls.size(); +} +//---------------------------------------------------------------------------- +HexBookMark *HexBookMarkManager_t::getBookMark( int index ) +{ + if ( index < 0 ) + { + return NULL; + } + else if ( index >= (int)v.size() ) + { + return NULL; + } + return v[index]; +} +//---------------------------------------------------------------------------- +int HexBookMarkManager_t::loadFromFile(void) +{ + int i,j,mode,addr; + FILE *fp; + QDir dir; + char line[256], fd[256], baseFile[512]; + const char *romFile = getRomFile(); + const char *baseDir = FCEUI_GetBaseDirectory(); + std::string path; + + if ( romFile == NULL ) + { + return -1; + } + path = std::string(baseDir) + "/bookmarks/"; + + dir.mkpath( QString::fromStdString(path) ); + + getFileBaseName( romFile, baseFile ); + + path += std::string(baseFile) + ".txt"; + + fp = ::fopen( path.c_str(), "r"); + + if ( fp == NULL ) + { + return -1; + } + + while ( ::fgets( line, sizeof(line), fp ) != NULL ) + { + i=0; j=0; + //printf("%s\n", line ); + // + while ( isspace(line[i]) ) i++; + + while ( isalpha(line[i]) ) + { + fd[j] = line[i]; i++; j++; + } + fd[j] = 0; + + mode = -1; + + for (j=0; j<4; j++) + { + if ( strcmp( fd, memViewNames[j] ) == 0 ) + { + mode = j; break; + } + } + if ( mode < 0 ) continue; + + while ( isspace(line[i]) ) i++; + if ( line[i] == ':' ) i++; + while ( isspace(line[i]) ) i++; + + j=0; + while ( isxdigit(line[i]) ) + { + fd[j] = line[i]; i++; j++; + } + fd[j] = 0; + + addr = strtol( fd, NULL, 16 ); + + while ( isspace(line[i]) ) i++; + if ( line[i] == ':' ) i++; + while ( isspace(line[i]) ) i++; + + j=0; + while ( line[i] ) + { + fd[j] = line[i]; i++; j++; + } + fd[j] = 0; + j--; + + while ( j >= 0 ) + { + if ( isspace( fd[j] ) ) + { + fd[j] = 0; + } + else + { + break; + } + j--; + } + + addBookMark( addr, mode, fd ); + } + ::fclose(fp); + + return 0; +} +//---------------------------------------------------------------------------- +int HexBookMarkManager_t::saveToFile(void) +{ + FILE *fp; + QDir dir; + char baseFile[512]; + const char *romFile = getRomFile(); + const char *baseDir = FCEUI_GetBaseDirectory(); + std::string path; + + if ( romFile == NULL ) + { + return -1; + } + path = std::string(baseDir) + "/bookmarks/"; + + dir.mkpath( QString::fromStdString(path) ); + + getFileBaseName( romFile, baseFile ); + + path += std::string(baseFile) + ".txt"; + + fp = ::fopen( path.c_str(), "w"); + + if ( fp == NULL ) + { + return -1; + } + + for (int i=0; imode ], v[i]->addr, v[i]->desc ); + } + ::fclose(fp); + + return 0; +} +//---------------------------------------------------------------------------- +HexBookMarkMenuAction::HexBookMarkMenuAction(QString desc, QWidget *parent) + : QAction( desc, parent ) +{ + bm = NULL; qedit = NULL; +} +//---------------------------------------------------------------------------- +HexBookMarkMenuAction::~HexBookMarkMenuAction(void) +{ + //printf("Hex Bookmark Menu Action Deleted\n"); +} +//---------------------------------------------------------------------------- +void HexBookMarkMenuAction::activateCB(void) +{ + //printf("Activate Bookmark: %p \n", bm ); + qedit->setMode( bm->mode ); + qedit->setAddr( bm->addr ); +} +//---------------------------------------------------------------------------- +HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) + : QDialog( parent ) +{ + //QVBoxLayout *mainLayout; + QGridLayout *grid; + QMenuBar *menuBar; + QMenu *fileMenu, *viewMenu, *colorMenu; + QAction *saveROM, *closeAct; + QAction *viewRAM, *viewPPU, *viewOAM, *viewROM; + QAction *actHlgt, *actHlgtRV, *actColorFG, *actColorBG; + QActionGroup *group; + int useNativeMenuBar; + + setWindowTitle("Hex Editor"); + + resize( 512, 512 ); + + menuBar = new QMenuBar(this); + + // This is needed for menu bar to show up on MacOS + g_config->getOption( "SDL.UseNativeMenuBar", &useNativeMenuBar ); + + menuBar->setNativeMenuBar( useNativeMenuBar ? true : false ); + //----------------------------------------------------------------------- + // Menu + //----------------------------------------------------------------------- + // File + fileMenu = menuBar->addMenu(tr("File")); + + // File -> Save ROM + saveROM = new QAction(tr("Save ROM"), this); + //saveROM->setShortcuts(QKeySequence::Open); + saveROM->setStatusTip(tr("Save ROM File")); + connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFile(void)) ); + + fileMenu->addAction(saveROM); + + // File -> Save ROM As + saveROM = new QAction(tr("Save ROM As"), this); + //saveROM->setShortcuts(QKeySequence::Open); + saveROM->setStatusTip(tr("Save ROM File As")); + connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFileAs(void)) ); + + fileMenu->addAction(saveROM); + + fileMenu->addSeparator(); + + // File -> Close + closeAct = new QAction(tr("Close"), this); + //closeAct->setShortcuts(QKeySequence::Open); + closeAct->setStatusTip(tr("Close Window")); + connect(closeAct, SIGNAL(triggered()), this, SLOT(closeWindow(void)) ); + + fileMenu->addAction(closeAct); + + // View + viewMenu = menuBar->addMenu(tr("View")); + + group = new QActionGroup(this); + + group->setExclusive(true); + + // View -> RAM + viewRAM = new QAction(tr("RAM"), this); + //viewRAM->setShortcuts(QKeySequence::Open); + viewRAM->setStatusTip(tr("View RAM")); + viewRAM->setCheckable(true); + connect(viewRAM, SIGNAL(triggered()), this, SLOT(setViewRAM(void)) ); + + group->addAction(viewRAM); + viewMenu->addAction(viewRAM); + + // View -> PPU + viewPPU = new QAction(tr("PPU"), this); + //viewPPU->setShortcuts(QKeySequence::Open); + viewPPU->setStatusTip(tr("View PPU")); + viewPPU->setCheckable(true); + connect(viewPPU, SIGNAL(triggered()), this, SLOT(setViewPPU(void)) ); + + group->addAction(viewPPU); + viewMenu->addAction(viewPPU); + + // View -> OAM + viewOAM = new QAction(tr("OAM"), this); + //viewOAM->setShortcuts(QKeySequence::Open); + viewOAM->setStatusTip(tr("View OAM")); + viewOAM->setCheckable(true); + connect(viewOAM, SIGNAL(triggered()), this, SLOT(setViewOAM(void)) ); + + group->addAction(viewOAM); + viewMenu->addAction(viewOAM); + + // View -> ROM + viewROM = new QAction(tr("ROM"), this); + //viewROM->setShortcuts(QKeySequence::Open); + viewROM->setStatusTip(tr("View ROM")); + viewROM->setCheckable(true); + connect(viewROM, SIGNAL(triggered()), this, SLOT(setViewROM(void)) ); + + group->addAction(viewROM); + viewMenu->addAction(viewROM); + + viewRAM->setChecked(true); // Set default view + + // Color Menu + colorMenu = menuBar->addMenu(tr("Color")); + + // Color -> Highlight Activity + actHlgt = new QAction(tr("Highlight Activity"), this); + //actHlgt->setShortcuts(QKeySequence::Open); + actHlgt->setStatusTip(tr("Highlight Activity")); + actHlgt->setCheckable(true); + actHlgt->setChecked(true); + connect(actHlgt, SIGNAL(triggered(bool)), this, SLOT(actvHighlightCB(bool)) ); + + colorMenu->addAction(actHlgt); + + // Color -> Highlight Reverse Video + actHlgtRV = new QAction(tr("Highlight Reverse Video"), this); + //actHlgtRV->setShortcuts(QKeySequence::Open); + actHlgtRV->setStatusTip(tr("Highlight Reverse Video")); + actHlgtRV->setCheckable(true); + actHlgtRV->setChecked(true); + connect(actHlgtRV, SIGNAL(triggered(bool)), this, SLOT(actvHighlightRVCB(bool)) ); + + colorMenu->addAction(actHlgtRV); + + // Color -> ForeGround Color + actColorFG = new QAction(tr("ForeGround Color"), this); + //actColorFG->setShortcuts(QKeySequence::Open); + actColorFG->setStatusTip(tr("ForeGround Color")); + connect(actColorFG, SIGNAL(triggered(void)), this, SLOT(pickForeGroundColor(void)) ); + + colorMenu->addAction(actColorFG); + + // Color -> BackGround Color + actColorBG = new QAction(tr("BackGround Color"), this); + //actColorBG->setShortcuts(QKeySequence::Open); + actColorBG->setStatusTip(tr("BackGround Color")); + connect(actColorBG, SIGNAL(triggered(void)), this, SLOT(pickBackGroundColor(void)) ); + + colorMenu->addAction(actColorBG); + + // Bookmarks Menu + bookmarkMenu = menuBar->addMenu(tr("Bookmarks")); + + //----------------------------------------------------------------------- + // Menu End + //----------------------------------------------------------------------- + //mainLayout = new QVBoxLayout(); + + grid = new QGridLayout(this); + editor = new QHexEdit(this); + vbar = new QScrollBar( Qt::Vertical, this ); + hbar = new QScrollBar( Qt::Horizontal, this ); + + grid->setMenuBar( menuBar ); + + grid->addWidget( editor, 0, 0 ); + grid->addWidget( vbar , 0, 1 ); + grid->addWidget( hbar , 1, 0 ); + //mainLayout->addLayout( grid ); + + setLayout( grid ); + + hbar->setMinimum(0); + hbar->setMaximum(100); + vbar->setMinimum(0); + vbar->setMaximum( 0x10000 / 16 ); + + editor->setScrollBars( hbar, vbar ); + + //connect( vbar, SIGNAL(sliderMoved(int)), this, SLOT(vbarMoved(int)) ); + connect( hbar, SIGNAL(valueChanged(int)), this, SLOT(hbarChanged(int)) ); + connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); + + editor->memModeUpdate(); + + periodicTimer = new QTimer( this ); + + connect( periodicTimer, &QTimer::timeout, this, &HexEditorDialog_t::updatePeriodic ); + + periodicTimer->start( 100 ); // 10hz + + winList.push_back(this); + + populateBookmarkMenu(); + +} +//---------------------------------------------------------------------------- +HexEditorDialog_t::~HexEditorDialog_t(void) +{ + std::list ::iterator it; + + printf("Hex Editor Deleted\n"); + periodicTimer->stop(); + + for (it = winList.begin(); it != winList.end(); it++) + { + if ( (*it) == this ) + { + winList.erase(it); + //printf("Removing Hex Edit Window\n"); + break; + } + } +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::removeAllBookmarks(void) +{ + int ret; + QMessageBox mbox(this); + + mbox.setWindowTitle( tr("Bookmarks") ); + mbox.setText( tr("Remove All Bookmarks?") ); + mbox.setIcon( QMessageBox::Question ); + mbox.setStandardButtons( QMessageBox::Cancel | QMessageBox::Ok ); + + ret = mbox.exec(); + + //printf("Ret: %i \n", ret ); + if ( ret == QMessageBox::Ok ) + { + hbm.removeAll(); + + populateBookmarkMenu(); + } +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::populateBookmarkMenu(void) +{ + QAction *act; + HexBookMarkMenuAction *hAct; + + bookmarkMenu->clear(); + + // Bookmarks -> Remove All Bookmarks + act = new QAction(tr("Remove All Bookmarks"), bookmarkMenu); + //act->setShortcuts(QKeySequence::Open); + act->setStatusTip(tr("Remove All Bookmarks")); + connect(act, SIGNAL(triggered(void)), this, SLOT(removeAllBookmarks(void)) ); + + bookmarkMenu->addAction(act); + bookmarkMenu->addSeparator(); + + for (int i=0; idesc), bookmarkMenu); + bookmarkMenu->addAction(hAct); + hAct->bm = b; hAct->qedit = editor; + connect(hAct, SIGNAL(triggered(void)), hAct, SLOT(activateCB(void)) ); + } + } +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Hex Editor Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::pickForeGroundColor(void) +{ + int ret; + QColorDialog dialog( this ); + + dialog.setOption( QColorDialog::DontUseNativeDialog, true ); + dialog.show(); + ret = dialog.exec(); + + if ( ret == QDialog::Accepted ) + { + QString colorText; + colorText = dialog.selectedColor().name(); + //printf("FG Color string '%s'\n", colorText.toStdString().c_str() ); + g_config->setOption("SDL.HexEditFgColor", colorText.toStdString().c_str() ); + editor->setForeGroundColor( dialog.selectedColor() ); + } +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::pickBackGroundColor(void) +{ + int ret; + QColorDialog dialog( this ); + + dialog.setOption( QColorDialog::DontUseNativeDialog, true ); + dialog.show(); + ret = dialog.exec(); + + if ( ret == QDialog::Accepted ) + { + QString colorText; + colorText = dialog.selectedColor().name(); + //printf("BG Color string '%s'\n", colorText.toStdString().c_str() ); + g_config->setOption("SDL.HexEditBgColor", colorText.toStdString().c_str() ); + editor->setBackGroundColor( dialog.selectedColor() ); + } +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::vbarMoved(int value) +{ + //printf("VBar Moved: %i\n", value); + editor->setLine( value ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::vbarChanged(int value) +{ + //printf("VBar Changed: %i\n", value); + editor->setLine( value ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::hbarChanged(int value) +{ + //printf("HBar Changed: %i\n", value); + editor->setHorzScroll( value ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::gotoAddress( int newAddr ) +{ + editor->setAddr( newAddr ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::saveRomFile(void) +{ + //FlushUndoBuffer(); + iNesSave(); + //UpdateColorTable(); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::saveRomFileAs(void) +{ + int ret, useNativeFileDialogVal; + QString filename; + QFileDialog dialog(this, tr("Save ROM To File") ); + + dialog.setFileMode(QFileDialog::AnyFile); + + dialog.setNameFilter(tr("NES Files (*.nes *.NES) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Save") ); + dialog.setDefaultSuffix( tr(".nes") ); + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + iNesSaveAs( filename.toStdString().c_str() ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::setViewRAM(void) +{ + editor->setMode( QHexEdit::MODE_NES_RAM ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::setViewPPU(void) +{ + editor->setMode( QHexEdit::MODE_NES_PPU ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::setViewOAM(void) +{ + editor->setMode( QHexEdit::MODE_NES_OAM ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::setViewROM(void) +{ + editor->setMode( QHexEdit::MODE_NES_ROM ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::actvHighlightCB(bool enable) +{ + //printf("Highlight: %i \n", enable ); + editor->setHighlightActivity( enable ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::actvHighlightRVCB(bool enable) +{ + //printf("Highlight: %i \n", enable ); + editor->setHighlightReverseVideo( enable ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::updatePeriodic(void) +{ + //printf("Update Periodic\n"); + + editor->checkMemActivity(); + + editor->memModeUpdate(); + + editor->update(); +} +//---------------------------------------------------------------------------- +QHexEdit::QHexEdit(QWidget *parent) + : QWidget( parent ) +{ + QPalette pal; + QColor bg, fg; + std::string colorString; + + this->parent = (HexEditorDialog_t*)parent; + this->setFocusPolicy(Qt::StrongFocus); + + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + + g_config->getOption("SDL.HexEditBgColor", &colorString); + bg.setNamedColor( colorString.c_str() ); + g_config->getOption("SDL.HexEditFgColor", &colorString); + fg.setNamedColor( colorString.c_str() ); + + pal = this->palette(); + pal.setColor(QPalette::Base , bg ); + pal.setColor(QPalette::Background, bg ); + pal.setColor(QPalette::WindowText, fg ); + + //editor->setAutoFillBackground(true); + this->setPalette(pal); + + calcFontData(); + + memAccessFunc = getRAM; + viewMode = MODE_NES_RAM; + lineOffset = 0; + cursorPosX = 0; + cursorPosY = 0; + cursorBlink = true; + cursorBlinkCount = 0; + maxLineOffset = 0; + editAddr = -1; + editValue = 0; + editMask = 0; + reverseVideo = true; + actvHighlightEnable = true; + total_instructions_lp = 0; + pxLineXScroll = 0; + + highLightColor[ 0].setRgb( 0x00, 0x00, 0x00 ); + highLightColor[ 1].setRgb( 0x35, 0x40, 0x00 ); + highLightColor[ 2].setRgb( 0x18, 0x52, 0x18 ); + highLightColor[ 3].setRgb( 0x34, 0x5C, 0x5E ); + highLightColor[ 4].setRgb( 0x00, 0x4C, 0x80 ); + highLightColor[ 5].setRgb( 0x00, 0x03, 0xBA ); + highLightColor[ 6].setRgb( 0x38, 0x00, 0xD1 ); + highLightColor[ 7].setRgb( 0x72, 0x12, 0xB2 ); + highLightColor[ 8].setRgb( 0xAB, 0x00, 0xBA ); + highLightColor[ 9].setRgb( 0xB0, 0x00, 0x6F ); + highLightColor[10].setRgb( 0xC2, 0x00, 0x37 ); + highLightColor[11].setRgb( 0xBA, 0x0C, 0x00 ); + highLightColor[12].setRgb( 0xC9, 0x2C, 0x00 ); + highLightColor[13].setRgb( 0xBF, 0x53, 0x00 ); + highLightColor[14].setRgb( 0xCF, 0x72, 0x00 ); + highLightColor[15].setRgb( 0xC7, 0x8B, 0x3C ); + + for (int i=0; i= 0.5 ) + { + grayScale = 0.0; + } + else + { + grayScale = 1.0; + } + rvActvTextColor[i].setRgbF( grayScale, grayScale, grayScale ); + } +} +//---------------------------------------------------------------------------- +QHexEdit::~QHexEdit(void) +{ + +} +//---------------------------------------------------------------------------- +void QHexEdit::calcFontData(void) +{ + this->setFont(font); + QFontMetrics metrics(font); +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + pxCharWidth = metrics.horizontalAdvance(QLatin1Char('2')); +#else + pxCharWidth = metrics.width(QLatin1Char('2')); +#endif + pxCharHeight = metrics.height(); + pxLineSpacing = metrics.lineSpacing() * 1.25; + pxLineLead = pxLineSpacing - pxCharHeight; + pxXoffset = pxCharWidth; + pxYoffset = pxLineSpacing * 2.0; + pxHexOffset = pxXoffset + (7*pxCharWidth); + pxHexAscii = pxHexOffset + (16*3*pxCharWidth) + (pxCharWidth); + pxLineWidth = pxHexAscii + (17*pxCharWidth); + //_pxGapAdr = _pxCharWidth / 2; + //_pxGapAdrHex = _pxCharWidth; + //_pxGapHexAscii = 2 * _pxCharWidth; + pxCursorHeight = pxCharHeight; + //_pxSelectionSub = _pxCharHeight / 5; + viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; +} +//---------------------------------------------------------------------------- +void QHexEdit::setHighlightActivity( int enable ) +{ + actvHighlightEnable = enable; +} +//---------------------------------------------------------------------------- +void QHexEdit::setHighlightReverseVideo( int enable ) +{ + reverseVideo = enable; +} +//---------------------------------------------------------------------------- +void QHexEdit::setForeGroundColor( QColor fg ) +{ + QPalette pal; + + pal = this->palette(); + //pal.setColor(QPalette::Base , Qt::black); + //pal.setColor(QPalette::Background, Qt::black); + pal.setColor(QPalette::WindowText, fg ); + + this->setPalette(pal); +} +//---------------------------------------------------------------------------- +void QHexEdit::setBackGroundColor( QColor bg ) +{ + QPalette pal; + + pal = this->palette(); + //pal.setColor(QPalette::Base , Qt::black); + pal.setColor(QPalette::Background, bg ); + //pal.setColor(QPalette::WindowText, fg ); + + this->setPalette(pal); +} +//---------------------------------------------------------------------------- +void QHexEdit::setMode( int mode ) +{ + if ( viewMode != mode ) + { + viewMode = mode; + memModeUpdate(); + } +} +//---------------------------------------------------------------------------- +void QHexEdit::setLine( int newLineOffset ) +{ + lineOffset = newLineOffset; +} +//---------------------------------------------------------------------------- +void QHexEdit::setAddr( int newAddr ) +{ + int addr; + lineOffset = newAddr / 16; + + if ( lineOffset < 0 ) + { + lineOffset = 0; + } + else if ( lineOffset >= maxLineOffset ) + { + lineOffset = maxLineOffset; + } + + addr = 16*lineOffset; + + cursorPosX = 2*((newAddr - addr)%16); + cursorPosY = (newAddr - addr)/16; + + vbar->setValue( lineOffset ); +} +//---------------------------------------------------------------------------- +void QHexEdit::setHorzScroll( int value ) +{ + float f; + //printf("Value: %i \n", value); + + if ( viewWidth >= pxLineWidth ) + { + f = 0.0; + } + else + { + f = 0.010f * (float)value * (float)(pxLineWidth - viewWidth); + } + + pxLineXScroll = (int)f; +} +//---------------------------------------------------------------------------- +void QHexEdit::setScrollBars( QScrollBar *h, QScrollBar *v ) +{ + hbar = h; vbar = v; +} +//---------------------------------------------------------------------------- +void QHexEdit::resizeEvent(QResizeEvent *event) +{ + viewWidth = event->size().width(); + viewHeight = event->size().height(); + + //printf("QHexEdit Resize: %ix%i\n", viewWidth, viewHeight ); + + viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; + + maxLineOffset = mb.numLines() - viewLines + 1; + + if ( viewWidth >= pxLineWidth ) + { + pxLineXScroll = 0; + } + else + { + pxLineXScroll = (int)(0.010f * (float)hbar->value() * (float)(pxLineWidth - viewWidth) ); + } + +} +//---------------------------------------------------------------------------- +void QHexEdit::resetCursor(void) +{ + cursorBlink = true; + cursorBlinkCount = 0; + editAddr = -1; + editValue = 0; + editMask = 0; +} +//---------------------------------------------------------------------------- +QPoint QHexEdit::convPixToCursor( QPoint p ) +{ + QPoint c(0,0); + + //printf("Pos: %ix%i \n", p.x(), p.y() ); + + p.setX( p.x() + pxLineXScroll ); + + if ( p.x() < pxHexOffset ) + { + c.setX(0); + } + else if ( (p.x() >= pxHexOffset) && (p.x() < pxHexAscii) ) + { + float px = ( (float)p.x() - (float)pxHexOffset) / (float)(pxCharWidth); + float ox = (px/3.0); + float rx = fmodf(px,3.0); + + if ( rx >= 2.50 ) + { + c.setX( 2*( (int)ox + 1 ) ); + } + else + { + //if ( rx >= 1.0 ) + //{ + // c.setX( 2*( (int)ox ) + 1 ); + //} + //else + //{ + c.setX( 2*( (int)ox ) ); + //} + } + } + else + { + c.setX( 32 + (p.x() - pxHexAscii) / pxCharWidth ); + } + if ( c.x() >= 48 ) + { + c.setX( 47 ); + } + + if ( p.y() < pxYoffset ) + { + c.setY( 0 ); + } + else + { + float ly = ( (float)pxLineLead / (float)pxLineSpacing ); + float py = ( (float)p.y() - (float)pxLineSpacing) / (float)pxLineSpacing; + float ry = fmod( py, 1.0 ); + + if ( ry < ly ) + { + c.setY( ((int)py) - 1 ); + } + else + { + c.setY( (int)py ); + } + } + if ( c.y() < 0 ) + { + c.setY(0); + } + else if ( c.y() >= viewLines ) + { + c.setY( viewLines - 1 ); + } + //printf("c: %ix%i \n", cx, cy ); + // + + return c; +} +//---------------------------------------------------------------------------- +int QHexEdit::convPixToAddr( QPoint p ) +{ + int a,addr; + QPoint c = convPixToCursor(p); + + //printf("Cursor: %ix%i\n", c.x(), c.y() ); + + if ( c.x() < 32 ) + { + a = (c.x() / 2); + + addr = 16*(lineOffset + c.y()) + a; + } + else + { + a = (c.x()-32); + + addr = 16*(lineOffset + c.y()) + a; + } + return addr; +} +//---------------------------------------------------------------------------- +void QHexEdit::keyPressEvent(QKeyEvent *event) +{ + printf("Hex Window Key Press: 0x%x \n", event->key() ); + + if (event->matches(QKeySequence::MoveToNextChar)) + { + if ( cursorPosX < 32 ) + { + if ( cursorPosX % 2 ) + { + cursorPosX++; + } + else + { + cursorPosX += 2; + } + } + else + { + cursorPosX++; + } + if ( cursorPosX >= 48 ) + { + cursorPosX = 47; + } + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToPreviousChar)) + { + if ( cursorPosX < 33 ) + { + if ( cursorPosX % 2 ) + { + cursorPosX -= 3; + } + else + { + cursorPosX -= 2; + } + } + else + { + cursorPosX--; + } + if ( cursorPosX < 0 ) + { + cursorPosX = 0; + } + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToEndOfLine)) + { + cursorPosX = 47; + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToStartOfLine)) + { + cursorPosX = 0; + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToPreviousLine)) + { + cursorPosY--; + + if ( cursorPosY < 0 ) + { + lineOffset--; + + if ( lineOffset < 0 ) + { + lineOffset = 0; + } + cursorPosY = 0; + + vbar->setValue( lineOffset ); + } + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToNextLine)) + { + cursorPosY++; + + if ( cursorPosY >= viewLines ) + { + lineOffset++; + + if ( lineOffset >= maxLineOffset ) + { + lineOffset = maxLineOffset; + } + cursorPosY = viewLines-1; + + vbar->setValue( lineOffset ); + } + resetCursor(); + + } + else if (event->matches(QKeySequence::MoveToNextPage)) + { + lineOffset += ( (3 * viewLines) / 4); + + if ( lineOffset >= maxLineOffset ) + { + lineOffset = maxLineOffset; + } + vbar->setValue( lineOffset ); + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToPreviousPage)) + { + lineOffset -= ( (3 * viewLines) / 4); + + if ( lineOffset < 0 ) + { + lineOffset = 0; + } + vbar->setValue( lineOffset ); + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToEndOfDocument)) + { + lineOffset = maxLineOffset; + vbar->setValue( lineOffset ); + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToStartOfDocument)) + { + lineOffset = 0; + vbar->setValue( lineOffset ); + resetCursor(); + } + else if (event->key() == Qt::Key_Tab && (cursorPosX < 32) ) + { // switch from hex to ascii edit + cursorPosX = 32 + (cursorPosX / 2); + } + else if (event->key() == Qt::Key_Backtab && (cursorPosX >= 32) ) + { // switch from ascii to hex edit + cursorPosX = 2 * (cursorPosX - 32); + } + else + { + int key; + if ( cursorPosX >= 32 ) + { // Edit Area is ASCII + key = (uchar)event->text()[0].toLatin1(); + + if ( ::isascii( key ) ) + { + int offs = (cursorPosX-32); + int addr = 16*(lineOffset+cursorPosY) + offs; + fceuWrapperLock(); + writeMem( viewMode, addr, key ); + fceuWrapperUnLock(); + + editAddr = -1; + editValue = 0; + editMask = 0; + } + } + else + { // Edit Area is Hex + key = int(event->text()[0].toUpper().toLatin1()); + + if ( ::isxdigit( key ) ) + { + int offs, nibbleValue, nibbleIndex; + + offs = (cursorPosX / 2); + nibbleIndex = (cursorPosX % 2); + + editAddr = 16*(lineOffset+cursorPosY) + offs; + + nibbleValue = convFromXchar( key ); + + if ( nibbleIndex ) + { + nibbleValue = editValue | nibbleValue; + + fceuWrapperLock(); + writeMem( viewMode, editAddr, nibbleValue ); + fceuWrapperUnLock(); + + editAddr = -1; + editValue = 0; + editMask = 0; + } + else + { + editValue = (nibbleValue << 4); + editMask = 0x00f0; + } + cursorPosX++; + + if ( cursorPosX >= 32 ) + { + cursorPosX = 0; + } + } + } + //printf("Key: %c %i \n", key, key); + } +} +//---------------------------------------------------------------------------- +void QHexEdit::keyReleaseEvent(QKeyEvent *event) +{ + printf("Hex Window Key Release: 0x%x \n", event->key() ); + //assignHotkey( event ); +} +//---------------------------------------------------------------------------- +void QHexEdit::mousePressEvent(QMouseEvent * event) +{ + QPoint c = convPixToCursor( event->pos() ); + + //printf("c: %ix%i \n", c.x(), c.y() ); + + if ( event->button() == Qt::LeftButton ) + { + cursorPosX = c.x(); + cursorPosY = c.y(); + resetCursor(); + } + +} +//---------------------------------------------------------------------------- +void QHexEdit::contextMenuEvent(QContextMenuEvent *event) +{ + QAction *act; + QMenu menu(this); + int addr; + char stmp[128]; + + ctxAddr = addr = convPixToAddr( event->pos() ); + //printf("contextMenuEvent\n"); + + switch ( viewMode ) + { + case MODE_NES_RAM: + { + act = new QAction(tr("TODO Add Symbolic Debug Name"), this); + menu.addAction(act); + + sprintf( stmp, "TODO Add Read Breakpoint for Address $%04X", addr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + + sprintf( stmp, "TODO Add Write Breakpoint for Address $%04X", addr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + + sprintf( stmp, "TODO Add Execute Breakpoint for Address $%04X", addr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + + if ( addr > 0x6000 ) + { + int romAddr = GetNesFileAddress(addr); + + if ( romAddr >= 0 ) + { + jumpToRomValue = romAddr; + sprintf( stmp, "Go Here in ROM File: (%08X)", romAddr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(jumpToROM(void)) ); + } + } + + act = new QAction(tr("Add Bookmark"), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); + } + break; + case MODE_NES_PPU: + { + act = new QAction(tr("Add Bookmark"), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); + } + break; + case MODE_NES_OAM: + { + act = new QAction(tr("Add Bookmark"), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); + } + break; + case MODE_NES_ROM: + { + act = new QAction(tr("Add Bookmark"), this); + menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); + } + break; + } + + menu.exec(event->globalPos()); + +} +//---------------------------------------------------------------------------- +void QHexEdit::addBookMarkCB(void) +{ + int ret; + char stmp[64]; + QInputDialog dialog(this); + + switch ( viewMode ) + { + default: + case MODE_NES_RAM: + sprintf( stmp, "RAM %04X", ctxAddr ); + break; + case MODE_NES_PPU: + sprintf( stmp, "PPU %04X", ctxAddr ); + break; + case MODE_NES_OAM: + sprintf( stmp, "OAM %04X", ctxAddr ); + break; + case MODE_NES_ROM: + sprintf( stmp, "ROM %04X", ctxAddr ); + break; + } + + dialog.setWindowTitle( tr("Add Bookmark") ); + dialog.setLabelText( tr("Specify New Bookmark Description") ); + dialog.setOkButtonText( tr("Add") ); + dialog.setTextValue( tr(stmp) ); + + dialog.show(); + ret = dialog.exec(); + + if ( QDialog::Accepted == ret ) + { + hbm.addBookMark( ctxAddr, viewMode, dialog.textValue().toStdString().c_str() ); + parent->populateBookmarkMenu(); + } +} +//---------------------------------------------------------------------------- +void QHexEdit::jumpToROM(void) +{ + setMode( MODE_NES_ROM ); + + maxLineOffset = mb.numLines() - viewLines + 1; + + if ( lineOffset > maxLineOffset ) + { + lineOffset = maxLineOffset; + } + setAddr( jumpToRomValue ); +} +//---------------------------------------------------------------------------- +int QHexEdit::checkMemActivity(void) +{ + int c; + + // Don't perform memory activity checks when: + // 1. In ROM View Mode + // 2. The simulation is not cycling (paused) + + if ( ( viewMode == MODE_NES_ROM ) || + ( total_instructions_lp == total_instructions ) ) + { + return -1; + } + + for (int i=0; i 0 ) + { + //mb.buf[i].draw = 1; + mb.buf[i].actv--; + } + } + } + total_instructions_lp = total_instructions; + + return 0; +} +//---------------------------------------------------------------------------- +void QHexEdit::memModeUpdate(void) +{ + int memSize; + + switch ( getMode() ) + { + default: + case MODE_NES_RAM: + memAccessFunc = getRAM; + memSize = 0x10000; + break; + case MODE_NES_PPU: + memAccessFunc = getPPU; + if ( GameInfo ) + { + memSize = (GameInfo->type == GIT_NSF ? 0x2000 : 0x4000); + } + else + { + memSize = 0x4000; + } + break; + case MODE_NES_OAM: + memAccessFunc = getOAM; + memSize = 0x100; + break; + case MODE_NES_ROM: + + if ( GameInfo != NULL ) + { + memAccessFunc = getROM; + memSize = 16 + CHRsize[0] + PRGsize[0]; + } + else + { // No Game Loaded!!! Get out of Function + memAccessFunc = NULL; + memSize = 0; + return; + } + break; + } + + if ( memSize != mb.size() ) + { + mb.setAccessFunc( memAccessFunc ); + + if ( mb.reAlloc( memSize ) ) + { + printf("Error: Failed to allocate memview buffer size\n"); + return; + } + } +} +//---------------------------------------------------------------------------- +void QHexEdit::paintEvent(QPaintEvent *event) +{ + int x, y, w, h, row, col, nrow, addr; + int c, cx, cy, ca; + char txt[32], asciiTxt[4]; + QPainter painter(this); + + painter.setFont(font); + w = event->rect().width(); + h = event->rect().height(); + + viewWidth = w; + viewHeight = h; + //painter.fillRect( 0, 0, w, h, QColor("white") ); + + nrow = (h - pxLineSpacing) / pxLineSpacing; + + if ( nrow < 1 ) nrow = 1; + + viewLines = nrow; + + if ( cursorPosY >= viewLines ) + { + cursorPosY = viewLines-1; + } + //printf("Draw Area: %ix%i \n", event->rect().width(), event->rect().height() ); + // + maxLineOffset = mb.numLines() - nrow + 1; + + if ( lineOffset > maxLineOffset ) + { + lineOffset = maxLineOffset; + } + + painter.fillRect( 0, 0, w, h, this->palette().color(QPalette::Background) ); + + if ( cursorBlinkCount >= 5 ) + { + cursorBlink = !cursorBlink; + cursorBlinkCount = 0; + } + else + { + cursorBlinkCount++; + } + + cy = pxYoffset + (pxLineSpacing*cursorPosY) - pxCursorHeight + pxLineLead; + + if ( cursorPosX < 32 ) + { + int a = (cursorPosX / 2); + int r = (cursorPosX % 2); + cx = pxHexOffset + (a*3*pxCharWidth) + (r*pxCharWidth) - pxLineXScroll; + + ca = 16*(lineOffset + cursorPosY) + a; + } + else + { + int a = (cursorPosX-32); + cx = pxHexAscii + (a*pxCharWidth) - pxLineXScroll; + + ca = 16*(lineOffset + cursorPosY) + a; + } + + if ( cursorBlink ) + { + painter.fillRect( cx , cy, pxCharWidth, pxCursorHeight, QColor("gray") ); + } + + painter.setPen( this->palette().color(QPalette::WindowText)); + + //painter.setPen( QColor("white") ); + addr = lineOffset * 16; + y = pxYoffset; + + for ( row=0; row < nrow; row++) + { + x = pxXoffset - pxLineXScroll; + + painter.setPen( this->palette().color(QPalette::WindowText)); + sprintf( txt, "%06X", addr ); + painter.drawText( x, y, tr(txt) ); + + x = pxHexOffset - pxLineXScroll; + + for (col=0; col<16; col++) + { + if ( addr < mb.size() ) + { + c = mb.buf[addr].data; + + if ( ::isprint(c) ) + { + asciiTxt[0] = c; + } + else + { + asciiTxt[0] = '.'; + } + asciiTxt[1] = 0; + + if ( addr == editAddr ) + { // Set a cell currently being editting to red text + painter.setPen( QColor("red") ); + txt[0] = convToXchar( (editValue >> 4) & 0x0F ); + txt[1] = convToXchar( c & 0x0F ); + txt[2] = 0; + painter.drawText( x, y, tr(txt) ); + painter.setPen( this->palette().color(QPalette::WindowText)); + } + else + { + if ( actvHighlightEnable && (mb.buf[addr].actv > 0) ) + { + if ( reverseVideo ) + { + painter.setPen( rvActvTextColor[ mb.buf[addr].actv ] ); + painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); + painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); + } + else + { + painter.setPen( highLightColor[ mb.buf[addr].actv ] ); + } + } + else + { + painter.setPen( this->palette().color(QPalette::WindowText)); + } + txt[0] = convToXchar( (c >> 4) & 0x0F ); + txt[1] = convToXchar( c & 0x0F ); + txt[2] = 0; + + if ( cursorBlink && (ca == addr) ) + { + painter.fillRect( cx , cy, pxCharWidth, pxCursorHeight, QColor("gray") ); + } + painter.drawText( x, y, tr(txt) ); + painter.drawText( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y, tr(asciiTxt) ); + } + } + x += (3*pxCharWidth); + addr++; + } + + //addr += 16; + y += pxLineSpacing; + } + + painter.setPen( this->palette().color(QPalette::WindowText)); + painter.drawText( pxHexOffset - pxLineXScroll, pxLineSpacing, "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" ); + painter.drawLine( pxHexOffset - (pxCharWidth/2) - pxLineXScroll, 0, pxHexOffset - (pxCharWidth/2) - pxLineXScroll, h ); + painter.drawLine( pxHexAscii - (pxCharWidth/2) - pxLineXScroll, 0, pxHexAscii - (pxCharWidth/2) - pxLineXScroll, h ); + painter.drawLine( 0, pxLineSpacing + (pxLineLead), w, pxLineSpacing + (pxLineLead) ); + +} +//---------------------------------------------------------------------------- +void hexEditorLoadBookmarks(void) +{ + std::list ::iterator it; + + hbm.removeAll(); + hbm.loadFromFile(); + + for (it = winList.begin(); it != winList.end(); it++) + { + (*it)->populateBookmarkMenu(); + } +} +//---------------------------------------------------------------------------- +void hexEditorSaveBookmarks(void) +{ + std::list ::iterator it; + + printf("Save Bookmarks\n"); + hbm.saveToFile(); + hbm.removeAll(); + + for (it = winList.begin(); it != winList.end(); it++) + { + (*it)->populateBookmarkMenu(); + } +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h new file mode 100644 index 00000000..6c2623a0 --- /dev/null +++ b/src/drivers/Qt/HexEditor.h @@ -0,0 +1,231 @@ +// GamePadConf.h +// + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct memByte_t +{ + unsigned char data; + unsigned char color; + unsigned char actv; +}; + +struct memBlock_t +{ + memBlock_t(void); + ~memBlock_t(void); + + void init(void); + int size(void){ return _size; } + int numLines(void){ return _maxLines; } + int reAlloc( int newSize ); + void setAccessFunc( int (*newMemAccessFunc)( unsigned int offset) ); + + struct memByte_t *buf; + int _size; + int _maxLines; + int (*memAccessFunc)( unsigned int offset); +}; + +class HexBookMark +{ + public: + HexBookMark(void); + ~HexBookMark(void); + + int addr; + int mode; + char desc[64]; +}; + +class HexBookMarkManager_t +{ + public: + HexBookMarkManager_t(void); + ~HexBookMarkManager_t(void); + + void removeAll(void); + int addBookMark( int addr, int mode, const char *desc ); + int size(void); + HexBookMark *getBookMark( int index ); + int saveToFile(void); + int loadFromFile(void); + private: + void updateVector(void); + std::list ls; + std::vector v; +}; + +class QHexEdit; + +class HexBookMarkMenuAction : public QAction +{ + Q_OBJECT + + public: + HexBookMarkMenuAction( QString desc, QWidget *parent = 0); + ~HexBookMarkMenuAction(void); + + QHexEdit *qedit; + HexBookMark *bm; + public slots: + void activateCB(void); + +}; + +class HexEditorDialog_t; + +class QHexEdit : public QWidget +{ + Q_OBJECT + + public: + QHexEdit(QWidget *parent = 0); + ~QHexEdit(void); + + int getMode(void){ return viewMode; }; + void setMode( int mode ); + void setLine( int newLineOffset ); + void setAddr( int newAddrOffset ); + void setScrollBars( QScrollBar *h, QScrollBar *v ); + void setHorzScroll( int value ); + void setHighlightActivity( int enable ); + void setHighlightReverseVideo( int enable ); + void setForeGroundColor( QColor fg ); + void setBackGroundColor( QColor bg ); + void memModeUpdate(void); + int checkMemActivity(void); + + enum { + MODE_NES_RAM = 0, + MODE_NES_PPU, + MODE_NES_OAM, + MODE_NES_ROM + }; + static const int HIGHLIGHT_ACTIVITY_NUM_COLORS = 16; + protected: + void paintEvent(QPaintEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + void mousePressEvent(QMouseEvent * event); + void resizeEvent(QResizeEvent *event); + void contextMenuEvent(QContextMenuEvent *event); + + void calcFontData(void); + void resetCursor(void); + QPoint convPixToCursor( QPoint p ); + int convPixToAddr( QPoint p ); + + QFont font; + + memBlock_t mb; + int (*memAccessFunc)( unsigned int offset); + + QScrollBar *vbar; + QScrollBar *hbar; + QColor highLightColor[ HIGHLIGHT_ACTIVITY_NUM_COLORS ]; + QColor rvActvTextColor[ HIGHLIGHT_ACTIVITY_NUM_COLORS ]; + + HexEditorDialog_t *parent; + + uint64_t total_instructions_lp; + + int viewMode; + int lineOffset; + int pxCharWidth; + int pxCharHeight; + int pxCursorHeight; + int pxLineSpacing; + int pxLineLead; + int pxLineWidth; + int pxLineXScroll; + int pxXoffset; + int pxYoffset; + int pxHexOffset; + int pxHexAscii; + int cursorPosX; + int cursorPosY; + int cursorBlinkCount; + int viewLines; + int viewWidth; + int viewHeight; + int maxLineOffset; + int editAddr; + int editValue; + int editMask; + int jumpToRomValue; + int ctxAddr; + + bool cursorBlink; + bool reverseVideo; + bool actvHighlightEnable; + + private slots: + void jumpToROM(void); + void addBookMarkCB(void); + +}; + +class HexEditorDialog_t : public QDialog +{ + Q_OBJECT + + public: + HexEditorDialog_t(QWidget *parent = 0); + ~HexEditorDialog_t(void); + + void gotoAddress(int newAddr); + void populateBookmarkMenu(void); + protected: + + void closeEvent(QCloseEvent *bar); + + QScrollBar *vbar; + QScrollBar *hbar; + QHexEdit *editor; + QTimer *periodicTimer; + QMenu *bookmarkMenu; + + private: + + public slots: + void closeWindow(void); + private slots: + void updatePeriodic(void); + void vbarMoved(int value); + void vbarChanged(int value); + void hbarChanged(int value); + void saveRomFile(void); + void saveRomFileAs(void); + void setViewRAM(void); + void setViewPPU(void); + void setViewOAM(void); + void setViewROM(void); + void actvHighlightCB(bool value); + void actvHighlightRVCB(bool value); + void pickForeGroundColor(void); + void pickBackGroundColor(void); + void removeAllBookmarks(void); +}; + +void hexEditorLoadBookmarks(void); +void hexEditorSaveBookmarks(void); diff --git a/src/drivers/Qt/HotKeyConf.cpp b/src/drivers/Qt/HotKeyConf.cpp index 13c33f1c..d1db2131 100644 --- a/src/drivers/Qt/HotKeyConf.cpp +++ b/src/drivers/Qt/HotKeyConf.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "Qt/main.h" #include "Qt/dface.h" @@ -68,13 +69,22 @@ HotKeyConfDialog_t::HotKeyConfDialog_t(QWidget *parent) //---------------------------------------------------------------------------- HotKeyConfDialog_t::~HotKeyConfDialog_t(void) { - + printf("Destroy Hot Key Config Window\n"); +} +//---------------------------------------------------------------------------- +void HotKeyConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Hot Key Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); } //---------------------------------------------------------------------------- void HotKeyConfDialog_t::closeWindow(void) { //printf("Close Window\n"); done(0); + deleteLater(); } //---------------------------------------------------------------------------- void HotKeyConfDialog_t::assignHotkey(QKeyEvent *event) diff --git a/src/drivers/Qt/HotKeyConf.h b/src/drivers/Qt/HotKeyConf.h index cba35cee..bf9c8a8f 100644 --- a/src/drivers/Qt/HotKeyConf.h +++ b/src/drivers/Qt/HotKeyConf.h @@ -27,6 +27,7 @@ class HotKeyConfDialog_t : public QDialog ~HotKeyConfDialog_t(void); protected: + void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void assignHotkey(QKeyEvent *event); diff --git a/src/drivers/Qt/LuaControl.cpp b/src/drivers/Qt/LuaControl.cpp new file mode 100644 index 00000000..2aa40271 --- /dev/null +++ b/src/drivers/Qt/LuaControl.cpp @@ -0,0 +1,266 @@ +// LuaControl.cpp +// +#include + +#include +#include + +#include "../../fceu.h" + +#ifdef _S9XLUA_H +#include "../../fceulua.h" +#endif + +#include "Qt/LuaControl.h" +#include "Qt/main.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/ConsoleUtilities.h" + +static bool luaScriptRunning = false; + +static std::string luaOutputText; +static std::list winList; +//---------------------------------------------------- +LuaControlDialog_t::LuaControlDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout; + QHBoxLayout *hbox; + QLabel *lbl; + std::string filename; + + resize( 512, 512 ); + + setWindowTitle( tr("Lua Script Control") ); + + mainLayout = new QVBoxLayout(); + + lbl = new QLabel( tr("Script File:") ); + + scriptPath = new QLineEdit(); + scriptArgs = new QLineEdit(); + + g_config->getOption ("SDL.LastLoadLua", &filename ); + + scriptPath->setText( filename.c_str() ); + + luaOutput = new QTextEdit(); + luaOutput->setReadOnly(true); + + hbox = new QHBoxLayout(); + + browseButton = new QPushButton( tr("Browse") ); + stopButton = new QPushButton( tr("Stop") ); + + if ( luaScriptRunning ) + { + startButton = new QPushButton( tr("Restart") ); + } + else + { + startButton = new QPushButton( tr("Start") ); + } + + stopButton->setEnabled( luaScriptRunning ); + + connect(browseButton , SIGNAL(clicked()), this, SLOT(openLuaScriptFile(void)) ); + connect(stopButton , SIGNAL(clicked()), this, SLOT(stopLuaScript(void)) ); + connect(startButton , SIGNAL(clicked()), this, SLOT(startLuaScript(void)) ); + + hbox->addWidget( browseButton ); + hbox->addWidget( stopButton ); + hbox->addWidget( startButton ); + + mainLayout->addWidget( lbl ); + mainLayout->addWidget( scriptPath ); + mainLayout->addLayout( hbox ); + + hbox = new QHBoxLayout(); + lbl = new QLabel( tr("Arguments:") ); + + hbox->addWidget( lbl ); + hbox->addWidget( scriptArgs ); + + mainLayout->addLayout( hbox ); + + lbl = new QLabel( tr("Output Console:") ); + mainLayout->addWidget( lbl ); + mainLayout->addWidget( luaOutput ); + + //connect(useNativeFileDialog , SIGNAL(stateChanged(int)), this, SLOT(useNativeFileDialogChanged(int)) ); + + setLayout( mainLayout ); + + winList.push_back( this ); +} + +//---------------------------------------------------- +LuaControlDialog_t::~LuaControlDialog_t(void) +{ + std::list ::iterator it; + + printf("Destroy Lua Control Window\n"); + + for (it = winList.begin(); it != winList.end(); it++) + { + if ( (*it) == this ) + { + winList.erase(it); + //printf("Removing Lua Window\n"); + break; + } + } +} +//---------------------------------------------------- +void LuaControlDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Lua Control Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------- +void LuaControlDialog_t::closeWindow(void) +{ + //printf("Lua Control Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------- +void LuaControlDialog_t::openLuaScriptFile(void) +{ +#ifdef _S9XLUA_H + int ret, useNativeFileDialogVal; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Open LUA Script") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("LUA Scripts (*.lua *.LUA) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Load") ); + + g_config->getOption ("SDL.LastLoadLua", &last ); + + if ( last.size() == 0 ) + { + last.assign( "/usr/share/fceux/luaScripts" ); + } + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + g_config->setOption ("SDL.LastLoadLua", filename.toStdString().c_str() ); + + scriptPath->setText( filename.toStdString().c_str() ); + +#endif +} +//---------------------------------------------------- +void LuaControlDialog_t::startLuaScript(void) +{ +#ifdef _S9XLUA_H + luaOutputText.clear(); + fceuWrapperLock(); + if ( 0 == FCEU_LoadLuaCode( scriptPath->text().toStdString().c_str(), scriptArgs->text().toStdString().c_str() ) ) + { + printf("Error: Could not open the selected lua script: '%s'\n", scriptPath->text().toStdString().c_str() ); + } + fceuWrapperUnLock(); +#endif +} +//---------------------------------------------------- +void LuaControlDialog_t::stopLuaScript(void) +{ +#ifdef _S9XLUA_H + fceuWrapperLock(); + FCEU_LuaStop(); + fceuWrapperUnLock(); +#endif +} +//---------------------------------------------------- +void LuaControlDialog_t::refreshState(void) +{ + if ( luaScriptRunning ) + { + stopButton->setEnabled( true ); + startButton->setText( tr("Restart") ); + } + else + { + stopButton->setEnabled( false ); + startButton->setText( tr("Start") ); + } + luaOutput->setText( luaOutputText.c_str() ); +} +//---------------------------------------------------- +void updateLuaWindows( void ) +{ + std::list ::iterator it; + + for (it = winList.begin(); it != winList.end(); it++) + { + (*it)->refreshState(); + } +} +//---------------------------------------------------- +void WinLuaOnStart(intptr_t hDlgAsInt) +{ + luaScriptRunning = true; + + //printf("Lua Script Running: %i \n", luaScriptRunning ); + + updateLuaWindows(); +} +//---------------------------------------------------- +void WinLuaOnStop(intptr_t hDlgAsInt) +{ + luaScriptRunning = false; + + //printf("Lua Script Running: %i \n", luaScriptRunning ); + + updateLuaWindows(); +} +//---------------------------------------------------- +void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str) +{ + //printf("%s\n", str ); + + luaOutputText.append( str ); + + updateLuaWindows(); +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/LuaControl.h b/src/drivers/Qt/LuaControl.h new file mode 100644 index 00000000..522e686a --- /dev/null +++ b/src/drivers/Qt/LuaControl.h @@ -0,0 +1,49 @@ +// LuaControl.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class LuaControlDialog_t : public QDialog +{ + Q_OBJECT + + public: + LuaControlDialog_t(QWidget *parent = 0); + ~LuaControlDialog_t(void); + + void refreshState(void); + + protected: + void closeEvent(QCloseEvent *bar); + + QLineEdit *scriptPath; + QLineEdit *scriptArgs; + QPushButton *browseButton; + QPushButton *stopButton; + QPushButton *startButton; + QTextEdit *luaOutput; + private: + + public slots: + void closeWindow(void); + private slots: + void openLuaScriptFile(void); + void startLuaScript(void); + void stopLuaScript(void); + +}; diff --git a/src/drivers/Qt/PaletteConf.cpp b/src/drivers/Qt/PaletteConf.cpp new file mode 100644 index 00000000..d799b8ca --- /dev/null +++ b/src/drivers/Qt/PaletteConf.cpp @@ -0,0 +1,369 @@ +// PaletteConf.cpp +// +#include +#include + +#include "Qt/PaletteConf.h" +#include "Qt/main.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/ConsoleUtilities.h" + +#include "../../ppu.h" + +extern bool force_grayscale; + +static const char *commentText = +"Palette Selection uses the 1st Matching Condition:\n\ + 1. Game type is NSF (always uses fixed palette) \n\ + 2. Custom User Palette is Available and Enabled \n\ + 3. NTSC Color Emulation is Enabled \n\ + 4. Individual Game Palette is Available \n\ + 5. Default Built-in Palette "; +//---------------------------------------------------- +PaletteConfDialog_t::PaletteConfDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout, *vbox; + QHBoxLayout *hbox1; + QGroupBox *frame; + //QPushButton *closebutton; + QPushButton *button; + QTextEdit *comments; + int hue, tint; + char stmp[64]; + std::string paletteFile; + + resize( 512, 600 ); + + // sync with config + g_config->getOption ("SDL.Hue", &hue); + g_config->getOption ("SDL.Tint", &tint); + + setWindowTitle( tr("Palette Config") ); + + mainLayout = new QVBoxLayout(); + + frame = new QGroupBox( tr("Custom Palette:") ); + vbox = new QVBoxLayout(); + hbox1 = new QHBoxLayout(); + + useCustom = new QCheckBox( tr("Use Custom Palette") ); + GrayScale = new QCheckBox( tr("Force Grayscale") ); + deemphSwap = new QCheckBox( tr("De-emphasis Bit Swap") ); + + useCustom->setChecked( FCEUI_GetUserPaletteAvail() ); + GrayScale->setChecked( force_grayscale ); + deemphSwap->setChecked( paldeemphswap ); + + connect(useCustom , SIGNAL(stateChanged(int)), this, SLOT(use_Custom_Changed(int)) ); + connect(GrayScale , SIGNAL(stateChanged(int)), this, SLOT(force_GrayScale_Changed(int)) ); + connect(deemphSwap, SIGNAL(stateChanged(int)), this, SLOT(deemphswap_Changed(int)) ); + + button = new QPushButton( tr("Open Palette") ); + hbox1->addWidget( button ); + + connect( button, SIGNAL(clicked(void)), this, SLOT(openPaletteFile(void)) ); + + g_config->getOption ("SDL.Palette", &paletteFile); + + custom_palette_path = new QLineEdit(); + custom_palette_path->setReadOnly(true); + custom_palette_path->setText( paletteFile.c_str() ); + + vbox->addWidget( useCustom ); + vbox->addLayout( hbox1 ); + vbox->addWidget( custom_palette_path ); + vbox->addWidget( GrayScale ); + vbox->addWidget( deemphSwap); + + + button = new QPushButton( tr("Clear") ); + hbox1->addWidget( button ); + + connect( button, SIGNAL(clicked(void)), this, SLOT(clearPalette(void)) ); + + frame->setLayout( vbox ); + + mainLayout->addWidget( frame ); + + frame = new QGroupBox( tr("NTSC Palette Controls:") ); + + vbox = new QVBoxLayout(); + useNTSC = new QCheckBox( tr("Use NTSC Palette") ); + + int ntscPaletteEnable; + g_config->getOption("SDL.NTSCpalette", &ntscPaletteEnable); + useNTSC->setChecked( ntscPaletteEnable ); + + connect(useNTSC , SIGNAL(stateChanged(int)), this, SLOT(use_NTSC_Changed(int)) ); + + vbox->addWidget( useNTSC ); + + sprintf( stmp, "Tint: %3i \n", tint ); + tintFrame = new QGroupBox( tr(stmp) ); + hbox1 = new QHBoxLayout(); + tintSlider = new QSlider( Qt::Horizontal ); + tintSlider->setMinimum( 0); + tintSlider->setMaximum(128); + tintSlider->setValue( tint ); + + connect( tintSlider, SIGNAL(valueChanged(int)), this, SLOT(tintChanged(int)) ); + + hbox1->addWidget( tintSlider ); + tintFrame->setLayout( hbox1 ); + vbox->addWidget( tintFrame ); + + sprintf( stmp, "Hue: %3i \n", hue ); + hueFrame = new QGroupBox( tr(stmp) ); + hbox1 = new QHBoxLayout(); + hueSlider = new QSlider( Qt::Horizontal ); + hueSlider->setMinimum( 0); + hueSlider->setMaximum(128); + hueSlider->setValue( hue ); + + connect( hueSlider, SIGNAL(valueChanged(int)), this, SLOT(hueChanged(int)) ); + + hbox1->addWidget( hueSlider ); + hueFrame->setLayout( hbox1 ); + vbox->addWidget( hueFrame ); + + frame->setLayout( vbox ); + + mainLayout->addWidget( frame ); + + comments = new QTextEdit(); + + comments->setText( commentText ); + comments->moveCursor(QTextCursor::Start); + comments->setReadOnly(true); + + mainLayout->addWidget( comments ); + + setLayout( mainLayout ); +} + +//---------------------------------------------------- +PaletteConfDialog_t::~PaletteConfDialog_t(void) +{ + printf("Destroy Palette Config Window\n"); +} +//---------------------------------------------------------------------------- +void PaletteConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Palette Config Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------- +void PaletteConfDialog_t::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); + deleteLater(); +} +//---------------------------------------------------- +void PaletteConfDialog_t::hueChanged(int v) +{ + int c, t; + char stmp[64]; + + sprintf( stmp, "Hue: %3i", v ); + + hueFrame->setTitle(stmp); + + g_config->setOption ("SDL.Hue", v); + g_config->save (); + g_config->getOption ("SDL.Tint", &t); + g_config->getOption ("SDL.NTSCpalette", &c); + + if ( fceuWrapperTryLock() ) + { + FCEUI_SetNTSCTH (c, t, v); + fceuWrapperUnLock(); + } +} +//---------------------------------------------------- +void PaletteConfDialog_t::tintChanged(int v) +{ + int c, h; + char stmp[64]; + + sprintf( stmp, "Tint: %3i", v ); + + tintFrame->setTitle(stmp); + + g_config->setOption ("SDL.Tint", v); + g_config->save (); + g_config->getOption ("SDL.NTSCpalette", &c); + g_config->getOption ("SDL.Hue", &h); + + if ( fceuWrapperTryLock() ) + { + FCEUI_SetNTSCTH (c, v, h); + fceuWrapperUnLock(); + } +} +//---------------------------------------------------- +void PaletteConfDialog_t::use_Custom_Changed(int state) +{ + int value = (state == Qt::Unchecked) ? 0 : 1; + std::string filename; + + //printf("Use Custom:%i \n", state ); + + g_config->getOption ("SDL.Palette", &filename); + + if ( fceuWrapperTryLock() ) + { + if ( value && (filename.size() > 0) ) + { + LoadCPalette ( filename.c_str() ); + } + else + { + FCEUI_SetUserPalette( NULL, 0); + } + fceuWrapperUnLock(); + } +} +//---------------------------------------------------- +void PaletteConfDialog_t::force_GrayScale_Changed(int state) +{ + int value = (state == Qt::Unchecked) ? 0 : 1; + + if ( fceuWrapperTryLock() ) + { + int e, h, t; + g_config->getOption ("SDL.NTSCpalette", &e); + g_config->getOption ("SDL.Hue", &h); + g_config->getOption ("SDL.Tint", &t); + force_grayscale = value ? true : false; + FCEUI_SetNTSCTH( e, t, h); + fceuWrapperUnLock(); + } +} +//---------------------------------------------------- +void PaletteConfDialog_t::deemphswap_Changed(int state) +{ + int value = (state == Qt::Unchecked) ? 0 : 1; + + if ( fceuWrapperTryLock() ) + { + int e, h, t; + g_config->getOption ("SDL.NTSCpalette", &e); + g_config->getOption ("SDL.Hue", &h); + g_config->getOption ("SDL.Tint", &t); + paldeemphswap = value ? true : false; + FCEUI_SetNTSCTH( e, t, h); + fceuWrapperUnLock(); + } +} +//---------------------------------------------------- +void PaletteConfDialog_t::use_NTSC_Changed(int state) +{ + int h, t; + int value = (state == Qt::Unchecked) ? 0 : 1; + + g_config->setOption ("SDL.NTSCpalette", value); + g_config->save (); + + g_config->getOption ("SDL.Hue", &h); + g_config->getOption ("SDL.Tint", &t); + + if ( fceuWrapperTryLock() ) + { + FCEUI_SetNTSCTH (value, t, h); + //UpdateEMUCore (g_config); + fceuWrapperUnLock(); + } +} +//---------------------------------------------------- +void PaletteConfDialog_t::clearPalette(void) +{ + g_config->setOption ("SDL.Palette", ""); + custom_palette_path->setText(""); + + if ( fceuWrapperTryLock() ) + { + FCEUI_SetUserPalette( NULL, 0); + fceuWrapperUnLock(); + useCustom->setChecked(false); + } +} +//---------------------------------------------------- +void PaletteConfDialog_t::openPaletteFile(void) +{ + int ret, useNativeFileDialogVal; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Open NES Palette") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("NES Palettes (*.pal *.PAL) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Load") ); + + g_config->getOption ("SDL.Palette", &last ); + + if ( last.size() == 0 ) + { + last.assign( "/usr/share/fceux/palettes" ); + } + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + if ( fceuWrapperTryLock() ) + { + if ( LoadCPalette ( filename.toStdString().c_str() ) ) + { + g_config->setOption ("SDL.Palette", filename.toStdString().c_str() ); + custom_palette_path->setText( filename.toStdString().c_str() ); + } + else + { + printf("Error: Failed to Load Palette File: %s \n", filename.toStdString().c_str() ); + } + fceuWrapperUnLock(); + + useCustom->setChecked( FCEUI_GetUserPaletteAvail() ); + } + + + return; +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/PaletteConf.h b/src/drivers/Qt/PaletteConf.h new file mode 100644 index 00000000..5b28d9c0 --- /dev/null +++ b/src/drivers/Qt/PaletteConf.h @@ -0,0 +1,54 @@ +// PaletteConf.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class PaletteConfDialog_t : public QDialog +{ + Q_OBJECT + + public: + PaletteConfDialog_t(QWidget *parent = 0); + ~PaletteConfDialog_t(void); + + protected: + void closeEvent(QCloseEvent *event); + + QLineEdit *custom_palette_path; + QCheckBox *useCustom; + QCheckBox *GrayScale; + QCheckBox *deemphSwap; + QCheckBox *useNTSC; + QSlider *tintSlider; + QSlider *hueSlider; + QGroupBox *tintFrame; + QGroupBox *hueFrame; + private: + + public slots: + void closeWindow(void); + private slots: + void hueChanged(int value); + void tintChanged(int value); + void openPaletteFile(void); + void clearPalette(void); + void use_NTSC_Changed(int v); + void use_Custom_Changed(int v); + void force_GrayScale_Changed(int v); + void deemphswap_Changed(int v); + +}; diff --git a/src/drivers/Qt/config.cpp b/src/drivers/Qt/config.cpp index 5c16c617..a161701c 100644 --- a/src/drivers/Qt/config.cpp +++ b/src/drivers/Qt/config.cpp @@ -102,20 +102,20 @@ LoadCPalette(const std::string &file) static void CreateDirs(const std::string &dir) { - const char *subs[8]={"fcs","snaps","gameinfo","sav","cheats","movies","cfg.d"}; + const char *subs[9]={"fcs","snaps","gameinfo","sav","cheats","movies","input"}; std::string subdir; int x; #if defined(WIN32) || defined(NEED_MINGW_HACKS) mkdir(dir.c_str()); chmod(dir.c_str(), 755); - for(x = 0; x < 6; x++) { + for(x = 0; x < 7; x++) { subdir = dir + PSS + subs[x]; mkdir(subdir.c_str()); } #else mkdir(dir.c_str(), S_IRWXU); - for(x = 0; x < 6; x++) { + for(x = 0; x < 7; x++) { subdir = dir + PSS + subs[x]; mkdir(subdir.c_str(), S_IRWXU); } @@ -199,6 +199,7 @@ InitConfig() // video controls config->addOption('f', "fullscreen", "SDL.Fullscreen", 0); + config->addOption("videoDriver", "SDL.VideoDriver", 0); // set x/y res to 0 for automatic fullscreen resolution detection (no change) config->addOption('x', "xres", "SDL.XResolution", 0); @@ -241,7 +242,7 @@ InitConfig() config->addOption("input4", "SDL.Input.3", "Gamepad.3"); // allow for input configuration - config->addOption('i', "inputcfg", "SDL.InputCfg", InputCfg); + //config->addOption('i', "inputcfg", "SDL.InputCfg", InputCfg); // display input config->addOption("inputdisplay", "SDL.InputDisplay", 0); @@ -253,6 +254,10 @@ InitConfig() config->addOption("pauseframe", "SDL.PauseFrame", 0); config->addOption("recordhud", "SDL.RecordHUD", 1); config->addOption("moviemsg", "SDL.MovieMsg", 1); + + // Hex Editor Options + config->addOption("hexEditBgColor", "SDL.HexEditBgColor", "#000000"); + config->addOption("hexEditFgColor", "SDL.HexEditFgColor", "#FFFFFF"); // overwrite the config file? config->addOption("no-config", "SDL.NoConfig", 0); @@ -292,6 +297,9 @@ InitConfig() config->addOption("_lastopennsf", "SDL.LastOpenNSF", home_dir); config->addOption("_lastsavestateas", "SDL.LastSaveStateAs", home_dir); config->addOption("_lastloadlua", "SDL.LastLoadLua", ""); + + config->addOption("_useNativeFileDialog", "SDL.UseNativeFileDialog", false); + config->addOption("_useNativeMenuBar" , "SDL.UseNativeMenuBar", false); // fcm -> fm2 conversion config->addOption("fcmconvert", "SDL.FCMConvert", ""); @@ -313,10 +321,8 @@ InitConfig() prefix = buf; config->addOption(prefix + "DeviceType", DefaultGamePadDevice[i]); - config->addOption(prefix + "DeviceNum", 0); - for(unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) { - config->addOption(prefix + GamePadNames[j], DefaultGamePad[i][j]); - } + config->addOption(prefix + "DeviceGUID", ""); + config->addOption(prefix + "Profile" , ""); } // PowerPad 0 - 1 diff --git a/src/drivers/Qt/dface.h b/src/drivers/Qt/dface.h index 2f3890ec..12c515ee 100644 --- a/src/drivers/Qt/dface.h +++ b/src/drivers/Qt/dface.h @@ -18,6 +18,8 @@ void SilenceSound(int s); /* DOS and SDL */ int InitJoysticks(void); int KillJoysticks(void); +int AddJoystick( int which ); +int RemoveJoystick( int which ); uint32 *GetJSOr(void); int InitVideo(FCEUGI *gi); diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 7e1daca0..9fe90965 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -14,7 +14,9 @@ #include "Qt/sdl-video.h" #include "Qt/nes_shm.h" #include "Qt/unix-netplay.h" +#include "Qt/HexEditor.h" #include "Qt/ConsoleWindow.h" +#include "Qt/fceux_git_info.h" #include "common/cheat.h" #include "../../fceu.h" @@ -56,7 +58,9 @@ static int inited = 0; static int noconfig=0; static int frameskip=0; static int periodic_saves = 0; -static bool mutexLocked = 0; +static int mutexLocks = 0; +static int mutexPending = 0; +static bool emulatorHasMutux = 0; extern double g_fpsScale; @@ -78,19 +82,22 @@ int mutecapture = 0; void FCEUD_Message(const char *text) { fputs(text, stdout); + //fprintf(stdout, "\n"); } /** * Shows an error message in a message box. * (For now: prints to stderr.) * -* If running in GTK mode, display a dialog message box of the error. +* If running in Qt mode, display a dialog message box of the error. * * @param errormsg Text of the error message. **/ void FCEUD_PrintError(const char *errormsg) { fprintf(stderr, "%s\n", errormsg); + + consoleWindow->QueueErrorMsgWindow( errormsg ); } /** @@ -98,7 +105,8 @@ void FCEUD_PrintError(const char *errormsg) */ FILE *FCEUD_UTF8fopen(const char *fn, const char *mode) { - return(fopen(fn,mode)); + FILE *fp = ::fopen(fn,mode); + return(fp); } /** @@ -190,8 +198,8 @@ DriverKill() if (!noconfig) g_config->save(); - if(inited&2) - KillJoysticks(); + KillJoysticks(); + if(inited&4) KillVideo(); if(inited&1) @@ -224,6 +232,8 @@ int LoadGame(const char *path) return 0; } + hexEditorLoadBookmarks(); + int state_to_load; g_config->getOption("SDL.AutoLoadState", &state_to_load); if (state_to_load >= 0 && state_to_load < 10){ @@ -270,6 +280,7 @@ CloseGame(void) if(!isloaded) { return(0); } + hexEditorSaveBookmarks(); int state_to_save; g_config->getOption("SDL.AutoSaveState", &state_to_save); @@ -405,12 +416,15 @@ static void ShowUsage(const char *prog) SDL_GetVersion(&v); printf("Linked with SDL version %d.%d.%d\n", v.major, v.minor, v.patch); printf("Compiled with QT version %d.%d.%d\n", QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH ); + printf("git URL: %s\n", fceu_get_git_url() ); + printf("git Rev: %s\n", fceu_get_git_rev() ); } int fceuWrapperInit( int argc, char *argv[] ) { int error; + std::string s; for (int i=0; isave(); } - std::string s; - g_config->getOption("SDL.InputCfg", &s); + //g_config->getOption("SDL.InputCfg", &s); - if (s.size() != 0) - { - InitVideo(GameInfo); - InputCfg(s); - } + //if (s.size() != 0) + //{ + // InitVideo(GameInfo); + // InputCfg(s); + //} // update the input devices UpdateInput(g_config); @@ -910,29 +927,33 @@ static void DoFun(int frameskip, int periodic_saves) void fceuWrapperLock(void) { + mutexPending++; consoleWindow->mutex->lock(); - mutexLocked = 1; + mutexPending--; + mutexLocks++; } bool fceuWrapperTryLock(int timeout) { bool lockAcq; + mutexPending++; lockAcq = consoleWindow->mutex->tryLock( timeout ); + mutexPending--; if ( lockAcq ) { - mutexLocked = 1; + mutexLocks++; } return lockAcq; } void fceuWrapperUnLock(void) { - if ( mutexLocked ) + if ( mutexLocks > 0 ) { consoleWindow->mutex->unlock(); - mutexLocked = 0; + mutexLocks--; } else { @@ -942,12 +963,30 @@ void fceuWrapperUnLock(void) bool fceuWrapperIsLocked(void) { - return mutexLocked; + return mutexLocks > 0; } int fceuWrapperUpdate( void ) { - fceuWrapperLock(); + bool lock_acq; + + // If a request is pending, + // sleep to allow request to be serviced. + if ( mutexPending > 0 ) + { + usleep( 100000 ); + } + + lock_acq = fceuWrapperTryLock(); + + if ( !lock_acq ) + { + printf("Error: Emulator Failed to Acquire Mutex\n"); + usleep( 100000 ); + + return -1; + } + emulatorHasMutux = 1; if ( GameInfo && !FCEUI_EmulationPaused() ) { @@ -955,6 +994,8 @@ int fceuWrapperUpdate( void ) fceuWrapperUnLock(); + emulatorHasMutux = 0; + while ( SpeedThrottle() ) { // Input device processing is in main thread @@ -966,6 +1007,8 @@ int fceuWrapperUpdate( void ) { fceuWrapperUnLock(); + emulatorHasMutux = 0; + usleep( 100000 ); } return 0; diff --git a/src/drivers/Qt/fceuWrapper.h b/src/drivers/Qt/fceuWrapper.h index e3ce55a8..e0928e09 100644 --- a/src/drivers/Qt/fceuWrapper.h +++ b/src/drivers/Qt/fceuWrapper.h @@ -26,7 +26,7 @@ int fceuWrapperInit( int argc, char *argv[] ); int fceuWrapperClose( void ); int fceuWrapperUpdate( void ); void fceuWrapperLock(void); -bool fceuWrapperTryLock(int timeout); +bool fceuWrapperTryLock(int timeout = 1000); bool fceuWrapperIsLocked(void); void fceuWrapperUnLock(void); int fceuWrapperSoftReset(void); diff --git a/src/drivers/Qt/input.cpp b/src/drivers/Qt/input.cpp index 552f7ad8..1510857b 100644 --- a/src/drivers/Qt/input.cpp +++ b/src/drivers/Qt/input.cpp @@ -24,8 +24,9 @@ #include "Qt/config.h" -#include "Qt/sdl-video.h" #include "Qt/sdl.h" +#include "Qt/sdl-video.h" +#include "Qt/sdl-joystick.h" #include "common/cheat.h" #include "../../movie.h" @@ -49,8 +50,8 @@ extern bool bindSavestate, frameAdvanceLagSkip, lagCounterDisplay; /* UsrInputType[] is user-specified. CurInputType[] is current (game loading can override user settings) */ -static int UsrInputType[NUM_INPUT_DEVICES]; -static int CurInputType[NUM_INPUT_DEVICES]; +static int UsrInputType[NUM_INPUT_DEVICES] = { SI_GAMEPAD, SI_GAMEPAD, SI_NONE }; +static int CurInputType[NUM_INPUT_DEVICES] = { SI_GAMEPAD, SI_GAMEPAD, SI_NONE }; static int cspec = 0; static int buttonConfigInProgress = 0; @@ -956,6 +957,12 @@ UpdatePhysicalInput () g_keyState[ event.key.keysym.scancode ] = (event.type == SDL_KEYDOWN) ? 1 : 0; //checkKeyBoardState( event.key.keysym.scancode ); break; + case SDL_JOYDEVICEADDED: + AddJoystick( event.jdevice.which ); + break; + case SDL_JOYDEVICEREMOVED: + RemoveJoystick( event.jdevice.which ); + break; default: break; } @@ -964,8 +971,6 @@ UpdatePhysicalInput () } -static int bcpv=0, bcpj=0; - /** * Begin configuring the buttons by placing the video and joystick * subsystems into a well-known state. Button configuration really @@ -973,13 +978,7 @@ static int bcpv=0, bcpj=0; */ int ButtonConfigBegin () { - // shut down the joystick subsystems - //SDL_Surface *screen; - - bcpj = KillJoysticks (); - - // XXX soules - why did we shut this down? - // initialize the joystick subsystem + // initialize the joystick subsystem (if not already inited) InitJoysticks (); buttonConfigInProgress = 1; @@ -995,18 +994,6 @@ int ButtonConfigBegin () void ButtonConfigEnd () { - // shutdown the joystick and video subsystems - KillJoysticks (); - //SDL_QuitSubSystem(SDL_INIT_VIDEO); - - // re-initialize joystick and video subsystems if they were active before - /*if(!bcpv) { - InitVideo(GameInfo); - } */ - if (!bcpj) - { - InitJoysticks (); - } buttonConfigInProgress = 0; } @@ -1016,49 +1003,50 @@ ButtonConfigEnd () static int DTestButton (ButtConfig * bc) { - int x; - for (x = 0; x < bc->NumC; x++) + if (bc->ButtType == BUTTC_KEYBOARD) { - if (bc->ButtType[x] == BUTTC_KEYBOARD) + if (g_keyState[SDL_GetScancodeFromKey (bc->ButtonNum)]) { - if (g_keyState[SDL_GetScancodeFromKey (bc->ButtonNum[x])]) - { - return 1; - } + bc->state = 1; + return 1; } - else if (bc->ButtType[x] == BUTTC_JOYSTICK) + else + { + bc->state = 0; + } + } + else if (bc->ButtType == BUTTC_JOYSTICK) + { + if (DTestButtonJoy (bc)) { - if (DTestButtonJoy (bc)) - { - return 1; - } + return 1; } } return 0; } -#define MK(x) {{BUTTC_KEYBOARD},{0},{MKK(x)},1} -#define MK2(x1,x2) {{BUTTC_KEYBOARD},{0},{MKK(x1),MKK(x2)},2} -#define MKZ() {{0},{0},{-1},0} +#define MK(x) {BUTTC_KEYBOARD,0,MKK(x),0} +//#define MK2(x1,x2) {BUTTC_KEYBOARD,0,MKK(x1)} +#define MKZ() {0,0,-1,0} #define GPZ() {MKZ(), MKZ(), MKZ(), MKZ()} -ButtConfig GamePadConfig[ GAMEPAD_NUM_DEVICES ][ GAMEPAD_NUM_BUTTONS ] = -{ -/* Gamepad 1 */ - {MK (KP_3), MK (KP_2), MK (SLASH), MK (ENTER), - MK (w), MK (z), MK (a), MK (s), MKZ (), MKZ ()}, - - /* Gamepad 2 */ - GPZ (), - - /* Gamepad 3 */ - GPZ (), - - /* Gamepad 4 */ - GPZ () -}; +//ButtConfig GamePadConfig[ GAMEPAD_NUM_DEVICES ][ GAMEPAD_NUM_BUTTONS ] = +//{ +///* Gamepad 1 */ +// {MK (KP_3), MK (KP_2), MK (SLASH), MK (ENTER), +// MK (w), MK (z), MK (a), MK (s), MKZ (), MKZ ()}, +// +// /* Gamepad 2 */ +// GPZ (), +// +// /* Gamepad 3 */ +// GPZ (), +// +// /* Gamepad 4 */ +// GPZ () +//}; /** * Update the status of the gamepad input devices. @@ -1090,7 +1078,7 @@ UpdateGamepad(void) // a, b, select, start, up, down, left, right for (x = 0; x < 8; x++) { - if (DTestButton (&GamePadConfig[wg][x])) + if (DTestButton (&GamePad[wg].bmap[x])) { //printf("GamePad%i Button Hit: %i \n", wg, x ); if(opposite_dirs == 0) @@ -1128,7 +1116,7 @@ UpdateGamepad(void) { for (x = 0; x < 2; x++) { - if (DTestButton (&GamePadConfig[wg][8 + x])) + if (DTestButton (&GamePad[wg].bmap[8 + x])) { JS |= (1 << x) << (wg << 3); } @@ -1563,42 +1551,42 @@ UpdateFTrainer () * @param bc the NES gamepad's button config * @param which the index of the button */ -const char * ButtonName (const ButtConfig * bc, int which) +const char * ButtonName (const ButtConfig * bc) { static char name[256]; name[0] = 0; - if (bc->ButtonNum[which] == -1) + if (bc->ButtonNum == -1) { return name; } - switch (bc->ButtType[which]) + switch (bc->ButtType) { case BUTTC_KEYBOARD: - return SDL_GetKeyName (bc->ButtonNum[which]); + return SDL_GetKeyName (bc->ButtonNum); break; case BUTTC_JOYSTICK: { int joyNum, inputNum; const char *inputType, *inputDirection; + char direction[128] = ""; - joyNum = bc->DeviceNum[which]; + joyNum = bc->DeviceNum; - if (bc->ButtonNum[which] & 0x8000) + if (bc->ButtonNum & 0x8000) { inputType = "Axis"; - inputNum = bc->ButtonNum[which] & 0x3FFF; - inputDirection = bc->ButtonNum[which] & 0x4000 ? "-" : "+"; + inputNum = bc->ButtonNum & 0x3FFF; + inputDirection = bc->ButtonNum & 0x4000 ? "-" : "+"; } - else if (bc->ButtonNum[which] & 0x2000) + else if (bc->ButtonNum & 0x2000) { int inputValue; - char direction[128] = ""; inputType = "Hat"; - inputNum = (bc->ButtonNum[which] >> 8) & 0x1F; - inputValue = bc->ButtonNum[which] & 0xF; + inputNum = (bc->ButtonNum >> 8) & 0x1F; + inputValue = bc->ButtonNum & 0xF; if (inputValue & SDL_HAT_UP) strncat (direction, "Up ", sizeof (direction)-1); @@ -1617,7 +1605,7 @@ const char * ButtonName (const ButtConfig * bc, int which) else { inputType = "Button"; - inputNum = bc->ButtonNum[which]; + inputNum = bc->ButtonNum; inputDirection = ""; } sprintf( name, "js%i:%s%i%s", joyNum, inputType, inputNum, inputDirection ); @@ -1632,7 +1620,7 @@ const char * ButtonName (const ButtConfig * bc, int which) * Waits for a button input and returns the information as to which * button was pressed. Used in button configuration. */ -int DWaitButton (const uint8_t * text, ButtConfig * bc, int wb, int *buttonConfigStatus ) +int DWaitButton (const uint8_t * text, ButtConfig * bc, int *buttonConfigStatus ) { SDL_Event event; static int32 LastAx[64][64]; @@ -1684,23 +1672,23 @@ int DWaitButton (const uint8_t * text, ButtConfig * bc, int wb, int *buttonConfi { case SDL_KEYDOWN: //printf("SDL KeyDown:%i \n", event.key.keysym.sym ); - bc->ButtType[wb] = BUTTC_KEYBOARD; - bc->DeviceNum[wb] = 0; - bc->ButtonNum[wb] = event.key.keysym.sym; + bc->ButtType = BUTTC_KEYBOARD; + bc->DeviceNum = 0; + bc->ButtonNum = event.key.keysym.sym; return (1); case SDL_JOYBUTTONDOWN: - bc->ButtType[wb] = BUTTC_JOYSTICK; - bc->DeviceNum[wb] = event.jbutton.which; - bc->ButtonNum[wb] = event.jbutton.button; + bc->ButtType = BUTTC_JOYSTICK; + bc->DeviceNum = event.jbutton.which; + bc->ButtonNum = event.jbutton.button; return (1); case SDL_JOYHATMOTION: if (event.jhat.value == SDL_HAT_CENTERED) done--; else { - bc->ButtType[wb] = BUTTC_JOYSTICK; - bc->DeviceNum[wb] = event.jhat.which; - bc->ButtonNum[wb] = + bc->ButtType = BUTTC_JOYSTICK; + bc->DeviceNum = event.jhat.which; + bc->ButtonNum = (0x2000 | ((event.jhat.hat & 0x1F) << 8) | event. jhat.value); return (1); @@ -1722,9 +1710,9 @@ int DWaitButton (const uint8_t * text, ButtConfig * bc, int wb, int *buttonConfi (LastAx[event.jaxis.which][event.jaxis.axis] - event.jaxis.value) >= 8192) { - bc->ButtType[wb] = BUTTC_JOYSTICK; - bc->DeviceNum[wb] = event.jaxis.which; - bc->ButtonNum[wb] = (0x8000 | event.jaxis.axis | + bc->ButtType = BUTTC_JOYSTICK; + bc->DeviceNum = event.jaxis.which; + bc->ButtonNum = (0x8000 | event.jaxis.axis | ((event.jaxis.value < 0) ? 0x4000 : 0)); return (1); @@ -1761,170 +1749,169 @@ int DWaitButton (const uint8_t * text, ButtConfig * bc, int wb, int *buttonConfi * used as input for the specified button, thus allowing up to four * possible settings for each input button. */ - void -ConfigButton (char *text, ButtConfig * bc) -{ - uint8 buf[256]; - int wc; - - for (wc = 0; wc < MAXBUTTCONFIG; wc++) - { - sprintf ((char *) buf, "%s (%d)", text, wc + 1); - DWaitButton (buf, bc, wc, NULL); - - if (wc && - bc->ButtType[wc] == bc->ButtType[wc - 1] && - bc->DeviceNum[wc] == bc->DeviceNum[wc - 1] && - bc->ButtonNum[wc] == bc->ButtonNum[wc - 1]) - { - break; - } - } - bc->NumC = wc; -} +// void +//ConfigButton (char *text, ButtConfig * bc) +//{ +// uint8 buf[256]; +// int wc; +// +// for (wc = 0; wc < MAXBUTTCONFIG; wc++) +// { +// sprintf ((char *) buf, "%s (%d)", text, wc + 1); +// DWaitButton (buf, bc, wc, NULL); +// +// if (wc && +// bc->ButtType[wc] == bc->ButtType[wc - 1] && +// bc->DeviceNum[wc] == bc->DeviceNum[wc - 1] && +// bc->ButtonNum[wc] == bc->ButtonNum[wc - 1]) +// { +// break; +// } +// } +//} /** * Update the button configuration for a specified device. */ extern Config *g_config; -void ConfigDevice (int which, int arg) -{ - char buf[256]; - int x; - std::string prefix; - const char *str[10] = - { "A", "B", "SELECT", "START", "UP", "DOWN", "LEFT", "RIGHT", "Rapid A", - "Rapid B" - }; - - // XXX soules - set the configuration options so that later calls - // don't override these. This is a temp hack until I - // can clean up this file. - - ButtonConfigBegin (); - switch (which) - { - case FCFGD_QUIZKING: - prefix = "SDL.Input.QuizKing."; - for (x = 0; x < 6; x++) - { - sprintf (buf, "Quiz King Buzzer #%d", x + 1); - ConfigButton (buf, &QuizKingButtons[x]); - - g_config->setOption (prefix + QuizKingNames[x], - QuizKingButtons[x].ButtonNum[0]); - } - - if (QuizKingButtons[0].ButtType[0] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (QuizKingButtons[0].ButtType[0] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - QuizKingButtons[0].DeviceNum[0]); - break; - case FCFGD_HYPERSHOT: - prefix = "SDL.Input.HyperShot."; - for (x = 0; x < 4; x++) - { - sprintf (buf, "Hyper Shot %d: %s", - ((x & 2) >> 1) + 1, (x & 1) ? "JUMP" : "RUN"); - ConfigButton (buf, &HyperShotButtons[x]); - - g_config->setOption (prefix + HyperShotNames[x], - HyperShotButtons[x].ButtonNum[0]); - } - - if (HyperShotButtons[0].ButtType[0] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (HyperShotButtons[0].ButtType[0] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - HyperShotButtons[0].DeviceNum[0]); - break; - case FCFGD_POWERPAD: - snprintf (buf, 256, "SDL.Input.PowerPad.%d", (arg & 1)); - prefix = buf; - for (x = 0; x < 12; x++) - { - sprintf (buf, "PowerPad %d: %d", (arg & 1) + 1, x + 11); - ConfigButton (buf, &powerpadsc[arg & 1][x]); - - g_config->setOption (prefix + PowerPadNames[x], - powerpadsc[arg & 1][x].ButtonNum[0]); - } - - if (powerpadsc[arg & 1][0].ButtType[0] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (powerpadsc[arg & 1][0].ButtType[0] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - powerpadsc[arg & 1][0].DeviceNum[0]); - break; - - case FCFGD_GAMEPAD: - snprintf (buf, 256, "SDL.Input.GamePad.%d", arg); - prefix = buf; - for (x = 0; x < 10; x++) - { - sprintf (buf, "GamePad #%d: %s", arg + 1, str[x]); - ConfigButton (buf, &GamePadConfig[arg][x]); - - g_config->setOption (prefix + GamePadNames[x], - GamePadConfig[arg][x].ButtonNum[0]); - } - - if (GamePadConfig[arg][0].ButtType[0] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (GamePadConfig[arg][0].ButtType[0] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - GamePadConfig[arg][0].DeviceNum[0]); - break; - } - - ButtonConfigEnd (); -} +//void ConfigDevice (int which, int arg) +//{ +// char buf[256]; +// int x; +// std::string prefix; +// const char *str[10] = +// { "A", "B", "SELECT", "START", "UP", "DOWN", "LEFT", "RIGHT", "Rapid A", +// "Rapid B" +// }; +// +// // XXX soules - set the configuration options so that later calls +// // don't override these. This is a temp hack until I +// // can clean up this file. +// +// ButtonConfigBegin (); +// switch (which) +// { +// case FCFGD_QUIZKING: +// prefix = "SDL.Input.QuizKing."; +// for (x = 0; x < 6; x++) +// { +// sprintf (buf, "Quiz King Buzzer #%d", x + 1); +// ConfigButton (buf, &QuizKingButtons[x]); +// +// g_config->setOption (prefix + QuizKingNames[x], +// QuizKingButtons[x].ButtonNum); +// } +// +// if (QuizKingButtons[0].ButtType == BUTTC_KEYBOARD) +// { +// g_config->setOption (prefix + "DeviceType", "Keyboard"); +// } +// else if (QuizKingButtons[0].ButtType == BUTTC_JOYSTICK) +// { +// g_config->setOption (prefix + "DeviceType", "Joystick"); +// } +// else +// { +// g_config->setOption (prefix + "DeviceType", "Unknown"); +// } +// g_config->setOption (prefix + "DeviceNum", +// QuizKingButtons[0].DeviceNum); +// break; +// case FCFGD_HYPERSHOT: +// prefix = "SDL.Input.HyperShot."; +// for (x = 0; x < 4; x++) +// { +// sprintf (buf, "Hyper Shot %d: %s", +// ((x & 2) >> 1) + 1, (x & 1) ? "JUMP" : "RUN"); +// ConfigButton (buf, &HyperShotButtons[x]); +// +// g_config->setOption (prefix + HyperShotNames[x], +// HyperShotButtons[x].ButtonNum); +// } +// +// if (HyperShotButtons[0].ButtType == BUTTC_KEYBOARD) +// { +// g_config->setOption (prefix + "DeviceType", "Keyboard"); +// } +// else if (HyperShotButtons[0].ButtType == BUTTC_JOYSTICK) +// { +// g_config->setOption (prefix + "DeviceType", "Joystick"); +// } +// else +// { +// g_config->setOption (prefix + "DeviceType", "Unknown"); +// } +// g_config->setOption (prefix + "DeviceNum", +// HyperShotButtons[0].DeviceNum); +// break; +// case FCFGD_POWERPAD: +// snprintf (buf, 256, "SDL.Input.PowerPad.%d", (arg & 1)); +// prefix = buf; +// for (x = 0; x < 12; x++) +// { +// sprintf (buf, "PowerPad %d: %d", (arg & 1) + 1, x + 11); +// ConfigButton (buf, &powerpadsc[arg & 1][x]); +// +// g_config->setOption (prefix + PowerPadNames[x], +// powerpadsc[arg & 1][x].ButtonNum); +// } +// +// if (powerpadsc[arg & 1][0].ButtType == BUTTC_KEYBOARD) +// { +// g_config->setOption (prefix + "DeviceType", "Keyboard"); +// } +// else if (powerpadsc[arg & 1][0].ButtType == BUTTC_JOYSTICK) +// { +// g_config->setOption (prefix + "DeviceType", "Joystick"); +// } +// else +// { +// g_config->setOption (prefix + "DeviceType", "Unknown"); +// } +// g_config->setOption (prefix + "DeviceNum", +// powerpadsc[arg & 1][0].DeviceNum); +// break; +// +// case FCFGD_GAMEPAD: +// snprintf (buf, 256, "SDL.Input.GamePad.%d", arg); +// prefix = buf; +// for (x = 0; x < 10; x++) +// { +// sprintf (buf, "GamePad #%d: %s", arg + 1, str[x]); +// ConfigButton (buf, &GamePadConfig[arg][x]); +// +// g_config->setOption (prefix + GamePadNames[x], +// GamePadConfig[arg][x].ButtonNum); +// } +// +// if (GamePadConfig[arg][0].ButtType == BUTTC_KEYBOARD) +// { +// g_config->setOption (prefix + "DeviceType", "Keyboard"); +// } +// else if (GamePadConfig[arg][0].ButtType == BUTTC_JOYSTICK) +// { +// g_config->setOption (prefix + "DeviceType", "Joystick"); +// } +// else +// { +// g_config->setOption (prefix + "DeviceType", "Unknown"); +// } +// g_config->setOption (prefix + "DeviceNum", +// GamePadConfig[arg][0].DeviceNum); +// break; +// } +// +// ButtonConfigEnd (); +//} /** * Update the button configuration for a device, specified by a text string. */ -void InputCfg (const std::string & text) -{ - +//void InputCfg (const std::string & text) +//{ +// // if (noGui) // { // if (text.find ("gamepad") != std::string::npos) @@ -1960,8 +1947,8 @@ void InputCfg (const std::string & text) // } // else // printf ("Please run \"fceux --nogui\" before using --inputcfg\n"); - -} +// +//} /** @@ -1973,7 +1960,9 @@ void InputCfg (const std::string & text) UpdateInput (Config * config) { char buf[64]; - std::string device, prefix; + std::string device, prefix, guid, mapping; + + InitJoysticks(); for (unsigned int i = 0; i < 3; i++) { @@ -2066,37 +2055,18 @@ UpdateInput (Config * config) snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%u.", i); prefix = buf; - config->getOption (prefix + "DeviceType", &device); - if (device.find ("Keyboard") != std::string::npos) - { - type = BUTTC_KEYBOARD; - } - else if (device.find ("Joystick") != std::string::npos) - { - type = BUTTC_JOYSTICK; - } - else - { - type = 0; - } + config->getOption (prefix + "DeviceType", &device ); + config->getOption (prefix + "DeviceGUID", &guid ); + config->getOption (prefix + "Profile" , &mapping); - config->getOption (prefix + "DeviceNum", &devnum); - for (unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) - { - config->getOption (prefix + GamePadNames[j], &button); - - GamePadConfig[i][j].ButtType[0] = type; - GamePadConfig[i][j].DeviceNum[0] = devnum; - GamePadConfig[i][j].ButtonNum[0] = button; - GamePadConfig[i][j].NumC = 1; - } + GamePad[i].init( i, guid.c_str(), mapping.c_str() ); } // PowerPad 0 - 1 for (unsigned int i = 0; i < POWERPAD_NUM_DEVICES; i++) { char buf[64]; - snprintf (buf, 32, "SDL.Input.PowerPad.%u.", i); + snprintf (buf, sizeof(buf)-1, "SDL.Input.PowerPad.%u.", i); prefix = buf; config->getOption (prefix + "DeviceType", &device); @@ -2118,10 +2088,9 @@ UpdateInput (Config * config) { config->getOption (prefix + PowerPadNames[j], &button); - powerpadsc[i][j].ButtType[0] = type; - powerpadsc[i][j].DeviceNum[0] = devnum; - powerpadsc[i][j].ButtonNum[0] = button; - powerpadsc[i][j].NumC = 1; + powerpadsc[i][j].ButtType = type; + powerpadsc[i][j].DeviceNum = devnum; + powerpadsc[i][j].ButtonNum = button; } } @@ -2145,10 +2114,9 @@ UpdateInput (Config * config) { config->getOption (prefix + QuizKingNames[j], &button); - QuizKingButtons[j].ButtType[0] = type; - QuizKingButtons[j].DeviceNum[0] = devnum; - QuizKingButtons[j].ButtonNum[0] = button; - QuizKingButtons[j].NumC = 1; + QuizKingButtons[j].ButtType = type; + QuizKingButtons[j].DeviceNum = devnum; + QuizKingButtons[j].ButtonNum = button; } // HyperShot @@ -2171,10 +2139,9 @@ UpdateInput (Config * config) { config->getOption (prefix + HyperShotNames[j], &button); - HyperShotButtons[j].ButtType[0] = type; - HyperShotButtons[j].DeviceNum[0] = devnum; - HyperShotButtons[j].ButtonNum[0] = button; - HyperShotButtons[j].NumC = 1; + HyperShotButtons[j].ButtType = type; + HyperShotButtons[j].DeviceNum = devnum; + HyperShotButtons[j].ButtonNum = button; } // Mahjong @@ -2197,10 +2164,9 @@ UpdateInput (Config * config) { config->getOption (prefix + MahjongNames[j], &button); - MahjongButtons[j].ButtType[0] = type; - MahjongButtons[j].DeviceNum[0] = devnum; - MahjongButtons[j].ButtonNum[0] = button; - MahjongButtons[j].NumC = 1; + MahjongButtons[j].ButtType = type; + MahjongButtons[j].DeviceNum = devnum; + MahjongButtons[j].ButtonNum = button; } // TopRider @@ -2223,10 +2189,9 @@ UpdateInput (Config * config) { config->getOption (prefix + TopRiderNames[j], &button); - TopRiderButtons[j].ButtType[0] = type; - TopRiderButtons[j].DeviceNum[0] = devnum; - TopRiderButtons[j].ButtonNum[0] = button; - TopRiderButtons[j].NumC = 1; + TopRiderButtons[j].ButtType = type; + TopRiderButtons[j].DeviceNum = devnum; + TopRiderButtons[j].ButtonNum = button; } // FTrainer @@ -2249,10 +2214,9 @@ UpdateInput (Config * config) { config->getOption (prefix + FTrainerNames[j], &button); - FTrainerButtons[j].ButtType[0] = type; - FTrainerButtons[j].DeviceNum[0] = devnum; - FTrainerButtons[j].ButtonNum[0] = button; - FTrainerButtons[j].NumC = 1; + FTrainerButtons[j].ButtType = type; + FTrainerButtons[j].DeviceNum = devnum; + FTrainerButtons[j].ButtonNum = button; } // FamilyKeyBoard @@ -2275,10 +2239,9 @@ UpdateInput (Config * config) { config->getOption (prefix + FamilyKeyBoardNames[j], &button); - fkbmap[j].ButtType[0] = type; - fkbmap[j].DeviceNum[0] = devnum; - fkbmap[j].ButtonNum[0] = button; - fkbmap[j].NumC = 1; + fkbmap[j].ButtType = type; + fkbmap[j].DeviceNum = devnum; + fkbmap[j].ButtonNum = button; } } diff --git a/src/drivers/Qt/input.h b/src/drivers/Qt/input.h index d9a70118..07dc1d04 100644 --- a/src/drivers/Qt/input.h +++ b/src/drivers/Qt/input.h @@ -5,7 +5,7 @@ #include "common/configSys.h" -#define MAXBUTTCONFIG 4 +//#define MAXBUTTCONFIG 4 enum { BUTTC_KEYBOARD = 0, @@ -14,14 +14,14 @@ enum { }; struct ButtConfig { - int ButtType[MAXBUTTCONFIG]; - int DeviceNum[MAXBUTTCONFIG]; - int ButtonNum[MAXBUTTCONFIG]; - uint32_t NumC; + int ButtType; //[MAXBUTTCONFIG]; + int DeviceNum; //[MAXBUTTCONFIG]; + int ButtonNum; //[MAXBUTTCONFIG]; + int state; + //uint32_t NumC; //uint64 DeviceID[MAXBUTTCONFIG]; /* TODO */ }; - extern int NoWaiting; extern CFGSTRUCT InputConfig[]; extern ARGPSTRUCT InputArgs[]; @@ -32,7 +32,7 @@ int getKeyState( int k ); int ButtonConfigBegin(); void ButtonConfigEnd(); void ConfigButton(char *text, ButtConfig *bc); -int DWaitButton(const uint8_t *text, ButtConfig *bc, int wb, int *buttonConfigStatus = NULL); +int DWaitButton(const uint8_t *text, ButtConfig *bc, int *buttonConfigStatus = NULL); #define FCFGD_GAMEPAD 1 @@ -46,7 +46,7 @@ void InitInputInterface(void); void InputUserActiveFix(void); extern bool replaceP2StartWithMicrophone; -extern ButtConfig GamePadConfig[4][10]; +//extern ButtConfig GamePadConfig[4][10]; //extern ButtConfig powerpadsc[2][12]; //extern ButtConfig QuizKingButtons[6]; //extern ButtConfig FTrainerButtons[12]; @@ -59,9 +59,9 @@ int DTestButtonJoy(ButtConfig *bc); void FCEUD_UpdateInput(void); void UpdateInput(Config *config); -void InputCfg(const std::string &); +//void InputCfg(const std::string &); std::string GetUserText(const char* title); -const char* ButtonName(const ButtConfig* bc, int which); +const char* ButtonName(const ButtConfig* bc); #endif diff --git a/src/drivers/Qt/main.cpp b/src/drivers/Qt/main.cpp index 0dc688c0..3b07821a 100644 --- a/src/drivers/Qt/main.cpp +++ b/src/drivers/Qt/main.cpp @@ -17,7 +17,14 @@ int main( int argc, char *argv[] ) consoleWindow->resize( 512, 512 ); consoleWindow->show(); - consoleWindow->viewport->init(); + if ( consoleWindow->viewport_SDL ) + { + consoleWindow->viewport_SDL->init(); + } + else + { + consoleWindow->viewport_GL->init(); + } retval = app.exec(); diff --git a/src/drivers/Qt/sdl-joystick.cpp b/src/drivers/Qt/sdl-joystick.cpp index 71148b2e..31f02316 100644 --- a/src/drivers/Qt/sdl-joystick.cpp +++ b/src/drivers/Qt/sdl-joystick.cpp @@ -22,106 +22,1056 @@ /// \file /// \brief Handles joystick input using the SDL. +#include #include "Qt/sdl.h" +#include "Qt/sdl-joystick.h" #include #include #include #include -#define MAX_JOYSTICKS 32 -static SDL_Joystick *s_Joysticks[MAX_JOYSTICKS] = {NULL}; +//#define MAX_JOYSTICKS 32 +// Public Variables +GamePad_t GamePad[4]; + +// Static Functions +static int sdlButton2NesGpIdx( const char *id ); + +// Static Variables static int s_jinited = 0; +static const char *buttonNames[ GAMEPAD_NUM_BUTTONS ] = +{ + "a", "b","back","start", + "dpup","dpdown","dpleft","dpright", + "turboA","turboB" +}; +//******************************************************************************** +// Joystick Device +jsDev_t::jsDev_t(void) +{ + js = NULL; + gc = NULL; + devIdx = 0; + portBindMask = 0; +}; + +//******************************************************************************** +int jsDev_t::close(void) +{ + if ( gc ) + { + SDL_GameControllerClose( gc ); gc = NULL; js = NULL; + } + else + { + if ( js ) + { + SDL_JoystickClose( js ); js = NULL; + } + } + return 0; +} + +//******************************************************************************** +SDL_Joystick *jsDev_t::getJS(void) +{ + return js; +} + +//******************************************************************************** +const char *jsDev_t::getName(void) +{ + return ( name.c_str() ); +} + +//******************************************************************************** +const char *jsDev_t::getGUID(void) +{ + return ( guidStr.c_str() ); +} + +//******************************************************************************** +int jsDev_t::bindPort( int idx ) +{ + portBindMask |= (0x00000001 << idx); + + return portBindMask; +} +//******************************************************************************** +int jsDev_t::unbindPort( int idx ) +{ + portBindMask &= ~(0x00000001 << idx); + + return portBindMask; +} +//******************************************************************************** +int jsDev_t::getBindPorts(void) +{ + return portBindMask; +} +//******************************************************************************** +bool jsDev_t::isGameController(void) +{ + return ( gc != NULL ); +} + +//******************************************************************************** +bool jsDev_t::isConnected(void) +{ + return ( (js != NULL) || (gc != NULL) ); +} + +//******************************************************************************** +void jsDev_t::init( int idx ) +{ + SDL_JoystickGUID guid; + char stmp[64]; + + devIdx = idx; + + if ( gc ) + { + js = SDL_GameControllerGetJoystick( gc ); + + guid = SDL_JoystickGetGUID( js ); + + name.assign( SDL_GameControllerName(gc) ); + } + else + { + guid = SDL_JoystickGetGUID( js ); + + name.assign( SDL_JoystickName(js) ); + } + SDL_JoystickGetGUIDString( guid, stmp, sizeof(stmp) ); + + guidStr.assign( stmp ); + + // If game controller, save default mapping if it does not already exist. + if ( gc ) + { + QDir dir; + QFile defaultMapFile; + std::string path; + const char *baseDir = FCEUI_GetBaseDirectory(); + + path = std::string(baseDir) + "/input/" + guidStr; + + dir.mkpath( QString::fromStdString(path) ); + + path += "/default.txt"; + + defaultMapFile.setFileName( QString::fromStdString(path) ); + + if ( !defaultMapFile.exists() ) + { + FILE *fp; + + fp = ::fopen( path.c_str(), "w" ); + + if ( fp != NULL ) + { + const char *defaultMap; + + defaultMap = SDL_GameControllerMapping(gc); + + if ( defaultMap ) + { + //printf("GameController Mapping: %s\n", defaultMap ); + fprintf( fp, "%s", defaultMap ); + } + ::fclose(fp); + } + } + //else + //{ + // printf("GameController Mapping Exists: '%s'\n", path.c_str() ); + //} + } +} + +void jsDev_t::print(void) +{ + char guidStr[64]; + + SDL_JoystickGUID guid = SDL_JoystickGetGUID( js ); + + SDL_JoystickGetGUIDString( guid, guidStr, sizeof(guidStr) ); + + printf("JoyStickID: %i: '%s' \n", + SDL_JoystickInstanceID( js ), SDL_JoystickName( js ) ); + printf("GUID: %s \n", guidStr ); + printf("NumAxes: %i \n", SDL_JoystickNumAxes(js) ); + printf("NumButtons: %i \n", SDL_JoystickNumButtons(js) ); + printf("NumHats: %i \n", SDL_JoystickNumHats(js) ); + + if ( gc ) + { + printf("GameController Name: '%s'\n", SDL_GameControllerName(gc) ); + printf("GameController Mapping: %s\n", SDL_GameControllerMapping(gc) ); + } +} + +static jsDev_t jsDev[ MAX_JOYSTICKS ]; + +//******************************************************************************** +nesGamePadMap_t::nesGamePadMap_t(void) +{ + clearMapping(); +} +//******************************************************************************** +nesGamePadMap_t::~nesGamePadMap_t(void) +{ + +} +//******************************************************************************** +void nesGamePadMap_t::clearMapping(void) +{ + guid[0] = 0; + name[0] = 0; + os[0] = 0; + for (int i=0; i= 0 ) + { + strcpy( btn[bIdx], val[i] ); + } + else if ( strcmp( id[i], "platform" ) == 0 ) + { + strcpy( os, val[i] ); + } + } + return 0; +} +//******************************************************************************** +GamePad_t::GamePad_t(void) +{ + devIdx = -1; + portNum = 0; + + for (int i=0; i= 0 ) + { + jsDev[ devIdx ].unbindPort( portNum ); + } + + devIdx = in; + + if ( devIdx >= 0 ) + { + jsDev[ devIdx ].bindPort( portNum ); + } + return 0; +} +//******************************************************************************** +const char *GamePad_t::getGUID(void) +{ + if ( devIdx < 0 ) + { + return "keyboard"; + } + if ( jsDev[ devIdx ].isConnected() ) + { + return jsDev[ devIdx ].getGUID(); + } + return NULL; +} +//******************************************************************************** +static int sdlButton2NesGpIdx( const char *id ) +{ + int i, idx = -1; + + for (i=0; ibtn[i][0] == 0) + { + continue; + } + if (gpm->btn[i][0] == 'k') + { + SDL_Keycode key; + + bmap[i].ButtType = BUTTC_KEYBOARD; + bmap[i].DeviceNum = -1; + + key = SDL_GetKeyFromName( &gpm->btn[i][1] ); + + if ( key != SDLK_UNKNOWN ) + { + bmap[i].ButtonNum = key; + } + else + { + bmap[i].ButtonNum = -1; + } + } + else if ( (gpm->btn[i][0] == 'b') && isdigit( gpm->btn[i][1] ) ) + { + bmap[i].ButtType = BUTTC_JOYSTICK; + bmap[i].DeviceNum = devIdx; + bmap[i].ButtonNum = atoi( &gpm->btn[i][1] ); + } + else if ( (gpm->btn[i][0] == 'h') && isdigit( gpm->btn[i][1] ) && + (gpm->btn[i][2] == '.') && isdigit( gpm->btn[i][3] ) ) + { + int hatIdx, hatVal; + + hatIdx = gpm->btn[i][1] - '0'; + hatVal = atoi( &gpm->btn[i][3] ); + + bmap[i].ButtType = BUTTC_JOYSTICK; + bmap[i].DeviceNum = devIdx; + bmap[i].ButtonNum = 0x2000 | ( (hatIdx & 0x1F) << 8) | (hatVal & 0xFF); + } + else if ( (gpm->btn[i][0] == 'a') || (gpm->btn[i][1] == 'a') ) + { + int l=0, axisIdx=0, axisSign=0; + + l=0; + if ( gpm->btn[i][l] == '-' ) + { + axisSign = 1; l++; + } + else if ( gpm->btn[i][l] == '+' ) + { + axisSign = 0; l++; + } + + if ( gpm->btn[i][l] == 'a' ) + { + l++; + } + if ( isdigit( gpm->btn[i][l] ) ) + { + axisIdx = atoi( &gpm->btn[i][l] ); + + while ( isdigit(gpm->btn[i][l]) ) l++; + } + if ( gpm->btn[i][l] == '-' ) + { + axisSign = 1; l++; + } + else if ( gpm->btn[i][l] == '+' ) + { + axisSign = 0; l++; + } + bmap[i].ButtType = BUTTC_JOYSTICK; + bmap[i].DeviceNum = devIdx; + bmap[i].ButtonNum = 0x8000 | (axisSign ? 0x4000 : 0) | (axisIdx & 0xFF); + } + } + return 0; +} +//******************************************************************************** +int GamePad_t::setMapping( const char *map ) +{ + nesGamePadMap_t gpm; + + gpm.parseMapping( map ); + setMapping( &gpm ); + + return 0; +} +//******************************************************************************** +int GamePad_t::getMapFromFile( const char *filename, char *out ) +{ + int i=0,j=0; + FILE *fp; + char line[256]; + + out[0] = 0; + + fp = ::fopen( filename, "r" ); + + if ( fp == NULL ) + { + return -1; + } + while ( fgets( line, sizeof(line), fp ) != 0 ) + { + i=0; + while (line[i] != 0) + { + if ( line[i] == '#' ) + { + line[i] = 0; break; + } + i++; + } + + if ( i < 32 ) continue; // need at least 32 chars for a valid line entry + + i=0; j=0; + while ( isspace(line[i]) ) i++; + + while ( line[i] != 0 ) + { + out[j] = line[i]; i++; j++; + } + out[j] = 0; + + if ( j < 34 ) continue; + + break; + } + + ::fclose(fp); + + return (j < 34); +} +//******************************************************************************** +int GamePad_t::getDefaultMap( char *out, const char *guid ) +{ + char txtMap[256]; + const char *baseDir = FCEUI_GetBaseDirectory(); + std::string path; + + out[0] = 0; + + if ( devIdx < 0 ) + { + guid = "keyboard"; + } + if ( guid == NULL ) + { + if ( jsDev[ devIdx ].isConnected() ) + { + guid = jsDev[ devIdx ].getGUID(); + } + } + if ( guid == NULL ) + { + return -1; + } + + path = std::string(baseDir) + "/input/" + std::string(guid) + "/default.txt"; + + if ( getMapFromFile( path.c_str(), txtMap ) == 0 ) + { + printf("Using Mapping From File: %s\n", path.c_str() ); + strcpy( out, txtMap ); + return 0; + } + + if ( devIdx >= 0 ) + { + if ( jsDev[ devIdx ].gc ) + { + char *sdlMapping; + + sdlMapping = SDL_GameControllerMapping( jsDev[ devIdx ].gc ); + + if ( sdlMapping == NULL ) return -1; + + strcpy( out, sdlMapping ); + + SDL_free(sdlMapping); + + return 0; + } + } + else + { + if ( strcmp( guid, "keyboard" ) == 0 ) + { + for (int x=0; x= 0 ) + { + if ( !jsDev[devIdx].isConnected() ) + { + printf("Error: JS%i Not Connected\n", devIdx ); + return -1; + } + guid = jsDev[devIdx].getGUID(); + } + else + { + guid = "keyboard"; + } + path = std::string(baseDir) + "/input/" + std::string(guid); + + dir.mkpath( QString::fromStdString(path) ); + + path += "/" + std::string(name) + ".txt"; + + output.assign( guid ); + output.append( "," ); + output.append( name ); + output.append( "," ); + + for (i=0; i> 8) & 0x1F, bmap[i].ButtonNum & 0xFF ); + } + else if (bmap[i].ButtonNum & 0x8000) + { + /* Axis "button" */ + sprintf( stmp, "%ca%i", + (bmap[i].ButtonNum & 0x4000) ? '-' : '+', bmap[i].ButtonNum & 0x3FFF ); + } + else + { + /* Button */ + sprintf( stmp, "b%i", bmap[i].ButtonNum ); + } + } + output.append( buttonNames[i] ); + output.append( ":" ); + output.append( stmp ); + output.append( "," ); + } + + return saveMappingToFile( path.c_str(), output.c_str() ); +} +//******************************************************************************** +int GamePad_t::saveMappingToFile( const char *filename, const char *txtMap ) +{ + FILE *fp; + + fp = ::fopen(filename, "w"); + + if ( fp == NULL ) + { + return -1; + } + fprintf( fp, "%s\n", txtMap ); + + ::fclose(fp); + + return 0; +} +//******************************************************************************** +int GamePad_t::createProfile( const char *name ) +{ + const char *guid = NULL; + const char *baseDir = FCEUI_GetBaseDirectory(); + std::string path; + QDir dir; + + if ( baseDir[0] == 0 ) + { + printf("Error: Invalid base directory\n"); + return -1; + } + if ( devIdx >= 0 ) + { + if ( !jsDev[devIdx].isConnected() ) + { + printf("Error: JS%i Not Connected\n", devIdx ); + return -1; + } + guid = jsDev[devIdx].getGUID(); + } + else + { + guid = "keyboard"; + } + path = std::string(baseDir) + "/input/" + std::string(guid); + + dir.mkpath( QString::fromStdString(path) ); + //printf("DIR: '%s'\n", path.c_str() ); + + //path += "/" + std::string(name) + ".txt"; + + //printf("File: '%s'\n", path.c_str() ); + + saveCurrentMapToFile( name ); + + return 0; +} +//******************************************************************************** +int GamePad_t::deleteMapping( const char *name ) +{ + const char *guid = NULL; + const char *baseDir = FCEUI_GetBaseDirectory(); + std::string path; + + if ( baseDir[0] == 0 ) + { + printf("Error: Invalid base directory\n"); + return -1; + } + if ( devIdx >= 0 ) + { + if ( !jsDev[devIdx].isConnected() ) + { + printf("Error: JS%i Not Connected\n", devIdx ); + return -1; + } + guid = jsDev[devIdx].getGUID(); + } + else + { + guid = "keyboard"; + } + path = std::string(baseDir) + "/input/" + std::string(guid) + + "/" + std::string(name) + ".txt"; + + //printf("File: '%s'\n", path.c_str() ); + + return remove( path.c_str() ); +} +//******************************************************************************** +jsDev_t *getJoystickDevice( int devNum ) +{ + if ( (devNum >= 0) && (devNum < MAX_JOYSTICKS) ) + { + return &jsDev[ devNum ]; + } + return NULL; +} + +//******************************************************************************** /** * Tests if the given button is active on the joystick. */ int DTestButtonJoy(ButtConfig *bc) { - int x; + SDL_Joystick *js; - for(x = 0; x < bc->NumC; x++) + if (bc->ButtonNum == -1) { - if (bc->ButtonNum[x] == -1) - { - continue; - } - if (bc->ButtonNum[x] & 0x2000) - { - /* Hat "button" */ - if(SDL_JoystickGetHat(s_Joysticks[bc->DeviceNum[x]], - ((bc->ButtonNum[x] >> 8) & 0x1F)) & - (bc->ButtonNum[x]&0xFF)) - return 1; - } - else if (bc->ButtonNum[x] & 0x8000) - { - /* Axis "button" */ - int pos; - pos = SDL_JoystickGetAxis(s_Joysticks[bc->DeviceNum[x]], - bc->ButtonNum[x] & 16383); - if ((bc->ButtonNum[x] & 0x4000) && pos <= -16383) { - return 1; - } else if (!(bc->ButtonNum[x] & 0x4000) && pos >= 16363) { - return 1; - } - } - else if(SDL_JoystickGetButton(s_Joysticks[bc->DeviceNum[x]], - bc->ButtonNum[x])) - return 1; + return 0; } + if ( bc->DeviceNum < 0 ) + { + return 0; + } + js = jsDev[bc->DeviceNum].getJS(); + + if (bc->ButtonNum & 0x2000) + { + /* Hat "button" */ + if (SDL_JoystickGetHat( js, + ((bc->ButtonNum >> 8) & 0x1F)) & + (bc->ButtonNum&0xFF)) + { + bc->state = 1; + return 1; + } + else + { + bc->state = 0; + } + } + else if (bc->ButtonNum & 0x8000) + { + /* Axis "button" */ + int pos; + pos = SDL_JoystickGetAxis( js, + bc->ButtonNum & 0x3FFF); + if ((bc->ButtonNum & 0x4000) && pos <= -16383) + { + bc->state = 1; + return 1; + } + else if (!(bc->ButtonNum & 0x4000) && pos >= 16363) + { + bc->state = 1; + return 1; + } + else + { + bc->state = 0; + } + } + else if (SDL_JoystickGetButton( js, + bc->ButtonNum)) + { + bc->state = 1; + return 1; + } + else + { + bc->state = 0; + } + return 0; } +//******************************************************************************** + +//static void printJoystick( SDL_Joystick *js ) +//{ +// char guidStr[64]; +// SDL_Joystick *js; +// +// js = jsDev[i].getJS(); +// +// SDL_JoystickGUID guid = SDL_JoystickGetGUID( js ); +// +// SDL_JoystickGetGUIDString( guid, guidStr, sizeof(guidStr) ); +// +// printf("JoyStickID: %i: %s \n", +// SDL_JoystickInstanceID( js ), SDL_JoystickName( js ) ); +// printf("GUID: %s \n", guidStr ); +// printf("NumAxes: %i \n", SDL_JoystickNumAxes(js) ); +// printf("NumButtons: %i \n", SDL_JoystickNumButtons(js) ); +// printf("NumHats: %i \n", SDL_JoystickNumHats(js) ); +// +//} + +//******************************************************************************** /** * Shutdown the SDL joystick subsystem. */ int -KillJoysticks() +KillJoysticks(void) { int n; /* joystick index */ - if(!s_jinited) { + if (!s_jinited) { return -1; } - for(n = 0; n < MAX_JOYSTICKS; n++) { - if (s_Joysticks[n] != 0) { - SDL_JoystickClose(s_Joysticks[n]); - } - s_Joysticks[n]=0; + for (n = 0; n < MAX_JOYSTICKS; n++) + { + jsDev[n].close(); } SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + + s_jinited = 0; + return 0; } +//******************************************************************************** +int AddJoystick( int which ) +{ + if ( jsDev[ which ].isConnected() ) + { + //printf("Error: Joystick already exists at device index %i \n", which ); + return -1; + } + else + { + if ( SDL_IsGameController(which) ) + { + jsDev[which].gc = SDL_GameControllerOpen(which); + + if ( jsDev[which].gc == NULL ) + { + printf("Could not open game controller %d: %s.\n", + which, SDL_GetError()); + } + else + { + //printf("Added Joystick: %i \n", which ); + jsDev[which].init(which); + //jsDev[which].print(); + //printJoystick( s_Joysticks[which] ); + } + } + else + { + jsDev[which].js = SDL_JoystickOpen(which); + + if ( jsDev[which].js == NULL ) + { + printf("Could not open joystick %d: %s.\n", + which, SDL_GetError()); + } + else + { + //printf("Added Joystick: %i \n", which ); + jsDev[which].init(which); + //jsDev[which].print(); + //printJoystick( s_Joysticks[which] ); + } + } + } + return 0; +} + +//******************************************************************************** +int RemoveJoystick( int which ) +{ + //printf("Remove Joystick: %i \n", which ); + + for (int i=0; iMAX_JOYSTICKS) { + if (total > MAX_JOYSTICKS) + { total = MAX_JOYSTICKS; } - for(n = 0; n < total; n++) { + for (n = 0; n < total; n++) + { /* Open the joystick under SDL. */ - s_Joysticks[n] = SDL_JoystickOpen(n); - //printf("Could not open joystick %d: %s.\n", - //joy[n] - 1, SDL_GetError()); - continue; + AddJoystick(n); } s_jinited = 1; return 1; } +//******************************************************************************** diff --git a/src/drivers/Qt/sdl-joystick.h b/src/drivers/Qt/sdl-joystick.h new file mode 100644 index 00000000..568f736b --- /dev/null +++ b/src/drivers/Qt/sdl-joystick.h @@ -0,0 +1,92 @@ +// sdl-joystick.h + +#ifndef __SDL_JOYSTICK_H__ +#define __SDL_JOYSTICK_H__ + +#include + +#include "Qt/main.h" +#include "Qt/input.h" +#include "Qt/sdl.h" + +#define MAX_JOYSTICKS 32 + +struct nesGamePadMap_t +{ + char guid[64]; + char name[128]; + char btn[GAMEPAD_NUM_BUTTONS][32]; + char os[64]; + + nesGamePadMap_t(void); + ~nesGamePadMap_t(void); + + void clearMapping(void); + int parseMapping( const char *text ); +}; + +struct jsDev_t +{ + SDL_Joystick *js; + SDL_GameController *gc; + + jsDev_t(void); + //~jsDev_t(void); + + void init( int idx ); + int close(void); + SDL_Joystick *getJS(void); + bool isGameController(void); + bool isConnected(void); + void print(void); + int bindPort( int idx ); + int unbindPort( int idx ); + int getBindPorts(void); + const char *getName(void); + const char *getGUID(void); + + private: + int devIdx; + int portBindMask; + std::string guidStr; + std::string name; +}; + +class GamePad_t +{ + public: + + ButtConfig bmap[GAMEPAD_NUM_BUTTONS]; + + GamePad_t(void); + ~GamePad_t(void); + + int init( int port, const char *guid, const char *profile = NULL ); + const char *getGUID(void); + + int loadDefaults(void); + int loadProfile( const char *name, const char *guid = NULL ); + + int getDeviceIndex(void){ return devIdx; } + int setDeviceIndex( int devIdx ); + int setMapping( const char *map ); + int setMapping( nesGamePadMap_t *map ); + + int createProfile( const char *name ); + int getMapFromFile( const char *filename, char *out ); + int getDefaultMap( char *out, const char *guid = NULL ); + int saveMappingToFile( const char *filename, const char *txtMap ); + int saveCurrentMapToFile( const char *filename ); + int deleteMapping( const char *name ); + + private: + int devIdx; + int portNum; + +}; + +extern GamePad_t GamePad[4]; + +jsDev_t *getJoystickDevice( int devNum ); + +#endif diff --git a/src/drivers/Qt/sdl-sound.cpp b/src/drivers/Qt/sdl-sound.cpp index 28c263ba..d869fc49 100644 --- a/src/drivers/Qt/sdl-sound.cpp +++ b/src/drivers/Qt/sdl-sound.cpp @@ -195,11 +195,19 @@ WriteSound(int32 *buf, extern int EmulationPaused; if (EmulationPaused == 0) { + int waitCount = 0; + while(Count) { while(s_BufferIn == s_BufferSize) { - SDL_Delay(1); + SDL_Delay(1); waitCount++; + + if ( waitCount > 1000 ) + { + printf("Error: Sound sink is not draining... Breaking out of audio loop to prevent lockup.\n"); + return; + } } s_Buffer[s_BufferWrite] = *buf; diff --git a/src/drivers/Qt/sdl-video.cpp b/src/drivers/Qt/sdl-video.cpp index 003f8dcd..aba7cc3d 100644 --- a/src/drivers/Qt/sdl-video.cpp +++ b/src/drivers/Qt/sdl-video.cpp @@ -51,6 +51,7 @@ // GLOBALS extern Config *g_config; +extern bool force_grayscale; // STATIC GLOBALS static int s_curbpp = 0; @@ -206,24 +207,6 @@ int InitVideo(FCEUGI *gi) return -1; } -#ifdef OPENGL - if(s_exs <= 0.01) { - FCEUD_PrintError("xscale out of bounds."); - KillVideo(); - return -1; - } - if(s_eys <= 0.01) { - FCEUD_PrintError("yscale out of bounds."); - KillVideo(); - return -1; - } - //if(s_sponge && s_useOpenGL) { - // FCEUD_PrintError("scalers not compatible with openGL mode."); - // KillVideo(); - // return -1; - //} -#endif - if ( !initBlitToHighDone ) { InitBlitToHigh(s_curbpp >> 3, @@ -269,9 +252,21 @@ FCEUD_SetPalette(uint8 index, uint8 g, uint8 b) { - s_psdl[index].r = r; - s_psdl[index].g = g; - s_psdl[index].b = b; + if ( force_grayscale ) + { + // convert the palette entry to grayscale + int gray = ((float)r * 0.299 + (float)g * 0.587 + (float)b * 0.114); + + s_psdl[index].r = gray; + s_psdl[index].g = gray; + s_psdl[index].b = gray; + } + else + { + s_psdl[index].r = r; + s_psdl[index].g = g; + s_psdl[index].b = b; + } s_paletterefresh = 1; } @@ -297,6 +292,7 @@ static void RedoPalette() { if (s_curbpp > 8) { + //printf("Refresh Palette\n"); SetPaletteBlitToHigh((uint8*)s_psdl); } } diff --git a/src/drivers/common/cheat.cpp b/src/drivers/common/cheat.cpp index f985876e..2cff0cd6 100644 --- a/src/drivers/common/cheat.cpp +++ b/src/drivers/common/cheat.cpp @@ -226,7 +226,7 @@ static void ModifyCheat(int num) printf("Address [$%04x]: ",(unsigned int)A); A=GetH16(A); - printf("Value [%03d]: ",(unsigned int)V); + printf("Value [%03u]: ",(unsigned int)V); V=Get8(V); printf("Compare [%3d]: ",compare); @@ -302,9 +302,9 @@ static void AddCheatParam(uint32 A, uint8 V) GetString(name,256); printf("Address [$%04x]: ",(unsigned int)A); A=GetH16(A); - printf("Value [%03d]: ",(unsigned int)V); + printf("Value [%03u]: ",(unsigned int)V); V=Get8(V); - printf("Add cheat \"%s\" for address $%04x with value %03d?",name,(unsigned int)A,(unsigned int)V); + printf("Add cheat \"%s\" for address $%04x with value %03u?",name,(unsigned int)A,(unsigned int)V); if(GetYN(0)) { if(FCEUI_AddCheat(name,A,V,-1,0)) @@ -326,9 +326,9 @@ static int clistcallb(char *name, uint32 a, uint8 v, int compare, int s, int typ int ret; if(compare>=0) - sprintf(tmp,"%s $%04x:%03d:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,compare,name); + sprintf(tmp,"%s $%04x:%03u:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,compare,name); else - sprintf(tmp,"%s $%04x:%03d - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,name); + sprintf(tmp,"%s $%04x:%03u - %s",s?"*":" ",(unsigned int)a,(unsigned int)v,name); if(type==1) tmp[2]='S'; ret=AddToList(tmp,lid); @@ -373,7 +373,7 @@ static void ResetSearch(void) static int srescallb(uint32 a, uint8 last, uint8 current, void *data) { char tmp[14]; - sprintf(tmp, "$%04x:%03d:%03d",(unsigned int)a,(unsigned int)last,(unsigned int)current); + sprintf(tmp, "$%04x:%03u:%03u",(unsigned int)a,(unsigned int)last,(unsigned int)current); return(AddToList(tmp,a)); } diff --git a/src/drivers/common/os_utils.cpp b/src/drivers/common/os_utils.cpp new file mode 100644 index 00000000..90460584 --- /dev/null +++ b/src/drivers/common/os_utils.cpp @@ -0,0 +1,87 @@ +// os_util.cpp +#include +#include + +#if defined(WIN32) +#include +#else +#include +#include +#endif + +#include "common/os_utils.h" +//************************************************************ +int fceu_mkdir( const char *path ) +{ + int retval; +#if defined(WIN32) + retval = mkdir(path); + chmod(path, 755); +#else + retval = mkdir(path, S_IRWXU); + + if ( retval != 0 ) + { + if ( errno == EEXIST ) + { + //printf("Path Exists: '%s'\n", path); + retval = 0; + } + } +#endif + return retval; +} +//************************************************************ +int fceu_mkpath( const char *path ) +{ + int i, retval = 0; + char p[512]; + + i=0; + while ( path[i] != 0 ) + { + if ( path[i] == '/' ) + { + if ( i > 0 ) + { + p[i] = 0; + + retval = fceu_mkdir( p ); + + if ( retval ) + { + return retval; + } + } + } + p[i] = path[i]; i++; + } + p[i] = 0; + + retval = fceu_mkdir( p ); + + return retval; +} +//************************************************************ +bool fceu_file_exists( const char *filepath ) +{ +#ifdef WIN32 + FILE *fp; + fp = ::fopen( filename, "r" ); + + if ( fp != NULL ) + { + ::fclose(fp); + return true; + } +#else + struct stat sb; + + if ( stat( filepath, &sb ) == 0 ) + { + return true; + } +#endif + return false; +} +//************************************************************ diff --git a/src/drivers/common/os_utils.h b/src/drivers/common/os_utils.h new file mode 100644 index 00000000..4ebd7e06 --- /dev/null +++ b/src/drivers/common/os_utils.h @@ -0,0 +1,9 @@ +// os_utils.h +// + +int fceu_mkdir( const char *path ); + +int fceu_mkpath( const char *path ); + +bool fceu_file_exists( const char *filepath ); + diff --git a/src/drivers/common/vidblit.cpp b/src/drivers/common/vidblit.cpp index d93c520a..53f907b5 100644 --- a/src/drivers/common/vidblit.cpp +++ b/src/drivers/common/vidblit.cpp @@ -88,13 +88,13 @@ static int PAL_LUT(uint32 *buffer, int index, int x, int y) static void CalculateShift(uint32 *CBM, int *cshiftr, int *cshiftl) { - int a,x,z,y; + int a,x,z; cshiftl[0]=cshiftl[1]=cshiftl[2]=-1; for(a=0;a<3;a++) { - for(x=0,y=-1,z=0;x<32;x++) + for(x=0,z=0;x<32;x++) { - if(CBM[a]&(1< +#include +#include + +#include + +#include "sdl/GamePadConf.h" +#include "sdl/main.h" +#include "sdl/dface.h" +#include "sdl/input.h" +#include "sdl/config.h" +#include "sdl/keyscan.h" +#include "sdl/sdl-joystick.h" +#include "sdl/gui.h" + +extern Config *g_config; +static GtkWidget *gamePadConfwin = NULL; +static GtkWidget *padNoCombo = NULL; +static GtkWidget *devSelCombo = NULL; +static GtkWidget *mapProfCombo = NULL; +static GtkWidget *buttonMappings[GAMEPAD_NUM_BUTTONS] = { NULL }; +static GtkWidget *buttonState[GAMEPAD_NUM_BUTTONS] = { NULL }; +static GtkWidget *guidLbl = NULL; +static GtkWidget *msgLbl = NULL; +static int buttonConfigStatus = 0; +static int padNo = 0; +static int numProfiles = 0; + +struct GamePadConfigLocalData_t +{ + std::string guid; + std::string profile; + + struct { + + char needsSave; + + } btn[GAMEPAD_NUM_BUTTONS]; + + GamePadConfigLocalData_t(void) + { + for (int i=0; i%s", + SDL_GetKeyName (GamePad[padNo].bmap[i]. + ButtonNum)); + } + else + sprintf (strBuf, "%s", ButtonName( &GamePad[padNo].bmap[i] ) ); + + if ( mappedKey != NULL ) + { + gtk_label_set_text (GTK_LABEL (mappedKey), strBuf); + gtk_label_set_use_markup (GTK_LABEL (mappedKey), TRUE); + } + } +} + +static void loadMapList(void) +{ + const char *baseDir = FCEUI_GetBaseDirectory(); + const char *guid; + std::string path; + std::string prefix, mapName; + int devIdx = -1; + jsDev_t *js; + size_t i,n=0; + char stmp[256]; + struct dirent *d; + DIR *dir; + + devIdx = getDeviceIndex(); + + if ( devIdx < 0 ) + { + guid = "keyboard"; + } + else + { + js = getJoystickDevice( devIdx ); + + guid = js->getGUID(); + } + + if ( guid == NULL ) + { + return; + } + + path = std::string(baseDir) + "/input/" + std::string(guid); + + sprintf( stmp, "SDL.Input.GamePad.%i.", padNo ); + prefix = stmp; + + g_config->getOption(prefix + "Profile", &mapName ); + + gtk_combo_box_text_remove_all( GTK_COMBO_BOX_TEXT(mapProfCombo) ); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (mapProfCombo), "default"); + gtk_combo_box_set_active (GTK_COMBO_BOX (mapProfCombo), 0); + + numProfiles = n = 1; + dir = ::opendir( path.c_str() ); + + if ( dir == NULL ) return; + + d = ::readdir( dir ); + + while ( d != NULL ) + { + i=0; + while ( d->d_name[i] != 0 ) + { + if ( d->d_name[i] == '.' ) + { + break; + } + stmp[i] = d->d_name[i]; i++; + } + stmp[i] = 0; + + //printf("Directory: '%s'\n", stmp ); + + if ( i > 0 ) + { + if ( strcmp( stmp, "default" ) != 0 ) + { + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (mapProfCombo), stmp); + + if ( mapName.compare(stmp) == 0 ) + { + gtk_combo_box_set_active (GTK_COMBO_BOX (mapProfCombo), n); + } + n++; + } + } + + d = ::readdir( dir ); + } + numProfiles = n; + + ::closedir( dir ); + +} + +static void selPortChanged( GtkWidget * w, gpointer p ) +{ + const char *txt; + + txt = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT (padNoCombo)); + + if ( txt == NULL ) + { + return; + } + padNo = atoi(txt) - 1; + + GtkTreeModel *treeModel = gtk_combo_box_get_model( GTK_COMBO_BOX (devSelCombo) ); + GtkTreeIter iter; + gboolean iterValid; + + iterValid = gtk_tree_model_get_iter_first( treeModel, &iter ); + + while ( iterValid ) + { + GValue value; + + memset( &value, 0, sizeof(value)); + + gtk_tree_model_get_value (treeModel, &iter, 0, &value ); + + if ( G_IS_VALUE(&value) ) + { + if ( G_VALUE_TYPE(&value) == G_TYPE_STRING ) + { + int devIdx = -1; + const char *s = (const char *)g_value_peek_pointer( &value ); + + if ( isdigit( s[0] ) ) + { + devIdx = atoi(s); + } + if ( (devIdx >= 0) && (devIdx == GamePad[padNo].getDeviceIndex() ) ) + { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (devSelCombo), &iter); + } + } + } + g_value_unset(&value); + + iterValid = gtk_tree_model_iter_next( treeModel, &iter ); + } + gtk_label_set_text( GTK_LABEL(guidLbl), GamePad[padNo].getGUID() ); + + loadMapList(); + + updateCntrlrDpy(); +} + +static void selInputDevice (GtkWidget * w, gpointer p) +{ + //std::string s = "SDL.Input."; + int devIdx = -1; + jsDev_t *js; + + if ( (padNoCombo == NULL) ) + { + return; + } + + devIdx = getDeviceIndex(); + + js = getJoystickDevice( devIdx ); + + if ( js != NULL ) + { + if ( js->isConnected() ) + { + gtk_label_set_text( GTK_LABEL(guidLbl), js->getGUID() ); + } + } + else + { + gtk_label_set_text( GTK_LABEL(guidLbl), "keyboard" ); + } + GamePad[padNo].setDeviceIndex( devIdx ); + + lcl[padNo].guid.assign( GamePad[padNo].getGUID() ); + lcl[padNo].profile.assign("default"); + + loadMapList(); + + updateCntrlrDpy(); + + return; +} + +static void saveConfig(void) +{ + int i; + char stmp[256]; + const char *txt; + std::string prefix, mapName; + + sprintf( stmp, "SDL.Input.GamePad.%i.", padNo ); + prefix = stmp; + + txt = gtk_combo_box_text_get_active_text( GTK_COMBO_BOX_TEXT(mapProfCombo) ); + + if ( txt == NULL ) + { + return; + } + mapName.assign( txt ); + + g_config->setOption(prefix + "DeviceGUID", GamePad[padNo].getGUID() ); + g_config->setOption(prefix + "Profile" , mapName.c_str() ); + + for (i=0; isave(); +} + +static void createNewProfile( const char *name ) +{ + char stmp[256]; + //printf("Creating: %s \n", name ); + + GamePad[padNo].createProfile(name); + + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (mapProfCombo), name); + numProfiles++; + + gtk_combo_box_set_active( GTK_COMBO_BOX (mapProfCombo), numProfiles - 1 ); + + saveConfig(); + + sprintf( stmp, "Mapping Created: %s/%s \n", GamePad[padNo].getGUID(), name ); + gtk_label_set_text( GTK_LABEL(msgLbl), stmp ); + + loadMapList(); +} + +static void loadProfileCB (GtkButton * button, gpointer p) +{ + char stmp[256]; + int devIdx, ret; + std::string mapName; + const char *txt; + + devIdx = getDeviceIndex(); + + txt = gtk_combo_box_text_get_active_text( GTK_COMBO_BOX_TEXT(mapProfCombo) ); + + if ( txt == NULL ) + { + return; + } + mapName.assign( txt ); + + GamePad[padNo].setDeviceIndex( devIdx ); + + if ( mapName.compare("default") == 0 ) + { + ret = GamePad[padNo].loadDefaults(); + } + else + { + ret = GamePad[padNo].loadProfile( mapName.c_str() ); + } + if ( ret == 0 ) + { + saveConfig(); + + sprintf( stmp, "Mapping Loaded: %s/%s \n", GamePad[padNo].getGUID(), mapName.c_str() ); + } + else + { + sprintf( stmp, "Error: Failed to Load Mapping: %s/%s \n", GamePad[padNo].getGUID(), mapName.c_str() ); + } + gtk_label_set_text( GTK_LABEL(msgLbl), stmp ); + + updateCntrlrDpy(); +} + +static void saveProfileCB (GtkButton * button, gpointer p) +{ + int ret; + std::string mapName; + char stmp[256]; + const char *txt; + + txt = gtk_combo_box_text_get_active_text( GTK_COMBO_BOX_TEXT(mapProfCombo) ); + + if ( txt == NULL ) + { + return; + } + mapName.assign( txt ); + + ret = GamePad[padNo].saveCurrentMapToFile( mapName.c_str() ); + + if ( ret == 0 ) + { + saveConfig(); + + sprintf( stmp, "Mapping Saved: %s/%s \n", GamePad[padNo].getGUID(), mapName.c_str() ); + } + else + { + sprintf( stmp, "Error: Failed to Save Mapping: %s \n", mapName.c_str() ); + } + gtk_label_set_text( GTK_LABEL(msgLbl), stmp ); +} + +static void newProfileCB (GtkButton * button, gpointer p) +{ + int ret; + GtkWidget *vbox, *lbl, *entry; + GtkWidget *dialog + = gtk_dialog_new_with_buttons ("New Profile", GTK_WINDOW(gamePadConfwin), + (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), + "_Cancel", GTK_RESPONSE_CANCEL, "_Create", GTK_RESPONSE_ACCEPT, NULL ); + + vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + gtk_box_set_homogeneous (GTK_BOX (vbox), FALSE); + + lbl = gtk_label_new("Specify New Profile Name"); + entry = gtk_entry_new(); + + gtk_box_pack_start (GTK_BOX (vbox), lbl, TRUE, TRUE, 5); + gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 5); + + gtk_widget_show_all( dialog ); + + ret = gtk_dialog_run( GTK_DIALOG(dialog) ); + + if ( ret == GTK_RESPONSE_ACCEPT ) + { + printf("Text: '%s'\n", gtk_entry_get_text( GTK_ENTRY(entry) ) ); + + createNewProfile( gtk_entry_get_text( GTK_ENTRY(entry) ) ); + } + + gtk_widget_destroy( dialog ); +} + +static void deleteProfileCB (GtkButton * button, gpointer p) +{ + int ret; + std::string mapName; + char stmp[256]; + const char *txt; + + txt = gtk_combo_box_text_get_active_text( GTK_COMBO_BOX_TEXT(mapProfCombo) ); + + if ( txt == NULL ) + { + return; + } + mapName.assign( txt ); + + ret = GamePad[padNo].deleteMapping( mapName.c_str() ); + + if ( ret == 0 ) + { + sprintf( stmp, "Mapping Deleted: %s/%s \n", GamePad[padNo].getGUID(), mapName.c_str() ); + } + else + { + sprintf( stmp, "Error: Failed to Delete Mapping: %s \n", mapName.c_str() ); + } + gtk_label_set_text( GTK_LABEL(msgLbl), stmp ); + + loadMapList(); +} + +// This function configures a single button on a gamepad +static void clearGamepadButton (GtkButton * button, gpointer p) +{ + long int x = (long int)p; + + GamePad[padNo].bmap[x].ButtonNum = -1; + + gtk_label_set_text (GTK_LABEL (buttonMappings[x]), ""); + + lcl[padNo].btn[x].needsSave = 1; + + updateCntrlrDpy(); +} + +// This function configures a single button on a gamepad +static void configGamepadButton (GtkButton * button, gpointer p) +{ + gint x = ((gint) (glong) (p)); + //gint x = GPOINTER_TO_INT(p); + + char buf[256]; + std::string prefix; + + // only configure when the "Change" button is pressed in, not when it is unpressed + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) + return; + + gtk_button_set_label (GTK_BUTTON (button), "Waiting"); + + buttonConfigStatus = 2; + + ButtonConfigBegin (); + + snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%d.", padNo); + prefix = buf; + DWaitButton (NULL, &GamePad[padNo].bmap[x], &buttonConfigStatus ); + +// g_config->setOption (prefix + GamePadNames[x], +// GamePadConfig[padNo][x].ButtonNum[configNo]); +// +// if (GamePadConfig[padNo][x].ButtType[0] == BUTTC_KEYBOARD) +// { +// g_config->setOption (prefix + "DeviceType", "Keyboard"); +// } +// else if (GamePadConfig[padNo][x].ButtType[0] == BUTTC_JOYSTICK) +// { +// g_config->setOption (prefix + "DeviceType", "Joystick"); +// } +// else +// { +// g_config->setOption (prefix + "DeviceType", "Unknown"); +// } +// g_config->setOption (prefix + "DeviceNum", +// GamePadConfig[padNo][x].DeviceNum[configNo]); + + snprintf (buf, sizeof (buf), "%s", + ButtonName (&GamePad[padNo].bmap[x])); + + if ( buttonMappings[x] != NULL ) + { + gtk_label_set_markup (GTK_LABEL (buttonMappings[x]), buf); + } + lcl[padNo].btn[x].needsSave = 1; + + ButtonConfigEnd (); + + buttonConfigStatus = 1; + + gtk_button_set_label (GTK_BUTTON (button), "Change"); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); + + return; +} + +//static void updateGamepadConfig (GtkWidget * w, gpointer p) +//{ +// updateCntrlrDpy(); +//} + +static gint timeout_callback (gpointer data) +{ + if ( gamePadConfwin == NULL ) + { + return FALSE; + } + + for (int i=0; isetStyleSheet("color: red;"); + //} + //else + //{ + // keyName[i]->setStyleSheet("color: black;"); + //} + } + + return TRUE; +} + +static void closeGamepadConfig (GtkWidget * w, GdkEvent * e, gpointer p) +{ + gtk_widget_destroy (w); + + gamePadConfwin = NULL; + padNoCombo = NULL; + + for (int i = 0; i < GAMEPAD_NUM_BUTTONS; i++) + { + buttonMappings[i] = NULL; + buttonState[i] = NULL; + } + buttonConfigStatus = 0; +} + +void openGamepadConfig (void) +{ + GtkWidget *win; + GtkWidget *mainVbox; + GtkWidget *hbox, /* *vbox,*/ *lbl; + GtkWidget *hboxPadNo; + GtkWidget *padNoLabel; + GtkWidget* devSelLabel, *devSelHbox; + GtkWidget *fourScoreChk; + GtkWidget *oppositeDirChk; + GtkWidget *buttonFrame; + GtkWidget *buttonTable; + GtkWidget *button; + GtkWidget *grid; + GtkWidget *mappingFrame; + char stmp[256]; + + if ( gamePadConfwin != NULL ) + { + return; + } + + // Ensure that joysticks are enabled, no harm calling init again. + InitJoysticks(); + + padNo = 0; + + win = gtk_dialog_new_with_buttons ("Controller Configuration", + GTK_WINDOW (MainWindow), + (GtkDialogFlags) + (GTK_DIALOG_DESTROY_WITH_PARENT), + "_Close", GTK_RESPONSE_OK, NULL); + gtk_window_set_title (GTK_WINDOW (win), "Controller Configuration"); + gtk_window_set_icon_name (GTK_WINDOW (win), "input-gaming"); + gtk_widget_set_size_request (win, 350, 500); + + mainVbox = gtk_dialog_get_content_area (GTK_DIALOG (win)); + gtk_box_set_homogeneous (GTK_BOX (mainVbox), FALSE); + + hboxPadNo = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous( GTK_BOX(hboxPadNo), TRUE ); + padNoLabel = gtk_label_new ("Port:"); + //configNoLabel = gtk_label_new("Config Number:"); + fourScoreChk = gtk_check_button_new_with_label ("Enable Four Score"); + oppositeDirChk = + gtk_check_button_new_with_label ("Allow Up+Down / Left+Right"); + + //typeCombo = gtk_combo_box_text_new (); + //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), + // "gamepad"); + //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), + // "zapper"); + //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), + // "powerpad.0"); + //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), + // "powerpad.1"); + //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), + // "arkanoid"); + + //gtk_combo_box_set_active (GTK_COMBO_BOX (typeCombo), 0); + + + padNoCombo = gtk_combo_box_text_new (); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "1"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "2"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "3"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "4"); + gtk_combo_box_set_active (GTK_COMBO_BOX (padNoCombo), 0); + g_signal_connect (padNoCombo, "changed", + G_CALLBACK (selPortChanged), NULL); + + devSelHbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous( GTK_BOX(devSelHbox), TRUE ); + devSelLabel = gtk_label_new ("Device:"); + devSelCombo = gtk_combo_box_text_new (); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (devSelCombo), "Keyboard"); + + gtk_combo_box_set_active (GTK_COMBO_BOX (devSelCombo), 0); + + for (int i=0; iisConnected() ) + { + sprintf( stmp, "%i: %s", i, js->getName() ); + gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT (devSelCombo), stmp ); + } + } + } + gtk_combo_box_set_active (GTK_COMBO_BOX (devSelCombo), 0); + + { + GtkTreeModel *treeModel = gtk_combo_box_get_model( GTK_COMBO_BOX (devSelCombo) ); + GtkTreeIter iter; + gboolean iterValid; + + iterValid = gtk_tree_model_get_iter_first( treeModel, &iter ); + + while ( iterValid ) + { + GValue value; + + memset( &value, 0, sizeof(value)); + + gtk_tree_model_get_value (treeModel, &iter, 0, &value ); + + if ( G_IS_VALUE(&value) ) + { + if ( G_VALUE_TYPE(&value) == G_TYPE_STRING ) + { + int devIdx = -1; + const char *s = (const char *)g_value_peek_pointer( &value ); + + if ( isdigit( s[0] ) ) + { + devIdx = atoi(s); + } + if ( (devIdx >= 0) && (devIdx == GamePad[padNo].getDeviceIndex() ) ) + { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (devSelCombo), &iter); + } + } + } + g_value_unset(&value); + + iterValid = gtk_tree_model_iter_next( treeModel, &iter ); + } + } + g_signal_connect (devSelCombo, "changed", G_CALLBACK (selInputDevice), NULL ); + + //g_signal_connect (typeCombo, "changed", G_CALLBACK (setInputDevice), + // gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT + // (typeCombo))); + + setCheckbox (fourScoreChk, "SDL.FourScore"); + g_signal_connect (fourScoreChk, "clicked", G_CALLBACK (toggleOption), + (gpointer) "SDL.FourScore"); + setCheckbox (oppositeDirChk, "SDL.Input.EnableOppositeDirectionals"); + g_signal_connect (oppositeDirChk, "clicked", G_CALLBACK (toggleOption), + (gpointer) "SDL.Input.EnableOppositeDirectionals"); + + + gtk_box_pack_start (GTK_BOX (hboxPadNo), padNoLabel, TRUE, TRUE, 5); + gtk_box_pack_start (GTK_BOX (hboxPadNo), padNoCombo, TRUE, TRUE, 5); + gtk_box_pack_start (GTK_BOX (mainVbox), hboxPadNo, FALSE, TRUE, 5); + //gtk_box_pack_start_defaults(GTK_BOX(mainVbox), typeCombo); + + gtk_box_pack_start (GTK_BOX (devSelHbox), devSelLabel, TRUE, TRUE, 5); + gtk_box_pack_start (GTK_BOX (devSelHbox), devSelCombo, TRUE, TRUE, 5); + gtk_box_pack_start (GTK_BOX (mainVbox), devSelHbox, TRUE, TRUE, 5); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous( GTK_BOX(hbox), TRUE ); + lbl = gtk_label_new ("GUID:"); + guidLbl = gtk_label_new (""); + + gtk_box_pack_start (GTK_BOX (hbox), lbl, TRUE, TRUE, 5); + gtk_box_pack_start (GTK_BOX (hbox), guidLbl, TRUE, TRUE, 5); + gtk_box_pack_start (GTK_BOX (mainVbox), hbox, TRUE, TRUE, 5); + + gtk_label_set_text( GTK_LABEL(guidLbl), GamePad[padNo].getGUID() ); + + mappingFrame = gtk_frame_new ("Mapping Profile:"); + gtk_label_set_use_markup (GTK_LABEL + (gtk_frame_get_label_widget + (GTK_FRAME (mappingFrame))), TRUE); + gtk_box_pack_start (GTK_BOX (mainVbox), mappingFrame, FALSE, TRUE, 5); + grid = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (grid), 5); + gtk_grid_set_column_spacing (GTK_GRID (grid), 5); + gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE); + + //vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_container_add (GTK_CONTAINER (mappingFrame), grid); + + mapProfCombo = gtk_combo_box_text_new (); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (mapProfCombo), "default"); + gtk_combo_box_set_active (GTK_COMBO_BOX (mapProfCombo), 0); + gtk_grid_attach (GTK_GRID (grid), mapProfCombo, 0, 0, 2, 1 ); + + button = gtk_button_new_with_label ("Load"); + gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 1, 1 ); + g_signal_connect (button, "clicked", G_CALLBACK (loadProfileCB), NULL ); + + button = gtk_button_new_with_label ("Save"); + gtk_grid_attach (GTK_GRID (grid), button, 1, 1, 1, 1 ); + g_signal_connect (button, "clicked", G_CALLBACK (saveProfileCB), NULL ); + + button = gtk_button_new_with_label ("New"); + gtk_grid_attach (GTK_GRID (grid), button, 0, 2, 1, 1 ); + g_signal_connect (button, "clicked", G_CALLBACK (newProfileCB), NULL ); + + button = gtk_button_new_with_label ("Delete"); + gtk_grid_attach (GTK_GRID (grid), button, 1, 2, 1, 1 ); + g_signal_connect (button, "clicked", G_CALLBACK (deleteProfileCB), NULL ); + + msgLbl = gtk_label_new(""); + gtk_grid_attach (GTK_GRID (grid), msgLbl, 0, 3, 2, 1 ); + + gtk_box_pack_start (GTK_BOX (mainVbox), fourScoreChk, FALSE, TRUE, 5); + gtk_box_pack_start (GTK_BOX (mainVbox), oppositeDirChk, FALSE, TRUE, 5); + + + // create gamepad buttons + buttonFrame = gtk_frame_new ("Active Button Mappings:"); + gtk_label_set_use_markup (GTK_LABEL + (gtk_frame_get_label_widget + (GTK_FRAME (buttonFrame))), TRUE); + buttonTable = gtk_grid_new (); + gtk_container_add (GTK_CONTAINER (buttonFrame), buttonTable); + + for (int i = 0; i < 3; i++) + { + gtk_grid_insert_column (GTK_GRID (buttonTable), i); + } + gtk_grid_set_column_spacing (GTK_GRID (buttonTable), 5); + gtk_grid_set_column_homogeneous (GTK_GRID (buttonTable), TRUE); + gtk_grid_set_row_spacing (GTK_GRID (buttonTable), 3); + + for (int i = 0; i < GAMEPAD_NUM_BUTTONS; i++) + { + GtkWidget *buttonName = gtk_label_new (GamePadNames[i]); + GtkWidget *mappedKey = gtk_label_new (NULL); + GtkWidget *changeButton = gtk_toggle_button_new (); + GtkWidget *clearButton = gtk_button_new (); + char strBuf[128]; + + lbl = gtk_label_new ("State:"); + buttonState[i] = gtk_label_new (" F "); + + gtk_grid_insert_row (GTK_GRID (buttonTable), i); + + sprintf (strBuf, "%s:", GamePadNames[i]); + gtk_label_set_text (GTK_LABEL (buttonName), strBuf); + + gtk_button_set_label (GTK_BUTTON (changeButton), "Change"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (changeButton), + FALSE); + + gtk_button_set_label (GTK_BUTTON (clearButton), "Clear"); + + gtk_grid_attach (GTK_GRID (buttonTable), buttonName, 0, i, 1, 1); + gtk_grid_attach (GTK_GRID (buttonTable), mappedKey, 1, i, 1, 1); + gtk_grid_attach (GTK_GRID (buttonTable), lbl, 2, i, 1, 1); + gtk_grid_attach (GTK_GRID (buttonTable), buttonState[i], 3, i, 1, 1); + gtk_grid_attach (GTK_GRID (buttonTable), changeButton, 4, i, 1, 1); + gtk_grid_attach (GTK_GRID (buttonTable), clearButton, 5, i, 1, 1); + + g_signal_connect (changeButton, "clicked", + G_CALLBACK (configGamepadButton), + GINT_TO_POINTER (i)); + + g_signal_connect (clearButton, "clicked", + G_CALLBACK (clearGamepadButton), + GINT_TO_POINTER (i)); + + buttonMappings[i] = mappedKey; + } + + gtk_box_pack_start (GTK_BOX (mainVbox), buttonFrame, TRUE, TRUE, 5); + + g_signal_connect (win, "delete-event", G_CALLBACK (closeGamepadConfig), NULL); + g_signal_connect (win, "response", G_CALLBACK (closeGamepadConfig), NULL); + + gtk_widget_show_all (win); + + g_signal_connect (G_OBJECT (win), "key-press-event", + G_CALLBACK (convertKeypress), NULL); + g_signal_connect (G_OBJECT (win), "key-release-event", + G_CALLBACK (convertKeypress), NULL); + + buttonConfigStatus = 1; + + gamePadConfwin = win; + + loadMapList(); + + // display the button mappings for the currently selected configuration + updateCntrlrDpy(); + + g_timeout_add ( 100, timeout_callback, NULL ); + + return; +} + diff --git a/src/drivers/sdl/GamePadConf.h b/src/drivers/sdl/GamePadConf.h new file mode 100644 index 00000000..4a84e9f8 --- /dev/null +++ b/src/drivers/sdl/GamePadConf.h @@ -0,0 +1,4 @@ +// GamePadConf.h + +// creates and opens the gamepad config window (GTK) +void openGamepadConfig (void); diff --git a/src/drivers/sdl/config.cpp b/src/drivers/sdl/config.cpp index 4856cbb2..f4631980 100644 --- a/src/drivers/sdl/config.cpp +++ b/src/drivers/sdl/config.cpp @@ -102,20 +102,20 @@ LoadCPalette(const std::string &file) static void CreateDirs(const std::string &dir) { - const char *subs[8]={"fcs","snaps","gameinfo","sav","cheats","movies","cfg.d"}; + const char *subs[9]={"fcs","snaps","gameinfo","sav","cheats","movies","input"}; std::string subdir; int x; #if defined(WIN32) || defined(NEED_MINGW_HACKS) mkdir(dir.c_str()); chmod(dir.c_str(), 755); - for(x = 0; x < 6; x++) { + for(x = 0; x < 7; x++) { subdir = dir + PSS + subs[x]; mkdir(subdir.c_str()); } #else mkdir(dir.c_str(), S_IRWXU); - for(x = 0; x < 6; x++) { + for(x = 0; x < 7; x++) { subdir = dir + PSS + subs[x]; mkdir(subdir.c_str(), S_IRWXU); } @@ -199,6 +199,7 @@ InitConfig() // video controls config->addOption('f', "fullscreen", "SDL.Fullscreen", 0); + config->addOption("videoDriver", "SDL.VideoDriver", 0); // set x/y res to 0 for automatic fullscreen resolution detection (no change) config->addOption('x', "xres", "SDL.XResolution", 0); @@ -241,7 +242,7 @@ InitConfig() config->addOption("input4", "SDL.Input.3", "Gamepad.3"); // allow for input configuration - config->addOption('i', "inputcfg", "SDL.InputCfg", InputCfg); + //config->addOption('i', "inputcfg", "SDL.InputCfg", InputCfg); // display input config->addOption("inputdisplay", "SDL.InputDisplay", 0); @@ -285,8 +286,6 @@ InitConfig() //TODO implement this config->addOption("periodicsaves", "SDL.PeriodicSaves", 0); - - #ifdef _GTK char* home_dir = getenv("HOME"); // prefixed with _ because they are internal (not cli options) config->addOption("_lastopenfile", "SDL.LastOpenFile", home_dir); @@ -294,7 +293,9 @@ InitConfig() config->addOption("_lastopennsf", "SDL.LastOpenNSF", home_dir); config->addOption("_lastsavestateas", "SDL.LastSaveStateAs", home_dir); config->addOption("_lastloadlua", "SDL.LastLoadLua", ""); - #endif + + config->addOption("_useNativeFileDialog", "SDL.UseNativeFileDialog", false); + config->addOption("_useNativeMenuBar" , "SDL.UseNativeMenuBar", false); // fcm -> fm2 conversion config->addOption("fcmconvert", "SDL.FCMConvert", ""); @@ -316,10 +317,8 @@ InitConfig() prefix = buf; config->addOption(prefix + "DeviceType", DefaultGamePadDevice[i]); - config->addOption(prefix + "DeviceNum", 0); - for(unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) { - config->addOption(prefix + GamePadNames[j], DefaultGamePad[i][j]); - } + config->addOption(prefix + "DeviceGUID", ""); + config->addOption(prefix + "Profile" , ""); } // PowerPad 0 - 1 diff --git a/src/drivers/sdl/dface.h b/src/drivers/sdl/dface.h index f753f3ca..827bbfaf 100644 --- a/src/drivers/sdl/dface.h +++ b/src/drivers/sdl/dface.h @@ -18,6 +18,8 @@ void SilenceSound(int s); /* DOS and SDL */ int InitJoysticks(void); int KillJoysticks(void); +int AddJoystick( int which ); +int RemoveJoystick( int which ); uint32 *GetJSOr(void); int InitVideo(FCEUGI *gi); diff --git a/src/drivers/sdl/fceux_git_info.h b/src/drivers/sdl/fceux_git_info.h new file mode 100644 index 00000000..fd9cdb8c --- /dev/null +++ b/src/drivers/sdl/fceux_git_info.h @@ -0,0 +1,4 @@ +// fceux_git_info.h + +const char *fceu_get_git_url(void); +const char *fceu_get_git_rev(void); diff --git a/src/drivers/sdl/glxwin.cpp b/src/drivers/sdl/glxwin.cpp index 547df24f..638db86b 100644 --- a/src/drivers/sdl/glxwin.cpp +++ b/src/drivers/sdl/glxwin.cpp @@ -33,6 +33,7 @@ static GLXContext glc = NULL; static XWindowAttributes gwa; static XEvent xev; static GLint double_buffer_ena = 1; +static bool isDoubleBuffered = true; static GLuint gltexture = 0; static int spawn_new_window = 0; @@ -89,8 +90,14 @@ static void getAttrbList( GLint *buf ) int i=0; buf[i] = GLX_RGBA; i++; - buf[i] = GLX_DEPTH_SIZE; i++; - buf[i] = 24; i++; + //buf[i] = GLX_DEPTH_SIZE; i++; + //buf[i] = 24; i++; + buf[i] = GLX_RED_SIZE; i++; + buf[i] = 8; i++; + buf[i] = GLX_GREEN_SIZE; i++; + buf[i] = 8; i++; + buf[i] = GLX_BLUE_SIZE; i++; + buf[i] = 8; i++; if ( double_buffer_ena ) { @@ -258,7 +265,7 @@ static void render_image(void) //print_pixbuf(); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, - GL_RGBA, GL_UNSIGNED_BYTE, glx_shm->pixbuf ); + GL_BGRA, GL_UNSIGNED_BYTE, glx_shm->pixbuf ); glBegin(GL_QUADS); glTexCoord2f(1.0f*l/256, 1.0f*b/256); // Bottom left of picture. @@ -283,7 +290,7 @@ static void render_image(void) //glVertex2f( 1.0f, 1.0f); // Top right of target. //glEnd(); - if ( double_buffer_ena ) + if ( isDoubleBuffered ) { glXSwapBuffers( dpy, win ); } @@ -392,6 +399,7 @@ int spawn_glxwin( int flags ) //************************************************************************ int init_gtk3_GLXContext( int flags ) { + int screenNumber; GLint att[32]; XWindowAttributes xattrb; @@ -410,12 +418,20 @@ int init_gtk3_GLXContext( int flags ) printf("Error: Failed to obtain gdkWindow Handle for evbox widget\n"); return -1; } + if (!GDK_IS_X11_WINDOW (gdkWin)) + { + printf("Error: GDK Window is not of X11 Type\n"); + return -1; + } + GdkDisplay *gdk_display = gdk_window_get_display (gdkWin); + GdkScreen *gdk_screen = gdk_window_get_screen (gdkWin); + screenNumber = gdk_x11_screen_get_screen_number (gdk_screen); + dpy = GDK_DISPLAY_XDISPLAY( gdk_display ); + win = GDK_WINDOW_XID( gdkWin ); root = GDK_ROOT_WINDOW(); - dpy = gdk_x11_get_default_xdisplay(); - if ( dpy == NULL ) { printf("Error: Failed to obtain X Display Handle for evbox widget\n"); @@ -431,16 +447,65 @@ int init_gtk3_GLXContext( int flags ) //printf("XWinSize: (%i x %i) \n", xattrb.width, xattrb.height ); //printf("XWinDepth: %i \n", xattrb.depth ); //printf("XWinVisual: %p \n", xattrb.visual ); + printf("XScreenNumber: %i \n", screenNumber ); - vi = glXChooseVisual(dpy, 0, att); + vi = glXChooseVisual(dpy, screenNumber, att); if (vi == NULL) { - printf("\n\tno appropriate visual found\n\n"); + printf("\n\tERROR: GLX No appropriate visual found\n\n"); exit(0); } - else { - printf("\n\tvisual %p selected\n", (void *)vi->visualid); /* %p creates hexadecimal output like in glxinfo */ + else + { + int val; + printf("\n\tGLX visual %p selected\n", (void *)vi->visualid); /* %p creates hexadecimal output like in glxinfo */ + + if ( glXGetConfig( dpy, vi, GLX_RGBA, &val ) == 0 ) + { + printf("GLX_RGBA: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_USE_GL, &val ) == 0 ) + { + printf("GLX_USE_GL: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_LEVEL, &val ) == 0 ) + { + printf("GLX_LEVEL: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_BUFFER_SIZE, &val ) == 0 ) + { + printf("GLX_BUFFER_SIZE: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_DOUBLEBUFFER, &val ) == 0 ) + { + isDoubleBuffered = val ? true : false; + printf("GLX_DOUBLEBUFFER: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_RED_SIZE, &val ) == 0 ) + { + printf("GLX_RED_SIZE: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_GREEN_SIZE, &val ) == 0 ) + { + printf("GLX_GREEN_SIZE: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_BLUE_SIZE, &val ) == 0 ) + { + printf("GLX_BLUE_SIZE: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_ALPHA_SIZE, &val ) == 0 ) + { + printf("GLX_ALPHA_SIZE: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_DEPTH_SIZE, &val ) == 0 ) + { + printf("GLX_DEPTH_SIZE: %i \n", val ); + } + if ( glXGetConfig( dpy, vi, GLX_STENCIL_SIZE, &val ) == 0 ) + { + printf("GLX_STENCIL_SIZE: %i \n", val ); + } } if ( glc == NULL ) @@ -449,11 +514,20 @@ int init_gtk3_GLXContext( int flags ) if ( glc == NULL ) { - printf("Error: glXCreateContext Failed\n"); + printf("ERROR: glXCreateContext Failed\n"); + } + else + { + printf("glXIsDirect: %i \n", glXIsDirect( dpy, glc ) ); } } XFree(vi); vi = NULL; + if ( glc == NULL ) + { + return -1; + } + glXMakeCurrent(dpy, win, glc); genTextures( flags & GLXWIN_PIXEL_LINEAR_FILTER ? 1 : 0 ); diff --git a/src/drivers/sdl/gui.cpp b/src/drivers/sdl/gui.cpp index fe82a062..4b7c2c03 100644 --- a/src/drivers/sdl/gui.cpp +++ b/src/drivers/sdl/gui.cpp @@ -19,6 +19,8 @@ #include "memview.h" #include "ramwatch.h" #include "debugger.h" +#include "sdl-joystick.h" +#include "fceux_git_info.h" #ifdef _S9XLUA_H #include "../../fceulua.h" @@ -50,6 +52,7 @@ #include #include "glxwin.h" +#include "sdl-video.h" // Fix compliation errors for older version of GTK (Ubuntu 10.04 LTS) #if GTK_MINOR_VERSION < 24 && GTK_MAJOR_VERSION == 2 @@ -67,20 +70,16 @@ void toggleSound (GtkWidget * check, gpointer data); void loadGame (void); void closeGame (void); extern Config *g_config; +extern bool gtk_gui_run; GtkWidget *MainWindow = NULL; GtkWidget *evbox = NULL; -GtkWidget *padNoCombo = NULL; -GtkWidget *configNoCombo = NULL; -GtkWidget *buttonMappings[10] = { NULL }; static GtkWidget *Menubar = NULL; static GtkRadioMenuItem *stateSlot[10] = { NULL }; bool gtkIsStarted = false; bool menuTogglingEnabled = false; -static int buttonConfigStatus = 0; -static char useCairoDraw = 0; -static int drawAreaGL = 0; +enum videoDriver_t videoDriver = VIDEO_NONE; unsigned int gtk_draw_area_width = NES_WIDTH; unsigned int gtk_draw_area_height = NES_HEIGHT; static GtkTreeStore *hotkey_store = NULL; @@ -90,8 +89,6 @@ static int *cairo_pix_remapper = NULL; static int numRendLines = 0; static void cairo_recalc_mapper(void); -static gint convertKeypress (GtkWidget * grab, GdkEventKey * event, gpointer user_data); - // check to see if a particular GTK version is available // 2.24 is required for most of the dialogs -- ie: checkGTKVersion(2,24); bool checkGTKVersion (int major_required, int minor_required) @@ -128,66 +125,63 @@ void setCheckbox (GtkWidget * w, const char *configName) } // This function configures a single button on a gamepad -int configGamepadButton (GtkButton * button, gpointer p) -{ - gint x = ((gint) (glong) (p)); - //gint x = GPOINTER_TO_INT(p); - int padNo = - atoi (gtk_combo_box_text_get_active_text - (GTK_COMBO_BOX_TEXT (padNoCombo))) - 1; - int configNo = - atoi (gtk_combo_box_text_get_active_text - (GTK_COMBO_BOX_TEXT (configNoCombo))) - 1; - - char buf[256]; - std::string prefix; - - // only configure when the "Change" button is pressed in, not when it is unpressed - if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) - return 0; - - buttonConfigStatus = 2; - - ButtonConfigBegin (); - - snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%d.", padNo); - prefix = buf; - DWaitButton (NULL, &GamePadConfig[padNo][x], configNo, &buttonConfigStatus ); - - g_config->setOption (prefix + GamePadNames[x], - GamePadConfig[padNo][x].ButtonNum[configNo]); - - if (GamePadConfig[padNo][x].ButtType[0] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (GamePadConfig[padNo][x].ButtType[0] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - GamePadConfig[padNo][x].DeviceNum[configNo]); - - snprintf (buf, sizeof (buf), "%s", - ButtonName (&GamePadConfig[padNo][x], configNo)); - - if ( buttonMappings[x] != NULL ) - { - gtk_label_set_markup (GTK_LABEL (buttonMappings[x]), buf); - } - - ButtonConfigEnd (); - - buttonConfigStatus = 1; - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); - - return 0; -} +//int configGamepadButton (GtkButton * button, gpointer p) +//{ +// gint x = ((gint) (glong) (p)); +// //gint x = GPOINTER_TO_INT(p); +// int padNo = +// atoi (gtk_combo_box_text_get_active_text +// (GTK_COMBO_BOX_TEXT (padNoCombo))) - 1; +// +// char buf[256]; +// std::string prefix; +// +// // only configure when the "Change" button is pressed in, not when it is unpressed +// if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) +// return 0; +// +// buttonConfigStatus = 2; +// +// ButtonConfigBegin (); +// +// snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%d.", padNo); +// prefix = buf; +// DWaitButton (NULL, &GamePad[padNo].bmap[x], &buttonConfigStatus ); +// +//// g_config->setOption (prefix + GamePadNames[x], +//// GamePadConfig[padNo][x].ButtonNum[configNo]); +//// +//// if (GamePadConfig[padNo][x].ButtType[0] == BUTTC_KEYBOARD) +//// { +//// g_config->setOption (prefix + "DeviceType", "Keyboard"); +//// } +//// else if (GamePadConfig[padNo][x].ButtType[0] == BUTTC_JOYSTICK) +//// { +//// g_config->setOption (prefix + "DeviceType", "Joystick"); +//// } +//// else +//// { +//// g_config->setOption (prefix + "DeviceType", "Unknown"); +//// } +//// g_config->setOption (prefix + "DeviceNum", +//// GamePadConfig[padNo][x].DeviceNum[configNo]); +// +// snprintf (buf, sizeof (buf), "%s", +// ButtonName (&GamePad[padNo].bmap[x])); +// +// if ( buttonMappings[x] != NULL ) +// { +// gtk_label_set_markup (GTK_LABEL (buttonMappings[x]), buf); +// } +// +// ButtonConfigEnd (); +// +// buttonConfigStatus = 1; +// +// gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); +// +// return 0; +//} void resetVideo (void) { @@ -675,228 +669,291 @@ void openHotkeyConfig (void) } -//GtkWidget *typeCombo; - -// TODO: finish this -//int setInputDevice (GtkWidget * w, gpointer p) +//static void selInputDevice (GtkWidget * w, gpointer p) //{ -// std::string s = "SDL.Input."; -// s = s + (char *) p; -// printf ("setInputDevice: %s", s.c_str ()); -// g_config->setOption (s, -// gtk_combo_box_text_get_active_text -// (GTK_COMBO_BOX_TEXT (typeCombo))); -// g_config->save (); +// //std::string s = "SDL.Input."; +// int padNo = 0, devIdx = -1; +// const char *devTxt; +// jsDev_t *js; // -// return 1; +// if ( (padNoCombo == NULL) ) +// { +// return; +// } +// padNo = +// atoi (gtk_combo_box_text_get_active_text +// (GTK_COMBO_BOX_TEXT (padNoCombo))) - 1; +// +// devTxt = gtk_combo_box_text_get_active_text ( GTK_COMBO_BOX_TEXT(w) ); +// +// if ( isdigit( devTxt[0] ) ) +// { +// devIdx = atoi( devTxt ); +// } +// printf ("setInputDevice: %s %i", devTxt, devIdx ); +// +// +// //g_config->setOption (s, +// // gtk_combo_box_text_get_active_text +// // (GTK_COMBO_BOX_TEXT (typeCombo))); +// //g_config->save (); +// +// return; +//} +// +//static void updateGamepadConfig (GtkWidget * w, gpointer p) +//{ +// int i; +// char strBuf[128]; +// +// if ( (padNoCombo == NULL) ) +// { +// return; +// } +// int padNo = +// atoi (gtk_combo_box_text_get_active_text +// (GTK_COMBO_BOX_TEXT (padNoCombo))) - 1; +// +// for (i = 0; i < 10; i++) +// { +// GtkWidget *mappedKey = buttonMappings[i]; +// if (GamePad[padNo].bmap[i].ButtType == BUTTC_KEYBOARD) +// { +// snprintf (strBuf, sizeof (strBuf), "%s", +// SDL_GetKeyName (GamePad[padNo].bmap[i]. +// ButtonNum)); +// } +// else +// sprintf (strBuf, "%s", ButtonName( &GamePad[padNo].bmap[i] ) ); +// +// if ( mappedKey != NULL ) +// { +// gtk_label_set_text (GTK_LABEL (mappedKey), strBuf); +// gtk_label_set_use_markup (GTK_LABEL (mappedKey), TRUE); +// } +// } +//} +// +//static void closeGamepadConfig (GtkWidget * w, GdkEvent * e, gpointer p) +//{ +// gtk_widget_destroy (w); +// +// padNoCombo = NULL; +// +// for (int i = 0; i < 10; i++) +// { +// buttonMappings[i] = NULL; +// } +// buttonConfigStatus = 0; +//} +// +//// creates and opens the gamepad config window (requires GTK 2.24) +//void openGamepadConfig (void) +//{ +// int portNum = 0; +// GtkWidget *win; +// GtkWidget *vbox; +// GtkWidget *hboxPadNo; +// GtkWidget *padNoLabel; +// GtkWidget* devSelLabel, *devSelHbox; +// GtkWidget *fourScoreChk; +// GtkWidget *oppositeDirChk; +// GtkWidget *buttonFrame; +// GtkWidget *buttonTable; +// char stmp[256]; +// +// win = gtk_dialog_new_with_buttons ("Controller Configuration", +// GTK_WINDOW (MainWindow), +// (GtkDialogFlags) +// (GTK_DIALOG_DESTROY_WITH_PARENT), +// "_Close", GTK_RESPONSE_OK, NULL); +// gtk_window_set_title (GTK_WINDOW (win), "Controller Configuration"); +// gtk_window_set_icon_name (GTK_WINDOW (win), "input-gaming"); +// gtk_widget_set_size_request (win, 350, 500); +// +// vbox = gtk_dialog_get_content_area (GTK_DIALOG (win)); +// gtk_box_set_homogeneous (GTK_BOX (vbox), FALSE); +// +// hboxPadNo = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); +// padNoLabel = gtk_label_new ("Port:"); +// //configNoLabel = gtk_label_new("Config Number:"); +// fourScoreChk = gtk_check_button_new_with_label ("Enable Four Score"); +// oppositeDirChk = +// gtk_check_button_new_with_label ("Allow Up+Down / Left+Right"); +// +// //typeCombo = gtk_combo_box_text_new (); +// //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), +// // "gamepad"); +// //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), +// // "zapper"); +// //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), +// // "powerpad.0"); +// //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), +// // "powerpad.1"); +// //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), +// // "arkanoid"); +// +// //gtk_combo_box_set_active (GTK_COMBO_BOX (typeCombo), 0); +// +// +// padNoCombo = gtk_combo_box_text_new (); +// gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "1"); +// gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "2"); +// gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "3"); +// gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "4"); +// gtk_combo_box_set_active (GTK_COMBO_BOX (padNoCombo), 0); +// g_signal_connect (padNoCombo, "changed", +// G_CALLBACK (updateGamepadConfig), NULL); +// +// devSelHbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); +// devSelLabel = gtk_label_new ("Device:"); +// devSelCombo = gtk_combo_box_text_new (); +// gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (devSelCombo), "Keyboard"); +// +// gtk_combo_box_set_active (GTK_COMBO_BOX (devSelCombo), 0); +// +// for (int i=0; iisConnected() ) +// { +// sprintf( stmp, "%i: %s", i, js->getName() ); +// gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT (devSelCombo), stmp ); +// } +// } +// } +// gtk_combo_box_set_active (GTK_COMBO_BOX (devSelCombo), 0); +// +// { +// GtkTreeModel *treeModel = gtk_combo_box_get_model( GTK_COMBO_BOX (devSelCombo) ); +// GtkTreeIter iter; +// gboolean iterValid; +// +// iterValid = gtk_tree_model_get_iter_first( treeModel, &iter ); +// +// while ( iterValid ) +// { +// GValue value; +// +// memset( &value, 0, sizeof(value)); +// +// gtk_tree_model_get_value (treeModel, &iter, 0, &value ); +// +// if ( G_IS_VALUE(&value) ) +// { +// if ( G_VALUE_TYPE(&value) == G_TYPE_STRING ) +// { +// int devIdx = -1; +// const char *s = (const char *)g_value_peek_pointer( &value ); +// +// if ( isdigit( s[0] ) ) +// { +// devIdx = atoi(s); +// } +// if ( (devIdx >= 0) && (devIdx == GamePad[portNum].getDeviceIndex() ) ) +// { +// gtk_combo_box_set_active_iter (GTK_COMBO_BOX (devSelCombo), &iter); +// } +// } +// } +// g_value_unset(&value); +// +// iterValid = gtk_tree_model_iter_next( treeModel, &iter ); +// } +// } +// g_signal_connect (devSelCombo, "changed", G_CALLBACK (selInputDevice), NULL ); +// +// //g_signal_connect (typeCombo, "changed", G_CALLBACK (setInputDevice), +// // gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT +// // (typeCombo))); +// +// setCheckbox (fourScoreChk, "SDL.FourScore"); +// g_signal_connect (fourScoreChk, "clicked", G_CALLBACK (toggleOption), +// (gpointer) "SDL.FourScore"); +// setCheckbox (oppositeDirChk, "SDL.Input.EnableOppositeDirectionals"); +// g_signal_connect (oppositeDirChk, "clicked", G_CALLBACK (toggleOption), +// (gpointer) "SDL.Input.EnableOppositeDirectionals"); +// +// +// gtk_box_pack_start (GTK_BOX (hboxPadNo), padNoLabel, TRUE, TRUE, 5); +// gtk_box_pack_start (GTK_BOX (hboxPadNo), padNoCombo, TRUE, TRUE, 5); +// gtk_box_pack_start (GTK_BOX (vbox), hboxPadNo, FALSE, TRUE, 5); +// //gtk_box_pack_start_defaults(GTK_BOX(vbox), typeCombo); +// +// gtk_box_pack_start (GTK_BOX (devSelHbox), devSelLabel, TRUE, TRUE, 5); +// gtk_box_pack_start (GTK_BOX (devSelHbox), devSelCombo, TRUE, TRUE, 5); +// gtk_box_pack_start (GTK_BOX (vbox), devSelHbox, FALSE, TRUE, 5); +// +// gtk_box_pack_start (GTK_BOX (vbox), fourScoreChk, FALSE, TRUE, 5); +// gtk_box_pack_start (GTK_BOX (vbox), oppositeDirChk, FALSE, TRUE, 5); +// +// +// // create gamepad buttons +// buttonFrame = gtk_frame_new ("Buttons"); +// gtk_label_set_use_markup (GTK_LABEL +// (gtk_frame_get_label_widget +// (GTK_FRAME (buttonFrame))), TRUE); +// buttonTable = gtk_grid_new (); +// gtk_container_add (GTK_CONTAINER (buttonFrame), buttonTable); +// +// for (int i = 0; i < 3; i++) +// { +// gtk_grid_insert_column (GTK_GRID (buttonTable), i); +// } +// gtk_grid_set_column_spacing (GTK_GRID (buttonTable), 5); +// gtk_grid_set_column_homogeneous (GTK_GRID (buttonTable), TRUE); +// gtk_grid_set_row_spacing (GTK_GRID (buttonTable), 3); +// +// for (int i = 0; i < 10; i++) +// { +// GtkWidget *buttonName = gtk_label_new (GamePadNames[i]); +// GtkWidget *mappedKey = gtk_label_new (NULL); +// GtkWidget *changeButton = gtk_toggle_button_new (); +// char strBuf[128]; +// +// gtk_grid_insert_row (GTK_GRID (buttonTable), i); +// +// sprintf (strBuf, "%s:", GamePadNames[i]); +// gtk_label_set_text (GTK_LABEL (buttonName), strBuf); +// +// gtk_button_set_label (GTK_BUTTON (changeButton), "Change"); +// gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (changeButton), +// FALSE); +// +// gtk_grid_attach (GTK_GRID (buttonTable), buttonName, 0, i, 1, +// 1); +// gtk_grid_attach (GTK_GRID (buttonTable), mappedKey, 1, i, 1, 1); +// gtk_grid_attach (GTK_GRID (buttonTable), changeButton, 2, i, 1, +// 1); +// +// g_signal_connect (changeButton, "clicked", +// G_CALLBACK (configGamepadButton), +// GINT_TO_POINTER (i)); +// buttonMappings[i] = mappedKey; +// } +// +// // display the button mappings for the currently selected configuration +// updateGamepadConfig (NULL, NULL); +// +// gtk_box_pack_start (GTK_BOX (vbox), buttonFrame, TRUE, TRUE, 5); +// +// g_signal_connect (win, "delete-event", G_CALLBACK (closeGamepadConfig), NULL); +// g_signal_connect (win, "response", G_CALLBACK (closeGamepadConfig), NULL); +// +// gtk_widget_show_all (win); +// +// g_signal_connect (G_OBJECT (win), "key-press-event", +// G_CALLBACK (convertKeypress), NULL); +// g_signal_connect (G_OBJECT (win), "key-release-event", +// G_CALLBACK (convertKeypress), NULL); +// +// buttonConfigStatus = 1; +// +// return; //} - -void updateGamepadConfig (GtkWidget * w, gpointer p) -{ - int i; - char strBuf[128]; - - if ( (padNoCombo == NULL) || (configNoCombo == NULL) ) - { - return; - } - int padNo = - atoi (gtk_combo_box_text_get_active_text - (GTK_COMBO_BOX_TEXT (padNoCombo))) - 1; - int configNo = - atoi (gtk_combo_box_text_get_active_text - (GTK_COMBO_BOX_TEXT (configNoCombo))) - 1; - - for (i = 0; i < 10; i++) - { - GtkWidget *mappedKey = buttonMappings[i]; - if (GamePadConfig[padNo][i].ButtType[configNo] == BUTTC_KEYBOARD) - { - snprintf (strBuf, sizeof (strBuf), "%s", - SDL_GetKeyName (GamePadConfig[padNo][i]. - ButtonNum[configNo])); - } - else - sprintf (strBuf, "%s", ButtonName( &GamePadConfig[padNo][i], configNo ) ); - - if ( mappedKey != NULL ) - { - gtk_label_set_text (GTK_LABEL (mappedKey), strBuf); - gtk_label_set_use_markup (GTK_LABEL (mappedKey), TRUE); - } - } -} - -static void closeGamepadConfig (GtkWidget * w, GdkEvent * e, gpointer p) -{ - gtk_widget_destroy (w); - - padNoCombo = NULL; - configNoCombo = NULL; - - for (int i = 0; i < 10; i++) - { - buttonMappings[i] = NULL; - } - buttonConfigStatus = 0; -} - -// creates and opens the gamepad config window (requires GTK 2.24) -void openGamepadConfig (void) -{ - GtkWidget *win; - GtkWidget *vbox; - GtkWidget *hboxPadNo; - GtkWidget *padNoLabel; - //GtkWidget* configNoLabel; - GtkWidget *fourScoreChk; - GtkWidget *oppositeDirChk; - GtkWidget *buttonFrame; - GtkWidget *buttonTable; - - win = gtk_dialog_new_with_buttons ("Controller Configuration", - GTK_WINDOW (MainWindow), - (GtkDialogFlags) - (GTK_DIALOG_DESTROY_WITH_PARENT), - "_Close", GTK_RESPONSE_OK, NULL); - gtk_window_set_title (GTK_WINDOW (win), "Controller Configuration"); - gtk_window_set_icon_name (GTK_WINDOW (win), "input-gaming"); - gtk_widget_set_size_request (win, 350, 500); - - vbox = gtk_dialog_get_content_area (GTK_DIALOG (win)); - gtk_box_set_homogeneous (GTK_BOX (vbox), FALSE); - - hboxPadNo = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - padNoLabel = gtk_label_new ("Port:"); - //configNoLabel = gtk_label_new("Config Number:"); - fourScoreChk = gtk_check_button_new_with_label ("Enable Four Score"); - oppositeDirChk = - gtk_check_button_new_with_label ("Allow Up+Down / Left+Right"); - - //typeCombo = gtk_combo_box_text_new (); - //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), - // "gamepad"); - //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), - // "zapper"); - //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), - // "powerpad.0"); - //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), - // "powerpad.1"); - //gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (typeCombo), - // "arkanoid"); - - //gtk_combo_box_set_active (GTK_COMBO_BOX (typeCombo), 0); - - - padNoCombo = gtk_combo_box_text_new (); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "1"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "2"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "3"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (padNoCombo), "4"); - gtk_combo_box_set_active (GTK_COMBO_BOX (padNoCombo), 0); - g_signal_connect (padNoCombo, "changed", - G_CALLBACK (updateGamepadConfig), NULL); - - configNoCombo = gtk_combo_box_text_new (); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (configNoCombo), - "1"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (configNoCombo), - "2"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (configNoCombo), - "3"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (configNoCombo), - "4"); - gtk_combo_box_set_active (GTK_COMBO_BOX (configNoCombo), 0); - g_signal_connect (padNoCombo, "changed", - G_CALLBACK (updateGamepadConfig), NULL); - - - //g_signal_connect (typeCombo, "changed", G_CALLBACK (setInputDevice), - // gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT - // (typeCombo))); - - setCheckbox (fourScoreChk, "SDL.FourScore"); - g_signal_connect (fourScoreChk, "clicked", G_CALLBACK (toggleOption), - (gpointer) "SDL.FourScore"); - setCheckbox (oppositeDirChk, "SDL.Input.EnableOppositeDirectionals"); - g_signal_connect (oppositeDirChk, "clicked", G_CALLBACK (toggleOption), - (gpointer) "SDL.Input.EnableOppositeDirectionals"); - - - gtk_box_pack_start (GTK_BOX (hboxPadNo), padNoLabel, TRUE, TRUE, 5); - gtk_box_pack_start (GTK_BOX (hboxPadNo), padNoCombo, TRUE, TRUE, 5); - //gtk_box_pack_start(GTK_BOX(hboxPadNo), configNoLabel, TRUE, TRUE, 5); - //gtk_box_pack_start(GTK_BOX(hboxPadNo), configNoCombo, TRUE, TRUE, 5); - gtk_box_pack_start (GTK_BOX (vbox), hboxPadNo, FALSE, TRUE, 5); - //gtk_box_pack_start_defaults(GTK_BOX(vbox), typeCombo); - - gtk_box_pack_start (GTK_BOX (vbox), fourScoreChk, FALSE, TRUE, 5); - gtk_box_pack_start (GTK_BOX (vbox), oppositeDirChk, FALSE, TRUE, 5); - - - // create gamepad buttons - buttonFrame = gtk_frame_new ("Buttons"); - gtk_label_set_use_markup (GTK_LABEL - (gtk_frame_get_label_widget - (GTK_FRAME (buttonFrame))), TRUE); - buttonTable = gtk_grid_new (); - gtk_container_add (GTK_CONTAINER (buttonFrame), buttonTable); - - for (int i = 0; i < 3; i++) - { - gtk_grid_insert_column (GTK_GRID (buttonTable), i); - } - gtk_grid_set_column_spacing (GTK_GRID (buttonTable), 5); - gtk_grid_set_column_homogeneous (GTK_GRID (buttonTable), TRUE); - gtk_grid_set_row_spacing (GTK_GRID (buttonTable), 3); - - for (int i = 0; i < 10; i++) - { - GtkWidget *buttonName = gtk_label_new (GamePadNames[i]); - GtkWidget *mappedKey = gtk_label_new (NULL); - GtkWidget *changeButton = gtk_toggle_button_new (); - char strBuf[128]; - - gtk_grid_insert_row (GTK_GRID (buttonTable), i); - - sprintf (strBuf, "%s:", GamePadNames[i]); - gtk_label_set_text (GTK_LABEL (buttonName), strBuf); - - gtk_button_set_label (GTK_BUTTON (changeButton), "Change"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (changeButton), - FALSE); - - gtk_grid_attach (GTK_GRID (buttonTable), buttonName, 0, i, 1, - 1); - gtk_grid_attach (GTK_GRID (buttonTable), mappedKey, 1, i, 1, 1); - gtk_grid_attach (GTK_GRID (buttonTable), changeButton, 2, i, 1, - 1); - - g_signal_connect (changeButton, "clicked", - G_CALLBACK (configGamepadButton), - GINT_TO_POINTER (i)); - buttonMappings[i] = mappedKey; - } - - // display the button mappings for the currently selected configuration - updateGamepadConfig (NULL, NULL); - - gtk_box_pack_start (GTK_BOX (vbox), buttonFrame, TRUE, TRUE, 5); - - g_signal_connect (win, "delete-event", G_CALLBACK (closeGamepadConfig), NULL); - g_signal_connect (win, "response", G_CALLBACK (closeGamepadConfig), NULL); - - gtk_widget_show_all (win); - - g_signal_connect (G_OBJECT (win), "key-press-event", - G_CALLBACK (convertKeypress), NULL); - g_signal_connect (G_OBJECT (win), "key-release-event", - G_CALLBACK (convertKeypress), NULL); - - buttonConfigStatus = 1; - - return; -} int setBufSize (GtkWidget * w, gpointer p) { @@ -953,45 +1010,17 @@ void resizeGtkWindow (void) return; } -void setScaler (GtkWidget * w, gpointer p) +static void setVideoDriver (GtkWidget * w, gpointer p) { - int scaler = gtk_combo_box_get_active (GTK_COMBO_BOX (w)); - int opengl; - g_config->getOption ("SDL.OpenGL", &opengl); - if (opengl && scaler) - { - FCEUD_PrintError ("Scalers not supported in OpenGL mode."); - gtk_combo_box_set_active (GTK_COMBO_BOX (w), 0); - return; - } + int vdSel = gtk_combo_box_get_active (GTK_COMBO_BOX (w)); - g_config->setOption ("SDL.SpecialFilter", scaler); - - // 1=hq2x 2=Scale2x 3=NTSC2x 4=hq3x 5=Scale3x 6=Prescale2x 7=Prescale3x 8=Prescale4x 9=pal - switch (scaler) - { - case 4: // hq3x - case 5: // scale3x - case 7: // prescale3x - g_config->setOption ("SDL.XScale", 3.0); - g_config->setOption ("SDL.YScale", 3.0); - resizeGtkWindow (); - break; - case 8: // prescale4x - g_config->setOption ("SDL.XScale", 4.0); - g_config->setOption ("SDL.YScale", 4.0); - break; - default: - g_config->setOption ("SDL.XScale", 2.0); - g_config->setOption ("SDL.YScale", 2.0); - resizeGtkWindow (); - break; - } + init_gui_video( (videoDriver_t)vdSel ); + g_config->setOption ("SDL.VideoDriver", videoDriver); g_config->save (); } -void setRegion (GtkWidget * w, gpointer p) +static void setRegion (GtkWidget * w, gpointer p) { int region = gtk_combo_box_get_active (GTK_COMBO_BOX (w)); g_config->setOption ("SDL.PAL", region); @@ -1001,7 +1030,7 @@ void setRegion (GtkWidget * w, gpointer p) } -int setXscale (GtkWidget * w, gpointer p) +static int setXscale (GtkWidget * w, gpointer p) { double v = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w)); g_config->setOption ("SDL.XScale", v); @@ -1010,7 +1039,7 @@ int setXscale (GtkWidget * w, gpointer p) return 0; } -int setYscale (GtkWidget * w, gpointer p) +static int setYscale (GtkWidget * w, gpointer p) { double v = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w)); g_config->setOption ("SDL.YScale", v); @@ -1019,26 +1048,7 @@ int setYscale (GtkWidget * w, gpointer p) return 0; } -#ifdef OPENGL -void setGl (GtkWidget * w, gpointer p) -{ - int scaler; - int opengl = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); - g_config->getOption ("SDL.SpecialFilter", &scaler); - if (scaler && opengl) - { - FCEUD_PrintError ("Scalers not supported in OpenGL mode."); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), 0); - return; - } - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) - g_config->setOption ("SDL.OpenGL", 1); - else - g_config->setOption ("SDL.OpenGL", 0); - g_config->save (); -} - -void setDoubleBuffering (GtkWidget * w, gpointer p) +static void setDoubleBuffering (GtkWidget * w, gpointer p) { if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))) g_config->setOption ("SDL.DoubleBuffering", 1); @@ -1046,7 +1056,6 @@ void setDoubleBuffering (GtkWidget * w, gpointer p) g_config->setOption ("SDL.DoubleBuffering", 0); g_config->save (); } -#endif void openVideoConfig (void) { @@ -1055,8 +1064,7 @@ void openVideoConfig (void) GtkWidget *lbl; GtkWidget *hbox1; GtkWidget *scalerLbl; - GtkWidget *scalerCombo; - GtkWidget *glChk; + GtkWidget *DriverCombo; GtkWidget *linearChk; GtkWidget *dbChk; GtkWidget *palHbox; @@ -1090,42 +1098,21 @@ void openVideoConfig (void) // scalar widgets hbox1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); - scalerLbl = gtk_label_new ("Special Scaler: "); - scalerCombo = gtk_combo_box_text_new (); + scalerLbl = gtk_label_new ("Video Driver: "); + DriverCombo = gtk_combo_box_text_new (); // -Video Modes Tag- - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (scalerCombo), - "none"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (scalerCombo), - "hq2x"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (scalerCombo), - "scale2x"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (scalerCombo), - "NTSC 2x"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (scalerCombo), - "hq3x"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (scalerCombo), - "scale3x"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (scalerCombo), - "prescale2x"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (scalerCombo), - "prescale3x"); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (scalerCombo), - "prescale4x"); - //gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(scalerCombo), "pal"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (DriverCombo), "OpenGL (GLX)"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (DriverCombo), "SDL"); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (DriverCombo), "Cairo"); // sync with cfg int buf; - g_config->getOption ("SDL.SpecialFilter", &buf); - gtk_combo_box_set_active (GTK_COMBO_BOX (scalerCombo), buf); + g_config->getOption ("SDL.VideoDriver", &buf); + gtk_combo_box_set_active (GTK_COMBO_BOX (DriverCombo), buf); - g_signal_connect (scalerCombo, "changed", G_CALLBACK (setScaler), NULL); + g_signal_connect (DriverCombo, "changed", G_CALLBACK (setVideoDriver), NULL); gtk_box_pack_start (GTK_BOX (hbox1), scalerLbl, FALSE, FALSE, 5); - gtk_box_pack_start (GTK_BOX (hbox1), scalerCombo, FALSE, FALSE, 5); -#ifdef OPENGL - // openGL check - glChk = gtk_check_button_new_with_label ("Enable OpenGL"); - g_signal_connect (glChk, "clicked", G_CALLBACK (setGl), NULL); - setCheckbox (glChk, "SDL.OpenGL"); + gtk_box_pack_start (GTK_BOX (hbox1), DriverCombo, FALSE, FALSE, 5); // openGL linear filter check linearChk = @@ -1139,7 +1126,6 @@ void openVideoConfig (void) g_signal_connect (dbChk, "clicked", G_CALLBACK (setDoubleBuffering), NULL); setCheckbox (dbChk, "SDL.DoubleBuffering"); -#endif // Region (NTSC/PAL/Dendy) palHbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); @@ -1216,11 +1202,10 @@ void openVideoConfig (void) gtk_box_pack_start (GTK_BOX (vbox), lbl, FALSE, FALSE, 5); gtk_box_pack_start (GTK_BOX (vbox), hbox1, FALSE, FALSE, 5); -#ifdef OPENGL - gtk_box_pack_start (GTK_BOX (vbox), glChk, FALSE, FALSE, 5); +//#ifdef OPENGL gtk_box_pack_start (GTK_BOX (vbox), linearChk, FALSE, FALSE, 5); gtk_box_pack_start (GTK_BOX (vbox), dbChk, FALSE, FALSE, 5); -#endif +//#endif gtk_box_pack_start (GTK_BOX (vbox), palHbox, FALSE, FALSE, 5); gtk_box_pack_start (GTK_BOX (vbox), ppuChk, FALSE, FALSE, 5); #ifdef FRAMESKIP @@ -1450,27 +1435,59 @@ void openSoundConfig (void) return; } -void quit (void) +static void mainMenuQuitCB( + GtkMenuItem *menuitem, + gpointer user_data) { - // manually flush GTK event queue - while (gtk_events_pending ()) - gtk_main_iteration_do (FALSE); + printf("Main Menu Quit\n"); + // Set gui run flag to false to allow main gui loop + // to exit normally. + gtk_gui_run = false; - // this is not neccesary to be explicitly called - // it raises a GTK-Critical when its called - //gtk_main_quit(); - FCEUI_CloseGame (); - FCEUI_Kill (); - // LoadGame() checks for an IP and if it finds one begins a network session - // clear the NetworkIP field so this doesn't happen unintentionally - g_config->setOption ("SDL.NetworkIP", ""); - g_config->save (); - SDL_Quit (); - exit (0); +// // manually flush GTK event queue +// while (gtk_events_pending ()) +// gtk_main_iteration_do (FALSE); +// +// // this is not neccesary to be explicitly called +// // it raises a GTK-Critical when its called +// //gtk_main_quit(); +// FCEUI_CloseGame (); +// FCEUI_Kill (); +// // LoadGame() checks for an IP and if it finds one begins a network session +// // clear the NetworkIP field so this doesn't happen unintentionally +// g_config->setOption ("SDL.NetworkIP", ""); +// g_config->save (); +// SDL_Quit (); +// exit (0); +} + +static gboolean deleteMainWindowCB( + GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + printf("Delete Main Window Requested...\n"); + + gtk_gui_run = false; + + return(TRUE); +} + +static gboolean destroyMainWindowCB( + GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + printf("Destroy Main Window\n"); + + gtk_gui_run = false; + + return(FALSE); } const char *Authors[] = { "Linux/SDL Developers:", + " mjbudd77", " Lukas Sabota //punkrockguy318", " Soules", " Bryan Cain", " radsaq", " Shinydoofy", "FceuX 2.0 Developers:", @@ -1491,11 +1508,16 @@ const char *Authors[] = { void openAbout (void) { + char versionString[512]; + GdkPixbuf *logo = gdk_pixbuf_new_from_xpm_data (icon_xpm); + sprintf( versionString, "%s\ngit URL: %s\ngit Rev: %s", + FCEU_VERSION_STRING, fceu_get_git_url(), fceu_get_git_rev() ); + gtk_show_about_dialog (GTK_WINDOW (MainWindow), "program-name", "fceuX", - "version", FCEU_VERSION_STRING, + "version", versionString, "copyright", "© 2016 FceuX development team", "license", "GPL-2; See COPYING", //"license-type", GTK_LICENSE_GPL_2_0, @@ -2374,7 +2396,7 @@ unsigned int GDKToSDLKeyval (int gdk_key) // Function adapted from Gens/GS (source/gens/input/input_sdl.c) -static gboolean convertKeypress (GtkWidget * grab, GdkEventKey * event, +gboolean convertKeypress (GtkWidget * grab, GdkEventKey * event, gpointer user_data) { SDL_Event sdlev; @@ -2607,7 +2629,7 @@ static GtkWidget *CreateMenubar (GtkWidget * window) //-File --> Quit ------------------ item = gtk_menu_item_new_with_label ("Quit"); - g_signal_connect (item, "activate", G_CALLBACK (quit), NULL); + g_signal_connect (item, "activate", G_CALLBACK (mainMenuQuitCB), NULL); gtk_widget_add_accelerator (item, "activate", accel_group, GDK_KEY_q, GDK_CONTROL_MASK, @@ -3136,18 +3158,19 @@ static void transferPix2CairoSurface(void) else { // RGBA to ARGB - #ifdef LSB_FIRST - p[i].u8[2] = g[j].u8[0]; - p[i].u8[1] = g[j].u8[1]; - p[i].u8[0] = g[j].u8[2]; - p[i].u8[3] = 0xff; // Force Alpha to full - #else - // Big-Endian is untested. - p[i].u8[2] = g[j].u8[0]; - p[i].u8[1] = g[j].u8[1]; - p[i].u8[0] = g[j].u8[2]; - p[i].u8[3] = 0xff; // Force Alpha to full - #endif + //#ifdef LSB_FIRST + p[i].u32 = g[j].u32 | 0xff000000; + //p[i].u8[0] = g[j].u8[0]; + //p[i].u8[1] = g[j].u8[1]; + //p[i].u8[2] = g[j].u8[2]; + //p[i].u8[3] = 0xff; // Force Alpha to full + //#else + //// Big-Endian is untested. + //p[i].u8[2] = g[j].u8[0]; + //p[i].u8[1] = g[j].u8[1]; + //p[i].u8[0] = g[j].u8[2]; + //p[i].u8[3] = 0xff; // Force Alpha to full + //#endif //p[i].u32 = 0xffffffff; } i++; @@ -3198,13 +3221,21 @@ int guiPixelBufferReDraw(void) { glx_shm->blit_count++; - if ( useCairoDraw ) + switch ( videoDriver ) { - transferPix2CairoSurface(); - } - else - { - gtk3_glx_render(); + case VIDEO_CAIRO: + transferPix2CairoSurface(); + break; + case VIDEO_OPENGL_GLX: + gtk3_glx_render(); + break; + case VIDEO_SDL: + gtk3_sdl_render(); + break; + default: + case VIDEO_NONE: + // Nothing to do + break; } return 0; @@ -3428,33 +3459,55 @@ int destroy_gui_video( void ) destroy_gtk3_GLXContext(); + destroy_gtk3_sdl_video(); + + videoDriver = VIDEO_NONE; + return 0; } -int init_gui_video( int use_openGL ) +int init_gui_video( videoDriver_t videoDriverSelect ) { - drawAreaGL = use_openGL; - useCairoDraw = !drawAreaGL; - - if ( use_openGL ) + if ( videoDriver == videoDriverSelect ) { - int flags=0; - int linear_interpolation_ena=0; - int double_buffer_ena=0; - - g_config->getOption("SDL.OpenGLip" , &linear_interpolation_ena ); - g_config->getOption("SDL.DoubleBuffering", &double_buffer_ena ); - - if ( linear_interpolation_ena ) flags |= GLXWIN_PIXEL_LINEAR_FILTER; - if ( double_buffer_ena ) flags |= GLXWIN_DOUBLE_BUFFER; - - destroy_cairo_screen(); - init_gtk3_GLXContext( flags ); + return 0; } - else + + destroy_gui_video(); + + videoDriver = videoDriverSelect; + + switch ( videoDriver ) { - destroy_gtk3_GLXContext(); - init_cairo_screen(); + case VIDEO_OPENGL_GLX: + { + int flags=0; + int linear_interpolation_ena=0; + int double_buffer_ena=0; + + g_config->getOption("SDL.OpenGLip" , &linear_interpolation_ena ); + g_config->getOption("SDL.DoubleBuffering", &double_buffer_ena ); + + if ( linear_interpolation_ena ) flags |= GLXWIN_PIXEL_LINEAR_FILTER; + if ( double_buffer_ena ) flags |= GLXWIN_DOUBLE_BUFFER; + + init_gtk3_GLXContext( flags ); + } + break; + case VIDEO_CAIRO: + { + init_cairo_screen(); + } + break; + case VIDEO_SDL: + { + init_gtk3_sdl_video(); + } + break; + default: + case VIDEO_NONE: + // Nothing to do + break; } return 0; } @@ -3502,7 +3555,7 @@ gboolean handle_resize (GtkWindow * win, GdkEvent * event, gpointer data) double xscale = width / (double) NES_WIDTH; double yscale = height / (double) NES_HEIGHT; - //printf("DRAW: %ix%i MenuY: %i \n", draw_width, draw_height, gtk_win_menu_ysize ); + printf("DRAW: %ix%i \n", width, height ); if ( (width != gtk_draw_area_width) || (height != gtk_draw_area_height) ) { @@ -3521,9 +3574,21 @@ gboolean handle_resize (GtkWindow * win, GdkEvent * event, gpointer data) if (yscale > xscale) yscale = xscale; - if ( useCairoDraw && winsize_changed ) + if ( winsize_changed ) { - cairo_handle_resize(); + switch ( videoDriver ) + { + case VIDEO_CAIRO: + cairo_handle_resize(); + break; + case VIDEO_SDL: + gtk3_sdl_resize(); + break; + default: + case VIDEO_OPENGL_GLX: + // Nothing to do + break; + } } //TODO if openGL make these integers @@ -3591,13 +3656,21 @@ static gboolean draw_cb (GtkWidget * widget, cairo_t * cr, gpointer data) if ( gtk_draw_area_width < NES_WIDTH ) gtk_draw_area_width = NES_WIDTH; if ( gtk_draw_area_height < NES_HEIGHT ) gtk_draw_area_height = NES_HEIGHT; - if ( useCairoDraw ) + switch ( videoDriver ) { - cairo_draw_cb( widget, cr, data ); - } - else - { - gtk3_glx_render(); + case VIDEO_CAIRO: + cairo_draw_cb( widget, cr, data ); + break; + case VIDEO_OPENGL_GLX: + gtk3_glx_render(); + break; + case VIDEO_SDL: + gtk3_sdl_render(); + break; + default: + case VIDEO_NONE: + // Nothing to do + break; } return FALSE; @@ -3607,16 +3680,18 @@ static void drawAreaRealizeCB (GtkWidget *widget, gpointer user_data) { - printf("Draw Area Realize\n"); + int vdSel = VIDEO_OPENGL_GLX; - init_gui_video( drawAreaGL ); + g_config->getOption("SDL.VideoDriver", &vdSel); + + printf("Draw Area Realize: Video Driver Select: %i\n", vdSel); + + init_gui_video( (videoDriver_t)vdSel ); } int InitGTKSubsystem (int argc, char **argv) { - - int s_useOpenGL=0; GtkWidget *vbox; MainWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); @@ -3649,13 +3724,6 @@ int InitGTKSubsystem (int argc, char **argv) // // prg - Bryan Cain, you are the man! - #ifdef OPENGL - g_config->getOption("SDL.OpenGL", &s_useOpenGL); - #endif - - drawAreaGL = s_useOpenGL; - useCairoDraw = !drawAreaGL; - evbox = gtk_drawing_area_new (); gtk_box_pack_start (GTK_BOX (vbox), evbox, TRUE, TRUE, 0); @@ -3678,8 +3746,8 @@ int InitGTKSubsystem (int argc, char **argv) G_CALLBACK (handleMouseClick), NULL); // signal handlers - g_signal_connect (MainWindow, "delete-event", quit, NULL); - g_signal_connect (MainWindow, "destroy-event", quit, NULL); + g_signal_connect (MainWindow, "delete-event", G_CALLBACK(deleteMainWindowCB), NULL); + g_signal_connect (MainWindow, "destroy-event", G_CALLBACK(destroyMainWindowCB), NULL); g_signal_connect (evbox, "configure-event", G_CALLBACK (handle_resize), NULL); diff --git a/src/drivers/sdl/gui.h b/src/drivers/sdl/gui.h index e824d4a2..98eaa81b 100644 --- a/src/drivers/sdl/gui.h +++ b/src/drivers/sdl/gui.h @@ -35,6 +35,10 @@ void pushOutputToGTK(const char* str); void showGui(bool b); void toggleMenuVis(void); +gint convertKeypress (GtkWidget * grab, GdkEventKey * event, gpointer user_data); +void toggleOption (GtkWidget * w, gpointer p); +void setCheckbox (GtkWidget * w, const char *configName); + bool checkGTKVersion(int major_required, int minor_required); int configHotkey(char* hotkeyString); @@ -50,16 +54,10 @@ void openGamepadConfig(); void resizeGtkWindow(); -#ifdef OPENGL -void setGl(GtkWidget* w, gpointer p); -void setDoubleBuffering(GtkWidget* w, gpointer p); -#endif - void setStateMenuItem( int i ); void openVideoConfig(); void openSoundConfig(); -void quit (); void openAbout (); void emuReset (); @@ -90,7 +88,16 @@ int InitGTKSubsystem(int argc, char** argv); uint32_t *getGuiPixelBuffer( int *w, int *h, int *s ); int guiPixelBufferReDraw(void); -int init_gui_video( int use_openGL ); +enum videoDriver_t +{ + VIDEO_NONE = -1, + VIDEO_OPENGL_GLX, + VIDEO_SDL, + VIDEO_CAIRO +}; +extern enum videoDriver_t videoDriver; + +int init_gui_video( videoDriver_t vd ); int destroy_gui_video( void ); void init_cairo_screen(void); void destroy_cairo_screen(void); diff --git a/src/drivers/sdl/input.cpp b/src/drivers/sdl/input.cpp index 9e7280c9..7c2f0c88 100644 --- a/src/drivers/sdl/input.cpp +++ b/src/drivers/sdl/input.cpp @@ -24,8 +24,9 @@ #include "config.h" -#include "sdl-video.h" #include "sdl.h" +#include "sdl-video.h" +#include "sdl-joystick.h" #include "../common/cheat.h" #include "../../movie.h" @@ -57,9 +58,10 @@ extern bool bindSavestate, frameAdvanceLagSkip, lagCounterDisplay; /* UsrInputType[] is user-specified. CurInputType[] is current (game loading can override user settings) */ -static int UsrInputType[NUM_INPUT_DEVICES]; -static int CurInputType[NUM_INPUT_DEVICES]; +static int UsrInputType[NUM_INPUT_DEVICES] = { SI_GAMEPAD, SI_GAMEPAD, SI_NONE }; +static int CurInputType[NUM_INPUT_DEVICES] = { SI_GAMEPAD, SI_GAMEPAD, SI_NONE }; static int cspec = 0; +static int buttonConfigInProgress = 0; extern int gametype; @@ -618,10 +620,10 @@ static void KeyboardCommands (void) if (_keyonly (Hotkeys[HK_DECREASE_SPEED])) { - DecreaseEmulationSpeed (); + DecreaseEmulationSpeed(); } - if (_keyonly (Hotkeys[HK_INCREASE_SPEED])) + if (_keyonly(Hotkeys[HK_INCREASE_SPEED])) { IncreaseEmulationSpeed (); } @@ -693,17 +695,10 @@ static void KeyboardCommands (void) //} if (_keyonly (Hotkeys[HK_QUIT])) { - if (noGui == 1) - { - CloseGame (); - } - else - { - CloseGame(); - FCEUI_Kill(); - SDL_Quit(); - exit(0); - } + CloseGame(); + FCEUI_Kill(); + SDL_Quit(); + exit(0); } else #ifdef _S9XLUA_H @@ -957,6 +952,8 @@ UpdatePhysicalInput () { SDL_Event event; + //SDL_JoystickUpdate(); + // loop, handling all pending events while (SDL_PollEvent (&event)) { @@ -985,6 +982,12 @@ UpdatePhysicalInput () g_keyState[ event.key.keysym.scancode ] = (event.type == SDL_KEYDOWN) ? 1 : 0; //checkKeyBoardState( event.key.keysym.scancode ); break; + case SDL_JOYDEVICEADDED: + AddJoystick( event.jdevice.which ); + break; + case SDL_JOYDEVICEREMOVED: + RemoveJoystick( event.jdevice.which ); + break; default: break; } @@ -993,8 +996,6 @@ UpdatePhysicalInput () } -static int bcpv, bcpj; - /** * Begin configuring the buttons by placing the video and joystick * subsystems into a well-known state. Button configuration really @@ -1002,31 +1003,11 @@ static int bcpv, bcpj; */ int ButtonConfigBegin () { -//dont shut down video subsystem if we are using gtk to prevent the sdl window from becoming detached to GTK window -// prg318 - 10-2-2011 -#ifdef _GTK - int noGui; - g_config->getOption ("SDL.NoGUI", &noGui); - if (noGui == 1) - { - //SDL_QuitSubSystem (SDL_INIT_VIDEO); - bcpv = KillVideo (); - } -#else - // XXX soules - why are we doing this right before KillVideo()? - //SDL_QuitSubSystem (SDL_INIT_VIDEO); - - // shut down the video and joystick subsystems - bcpv = KillVideo (); -#endif - //SDL_Surface *screen; - - bcpj = KillJoysticks (); - - // XXX soules - why did we shut this down? - // initialize the joystick subsystem + // initialize the joystick subsystem (if not already inited) InitJoysticks (); + buttonConfigInProgress = 1; + return 1; } @@ -1038,18 +1019,7 @@ int ButtonConfigBegin () void ButtonConfigEnd () { - // shutdown the joystick and video subsystems - KillJoysticks (); - //SDL_QuitSubSystem(SDL_INIT_VIDEO); - - // re-initialize joystick and video subsystems if they were active before - /*if(!bcpv) { - InitVideo(GameInfo); - } */ - if (!bcpj) - { - InitJoysticks (); - } + buttonConfigInProgress = 0; } /** @@ -1058,48 +1028,50 @@ ButtonConfigEnd () static int DTestButton (ButtConfig * bc) { - int x; - for (x = 0; x < bc->NumC; x++) + if (bc->ButtType == BUTTC_KEYBOARD) { - if (bc->ButtType[x] == BUTTC_KEYBOARD) + if (g_keyState[SDL_GetScancodeFromKey (bc->ButtonNum)]) { - if (g_keyState[SDL_GetScancodeFromKey (bc->ButtonNum[x])]) - { - return 1; - } + bc->state = 1; + return 1; } - else if (bc->ButtType[x] == BUTTC_JOYSTICK) + else + { + bc->state = 0; + } + } + else if (bc->ButtType == BUTTC_JOYSTICK) + { + if (DTestButtonJoy (bc)) { - if (DTestButtonJoy (bc)) - { - return 1; - } + return 1; } } return 0; } -#define MK(x) {{BUTTC_KEYBOARD},{0},{MKK(x)},1} -#define MK2(x1,x2) {{BUTTC_KEYBOARD},{0},{MKK(x1),MKK(x2)},2} -#define MKZ() {{0},{0},{0},0} +#define MK(x) {BUTTC_KEYBOARD,0,MKK(x),0} +//#define MK2(x1,x2) {BUTTC_KEYBOARD,0,MKK(x1)} +#define MKZ() {0,0,-1,0} #define GPZ() {MKZ(), MKZ(), MKZ(), MKZ()} -ButtConfig GamePadConfig[4][10] = { -/* Gamepad 1 */ - {MK (KP_3), MK (KP_2), MK (SLASH), MK (ENTER), - MK (W), MK (Z), MK (A), MK (S), MKZ (), MKZ ()}, - - /* Gamepad 2 */ - GPZ (), - - /* Gamepad 3 */ - GPZ (), - - /* Gamepad 4 */ - GPZ () -}; +//ButtConfig GamePadConfig[ GAMEPAD_NUM_DEVICES ][ GAMEPAD_NUM_BUTTONS ] = +//{ +///* Gamepad 1 */ +// {MK (KP_3), MK (KP_2), MK (SLASH), MK (ENTER), +// MK (w), MK (z), MK (a), MK (s), MKZ (), MKZ ()}, +// +// /* Gamepad 2 */ +// GPZ (), +// +// /* Gamepad 3 */ +// GPZ (), +// +// /* Gamepad 4 */ +// GPZ () +//}; /** * Update the status of the gamepad input devices. @@ -1131,7 +1103,7 @@ UpdateGamepad(void) // a, b, select, start, up, down, left, right for (x = 0; x < 8; x++) { - if (DTestButton (&GamePadConfig[wg][x])) + if (DTestButton (&GamePad[wg].bmap[x])) { //printf("GamePad%i Button Hit: %i \n", wg, x ); if(opposite_dirs == 0) @@ -1169,7 +1141,7 @@ UpdateGamepad(void) { for (x = 0; x < 2; x++) { - if (DTestButton (&GamePadConfig[wg][8 + x])) + if (DTestButton (&GamePad[wg].bmap[8 + x])) { JS |= (1 << x) << (wg << 3); } @@ -1238,11 +1210,15 @@ static uint8 fkbkeys[0x48]; /** * Update all of the input devices required for the active game. */ -void FCEUD_UpdateInput () +void FCEUD_UpdateInput(void) { int x; int t = 0; + if ( buttonConfigInProgress ) + { + return; + } UpdatePhysicalInput (); KeyboardCommands (); @@ -1356,8 +1332,8 @@ void InitInputInterface () { void *InputDPtr; - int t; - int x; + int t = 0; + int x = 0; int attrib; memset( g_keyState, 0, sizeof(g_keyState) ); @@ -1600,36 +1576,42 @@ UpdateFTrainer () * @param bc the NES gamepad's button config * @param which the index of the button */ -const char * ButtonName (const ButtConfig * bc, int which) +const char * ButtonName (const ButtConfig * bc) { static char name[256]; - switch (bc->ButtType[which]) + name[0] = 0; + + if (bc->ButtonNum == -1) + { + return name; + } + switch (bc->ButtType) { case BUTTC_KEYBOARD: - return SDL_GetKeyName (bc->ButtonNum[which]); + return SDL_GetKeyName (bc->ButtonNum); break; case BUTTC_JOYSTICK: { int joyNum, inputNum; const char *inputType, *inputDirection; - joyNum = bc->DeviceNum[which]; + joyNum = bc->DeviceNum; - if (bc->ButtonNum[which] & 0x8000) + if (bc->ButtonNum & 0x8000) { inputType = "Axis"; - inputNum = bc->ButtonNum[which] & 0x3FFF; - inputDirection = bc->ButtonNum[which] & 0x4000 ? "-" : "+"; + inputNum = bc->ButtonNum & 0x3FFF; + inputDirection = bc->ButtonNum & 0x4000 ? "-" : "+"; } - else if (bc->ButtonNum[which] & 0x2000) + else if (bc->ButtonNum & 0x2000) { int inputValue; char direction[128] = ""; inputType = "Hat"; - inputNum = (bc->ButtonNum[which] >> 8) & 0x1F; - inputValue = bc->ButtonNum[which] & 0xF; + inputNum = (bc->ButtonNum >> 8) & 0x1F; + inputValue = bc->ButtonNum & 0xF; if (inputValue & SDL_HAT_UP) strncat (direction, "Up ", sizeof (direction)-1); @@ -1648,7 +1630,7 @@ const char * ButtonName (const ButtConfig * bc, int which) else { inputType = "Button"; - inputNum = bc->ButtonNum[which]; + inputNum = bc->ButtonNum; inputDirection = ""; } sprintf( name, "js%i:%s%i%s", joyNum, inputType, inputNum, inputDirection ); @@ -1663,11 +1645,12 @@ const char * ButtonName (const ButtConfig * bc, int which) * Waits for a button input and returns the information as to which * button was pressed. Used in button configuration. */ -int DWaitButton (const uint8 * text, ButtConfig * bc, int wb, int *buttonConfigStatus ) +int DWaitButton (const uint8_t * text, ButtConfig * bc, int *buttonConfigStatus ) { SDL_Event event; static int32 LastAx[64][64]; int x, y; + int timeout_ms = 10000; if (text) { @@ -1686,36 +1669,53 @@ int DWaitButton (const uint8 * text, ButtConfig * bc, int wb, int *buttonConfigS } } + // Purge all pending events, so that this next button press + // will be the one we want. + while (SDL_PollEvent (&event)) + { + + } + while (1) { int done = 0; + + usleep(10000); + timeout_ms -= 10; + + if ( timeout_ms <= 0 ) + { + break; + } #ifdef _GTK while (gtk_events_pending ()) gtk_main_iteration_do (FALSE); #endif while (SDL_PollEvent (&event)) { + printf("Event Type: %i \n", event.type ); done++; switch (event.type) { case SDL_KEYDOWN: - bc->ButtType[wb] = BUTTC_KEYBOARD; - bc->DeviceNum[wb] = 0; - bc->ButtonNum[wb] = event.key.keysym.sym; + //printf("SDL KeyDown:%i \n", event.key.keysym.sym ); + bc->ButtType = BUTTC_KEYBOARD; + bc->DeviceNum = 0; + bc->ButtonNum = event.key.keysym.sym; return (1); case SDL_JOYBUTTONDOWN: - bc->ButtType[wb] = BUTTC_JOYSTICK; - bc->DeviceNum[wb] = event.jbutton.which; - bc->ButtonNum[wb] = event.jbutton.button; + bc->ButtType = BUTTC_JOYSTICK; + bc->DeviceNum = event.jbutton.which; + bc->ButtonNum = event.jbutton.button; return (1); case SDL_JOYHATMOTION: if (event.jhat.value == SDL_HAT_CENTERED) done--; else { - bc->ButtType[wb] = BUTTC_JOYSTICK; - bc->DeviceNum[wb] = event.jhat.which; - bc->ButtonNum[wb] = + bc->ButtType = BUTTC_JOYSTICK; + bc->DeviceNum = event.jhat.which; + bc->ButtonNum = (0x2000 | ((event.jhat.hat & 0x1F) << 8) | event. jhat.value); return (1); @@ -1737,9 +1737,9 @@ int DWaitButton (const uint8 * text, ButtConfig * bc, int wb, int *buttonConfigS (LastAx[event.jaxis.which][event.jaxis.axis] - event.jaxis.value) >= 8192) { - bc->ButtType[wb] = BUTTC_JOYSTICK; - bc->DeviceNum[wb] = event.jaxis.which; - bc->ButtonNum[wb] = (0x8000 | event.jaxis.axis | + bc->ButtType = BUTTC_JOYSTICK; + bc->DeviceNum = event.jaxis.which; + bc->ButtonNum = (0x8000 | event.jaxis.axis | ((event.jaxis.value < 0) ? 0x4000 : 0)); return (1); @@ -1776,213 +1776,206 @@ int DWaitButton (const uint8 * text, ButtConfig * bc, int wb, int *buttonConfigS * used as input for the specified button, thus allowing up to four * possible settings for each input button. */ - void -ConfigButton (char *text, ButtConfig * bc) -{ - uint8 buf[256]; - int wc; - - for (wc = 0; wc < MAXBUTTCONFIG; wc++) - { - sprintf ((char *) buf, "%s (%d)", text, wc + 1); - DWaitButton (buf, bc, wc, NULL); - - if (wc && - bc->ButtType[wc] == bc->ButtType[wc - 1] && - bc->DeviceNum[wc] == bc->DeviceNum[wc - 1] && - bc->ButtonNum[wc] == bc->ButtonNum[wc - 1]) - { - break; - } - } - bc->NumC = wc; -} +// void +//ConfigButton (char *text, ButtConfig * bc) +//{ +// uint8 buf[256]; +// int wc; +// +// for (wc = 0; wc < MAXBUTTCONFIG; wc++) +// { +// sprintf ((char *) buf, "%s (%d)", text, wc + 1); +// DWaitButton (buf, bc, wc, NULL); +// +// if (wc && +// bc->ButtType[wc] == bc->ButtType[wc - 1] && +// bc->DeviceNum[wc] == bc->DeviceNum[wc - 1] && +// bc->ButtonNum[wc] == bc->ButtonNum[wc - 1]) +// { +// break; +// } +// } +//} /** * Update the button configuration for a specified device. */ extern Config *g_config; -void ConfigDevice (int which, int arg) -{ - char buf[256]; - int x; - std::string prefix; - const char *str[10] = - { "A", "B", "SELECT", "START", "UP", "DOWN", "LEFT", "RIGHT", "Rapid A", - "Rapid B" - }; - - // XXX soules - set the configuration options so that later calls - // don't override these. This is a temp hack until I - // can clean up this file. - - ButtonConfigBegin (); - switch (which) - { - case FCFGD_QUIZKING: - prefix = "SDL.Input.QuizKing."; - for (x = 0; x < 6; x++) - { - sprintf (buf, "Quiz King Buzzer #%d", x + 1); - ConfigButton (buf, &QuizKingButtons[x]); - - g_config->setOption (prefix + QuizKingNames[x], - QuizKingButtons[x].ButtonNum[0]); - } - - if (QuizKingButtons[0].ButtType[0] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (QuizKingButtons[0].ButtType[0] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - QuizKingButtons[0].DeviceNum[0]); - break; - case FCFGD_HYPERSHOT: - prefix = "SDL.Input.HyperShot."; - for (x = 0; x < 4; x++) - { - sprintf (buf, "Hyper Shot %d: %s", - ((x & 2) >> 1) + 1, (x & 1) ? "JUMP" : "RUN"); - ConfigButton (buf, &HyperShotButtons[x]); - - g_config->setOption (prefix + HyperShotNames[x], - HyperShotButtons[x].ButtonNum[0]); - } - - if (HyperShotButtons[0].ButtType[0] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (HyperShotButtons[0].ButtType[0] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - HyperShotButtons[0].DeviceNum[0]); - break; - case FCFGD_POWERPAD: - snprintf (buf, 256, "SDL.Input.PowerPad.%d", (arg & 1)); - prefix = buf; - for (x = 0; x < 12; x++) - { - sprintf (buf, "PowerPad %d: %d", (arg & 1) + 1, x + 11); - ConfigButton (buf, &powerpadsc[arg & 1][x]); - - g_config->setOption (prefix + PowerPadNames[x], - powerpadsc[arg & 1][x].ButtonNum[0]); - } - - if (powerpadsc[arg & 1][0].ButtType[0] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (powerpadsc[arg & 1][0].ButtType[0] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - powerpadsc[arg & 1][0].DeviceNum[0]); - break; - - case FCFGD_GAMEPAD: - snprintf (buf, 256, "SDL.Input.GamePad.%d", arg); - prefix = buf; - for (x = 0; x < 10; x++) - { - sprintf (buf, "GamePad #%d: %s", arg + 1, str[x]); - ConfigButton (buf, &GamePadConfig[arg][x]); - - g_config->setOption (prefix + GamePadNames[x], - GamePadConfig[arg][x].ButtonNum[0]); - } - - if (GamePadConfig[arg][0].ButtType[0] == BUTTC_KEYBOARD) - { - g_config->setOption (prefix + "DeviceType", "Keyboard"); - } - else if (GamePadConfig[arg][0].ButtType[0] == BUTTC_JOYSTICK) - { - g_config->setOption (prefix + "DeviceType", "Joystick"); - } - else - { - g_config->setOption (prefix + "DeviceType", "Unknown"); - } - g_config->setOption (prefix + "DeviceNum", - GamePadConfig[arg][0].DeviceNum[0]); - break; - } - - ButtonConfigEnd (); -} +//void ConfigDevice (int which, int arg) +//{ +// char buf[256]; +// int x; +// std::string prefix; +// const char *str[10] = +// { "A", "B", "SELECT", "START", "UP", "DOWN", "LEFT", "RIGHT", "Rapid A", +// "Rapid B" +// }; +// +// // XXX soules - set the configuration options so that later calls +// // don't override these. This is a temp hack until I +// // can clean up this file. +// +// ButtonConfigBegin (); +// switch (which) +// { +// case FCFGD_QUIZKING: +// prefix = "SDL.Input.QuizKing."; +// for (x = 0; x < 6; x++) +// { +// sprintf (buf, "Quiz King Buzzer #%d", x + 1); +// ConfigButton (buf, &QuizKingButtons[x]); +// +// g_config->setOption (prefix + QuizKingNames[x], +// QuizKingButtons[x].ButtonNum); +// } +// +// if (QuizKingButtons[0].ButtType == BUTTC_KEYBOARD) +// { +// g_config->setOption (prefix + "DeviceType", "Keyboard"); +// } +// else if (QuizKingButtons[0].ButtType == BUTTC_JOYSTICK) +// { +// g_config->setOption (prefix + "DeviceType", "Joystick"); +// } +// else +// { +// g_config->setOption (prefix + "DeviceType", "Unknown"); +// } +// g_config->setOption (prefix + "DeviceNum", +// QuizKingButtons[0].DeviceNum); +// break; +// case FCFGD_HYPERSHOT: +// prefix = "SDL.Input.HyperShot."; +// for (x = 0; x < 4; x++) +// { +// sprintf (buf, "Hyper Shot %d: %s", +// ((x & 2) >> 1) + 1, (x & 1) ? "JUMP" : "RUN"); +// ConfigButton (buf, &HyperShotButtons[x]); +// +// g_config->setOption (prefix + HyperShotNames[x], +// HyperShotButtons[x].ButtonNum); +// } +// +// if (HyperShotButtons[0].ButtType == BUTTC_KEYBOARD) +// { +// g_config->setOption (prefix + "DeviceType", "Keyboard"); +// } +// else if (HyperShotButtons[0].ButtType == BUTTC_JOYSTICK) +// { +// g_config->setOption (prefix + "DeviceType", "Joystick"); +// } +// else +// { +// g_config->setOption (prefix + "DeviceType", "Unknown"); +// } +// g_config->setOption (prefix + "DeviceNum", +// HyperShotButtons[0].DeviceNum); +// break; +// case FCFGD_POWERPAD: +// snprintf (buf, 256, "SDL.Input.PowerPad.%d", (arg & 1)); +// prefix = buf; +// for (x = 0; x < 12; x++) +// { +// sprintf (buf, "PowerPad %d: %d", (arg & 1) + 1, x + 11); +// ConfigButton (buf, &powerpadsc[arg & 1][x]); +// +// g_config->setOption (prefix + PowerPadNames[x], +// powerpadsc[arg & 1][x].ButtonNum); +// } +// +// if (powerpadsc[arg & 1][0].ButtType == BUTTC_KEYBOARD) +// { +// g_config->setOption (prefix + "DeviceType", "Keyboard"); +// } +// else if (powerpadsc[arg & 1][0].ButtType == BUTTC_JOYSTICK) +// { +// g_config->setOption (prefix + "DeviceType", "Joystick"); +// } +// else +// { +// g_config->setOption (prefix + "DeviceType", "Unknown"); +// } +// g_config->setOption (prefix + "DeviceNum", +// powerpadsc[arg & 1][0].DeviceNum); +// break; +// +// case FCFGD_GAMEPAD: +// snprintf (buf, 256, "SDL.Input.GamePad.%d", arg); +// prefix = buf; +// for (x = 0; x < 10; x++) +// { +// sprintf (buf, "GamePad #%d: %s", arg + 1, str[x]); +// ConfigButton (buf, &GamePadConfig[arg][x]); +// +// g_config->setOption (prefix + GamePadNames[x], +// GamePadConfig[arg][x].ButtonNum); +// } +// +// if (GamePadConfig[arg][0].ButtType == BUTTC_KEYBOARD) +// { +// g_config->setOption (prefix + "DeviceType", "Keyboard"); +// } +// else if (GamePadConfig[arg][0].ButtType == BUTTC_JOYSTICK) +// { +// g_config->setOption (prefix + "DeviceType", "Joystick"); +// } +// else +// { +// g_config->setOption (prefix + "DeviceType", "Unknown"); +// } +// g_config->setOption (prefix + "DeviceNum", +// GamePadConfig[arg][0].DeviceNum); +// break; +// } +// +// ButtonConfigEnd (); +//} /** * Update the button configuration for a device, specified by a text string. */ -void InputCfg (const std::string & text) -{ -#ifdef _GTK - // enable noGui to prevent the gtk x11 hack from executing - noGui = 1; - // this is only called at the begininng of execution; make sure the video subsystem is initialized - InitVideo (GameInfo); -#endif - - if (noGui) - { - if (text.find ("gamepad") != std::string::npos) - { - int device = (text[strlen ("gamepad")] - '1'); - if (device < 0 || device > 3) - { - FCEUD_PrintError - ("Invalid gamepad device specified; must be one of gamepad1 through gamepad4"); - exit (-1); - } - ConfigDevice (FCFGD_GAMEPAD, device); - } - else if (text.find ("powerpad") != std::string::npos) - { - int device = (text[strlen ("powerpad")] - '1'); - if (device < 0 || device > 1) - { - FCEUD_PrintError - ("Invalid powerpad device specified; must be powerpad1 or powerpad2"); - exit (-1); - } - ConfigDevice (FCFGD_POWERPAD, device); - } - else if (text.find ("hypershot") != std::string::npos) - { - ConfigDevice (FCFGD_HYPERSHOT, 0); - } - else if (text.find ("quizking") != std::string::npos) - { - ConfigDevice (FCFGD_QUIZKING, 0); - } - } - else - printf ("Please run \"fceux --nogui\" before using --inputcfg\n"); - -} +//void InputCfg (const std::string & text) +//{ +// +// if (noGui) +// { +// if (text.find ("gamepad") != std::string::npos) +// { +// int device = (text[strlen ("gamepad")] - '1'); +// if (device < 0 || device > 3) +// { +// FCEUD_PrintError +// ("Invalid gamepad device specified; must be one of gamepad1 through gamepad4"); +// exit (-1); +// } +// ConfigDevice (FCFGD_GAMEPAD, device); +// } +// else if (text.find ("powerpad") != std::string::npos) +// { +// int device = (text[strlen ("powerpad")] - '1'); +// if (device < 0 || device > 1) +// { +// FCEUD_PrintError +// ("Invalid powerpad device specified; must be powerpad1 or powerpad2"); +// exit (-1); +// } +// ConfigDevice (FCFGD_POWERPAD, device); +// } +// else if (text.find ("hypershot") != std::string::npos) +// { +// ConfigDevice (FCFGD_HYPERSHOT, 0); +// } +// else if (text.find ("quizking") != std::string::npos) +// { +// ConfigDevice (FCFGD_QUIZKING, 0); +// } +// } +// else +// printf ("Please run \"fceux --nogui\" before using --inputcfg\n"); +// +//} /** @@ -1994,7 +1987,9 @@ void InputCfg (const std::string & text) UpdateInput (Config * config) { char buf[64]; - std::string device, prefix; + std::string device, prefix, guid, mapping; + + InitJoysticks(); for (unsigned int i = 0; i < 3; i++) { @@ -2087,37 +2082,18 @@ UpdateInput (Config * config) snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%u.", i); prefix = buf; - config->getOption (prefix + "DeviceType", &device); - if (device.find ("Keyboard") != std::string::npos) - { - type = BUTTC_KEYBOARD; - } - else if (device.find ("Joystick") != std::string::npos) - { - type = BUTTC_JOYSTICK; - } - else - { - type = 0; - } + config->getOption (prefix + "DeviceType", &device ); + config->getOption (prefix + "DeviceGUID", &guid ); + config->getOption (prefix + "Profile" , &mapping); - config->getOption (prefix + "DeviceNum", &devnum); - for (unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) - { - config->getOption (prefix + GamePadNames[j], &button); - - GamePadConfig[i][j].ButtType[0] = type; - GamePadConfig[i][j].DeviceNum[0] = devnum; - GamePadConfig[i][j].ButtonNum[0] = button; - GamePadConfig[i][j].NumC = 1; - } + GamePad[i].init( i, guid.c_str(), mapping.c_str() ); } // PowerPad 0 - 1 for (unsigned int i = 0; i < POWERPAD_NUM_DEVICES; i++) { char buf[64]; - snprintf (buf, 32, "SDL.Input.PowerPad.%u.", i); + snprintf (buf, sizeof(buf)-1, "SDL.Input.PowerPad.%u.", i); prefix = buf; config->getOption (prefix + "DeviceType", &device); @@ -2139,10 +2115,9 @@ UpdateInput (Config * config) { config->getOption (prefix + PowerPadNames[j], &button); - powerpadsc[i][j].ButtType[0] = type; - powerpadsc[i][j].DeviceNum[0] = devnum; - powerpadsc[i][j].ButtonNum[0] = button; - powerpadsc[i][j].NumC = 1; + powerpadsc[i][j].ButtType = type; + powerpadsc[i][j].DeviceNum = devnum; + powerpadsc[i][j].ButtonNum = button; } } @@ -2166,10 +2141,9 @@ UpdateInput (Config * config) { config->getOption (prefix + QuizKingNames[j], &button); - QuizKingButtons[j].ButtType[0] = type; - QuizKingButtons[j].DeviceNum[0] = devnum; - QuizKingButtons[j].ButtonNum[0] = button; - QuizKingButtons[j].NumC = 1; + QuizKingButtons[j].ButtType = type; + QuizKingButtons[j].DeviceNum = devnum; + QuizKingButtons[j].ButtonNum = button; } // HyperShot @@ -2192,10 +2166,9 @@ UpdateInput (Config * config) { config->getOption (prefix + HyperShotNames[j], &button); - HyperShotButtons[j].ButtType[0] = type; - HyperShotButtons[j].DeviceNum[0] = devnum; - HyperShotButtons[j].ButtonNum[0] = button; - HyperShotButtons[j].NumC = 1; + HyperShotButtons[j].ButtType = type; + HyperShotButtons[j].DeviceNum = devnum; + HyperShotButtons[j].ButtonNum = button; } // Mahjong @@ -2218,10 +2191,9 @@ UpdateInput (Config * config) { config->getOption (prefix + MahjongNames[j], &button); - MahjongButtons[j].ButtType[0] = type; - MahjongButtons[j].DeviceNum[0] = devnum; - MahjongButtons[j].ButtonNum[0] = button; - MahjongButtons[j].NumC = 1; + MahjongButtons[j].ButtType = type; + MahjongButtons[j].DeviceNum = devnum; + MahjongButtons[j].ButtonNum = button; } // TopRider @@ -2244,10 +2216,9 @@ UpdateInput (Config * config) { config->getOption (prefix + TopRiderNames[j], &button); - TopRiderButtons[j].ButtType[0] = type; - TopRiderButtons[j].DeviceNum[0] = devnum; - TopRiderButtons[j].ButtonNum[0] = button; - TopRiderButtons[j].NumC = 1; + TopRiderButtons[j].ButtType = type; + TopRiderButtons[j].DeviceNum = devnum; + TopRiderButtons[j].ButtonNum = button; } // FTrainer @@ -2270,10 +2241,9 @@ UpdateInput (Config * config) { config->getOption (prefix + FTrainerNames[j], &button); - FTrainerButtons[j].ButtType[0] = type; - FTrainerButtons[j].DeviceNum[0] = devnum; - FTrainerButtons[j].ButtonNum[0] = button; - FTrainerButtons[j].NumC = 1; + FTrainerButtons[j].ButtType = type; + FTrainerButtons[j].DeviceNum = devnum; + FTrainerButtons[j].ButtonNum = button; } // FamilyKeyBoard @@ -2296,10 +2266,9 @@ UpdateInput (Config * config) { config->getOption (prefix + FamilyKeyBoardNames[j], &button); - fkbmap[j].ButtType[0] = type; - fkbmap[j].DeviceNum[0] = devnum; - fkbmap[j].ButtonNum[0] = button; - fkbmap[j].NumC = 1; + fkbmap[j].ButtType = type; + fkbmap[j].DeviceNum = devnum; + fkbmap[j].ButtonNum = button; } } @@ -2311,11 +2280,11 @@ const char *GamePadNames[GAMEPAD_NUM_BUTTONS] = { "A", "B", "Select", "Start", const char *DefaultGamePadDevice[GAMEPAD_NUM_DEVICES] = { "Keyboard", "None", "None", "None" }; const int DefaultGamePad[GAMEPAD_NUM_DEVICES][GAMEPAD_NUM_BUTTONS] = -{ {SDLK_F, SDLK_D, SDLK_S, SDLK_RETURN, - SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -{0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +{ {SDLK_f, SDLK_d, SDLK_s, SDLK_RETURN, + SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT, -1, -1}, +{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, +{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, +{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1} }; // PowerPad defaults diff --git a/src/drivers/sdl/input.h b/src/drivers/sdl/input.h index 2a1a2d85..07dc1d04 100644 --- a/src/drivers/sdl/input.h +++ b/src/drivers/sdl/input.h @@ -1,34 +1,39 @@ #ifndef _aosdfjk02fmasf #define _aosdfjk02fmasf -#include "../common/configSys.h" +#include -#define MAXBUTTCONFIG 4 -typedef struct { - uint8 ButtType[MAXBUTTCONFIG]; - uint8 DeviceNum[MAXBUTTCONFIG]; - //uint16 ButtonNum[MAXBUTTCONFIG]; - int ButtonNum[MAXBUTTCONFIG]; - uint32 NumC; +#include "common/configSys.h" + +//#define MAXBUTTCONFIG 4 + +enum { + BUTTC_KEYBOARD = 0, + BUTTC_JOYSTICK = 1, + BUTTC_MOUSE = 2 +}; +struct ButtConfig +{ + int ButtType; //[MAXBUTTCONFIG]; + int DeviceNum; //[MAXBUTTCONFIG]; + int ButtonNum; //[MAXBUTTCONFIG]; + int state; + //uint32_t NumC; //uint64 DeviceID[MAXBUTTCONFIG]; /* TODO */ -} ButtConfig; - +}; extern int NoWaiting; extern CFGSTRUCT InputConfig[]; extern ARGPSTRUCT InputArgs[]; extern int Hotkeys[]; void ParseGIInput(FCEUGI *GI); -void setHotKeys(); +void setHotKeys(void); int getKeyState( int k ); int ButtonConfigBegin(); void ButtonConfigEnd(); void ConfigButton(char *text, ButtConfig *bc); -int DWaitButton(const uint8 *text, ButtConfig *bc, int wb, int *buttonConfigStatus = NULL); +int DWaitButton(const uint8_t *text, ButtConfig *bc, int *buttonConfigStatus = NULL); -#define BUTTC_KEYBOARD 0x00 -#define BUTTC_JOYSTICK 0x01 -#define BUTTC_MOUSE 0x02 #define FCFGD_GAMEPAD 1 #define FCFGD_POWERPAD 2 @@ -41,7 +46,7 @@ void InitInputInterface(void); void InputUserActiveFix(void); extern bool replaceP2StartWithMicrophone; -extern ButtConfig GamePadConfig[4][10]; +//extern ButtConfig GamePadConfig[4][10]; //extern ButtConfig powerpadsc[2][12]; //extern ButtConfig QuizKingButtons[6]; //extern ButtConfig FTrainerButtons[12]; @@ -54,9 +59,9 @@ int DTestButtonJoy(ButtConfig *bc); void FCEUD_UpdateInput(void); void UpdateInput(Config *config); -void InputCfg(const std::string &); +//void InputCfg(const std::string &); std::string GetUserText(const char* title); -const char* ButtonName(const ButtConfig* bc, int which); +const char* ButtonName(const ButtConfig* bc); #endif diff --git a/src/drivers/sdl/sdl-joystick.cpp b/src/drivers/sdl/sdl-joystick.cpp index 690b012b..a5e52623 100644 --- a/src/drivers/sdl/sdl-joystick.cpp +++ b/src/drivers/sdl/sdl-joystick.cpp @@ -22,102 +22,1054 @@ /// \file /// \brief Handles joystick input using the SDL. -#include "sdl.h" +//#include +#include "sdl/sdl.h" +#include "sdl/sdl-joystick.h" +#include "common/os_utils.h" #include #include #include #include -#define MAX_JOYSTICKS 32 -static SDL_Joystick *s_Joysticks[MAX_JOYSTICKS] = {NULL}; +//#define MAX_JOYSTICKS 32 +// Public Variables +GamePad_t GamePad[4]; + +// Static Functions +static int sdlButton2NesGpIdx( const char *id ); + +// Static Variables static int s_jinited = 0; +static const char *buttonNames[ GAMEPAD_NUM_BUTTONS ] = +{ + "a", "b","back","start", + "dpup","dpdown","dpleft","dpright", + "turboA","turboB" +}; +//******************************************************************************** +// Joystick Device +jsDev_t::jsDev_t(void) +{ + js = NULL; + gc = NULL; + devIdx = 0; + portBindMask = 0; +}; + +//******************************************************************************** +int jsDev_t::close(void) +{ + if ( gc ) + { + SDL_GameControllerClose( gc ); gc = NULL; js = NULL; + } + else + { + if ( js ) + { + SDL_JoystickClose( js ); js = NULL; + } + } + return 0; +} + +//******************************************************************************** +SDL_Joystick *jsDev_t::getJS(void) +{ + return js; +} + +//******************************************************************************** +const char *jsDev_t::getName(void) +{ + return ( name.c_str() ); +} + +//******************************************************************************** +const char *jsDev_t::getGUID(void) +{ + return ( guidStr.c_str() ); +} + +//******************************************************************************** +int jsDev_t::bindPort( int idx ) +{ + portBindMask |= (0x00000001 << idx); + + return portBindMask; +} +//******************************************************************************** +int jsDev_t::unbindPort( int idx ) +{ + portBindMask &= ~(0x00000001 << idx); + + return portBindMask; +} +//******************************************************************************** +int jsDev_t::getBindPorts(void) +{ + return portBindMask; +} +//******************************************************************************** +bool jsDev_t::isGameController(void) +{ + return ( gc != NULL ); +} + +//******************************************************************************** +bool jsDev_t::isConnected(void) +{ + return ( (js != NULL) || (gc != NULL) ); +} + +//******************************************************************************** +void jsDev_t::init( int idx ) +{ + SDL_JoystickGUID guid; + char stmp[64]; + + devIdx = idx; + + if ( gc ) + { + js = SDL_GameControllerGetJoystick( gc ); + + guid = SDL_JoystickGetGUID( js ); + + name.assign( SDL_GameControllerName(gc) ); + } + else + { + guid = SDL_JoystickGetGUID( js ); + + name.assign( SDL_JoystickName(js) ); + } + SDL_JoystickGetGUIDString( guid, stmp, sizeof(stmp) ); + + guidStr.assign( stmp ); + + // If game controller, save default mapping if it does not already exist. + if ( gc ) + { + std::string path; + const char *baseDir = FCEUI_GetBaseDirectory(); + + path = std::string(baseDir) + "/input/" + guidStr; + + fceu_mkpath( path.c_str() ); + + path += "/default.txt"; + + if ( !fceu_file_exists( path.c_str() ) ) + { + FILE *fp; + + fp = ::fopen( path.c_str(), "w" ); + + if ( fp != NULL ) + { + const char *defaultMap; + + defaultMap = SDL_GameControllerMapping(gc); + + if ( defaultMap ) + { + //printf("GameController Mapping: %s\n", defaultMap ); + fprintf( fp, "%s", defaultMap ); + } + ::fclose(fp); + } + } + } +} + +void jsDev_t::print(void) +{ + char guidStr[64]; + + SDL_JoystickGUID guid = SDL_JoystickGetGUID( js ); + + SDL_JoystickGetGUIDString( guid, guidStr, sizeof(guidStr) ); + + printf("JoyStickID: %i: '%s' \n", + SDL_JoystickInstanceID( js ), SDL_JoystickName( js ) ); + printf("GUID: %s \n", guidStr ); + printf("NumAxes: %i \n", SDL_JoystickNumAxes(js) ); + printf("NumButtons: %i \n", SDL_JoystickNumButtons(js) ); + printf("NumHats: %i \n", SDL_JoystickNumHats(js) ); + + if ( gc ) + { + printf("GameController Name: '%s'\n", SDL_GameControllerName(gc) ); + printf("GameController Mapping: %s\n", SDL_GameControllerMapping(gc) ); + } +} + +static jsDev_t jsDev[ MAX_JOYSTICKS ]; + +//******************************************************************************** +nesGamePadMap_t::nesGamePadMap_t(void) +{ + clearMapping(); +} +//******************************************************************************** +nesGamePadMap_t::~nesGamePadMap_t(void) +{ + +} +//******************************************************************************** +void nesGamePadMap_t::clearMapping(void) +{ + guid[0] = 0; + name[0] = 0; + os[0] = 0; + for (int i=0; i= 0 ) + { + strcpy( btn[bIdx], val[i] ); + } + else if ( strcmp( id[i], "platform" ) == 0 ) + { + strcpy( os, val[i] ); + } + } + return 0; +} +//******************************************************************************** +GamePad_t::GamePad_t(void) +{ + devIdx = -1; + portNum = 0; + + for (int i=0; i= 0 ) + { + jsDev[ devIdx ].unbindPort( portNum ); + } + + devIdx = in; + + if ( devIdx >= 0 ) + { + jsDev[ devIdx ].bindPort( portNum ); + } + return 0; +} +//******************************************************************************** +const char *GamePad_t::getGUID(void) +{ + if ( devIdx < 0 ) + { + return "keyboard"; + } + if ( jsDev[ devIdx ].isConnected() ) + { + return jsDev[ devIdx ].getGUID(); + } + return NULL; +} +//******************************************************************************** +static int sdlButton2NesGpIdx( const char *id ) +{ + int i, idx = -1; + + for (i=0; ibtn[i][0] == 0) + { + continue; + } + if (gpm->btn[i][0] == 'k') + { + SDL_Keycode key; + + bmap[i].ButtType = BUTTC_KEYBOARD; + bmap[i].DeviceNum = -1; + + key = SDL_GetKeyFromName( &gpm->btn[i][1] ); + + if ( key != SDLK_UNKNOWN ) + { + bmap[i].ButtonNum = key; + } + else + { + bmap[i].ButtonNum = -1; + } + } + else if ( (gpm->btn[i][0] == 'b') && isdigit( gpm->btn[i][1] ) ) + { + bmap[i].ButtType = BUTTC_JOYSTICK; + bmap[i].DeviceNum = devIdx; + bmap[i].ButtonNum = atoi( &gpm->btn[i][1] ); + } + else if ( (gpm->btn[i][0] == 'h') && isdigit( gpm->btn[i][1] ) && + (gpm->btn[i][2] == '.') && isdigit( gpm->btn[i][3] ) ) + { + int hatIdx, hatVal; + + hatIdx = gpm->btn[i][1] - '0'; + hatVal = atoi( &gpm->btn[i][3] ); + + bmap[i].ButtType = BUTTC_JOYSTICK; + bmap[i].DeviceNum = devIdx; + bmap[i].ButtonNum = 0x2000 | ( (hatIdx & 0x1F) << 8) | (hatVal & 0xFF); + } + else if ( (gpm->btn[i][0] == 'a') || (gpm->btn[i][1] == 'a') ) + { + int l=0, axisIdx=0, axisSign=0; + + l=0; + if ( gpm->btn[i][l] == '-' ) + { + axisSign = 1; l++; + } + else if ( gpm->btn[i][l] == '+' ) + { + axisSign = 0; l++; + } + + if ( gpm->btn[i][l] == 'a' ) + { + l++; + } + if ( isdigit( gpm->btn[i][l] ) ) + { + axisIdx = atoi( &gpm->btn[i][l] ); + + while ( isdigit(gpm->btn[i][l]) ) l++; + } + if ( gpm->btn[i][l] == '-' ) + { + axisSign = 1; l++; + } + else if ( gpm->btn[i][l] == '+' ) + { + axisSign = 0; l++; + } + bmap[i].ButtType = BUTTC_JOYSTICK; + bmap[i].DeviceNum = devIdx; + bmap[i].ButtonNum = 0x8000 | (axisSign ? 0x4000 : 0) | (axisIdx & 0xFF); + } + } + return 0; +} +//******************************************************************************** +int GamePad_t::setMapping( const char *map ) +{ + nesGamePadMap_t gpm; + + gpm.parseMapping( map ); + setMapping( &gpm ); + + return 0; +} +//******************************************************************************** +int GamePad_t::getMapFromFile( const char *filename, char *out ) +{ + int i=0,j=0; + FILE *fp; + char line[256]; + + out[0] = 0; + + fp = ::fopen( filename, "r" ); + + if ( fp == NULL ) + { + return -1; + } + while ( fgets( line, sizeof(line), fp ) != 0 ) + { + i=0; + while (line[i] != 0) + { + if ( line[i] == '#' ) + { + line[i] = 0; break; + } + i++; + } + + if ( i < 32 ) continue; // need at least 32 chars for a valid line entry + + i=0; j=0; + while ( isspace(line[i]) ) i++; + + while ( line[i] != 0 ) + { + out[j] = line[i]; i++; j++; + } + out[j] = 0; + + if ( j < 34 ) continue; + + break; + } + + ::fclose(fp); + + return (j < 34); +} +//******************************************************************************** +int GamePad_t::getDefaultMap( char *out, const char *guid ) +{ + char txtMap[256]; + const char *baseDir = FCEUI_GetBaseDirectory(); + std::string path; + + out[0] = 0; + + if ( devIdx < 0 ) + { + guid = "keyboard"; + } + if ( guid == NULL ) + { + if ( jsDev[ devIdx ].isConnected() ) + { + guid = jsDev[ devIdx ].getGUID(); + } + } + if ( guid == NULL ) + { + return -1; + } + + path = std::string(baseDir) + "/input/" + std::string(guid) + "/default.txt"; + + if ( getMapFromFile( path.c_str(), txtMap ) == 0 ) + { + printf("Using Mapping From File: %s\n", path.c_str() ); + strcpy( out, txtMap ); + return 0; + } + + if ( devIdx >= 0 ) + { + if ( jsDev[ devIdx ].gc ) + { + char *sdlMapping; + + sdlMapping = SDL_GameControllerMapping( jsDev[ devIdx ].gc ); + + if ( sdlMapping == NULL ) return -1; + + strcpy( out, sdlMapping ); + + SDL_free(sdlMapping); + + return 0; + } + } + else + { + if ( strcmp( guid, "keyboard" ) == 0 ) + { + for (int x=0; x= 0 ) + { + if ( !jsDev[devIdx].isConnected() ) + { + printf("Error: JS%i Not Connected\n", devIdx ); + return -1; + } + guid = jsDev[devIdx].getGUID(); + } + else + { + guid = "keyboard"; + } + path = std::string(baseDir) + "/input/" + std::string(guid); + + fceu_mkpath( path.c_str() ); + + path += "/" + std::string(name) + ".txt"; + + output.assign( guid ); + output.append( "," ); + output.append( name ); + output.append( "," ); + + for (i=0; i> 8) & 0x1F, bmap[i].ButtonNum & 0xFF ); + } + else if (bmap[i].ButtonNum & 0x8000) + { + /* Axis "button" */ + sprintf( stmp, "%ca%i", + (bmap[i].ButtonNum & 0x4000) ? '-' : '+', bmap[i].ButtonNum & 0x3FFF ); + } + else + { + /* Button */ + sprintf( stmp, "b%i", bmap[i].ButtonNum ); + } + } + output.append( buttonNames[i] ); + output.append( ":" ); + output.append( stmp ); + output.append( "," ); + } + + return saveMappingToFile( path.c_str(), output.c_str() ); +} +//******************************************************************************** +int GamePad_t::saveMappingToFile( const char *filename, const char *txtMap ) +{ + FILE *fp; + + fp = ::fopen(filename, "w"); + + if ( fp == NULL ) + { + return -1; + } + fprintf( fp, "%s\n", txtMap ); + + ::fclose(fp); + + return 0; +} +//******************************************************************************** +int GamePad_t::createProfile( const char *name ) +{ + const char *guid = NULL; + const char *baseDir = FCEUI_GetBaseDirectory(); + std::string path; + //QDir dir; + + if ( baseDir[0] == 0 ) + { + printf("Error: Invalid base directory\n"); + return -1; + } + if ( devIdx >= 0 ) + { + if ( !jsDev[devIdx].isConnected() ) + { + printf("Error: JS%i Not Connected\n", devIdx ); + return -1; + } + guid = jsDev[devIdx].getGUID(); + } + else + { + guid = "keyboard"; + } + path = std::string(baseDir) + "/input/" + std::string(guid); + + fceu_mkpath( path.c_str() ); + //printf("DIR: '%s'\n", path.c_str() ); + + //path += "/" + std::string(name) + ".txt"; + + //printf("File: '%s'\n", path.c_str() ); + + saveCurrentMapToFile( name ); + + return 0; +} +//******************************************************************************** +int GamePad_t::deleteMapping( const char *name ) +{ + const char *guid = NULL; + const char *baseDir = FCEUI_GetBaseDirectory(); + std::string path; + + if ( baseDir[0] == 0 ) + { + printf("Error: Invalid base directory\n"); + return -1; + } + if ( devIdx >= 0 ) + { + if ( !jsDev[devIdx].isConnected() ) + { + printf("Error: JS%i Not Connected\n", devIdx ); + return -1; + } + guid = jsDev[devIdx].getGUID(); + } + else + { + guid = "keyboard"; + } + path = std::string(baseDir) + "/input/" + std::string(guid) + + "/" + std::string(name) + ".txt"; + + //printf("File: '%s'\n", path.c_str() ); + + return remove( path.c_str() ); +} +//******************************************************************************** +jsDev_t *getJoystickDevice( int devNum ) +{ + if ( (devNum >= 0) && (devNum < MAX_JOYSTICKS) ) + { + return &jsDev[ devNum ]; + } + return NULL; +} + +//******************************************************************************** /** * Tests if the given button is active on the joystick. */ int DTestButtonJoy(ButtConfig *bc) { - int x; + SDL_Joystick *js; - for(x = 0; x < bc->NumC; x++) + if (bc->ButtonNum == -1) { - if(bc->ButtonNum[x] & 0x2000) - { - /* Hat "button" */ - if(SDL_JoystickGetHat(s_Joysticks[bc->DeviceNum[x]], - ((bc->ButtonNum[x] >> 8) & 0x1F)) & - (bc->ButtonNum[x]&0xFF)) - return 1; - } - else if(bc->ButtonNum[x] & 0x8000) - { - /* Axis "button" */ - int pos; - pos = SDL_JoystickGetAxis(s_Joysticks[bc->DeviceNum[x]], - bc->ButtonNum[x] & 16383); - if ((bc->ButtonNum[x] & 0x4000) && pos <= -16383) { - return 1; - } else if (!(bc->ButtonNum[x] & 0x4000) && pos >= 16363) { - return 1; - } - } - else if(SDL_JoystickGetButton(s_Joysticks[bc->DeviceNum[x]], - bc->ButtonNum[x])) - return 1; + return 0; } + if ( bc->DeviceNum < 0 ) + { + return 0; + } + js = jsDev[bc->DeviceNum].getJS(); + + if (bc->ButtonNum & 0x2000) + { + /* Hat "button" */ + if (SDL_JoystickGetHat( js, + ((bc->ButtonNum >> 8) & 0x1F)) & + (bc->ButtonNum&0xFF)) + { + bc->state = 1; + return 1; + } + else + { + bc->state = 0; + } + } + else if (bc->ButtonNum & 0x8000) + { + /* Axis "button" */ + int pos; + pos = SDL_JoystickGetAxis( js, + bc->ButtonNum & 0x3FFF); + if ((bc->ButtonNum & 0x4000) && pos <= -16383) + { + bc->state = 1; + return 1; + } + else if (!(bc->ButtonNum & 0x4000) && pos >= 16363) + { + bc->state = 1; + return 1; + } + else + { + bc->state = 0; + } + } + else if (SDL_JoystickGetButton( js, + bc->ButtonNum)) + { + bc->state = 1; + return 1; + } + else + { + bc->state = 0; + } + return 0; } +//******************************************************************************** + +//static void printJoystick( SDL_Joystick *js ) +//{ +// char guidStr[64]; +// SDL_Joystick *js; +// +// js = jsDev[i].getJS(); +// +// SDL_JoystickGUID guid = SDL_JoystickGetGUID( js ); +// +// SDL_JoystickGetGUIDString( guid, guidStr, sizeof(guidStr) ); +// +// printf("JoyStickID: %i: %s \n", +// SDL_JoystickInstanceID( js ), SDL_JoystickName( js ) ); +// printf("GUID: %s \n", guidStr ); +// printf("NumAxes: %i \n", SDL_JoystickNumAxes(js) ); +// printf("NumButtons: %i \n", SDL_JoystickNumButtons(js) ); +// printf("NumHats: %i \n", SDL_JoystickNumHats(js) ); +// +//} + +//******************************************************************************** /** * Shutdown the SDL joystick subsystem. */ int -KillJoysticks() +KillJoysticks(void) { int n; /* joystick index */ - if(!s_jinited) { + if (!s_jinited) { return -1; } - for(n = 0; n < MAX_JOYSTICKS; n++) { - if (s_Joysticks[n] != 0) { - SDL_JoystickClose(s_Joysticks[n]); - } - s_Joysticks[n]=0; + for (n = 0; n < MAX_JOYSTICKS; n++) + { + jsDev[n].close(); } SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + + printf("Kill Joysticks:\n"); + s_jinited = 0; + return 0; } +//******************************************************************************** +int AddJoystick( int which ) +{ + if ( jsDev[ which ].isConnected() ) + { + //printf("Error: Joystick already exists at device index %i \n", which ); + return -1; + } + else + { + if ( SDL_IsGameController(which) ) + { + jsDev[which].gc = SDL_GameControllerOpen(which); + + if ( jsDev[which].gc == NULL ) + { + printf("Could not open game controller %d: %s.\n", + which, SDL_GetError()); + } + else + { + //printf("Added Joystick: %i \n", which ); + jsDev[which].init(which); + //jsDev[which].print(); + //printJoystick( s_Joysticks[which] ); + } + } + else + { + jsDev[which].js = SDL_JoystickOpen(which); + + if ( jsDev[which].js == NULL ) + { + printf("Could not open joystick %d: %s.\n", + which, SDL_GetError()); + } + else + { + //printf("Added Joystick: %i \n", which ); + jsDev[which].init(which); + //jsDev[which].print(); + //printJoystick( s_Joysticks[which] ); + } + } + } + return 0; +} + +//******************************************************************************** +int RemoveJoystick( int which ) +{ + //printf("Remove Joystick: %i \n", which ); + + for (int i=0; iMAX_JOYSTICKS) { + if (total > MAX_JOYSTICKS) + { total = MAX_JOYSTICKS; } - for(n = 0; n < total; n++) { + for (n = 0; n < total; n++) + { /* Open the joystick under SDL. */ - s_Joysticks[n] = SDL_JoystickOpen(n); - //printf("Could not open joystick %d: %s.\n", - //joy[n] - 1, SDL_GetError()); - continue; + AddJoystick(n); } + printf("Init Joysticks: %i \n", total ); s_jinited = 1; return 1; } +//******************************************************************************** diff --git a/src/drivers/sdl/sdl-joystick.h b/src/drivers/sdl/sdl-joystick.h new file mode 100644 index 00000000..19f1e660 --- /dev/null +++ b/src/drivers/sdl/sdl-joystick.h @@ -0,0 +1,92 @@ +// sdl-joystick.h + +#ifndef __SDL_JOYSTICK_H__ +#define __SDL_JOYSTICK_H__ + +#include + +#include "sdl/main.h" +#include "sdl/input.h" +#include "sdl/sdl.h" + +#define MAX_JOYSTICKS 32 + +struct nesGamePadMap_t +{ + char guid[64]; + char name[128]; + char btn[GAMEPAD_NUM_BUTTONS][32]; + char os[64]; + + nesGamePadMap_t(void); + ~nesGamePadMap_t(void); + + void clearMapping(void); + int parseMapping( const char *text ); +}; + +struct jsDev_t +{ + SDL_Joystick *js; + SDL_GameController *gc; + + jsDev_t(void); + //~jsDev_t(void); + + void init( int idx ); + int close(void); + SDL_Joystick *getJS(void); + bool isGameController(void); + bool isConnected(void); + void print(void); + int bindPort( int idx ); + int unbindPort( int idx ); + int getBindPorts(void); + const char *getName(void); + const char *getGUID(void); + + private: + int devIdx; + int portBindMask; + std::string guidStr; + std::string name; +}; + +class GamePad_t +{ + public: + + ButtConfig bmap[GAMEPAD_NUM_BUTTONS]; + + GamePad_t(void); + ~GamePad_t(void); + + int init( int port, const char *guid, const char *profile = NULL ); + const char *getGUID(void); + + int loadDefaults(void); + int loadProfile( const char *name, const char *guid = NULL ); + + int getDeviceIndex(void){ return devIdx; } + int setDeviceIndex( int devIdx ); + int setMapping( const char *map ); + int setMapping( nesGamePadMap_t *map ); + + int createProfile( const char *name ); + int getMapFromFile( const char *filename, char *out ); + int getDefaultMap( char *out, const char *guid = NULL ); + int saveMappingToFile( const char *filename, const char *txtMap ); + int saveCurrentMapToFile( const char *filename ); + int deleteMapping( const char *name ); + + private: + int devIdx; + int portNum; + +}; + +extern GamePad_t GamePad[4]; + +jsDev_t *getJoystickDevice( int devNum ); + +#endif diff --git a/src/drivers/sdl/sdl-sound.cpp b/src/drivers/sdl/sdl-sound.cpp index 00b7c9a6..dbba79df 100644 --- a/src/drivers/sdl/sdl-sound.cpp +++ b/src/drivers/sdl/sdl-sound.cpp @@ -49,16 +49,21 @@ fillaudio(void *udata, uint8 *stream, int len) { + static int16_t sample = 0; int16 *tmps = (int16*)stream; len >>= 1; - while(len) { - int16 sample = 0; - if(s_BufferIn) { + while (len) + { + if (s_BufferIn) + { sample = s_Buffer[s_BufferRead]; s_BufferRead = (s_BufferRead + 1) % s_BufferSize; s_BufferIn--; } else { - sample = 0; + // Retain last known sample value, helps avoid clicking + // noise when sound system is starved of audio data. + //sample = 0; + //bufStarveDetected = 1; } *tmps = sample; @@ -179,11 +184,20 @@ WriteSound(int32 *buf, { extern int EmulationPaused; if (EmulationPaused == 0) + { + int waitCount = 0; + while(Count) { while(s_BufferIn == s_BufferSize) { - SDL_Delay(1); + SDL_Delay(1); waitCount++; + + if ( waitCount > 1000 ) + { + printf("Error: Sound sink is not draining... Breaking out of audio loop to prevent lockup.\n"); + return; + } } s_Buffer[s_BufferWrite] = *buf; @@ -196,6 +210,7 @@ WriteSound(int32 *buf, buf++; } + } } /** diff --git a/src/drivers/sdl/sdl-video.cpp b/src/drivers/sdl/sdl-video.cpp index 2b5e44f2..0edbfb4c 100644 --- a/src/drivers/sdl/sdl-video.cpp +++ b/src/drivers/sdl/sdl-video.cpp @@ -51,6 +51,10 @@ #include #include +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define LSB_FIRST +#endif + // GLOBALS extern Config *g_config; @@ -79,6 +83,13 @@ extern bool MaxSpeed; extern unsigned int gtk_draw_area_width; extern unsigned int gtk_draw_area_height; + +static int sdl_win_width = 0; +static int sdl_win_height = 0; +static SDL_Window *sdlWindow = NULL; +static SDL_Renderer *sdlRenderer = NULL; +static SDL_Texture *sdlTexture = NULL; + /** * Attempts to destroy the graphical video display. Returns 0 on * success, -1 on failure. @@ -148,6 +159,7 @@ void FCEUD_VideoChanged() int InitVideo(FCEUGI *gi) { + int vdSel; int doublebuf, xstretch, ystretch, xres, yres, show_fps; FCEUI_printf("Initializing video..."); @@ -180,7 +192,9 @@ int InitVideo(FCEUGI *gi) FCEUI_GetCurrentVidSystem(&s_srendline, &s_erendline); s_tlines = s_erendline - s_srendline + 1; - init_gui_video( s_useOpenGL ); + g_config->getOption("SDL.VideoDriver", &vdSel); + + init_gui_video( (videoDriver_t)vdSel ); s_inited = 1; @@ -188,9 +202,9 @@ int InitVideo(FCEUGI *gi) FCEUI_SetShowFPS(show_fps); #ifdef LSB_FIRST - rmask = 0x000000FF; + rmask = 0x00FF0000; gmask = 0x0000FF00; - bmask = 0x00FF0000; + bmask = 0x000000FF; #else rmask = 0x00FF0000; gmask = 0x0000FF00; @@ -210,24 +224,6 @@ int InitVideo(FCEUGI *gi) return -1; } -#ifdef OPENGL - if(s_exs <= 0.01) { - FCEUD_PrintError("xscale out of bounds."); - KillVideo(); - return -1; - } - if(s_eys <= 0.01) { - FCEUD_PrintError("yscale out of bounds."); - KillVideo(); - return -1; - } - if(s_sponge && s_useOpenGL) { - FCEUD_PrintError("scalers not compatible with openGL mode."); - KillVideo(); - return -1; - } -#endif - if ( !initBlitToHighDone ) { InitBlitToHigh(s_curbpp >> 3, @@ -467,3 +463,176 @@ void FCEUI_SetAviDisableMovieMessages(bool disable) { disableMovieMessages = disable; } + +//***************************************************************************** +int init_gtk3_sdl_video( void ) +{ + GdkWindow *gdkWin = gtk_widget_get_window(evbox); + Window win; + int sdlRendW, sdlRendH; + int vsyncEnabled=0; + + if ( (gtk_draw_area_width < GLX_NES_WIDTH) || (gtk_draw_area_height < GLX_NES_HEIGHT) ) + { + usleep(100000); + return -1; + } + if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) + { + printf("[SDL] Failed to initialize video subsystem.\n"); + return -1; + } + else + { + printf("Initialized SDL Video Subsystem\n"); + } + + if ( gdkWin == NULL ) + { + printf("Error: Failed to obtain gdkWindow Handle for evbox widget\n"); + return -1; + } + win = GDK_WINDOW_XID( gdkWin ); + + for (int i=0; incol; + nesHeight = glx_shm->nrow; + } + //printf(" %i x %i \n", nesWidth, nesHeight ); + float xscale = (float)gtk_draw_area_width / (float)nesWidth; + float yscale = (float)gtk_draw_area_height / (float)nesHeight; + + if (xscale < yscale ) + { + yscale = xscale; + } + else + { + xscale = yscale; + } + + rw=(int)(nesWidth*xscale); + rh=(int)(nesHeight*yscale); + //sx=sdlViewport.x + (view_width-rw)/2; + //sy=sdlViewport.y + (view_height-rh)/2; + sx=(gtk_draw_area_width-rw)/2; + sy=(gtk_draw_area_height-rh)/2; + + if ( (sdlRenderer == NULL) || (sdlTexture == NULL) ) + { + return -1; + } + + SDL_SetRenderDrawColor( sdlRenderer, 0, 0, 0, 0 ); + + SDL_RenderClear(sdlRenderer); + + uint8_t *textureBuffer; + int rowPitch; + SDL_LockTexture( sdlTexture, nullptr, (void**)&textureBuffer, &rowPitch); + { + memcpy( textureBuffer, glx_shm->pixbuf, GLX_NES_HEIGHT*GLX_NES_WIDTH*sizeof(uint32_t) ); + } + SDL_UnlockTexture(sdlTexture); + + //SDL_RenderSetViewport( sdlRenderer, &sdlViewport ); + + SDL_Rect source = {0, 0, nesWidth, nesHeight }; + SDL_Rect dest = { sx, sy, rw, rh }; + SDL_RenderCopy(sdlRenderer, sdlTexture, &source, &dest); + + SDL_RenderPresent(sdlRenderer); + + return 0; +} +//***************************************************************************** diff --git a/src/drivers/sdl/sdl-video.h b/src/drivers/sdl/sdl-video.h index 82ac15f7..efc055e1 100644 --- a/src/drivers/sdl/sdl-video.h +++ b/src/drivers/sdl/sdl-video.h @@ -13,5 +13,11 @@ bool FCEUI_AviEnableHUDrecording(); void FCEUI_SetAviEnableHUDrecording(bool enable); bool FCEUI_AviDisableMovieMessages(); void FCEUI_SetAviDisableMovieMessages(bool disable); + +int init_gtk3_sdl_video(void); +int destroy_gtk3_sdl_video(void); +int gtk3_sdl_render(void); +int gtk3_sdl_resize(void); + #endif diff --git a/src/drivers/sdl/sdl.cpp b/src/drivers/sdl/sdl.cpp index dd3d1c83..25f7f0aa 100644 --- a/src/drivers/sdl/sdl.cpp +++ b/src/drivers/sdl/sdl.cpp @@ -35,6 +35,8 @@ #include "gui.h" #endif +#include "fceux_git_info.h" + #include #include #include @@ -57,6 +59,7 @@ extern bool MaxSpeed; int isloaded; bool turbo = false; +bool gtk_gui_run = true; int closeFinishedMovie = 0; @@ -77,6 +80,8 @@ int pal_emulation; int dendy; bool swapDuty; +static bool luaScriptRunning = false; + // -Video Modes Tag- : See --special static const char *DriverUsage= "Option Value Description\n" @@ -179,6 +184,8 @@ static void ShowUsage(char *prog) printf("Compiled with GTK version %d.%d.%d\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION ); //printf("Linked with GTK version %d.%d.%d\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION ); #endif + printf("git URL: %s\n", fceu_get_git_url() ); + printf("git Rev: %s\n", fceu_get_git_rev() ); } @@ -330,8 +337,8 @@ DriverKill() if (!noconfig) g_config->save(); - if(inited&2) - KillJoysticks(); + KillJoysticks(); + if(inited&4) KillVideo(); if(inited&1) @@ -348,6 +355,7 @@ FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count) { + int blitDone = 0; extern int FCEUDnetplay; #ifdef CREATE_AVI @@ -374,8 +382,8 @@ FCEUD_Update(uint8 *XBuf, if (!mutecapture) if(Count > 0 && Buffer) WriteSound(Buffer,Count); } - if(inited & 2) - FCEUD_UpdateInput(); + // if(inited & 2) + // FCEUD_UpdateInput(); if(XBuf && (inited & 4)) BlitScreen(XBuf); //SpeedThrottle(); @@ -407,7 +415,9 @@ FCEUD_Update(uint8 *XBuf, // don't underflow when scaling fps if(g_fpsScale>1.0 || ((tmpcan < Count*0.90) && !uflow)) { if(XBuf && (inited&4) && !(NoWaiting & 2)) - BlitScreen(XBuf); + { + BlitScreen(XBuf); blitDone = 1; + } Buffer+=can; Count-=can; if(Count) { @@ -442,24 +452,23 @@ FCEUD_Update(uint8 *XBuf, } } else { - if(!NoWaiting && (!(eoptions&EO_NOTHROTTLE) || FCEUI_EmulationPaused())) - while (SpeedThrottle()) + //if(!NoWaiting && (!(eoptions&EO_NOTHROTTLE) || FCEUI_EmulationPaused())) + //while (SpeedThrottle()) + //{ + // FCEUD_UpdateInput(); + //} + if (XBuf && (inited&4)) { - FCEUD_UpdateInput(); - } - if(XBuf && (inited&4)) { - BlitScreen(XBuf); + BlitScreen(XBuf); blitDone = 1; + } + } + if ( !blitDone ) + { + if (XBuf && (inited&4)) + { + BlitScreen(XBuf); blitDone = 1; } } - FCEUD_UpdateInput(); - //if(!Count && !NoWaiting && !(eoptions&EO_NOTHROTTLE)) - // SpeedThrottle(); - //if(XBuf && (inited&4)) - //{ - // BlitScreen(XBuf); - //} - //if(Count) - // WriteSound(Buffer,Count,NoWaiting); //FCEUD_UpdateInput(); } @@ -552,10 +561,15 @@ int main(int argc, char *argv[]) #endif /* SDL_INIT_VIDEO Needed for (joystick config) event processing? */ - if(SDL_Init(SDL_INIT_VIDEO)) { + if (SDL_Init(SDL_INIT_VIDEO)) + { printf("Could not initialize SDL: %s.\n", SDL_GetError()); return(-1); } + if ( SDL_SetHint( SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1" ) == SDL_FALSE ) + { + printf("Error setting SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS\n"); + } //#ifdef OPENGL // SDL_GL_LoadLibrary(0); @@ -608,12 +622,14 @@ int main(int argc, char *argv[]) std::string s; - g_config->getOption("SDL.InputCfg", &s); - if(s.size() != 0) - { - InitVideo(GameInfo); - InputCfg(s); - } + //g_config->getOption("SDL.InputCfg", &s); + // + //if(s.size() != 0) + //{ + // InitVideo(GameInfo); + // InputCfg(s); + //} + // set the FAMICOM PAD 2 Mic thing { int t; @@ -625,18 +641,6 @@ int main(int argc, char *argv[]) // update the input devices UpdateInput(g_config); - // check if opengl is enabled with a scaler and display an error and bail - int opengl; - int scaler; - g_config->getOption("SDL.OpenGL", &opengl); - g_config->getOption("SDL.SpecialFilter", &scaler); - if(opengl && scaler) - { - printf("Scalers are not supported in OpenGL mode. Terminating.\n"); - exit(2); - } - - // check for a .fcm file to convert to .fm2 g_config->getOption ("SDL.FCMConvert", &s); g_config->setOption ("SDL.FCMConvert", ""); @@ -908,7 +912,7 @@ int main(int argc, char *argv[]) #ifdef _GTK if(noGui == 0) { - while(1) + while ( gtk_gui_run ) { if(GameInfo) { @@ -916,14 +920,16 @@ int main(int argc, char *argv[]) } else { - SDL_Delay(1); + SDL_Delay(10); } + FCEUD_UpdateInput(); while(gtk_events_pending()) { gtk_main_iteration_do(FALSE); } } + printf("Exiting GUI Main Loop...\n"); } else { @@ -936,11 +942,34 @@ int main(int argc, char *argv[]) DoFun(frameskip, periodic_saves); } #endif + printf("Closing Game...\n"); CloseGame(); + printf("Exiting Infrastructure...\n"); // exit the infrastructure FCEUI_Kill(); SDL_Quit(); + +#ifdef _GTK + usleep(50000); + if ( MainWindow != NULL ) + { + printf("Destroying GUI Window...\n"); + gtk_widget_destroy( MainWindow ); MainWindow = NULL; + } + usleep(50000); + while(gtk_events_pending()) + { + //printf("Processing the last of the events...\n"); + gtk_main_iteration_do(FALSE); + } +#endif + // LoadGame() checks for an IP and if it finds one begins a network session + // clear the NetworkIP field so this doesn't happen unintentionally + g_config->setOption ("SDL.NetworkIP", ""); + g_config->save (); + + printf("Done!\n"); return 0; } @@ -1002,6 +1031,27 @@ void FCEUD_PrintError(const char *errormsg) fprintf(stderr, "%s\n", errormsg); } +//---------------------------------------------------- +void WinLuaOnStart(intptr_t hDlgAsInt) +{ + luaScriptRunning = true; + + //printf("Lua Script Running: %i \n", luaScriptRunning ); +} +//---------------------------------------------------- +void WinLuaOnStop(intptr_t hDlgAsInt) +{ + luaScriptRunning = false; + + //printf("Lua Script Running: %i \n", luaScriptRunning ); +} +//---------------------------------------------------- +void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str) +{ + printf("Lua Output: %s\n", str ); +} +//---------------------------------------------------- + // dummy functions diff --git a/src/drivers/videolog/nesvideos-piece.cpp b/src/drivers/videolog/nesvideos-piece.cpp index 5bb82b4a..54763abd 100644 --- a/src/drivers/videolog/nesvideos-piece.cpp +++ b/src/drivers/videolog/nesvideos-piece.cpp @@ -828,7 +828,7 @@ extern "C" || new_height != LogoInfo::height) { if(new_height < LogoInfo::height || new_height > LogoInfo::height+20) - fprintf(stderr, "'%s': ERROR, expected %dx%d, got %dx%d\n", fn, + fprintf(stderr, "'%s': ERROR, expected %ux%u, got %ux%u\n", fn, LogoInfo::width, LogoInfo::height, new_width, new_height); } @@ -857,7 +857,7 @@ extern "C" std::string avdir = "/home/you/yourlogo/"; char AvName[512]; - sprintf(AvName, "logo_%d_%d_f%03u.png", + sprintf(AvName, "logo_%u_%u_f%03u.png", LogoInfo::width, LogoInfo::height, frameno); diff --git a/src/drivers/win/Win32InputBox.cpp b/src/drivers/win/Win32InputBox.cpp index 3c4ce64d..78cb968a 100644 --- a/src/drivers/win/Win32InputBox.cpp +++ b/src/drivers/win/Win32InputBox.cpp @@ -246,6 +246,29 @@ INT_PTR CWin32InputBox::GetInteger( return ret; } +INT_PTR CWin32InputBox::GetString( + LPCTSTR szTitle, + LPCTSTR szPrompt, + CHAR* result, + HWND hwndParent) +{ + WIN32INPUTBOX_PARAM param; + + char szResult[32+1]; + sprintf(szResult, ""); + param.szTitle = szTitle; + param.szPrompt = szPrompt; + param.szResult = szResult; + param.nResultSize = sizeof(szResult); + param.bMultiline = false; + param.hwndOwner = hwndParent; + + INT_PTR ret = InputBoxEx(¶m); + if (ret == IDOK) + sprintf(result, "%s", szResult); + return ret; +} + void CWin32InputBox::InitDialog() { // Set the button captions @@ -290,7 +313,7 @@ void CWin32InputBox::InitDialog() 0, 0, rectDlg.right - rectDlg.left, - rectDlg.bottom - rectDlg.top - (rectEdit1.bottom - rectEdit1.top), + rectDlg.bottom - rectDlg.top - (rectEdit1.bottom - rectEdit1.top) + 16, SWP_NOMOVE); } @@ -302,7 +325,7 @@ void CWin32InputBox::InitDialog() 0, 0, rectDlg.right - rectDlg.left, - rectEdit1.bottom - rectDlg.top + 5, + rectEdit1.bottom - rectDlg.top + 5 + 16, SWP_NOMOVE); ::ShowWindow(hwndEdit2, SW_HIDE); diff --git a/src/drivers/win/Win32InputBox.h b/src/drivers/win/Win32InputBox.h index e7c87fbf..8d03cef0 100644 --- a/src/drivers/win/Win32InputBox.h +++ b/src/drivers/win/Win32InputBox.h @@ -99,6 +99,12 @@ public: LPCTSTR szPrompt, int& result, HWND hwndParent = 0); + + static INT_PTR GetString( + LPCTSTR szTitle, + LPCTSTR szPrompt, + CHAR* result, + HWND hwndParent = 0); }; #endif \ No newline at end of file diff --git a/src/drivers/win/input.cpp b/src/drivers/win/input.cpp index 3420e8b9..dde34a06 100644 --- a/src/drivers/win/input.cpp +++ b/src/drivers/win/input.cpp @@ -106,8 +106,6 @@ static uint32 FTrainerData=0; static uint8 TopRiderData=0; static uint32 FamiNetSysData = 0; -static uint8 BWorldData[1+13+1]; - static void UpdateFKB(void); static void UpdateSuborKB(void); void UpdateGamepad(void); diff --git a/src/drivers/win/input.h b/src/drivers/win/input.h index 015eec49..beca0918 100644 --- a/src/drivers/win/input.h +++ b/src/drivers/win/input.h @@ -1,5 +1,5 @@ #ifndef WIN_INPUT_H -#define WIN_INPU_H +#define WIN_INPUT_H #include "dinput.h" @@ -30,6 +30,8 @@ extern LPDIRECTINPUT7 lpDI; extern int InputType[3]; //extern int UsrInputType[3]; extern int cidisabled; +extern uint8 BWorldData[1 + 13 + 1]; + #ifndef _aosdfjk02fmasf #define _aosdfjk02fmasf diff --git a/src/drivers/win/monitor.cpp b/src/drivers/win/monitor.cpp index d70c13a4..770511dd 100644 --- a/src/drivers/win/monitor.cpp +++ b/src/drivers/win/monitor.cpp @@ -108,7 +108,7 @@ BOOL updateResults(HWND hwndDlg, int rule) int chosen_rules[NUMBER_OF_RULES] = { 0 }; unsigned int values[NUMBER_OF_RULES] = { 0 }; - for (int i=0;icomment) free(sep->comment); + free(sep); } if (msg.comment) free(msg.comment); diff --git a/src/drivers/win/window.cpp b/src/drivers/win/window.cpp index 548d621d..27fbb095 100644 --- a/src/drivers/win/window.cpp +++ b/src/drivers/win/window.cpp @@ -148,6 +148,7 @@ int menuYoffset = 0; bool wasPausedByCheats = false; //For unpausing the emulator if paused by the cheats dialog bool rightClickEnabled = true; //If set to false, the right click context menu will be disabled. bool fullscreenByDoubleclick = false; +uint8 BWorldData[1 + 13 + 1]; //Function Prototypes void ChangeMenuItemText(int menuitem, string text); //Alters a menu item name @@ -381,6 +382,7 @@ void updateGameDependentMenus() MENU_SWITCH_DISK, MENU_EJECT_DISK, MENU_RECORD_AVI, + MENU_INPUT_BARCODE, MENU_STOP_AVI, MENU_RECORD_WAV, MENU_STOP_WAV, @@ -1303,7 +1305,7 @@ void DumpSubtitles(HWND hWnd) for (unsigned int i = 0; i < subtitleFrames.size(); i++) { - fprintf(srtfile, "%i\n", i+1); // starts with 1, not 0 + fprintf(srtfile, "%u\n", i+1); // starts with 1, not 0 double seconds, ms, endseconds, endms; seconds = subtitleFrames[i]/fps; if (i+1 < subtitleFrames.size()) // there's another subtitle coming after this one @@ -1327,8 +1329,8 @@ void DumpSubtitles(HWND hWnd) floor(endseconds/3600), (int)floor(endseconds/60) % 60, (int)floor(endseconds) % 60, (int)(endms*1000)); fprintf(srtfile, "%s\n\n", subtitleMessages[i].c_str()); // new line for every subtitle } + fclose(srtfile); } - fclose(srtfile); } return; @@ -1930,7 +1932,24 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) case MENU_INSERT_COIN: FCEUI_VSUniCoin(); break; - + case MENU_INPUT_BARCODE: + char bbuf[32 + 1]; + if ((CWin32InputBox::GetString("Input Barcode", "Input full 13- or 8-digit barcode to be directly send to the reader. Or input partial 12- or 7-digit number to allow the program to calculate control code automatically.", bbuf, hWnd) == IDOK)) { + uint32 stl = strlen(bbuf); + if (InputType[2] == SIFC_BWORLD) { + strcpy((char *)&BWorldData[1], (char *)bbuf); + BWorldData[0] = 1; + FCEU_DispMessage("Barcode entered: %s", 0, bbuf); + } + else { + if(FCEUI_DatachSet((uint8 *)bbuf) == 1) + FCEU_DispMessage("Barcode entered: %s", 0, bbuf); + else + FCEU_DispMessage("Invalid barcode size or characters!", 0); + } + } + break; + //Emulation submenu case ID_NES_PAUSE: FCEUI_ToggleEmulationPause(); @@ -2521,6 +2540,7 @@ adelikat: Outsourced this to a remappable hotkey EnableMenuItem(fceumenu,MENU_EJECT_DISK,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_EJECT_DISK)?MF_ENABLED:MF_GRAYED)); EnableMenuItem(fceumenu,MENU_SWITCH_DISK,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_SWITCH_DISK)?MF_ENABLED:MF_GRAYED)); EnableMenuItem(fceumenu,MENU_INSERT_COIN,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_INSERT_COIN)?MF_ENABLED:MF_GRAYED)); + EnableMenuItem(fceumenu,MENU_INPUT_BARCODE,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_INPUT_BARCODE)?MF_ENABLED:MF_GRAYED)); EnableMenuItem(fceumenu,MENU_TASEDITOR,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_TASEDITOR)?MF_ENABLED:MF_GRAYED)); EnableMenuItem(fceumenu,MENU_CLOSE_FILE,MF_BYCOMMAND | (FCEU_IsValidUI(FCEUI_CLOSEGAME) && GameInfo ?MF_ENABLED:MF_GRAYED)); EnableMenuItem(fceumenu,MENU_RECENT_FILES,MF_BYCOMMAND | ((FCEU_IsValidUI(FCEUI_OPENGAME) && HasRecentFiles()) ?MF_ENABLED:MF_GRAYED)); //adelikat - added && recent_files, otherwise this line prevents recent from ever being gray when TAS Editor is not engaged @@ -3506,4 +3526,4 @@ inline bool IsLetterLegalDecHexMixed(char letter) inline bool IsLetterLegalUnsignedDecHexMixed(char letter) { return letter >= '0' && letter <= '9' || letter >= 'A' && letter <= 'F' || letter >= 'a' && letter <= 'f' || letter == '$'; -} \ No newline at end of file +} diff --git a/src/file.cpp b/src/file.cpp index f7f58cbd..9fe6e933 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -465,6 +465,11 @@ void FCEUI_SetBaseDirectory(std::string const & dir) { BaseDirectory = dir; } +/// Gets the base directory +const char *FCEUI_GetBaseDirectory(void) +{ + return BaseDirectory.c_str(); +} static char *odirs[FCEUIOD__COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0}; // odirs, odors. ^_^ diff --git a/src/ines.cpp b/src/ines.cpp index 1b75ae07..00abebeb 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -956,7 +956,7 @@ init_ok: } // bbit edited: the whole function below was added -int iNesSave() { +int iNesSave(void) { char name[2048]; strcpy(name, LoadedRomFName); @@ -967,7 +967,7 @@ int iNesSave() { return iNesSaveAs(name); } -int iNesSaveAs(char* name) +int iNesSaveAs(const char* name) { //adelikat: TODO: iNesSave() and this have pretty much the same code, outsource the common code to a single function //caitsith2: done. iNesSave() now gets filename and calls iNesSaveAs with that filename. diff --git a/src/ines.h b/src/ines.h index 6ad2657b..6f9d65e8 100644 --- a/src/ines.h +++ b/src/ines.h @@ -43,8 +43,8 @@ extern uint8 *VROM; extern uint32 VROM_size; extern uint32 ROM_size; extern uint8 *ExtraNTARAM; -extern int iNesSave(); //bbit Edited: line added -extern int iNesSaveAs(char* name); +extern int iNesSave(void); //bbit Edited: line added +extern int iNesSaveAs(const char* name); extern char LoadedRomFName[2048]; //bbit Edited: line added extern const TMasterRomInfo* MasterRomInfo; extern TMasterRomInfoParams MasterRomInfoParams; diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index 645eaf31..42344162 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -170,11 +170,11 @@ static intptr_t info_uid; #ifdef WIN32 extern HWND LuaConsoleHWnd; extern INT_PTR CALLBACK DlgLuaScriptDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); +void TaseditorDisableManualFunctionIfNeeded(); +#endif extern void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str); extern void WinLuaOnStart(intptr_t hDlgAsInt); extern void WinLuaOnStop(intptr_t hDlgAsInt); -void TaseditorDisableManualFunctionIfNeeded(); -#endif static lua_State *L; @@ -6249,9 +6249,10 @@ int FCEU_LoadLuaCode(const char *filename, const char *arg) { LuaConsoleHWnd = CreateDialog(fceu_hInstance, MAKEINTRESOURCE(IDD_LUA), hAppWnd, DlgLuaScriptDialog); info_uid = (intptr_t)LuaConsoleHWnd; #else - info_print = NULL; - info_onstart = NULL; - info_onstop = NULL; + info_print = PrintToWindowConsole; + info_onstart = WinLuaOnStart; + info_onstop = WinLuaOnStop; + info_uid = (intptr_t)0; #endif if (info_onstart) info_onstart(info_uid); diff --git a/src/palette.cpp b/src/palette.cpp index 3ab97f4a..5a9c2709 100644 --- a/src/palette.cpp +++ b/src/palette.cpp @@ -46,8 +46,8 @@ pal palette_game[64*8]; //custom palette for an individual game. (formerly palet pal palette_user[64*8]; //user's overridden palette (formerly palettec) pal palette_ntsc[64*8]; //mathematically generated NTSC palette (formerly paletten) -static bool palette_game_available; //whether palette_game is available -static bool palette_user_available; //whether palette_user is available +static bool palette_game_available=false; //whether palette_game is available +static bool palette_user_available=false; //whether palette_user is available //ntsc parameters: bool ntsccol_enable = false; //whether NTSC palette is selected @@ -289,6 +289,11 @@ static void ApplyDeemphasisComplete(pal* pal512) } } +bool FCEUI_GetUserPaletteAvail( void ) +{ + return palette_user_available; +} + void FCEUI_SetUserPalette(uint8 *pal, int nEntries) { if(!pal) diff --git a/vc/vc14_fceux.sln b/vc/vc14_fceux.sln index c598079e..87a0b3db 100644 --- a/vc/vc14_fceux.sln +++ b/vc/vc14_fceux.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2015 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fceux", "vc14_fceux.vcxproj", "{6893EF44-FEA3-46DF-B236-C4C200F54294}" EndProject Global diff --git a/web/download.html b/web/download.html index 8c2b2faf..ea94a569 100644 --- a/web/download.html +++ b/web/download.html @@ -84,6 +84,7 @@
  • Windows 32-bit
  • Windows 64-bit
  • Ubuntu Linux
  • +
  • Mac OS X
  • Source Code

    diff --git a/web/osx.html b/web/osx.html index 9459aa6c..cb6670c6 100644 --- a/web/osx.html +++ b/web/osx.html @@ -59,37 +59,23 @@
    - To compile FCEUX in osx, you must have fink or macports. The FCEUX developers recommend fink, since that's what they use, but then again, the only time they compile software on osx is when folks come nagging.

    + To run FCEUX in Mac OSX, you must have the following library dependencies installed on your system:

    -first, install the prerequisites.

    -

    -macports requires these prerequisites: scons, libsdl, zenity, lua, gtk2

    -fink requires these prerequisites: try all the same ones as macports, but i know at least one of them is named gtk+2 instead. please report your results.

    -

    -Building instructions for fink:

    -

    -CFLAGS=-I/sw/include LDFLAGS=-L/sw/lib scons

    -if you are getting link errors about 64bitness then your system is compiling fceux as 64bit but fink is providing i386 libraries. you need to force fceux to compile 32 bits:

    -CFLAGS="-I/sw/include -arch i386" LDFLAGS="-L/sw/lib -arch i386" scons

    -

    -None of the modifications listed at the paperkettle URL were necessary in our latest fink test only 18-jul-2010

    -

    -This URL is a little old, but he got FCEUX compiling via fink

    -http://beesbuzz.biz/blog/e/2009/04/14-how_to_build_fceux_for_mac_os_x.php

    -

    -Building instructions for macports:

    -

    -CFLAGS=-I/opt/local/include LDFLAGS=-L/opt/local/lib scons

    -

    -This URL is fresh, and he got FCEUX compiling via macports:

    -http://www.paperkettle.com/blog/2010/07/17/fceux-2-14a-compiled-on-mac-osx-10-6/

    -

    ----

    -

    -At any given time while fooling around you may discover that scons begins behaving irrationally. To fix this, try deleting .sconsign.dblite which will clear out its memory of what has come before.

    -

    -To clean your scons build, issue the main scons build command as discussed above with the -c parameter

    - + Qt5, SDL2, minizip, and zlib +

    + If you are attempting to use the appveyor pipeline autobuild of fceux, you must install these + dependencies via the home brew package management tool. The following commands will install + the necessary dependencies to run the autobuild: +

    +		 brew install qt5
    +		 brew install sdl2
    +		 brew install minizip
    +		 
    + If you are attempting to compile fceux, you can either install the dependencies via home brew + or you can install the dmg packages available from the Qt and SDL websites. The cmake and make + build tools are required to compile fceux. See the README file in the root directory of the + project for build instructions. You can also look at what is being done in the ./pipelines/macOS_build.sh + script if you wish to build fceux in the same way the autobuild does.