From e85eb32a0add5850cd08d853f2e2c543df42f8b9 Mon Sep 17 00:00:00 2001 From: Andrea Odetti Date: Wed, 23 Dec 2020 18:55:26 +0000 Subject: [PATCH] Add some controls via the joypad (video mode, 50% scan lines and reset). Signed-off-by: Andrea Odetti --- linux.md | 6 +++ source/frontends/retro/environment.h | 4 +- source/frontends/retro/game.cpp | 65 +++++++++++++++++++++++++++- source/frontends/retro/game.h | 7 +++ source/frontends/retro/libretro.cpp | 2 + 5 files changed, 81 insertions(+), 3 deletions(-) diff --git a/linux.md b/linux.md index dca464da..c790a497 100644 --- a/linux.md +++ b/linux.md @@ -97,6 +97,12 @@ There is an initial [libretro](https://docs.libretro.com/development/cores/devel A retropad can be plugged in port 1 (with or without analog stick). +Keyboard emulation + +* ``JOYPAD_R``: equivalent to ``F9`` to cycle video types +* ``JOYPAD_L``: equivalent to ``CTRL-SHIFT-F6`` to cycle 50% scan lines +* ``START``: equivalent to ``F2`` to reset the machine + In order to have a better experience with the keyboard, one should probably enable *Game Focus Mode* (normally Scroll-Lock) to disable hotkeys. Video works, but the vertical flip is done in software. diff --git a/source/frontends/retro/environment.h b/source/frontends/retro/environment.h index 9232ecb0..cdd2af21 100644 --- a/source/frontends/retro/environment.h +++ b/source/frontends/retro/environment.h @@ -10,8 +10,10 @@ extern retro_input_state_t input_state_cb; extern retro_environment_t environ_cb; extern retro_video_refresh_t video_cb; extern retro_audio_sample_t audio_cb; -extern retro_audio_sample_batch_t audio_batch_cb; +extern retro_audio_sample_batch_t audio_batch_cb; extern std::string retro_base_directory; +#define MAX_PADS 1 + void display_message(const std::string & message); diff --git a/source/frontends/retro/game.cpp b/source/frontends/retro/game.cpp index f437388f..953ab7a1 100644 --- a/source/frontends/retro/game.cpp +++ b/source/frontends/retro/game.cpp @@ -12,13 +12,14 @@ #include "CPU.h" #include "NTSC.h" #include "Utilities.h" +#include "Video.h" +#include "Interface.h" #include "linux/keyboard.h" #include "linux/paddle.h" #include "frontends/common2/programoptions.h" #include "frontends/common2/configuration.h" #include "frontends/common2/utils.h" -#include "frontends/retro/environment.h" #include "libretro.h" @@ -43,10 +44,18 @@ namespace } } + void updateWindowTitle() + { + GetAppleWindowTitle(); + display_message(g_pAppTitle.c_str()); + } + } +unsigned Game::input_devices[MAX_PADS] = {0}; + Game::Game() - : mySpeed(true) + : mySpeed(true), myButtonStates(RETRO_DEVICE_ID_JOYPAD_R3 + 1) { EmulatorOptions options; options.memclear = g_nMemoryClearType; @@ -87,6 +96,7 @@ void Game::executeOneFrame() void Game::processInputEvents() { input_poll_cb(); + keyboardEmulation(); } void Game::keyboardCallback(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers) @@ -215,6 +225,57 @@ void Game::processKeyUp(unsigned keycode, uint32_t character, uint16_t key_modif } } +bool Game::checkButtonPressed(unsigned id) +{ + // pressed if it is down now, but was up before + const int value = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, id); + const bool pressed = (value != 0) && myButtonStates[id] == 0; + + // update to avoid multiple fires + myButtonStates[id] = value; + + return pressed; +} + + +void Game::keyboardEmulation() +{ + if (input_devices[0] != RETRO_DEVICE_NONE) + { + if (checkButtonPressed(RETRO_DEVICE_ID_JOYPAD_R)) + { + g_eVideoType++; + if (g_eVideoType >= NUM_VIDEO_MODES) + g_eVideoType = 0; + + Config_Save_Video(); + VideoReinitialize(); + VideoRedrawScreen(); + updateWindowTitle(); + } + if (checkButtonPressed(RETRO_DEVICE_ID_JOYPAD_L)) + { + VideoStyle_e videoStyle = GetVideoStyle(); + videoStyle = VideoStyle_e(videoStyle ^ VS_HALF_SCANLINES); + + SetVideoStyle(videoStyle); + + Config_Save_Video(); + VideoReinitialize(); + VideoRedrawScreen(); + updateWindowTitle(); + } + if (checkButtonPressed(RETRO_DEVICE_ID_JOYPAD_START)) + { + ResetMachineState(); + } + } + else + { + std::fill(myButtonStates.begin(), myButtonStates.end(), 0); + } +} + void Game::drawVideoBuffer() { // this should not be necessary diff --git a/source/frontends/retro/game.h b/source/frontends/retro/game.h index 224a375e..90037705 100644 --- a/source/frontends/retro/game.h +++ b/source/frontends/retro/game.h @@ -1,6 +1,7 @@ #pragma once #include "frontends/common2/speed.h" +#include "frontends/retro/environment.h" class Game { @@ -17,6 +18,8 @@ public: static void keyboardCallback(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); + static unsigned input_devices[MAX_PADS]; + private: Speed mySpeed; // fixed speed std::vector myVideoBuffer; @@ -27,6 +30,10 @@ private: size_t myBorderlessWidth; size_t myBorderlessHeight; + std::vector myButtonStates; + + bool checkButtonPressed(unsigned id); + void keyboardEmulation(); static void processKeyDown(unsigned keycode, uint32_t character, uint16_t key_modifiers); static void processKeyUp(unsigned keycode, uint32_t character, uint16_t key_modifiers); diff --git a/source/frontends/retro/libretro.cpp b/source/frontends/retro/libretro.cpp index e73e4aa4..e453e602 100644 --- a/source/frontends/retro/libretro.cpp +++ b/source/frontends/retro/libretro.cpp @@ -61,6 +61,8 @@ void retro_set_controller_port_device(unsigned port, unsigned device) default: break; } + + Game::input_devices[port] = device; } }