From cba596dde78784ba8f737adb9e9a204df2a7a465 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 11 Sep 2020 16:05:07 -0400 Subject: [PATCH] [ion/simulator] Add actions --- ion/src/simulator/linux/Makefile | 7 +- ion/src/simulator/linux/platform_files.cpp | 21 ++++ ion/src/simulator/macos/Makefile | 3 + ion/src/simulator/macos/platform_files.mm | 32 +++++++ ion/src/simulator/shared/actions.cpp | 38 ++++++++ ion/src/simulator/shared/actions.h | 17 ++++ ion/src/simulator/shared/dummy/actions.cpp | 22 +++++ .../simulator/shared/dummy/platform_files.cpp | 17 ++++ ion/src/simulator/shared/dummy/state_file.cpp | 95 +++++++++++++++++++ ion/src/simulator/shared/events_platform.cpp | 9 +- ion/src/simulator/shared/main.cpp | 1 + .../shared/platform_action_modifier_ctrl.cpp | 13 +++ .../shared/platform_action_modifier_gui.cpp | 13 +++ ion/src/simulator/web/Makefile | 1 + ion/src/simulator/web/exports.cpp | 5 +- ion/src/simulator/windows/Makefile | 4 + ion/src/simulator/windows/platform_files.cpp | 51 ++++++++++ 17 files changed, 342 insertions(+), 7 deletions(-) create mode 100644 ion/src/simulator/linux/platform_files.cpp create mode 100644 ion/src/simulator/macos/platform_files.mm create mode 100644 ion/src/simulator/shared/actions.cpp create mode 100644 ion/src/simulator/shared/actions.h create mode 100644 ion/src/simulator/shared/dummy/actions.cpp create mode 100644 ion/src/simulator/shared/dummy/platform_files.cpp create mode 100644 ion/src/simulator/shared/dummy/state_file.cpp create mode 100644 ion/src/simulator/shared/platform_action_modifier_ctrl.cpp create mode 100644 ion/src/simulator/shared/platform_action_modifier_gui.cpp create mode 100644 ion/src/simulator/windows/platform_files.cpp diff --git a/ion/src/simulator/linux/Makefile b/ion/src/simulator/linux/Makefile index 5425edddd..a52e873eb 100644 --- a/ion/src/simulator/linux/Makefile +++ b/ion/src/simulator/linux/Makefile @@ -9,18 +9,23 @@ SFLAGS += -Iion/src/simulator/linux/include ion_src += $(addprefix ion/src/simulator/linux/, \ assets.s \ + platform_files.cpp \ platform_images.cpp \ platform_language.cpp \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ - dummy/callback.cpp \ dummy/haptics_enabled.cpp \ + dummy/keyboard_callback.cpp \ + dummy/window_callback.cpp \ + actions.cpp \ clipboard_helper.cpp \ collect_registers_x86_64.s \ collect_registers.cpp \ haptics.cpp \ journal.cpp \ + platform_action_modifier_ctrl.cpp \ + state_file.cpp \ ) ifeq ($(EPSILON_TELEMETRY),1) diff --git a/ion/src/simulator/linux/platform_files.cpp b/ion/src/simulator/linux/platform_files.cpp new file mode 100644 index 000000000..b866fe05c --- /dev/null +++ b/ion/src/simulator/linux/platform_files.cpp @@ -0,0 +1,21 @@ +#include "../shared/platform.h" + +namespace Ion { +namespace Simulator { +namespace Platform { + +const char * filePathForReading(const char * extension) { + return nullptr; +} + +const char * filePathForWriting(const char * extension) { + static char path[64]; + if (snprintf(path, sizeof(path), "/tmp/epsilon.%s", extension) < 0) { + return nullptr; + } + return path; +} + +} +} +} diff --git a/ion/src/simulator/macos/Makefile b/ion/src/simulator/macos/Makefile index 238da5daf..52a76b36a 100644 --- a/ion/src/simulator/macos/Makefile +++ b/ion/src/simulator/macos/Makefile @@ -1,4 +1,5 @@ ion_src += $(addprefix ion/src/simulator/macos/, \ + platform_files.mm \ platform_images.mm \ ) @@ -10,8 +11,10 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ clipboard_helper.cpp \ collect_registers_x86_64.s \ collect_registers.cpp \ + actions.cpp \ haptics.cpp \ journal.cpp \ + state_file.cpp \ ) ifeq ($(EPSILON_TELEMETRY),1) diff --git a/ion/src/simulator/macos/platform_files.mm b/ion/src/simulator/macos/platform_files.mm new file mode 100644 index 000000000..990cf3a5f --- /dev/null +++ b/ion/src/simulator/macos/platform_files.mm @@ -0,0 +1,32 @@ +#include "../shared/platform.h" +#include + +namespace Ion { +namespace Simulator { +namespace Platform { + +static const char * getPath(NSSavePanel * panel, const char * extension) { + [panel setAllowedFileTypes:[NSArray arrayWithObject:[NSString stringWithUTF8String:extension]]]; + static NSString * path = nil; + [path release]; path = nil; // Discard previous path if any + NSWindow * mainWindow = [[NSApplication sharedApplication] keyWindow]; + if ([panel runModal] == NSFileHandlingPanelOKButton) { + path = [[[panel URL] path] retain]; + } + [mainWindow makeKeyAndOrderFront:nil]; + return [path UTF8String]; +} + +const char * filePathForReading(const char * extension) { + NSOpenPanel * panel = [NSOpenPanel openPanel]; + return getPath(panel, extension); +} + +const char * filePathForWriting(const char * extension) { + NSSavePanel * panel = [NSSavePanel savePanel]; + return getPath(panel, extension); +} + +} +} +} diff --git a/ion/src/simulator/shared/actions.cpp b/ion/src/simulator/shared/actions.cpp new file mode 100644 index 000000000..81716d03f --- /dev/null +++ b/ion/src/simulator/shared/actions.cpp @@ -0,0 +1,38 @@ +#include "actions.h" +#include "framebuffer.h" +#include "platform.h" +#include "state_file.h" + +namespace Ion { +namespace Simulator { +namespace Actions { + +constexpr const char * kStateFileExtension = "nws"; + +void saveState() { + const char * path = Platform::filePathForWriting(kStateFileExtension); + if (path != nullptr) { + StateFile::save(path); + } +} + +#if 0 +void loadState() { +// We would need to be able to perform a reset for this to be callable anytime + const char * path = Platform::filePathForReading(kStateFileExtension); + if (path != nullptr) { + StateFile::load(path); + } +} +#endif + +void takeScreenshot() { + const char * path = Platform::filePathForWriting("png"); + if (path != nullptr) { +// Framebuffer::writeToFile(path); + } +} + +} +} +} diff --git a/ion/src/simulator/shared/actions.h b/ion/src/simulator/shared/actions.h new file mode 100644 index 000000000..ad5b1f3e2 --- /dev/null +++ b/ion/src/simulator/shared/actions.h @@ -0,0 +1,17 @@ +#ifndef ION_SIMULATOR_ACTIONS_H +#define ION_SIMULATOR_ACTIONS_H + +#include + +namespace Ion { +namespace Simulator { +namespace Actions { + +void saveState(); +void takeScreenshot(); + +} +} +} + +#endif diff --git a/ion/src/simulator/shared/dummy/actions.cpp b/ion/src/simulator/shared/dummy/actions.cpp new file mode 100644 index 000000000..1e9055507 --- /dev/null +++ b/ion/src/simulator/shared/dummy/actions.cpp @@ -0,0 +1,22 @@ +#include "../actions.h" + +namespace Ion { +namespace Simulator { +namespace Actions { + +bool actionForEvent(SDL_KeyboardEvent event) { + return false; +} + +void saveState() { +} + +void loadState() { +} + +void takeScreenshot() { +} + +} +} +} diff --git a/ion/src/simulator/shared/dummy/platform_files.cpp b/ion/src/simulator/shared/dummy/platform_files.cpp new file mode 100644 index 000000000..fb73fbf22 --- /dev/null +++ b/ion/src/simulator/shared/dummy/platform_files.cpp @@ -0,0 +1,17 @@ +#include "../platform.h" + +namespace Ion { +namespace Simulator { +namespace Platform { + +const char * filePathForReading(const char * extension) { + return nullptr; +} + +const char * filePathForWriting(const char * extension) { + return nullptr; +} + +} +} +} diff --git a/ion/src/simulator/shared/dummy/state_file.cpp b/ion/src/simulator/shared/dummy/state_file.cpp new file mode 100644 index 000000000..462f5a213 --- /dev/null +++ b/ion/src/simulator/shared/dummy/state_file.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include "journal.h" + +namespace Ion { +namespace Simulator { +namespace StateFile { + +static constexpr const char * sHeader = "NWSF"; +static constexpr int sHeaderLength = 4; +static constexpr int sVersionLength = 8; + +/* File format: * "NWSF" + "XXXXXXXX" (version) + EVENTS... */ + +static inline bool load(FILE * f) { + char buffer[sVersionLength+1]; + + // Header + buffer[sHeaderLength] = 0; + if (fread(buffer, sHeaderLength, 1, f) != 1) { + return false; + } + printf("READ\n"); + if (strcmp(buffer, sHeader) != 0) { + return false; + } + + // Software version + buffer[sVersionLength] = 0; + if (fread(buffer, sVersionLength, 1, f) != 1) { + return false; + } + if (strcmp(buffer, softwareVersion()) != 0) { + return false; + } + + // Events + Ion::Events::Journal * journal = Journal::replayJournal(); + while (fread(buffer, 1, 1, f) == 1) { + Ion::Events::Event e = Ion::Events::Event(buffer[0]); + journal->pushEvent(e); + } + Ion::Events::replayFrom(journal); + + return true; +} + +void load(const char * filename) { + FILE * f = nullptr; + if (strcmp(filename, "-") == 0) { + f = stdin; + } else { + f = fopen(filename, "rb"); + } + if (f == nullptr) { + return; + } + load(f); + fclose(f); +} + +static inline bool save(FILE * f) { + if (fwrite(sHeader, sHeaderLength, 1, f) != 1) { + return false; + } + if (fwrite(softwareVersion(), sVersionLength, 1, f) != 1) { + return false; + } + Ion::Events::Journal * journal = Journal::logJournal(); + Ion::Events::Event e; + while (!journal->isEmpty()) { + Ion::Events::Event e = journal->popEvent(); + uint8_t code = static_cast(e); + if (fwrite(&code, 1, 1, f) != 1) { + return false; + } + } + return true; +} + +void save(const char * filename) { + printf("Saving to \"%s\"\n", filename); + FILE * f = fopen(filename, "w"); + if (f == nullptr) { + return; + } + save(f); + fclose(f); +} + +} +} +} diff --git a/ion/src/simulator/shared/events_platform.cpp b/ion/src/simulator/shared/events_platform.cpp index 072b3bc2b..f89bd881e 100644 --- a/ion/src/simulator/shared/events_platform.cpp +++ b/ion/src/simulator/shared/events_platform.cpp @@ -1,6 +1,8 @@ +#include "actions.h" +#include "events.h" #include "keyboard.h" #include "layout.h" -#include "events.h" +#include "state_file.h" #include "window.h" #include @@ -12,7 +14,7 @@ namespace Ion { namespace Events { -static Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { +static inline Event eventFromSDLKeyboardEvent(SDL_KeyboardEvent event) { /* If an event is detected, we want to remove the Shift modifier to mimic the * device behaviour. If no event was detected, we restore the previous * ShiftAlphaStatus. */ @@ -120,8 +122,7 @@ static Event eventFromSDLTextInputEvent(SDL_TextInputEvent event) { Event getPlatformEvent() { SDL_Event event; Event result = None; - while (SDL_PollEvent(&event)) { - // The while is important: it'll do a fast-pass over all useless SDL events + while (SDL_PollEvent(&event)) { // That "while" is important: it'll do a fast-pass over all useless SDL events if (event.type == SDL_WINDOWEVENT) { Ion::Simulator::Window::relayout(); break; diff --git a/ion/src/simulator/shared/main.cpp b/ion/src/simulator/shared/main.cpp index c05ac937c..d93cbe225 100644 --- a/ion/src/simulator/shared/main.cpp +++ b/ion/src/simulator/shared/main.cpp @@ -2,6 +2,7 @@ #include "journal.h" #include "platform.h" #include "random.h" +#include "state_file.h" #include "telemetry.h" #include "window.h" #include diff --git a/ion/src/simulator/shared/platform_action_modifier_ctrl.cpp b/ion/src/simulator/shared/platform_action_modifier_ctrl.cpp new file mode 100644 index 000000000..9f6c3a3f2 --- /dev/null +++ b/ion/src/simulator/shared/platform_action_modifier_ctrl.cpp @@ -0,0 +1,13 @@ +#include "../shared/platform.h" + +namespace Ion { +namespace Simulator { +namespace Platform { + +SDL_Keymod actionModifier() { + return static_cast(KMOD_CTRL); +} + +} +} +} diff --git a/ion/src/simulator/shared/platform_action_modifier_gui.cpp b/ion/src/simulator/shared/platform_action_modifier_gui.cpp new file mode 100644 index 000000000..b9f3021ad --- /dev/null +++ b/ion/src/simulator/shared/platform_action_modifier_gui.cpp @@ -0,0 +1,13 @@ +#include "../shared/platform.h" + +namespace Ion { +namespace Simulator { +namespace Platform { + +SDL_Keymod actionModifier() { + return KMOD_GUI; +} + +} +} +} diff --git a/ion/src/simulator/web/Makefile b/ion/src/simulator/web/Makefile index c79e47f99..5e980c274 100644 --- a/ion/src/simulator/web/Makefile +++ b/ion/src/simulator/web/Makefile @@ -21,6 +21,7 @@ ion_src += $(addprefix ion/src/simulator/web/, \ ) ion_src += $(addprefix ion/src/simulator/shared/, \ + dummy/actions.cpp \ dummy/language.cpp \ dummy/haptics_enabled.cpp \ haptics.cpp \ diff --git a/ion/src/simulator/web/exports.cpp b/ion/src/simulator/web/exports.cpp index babe1825c..e4f32ce2b 100644 --- a/ion/src/simulator/web/exports.cpp +++ b/ion/src/simulator/web/exports.cpp @@ -1,6 +1,7 @@ #include "exports.h" -#include "../shared/events_journal.h" +#include "../shared/journal.h" #include "../shared/keyboard.h" +#include "../shared/window.h" #include const char * IonSoftwareVersion() { @@ -27,7 +28,7 @@ void IonSimulatorKeyboardKeyUp(int keyNumber) { } void IonSimulatorEventsPushEvent(int eventNumber) { - Ion::Events::Journal * j = Ion::Simulator::Events::replayJournal(); + Ion::Events::Journal * j = Ion::Simulator::Journal::replayJournal(); if (j != nullptr) { Ion::Events::Event event(eventNumber); j->pushEvent(event); diff --git a/ion/src/simulator/windows/Makefile b/ion/src/simulator/windows/Makefile index 3bb4528b8..0ebf03945 100644 --- a/ion/src/simulator/windows/Makefile +++ b/ion/src/simulator/windows/Makefile @@ -1,4 +1,5 @@ ion_src += $(addprefix ion/src/simulator/windows/, \ + platform_files.cpp \ platform_images.cpp \ platform_language.cpp \ resources.rc \ @@ -8,9 +9,12 @@ ion_src += $(addprefix ion/src/simulator/shared/, \ dummy/haptics_enabled.cpp \ dummy/keyboard_callback.cpp \ dummy/window_callback.cpp \ + actions.cpp \ clipboard_helper.cpp \ haptics.cpp \ journal.cpp \ + platform_action_modifier_ctrl.cpp \ + state_file.cpp \ ) ion_src += ion/src/shared/collect_registers.cpp diff --git a/ion/src/simulator/windows/platform_files.cpp b/ion/src/simulator/windows/platform_files.cpp new file mode 100644 index 000000000..865f47179 --- /dev/null +++ b/ion/src/simulator/windows/platform_files.cpp @@ -0,0 +1,51 @@ +#include "../shared/platform.h" +#include +#include + +namespace Ion { +namespace Simulator { +namespace Platform { + +static OPENFILENAME * getOFN(const char * extension) { + static OPENFILENAME ofn; + memset(&ofn, 0, sizeof(ofn)); // Zero-out ofn + + static char path[PATH_MAX]; + path[0] = 0; // Reset the path + + static char filter[32]; + if (snprintf(filter, sizeof(filter), "%s%c*.%s%c%c", extension, 0, extension, 0, 0) < 0) { + /* Note: We cannot use litteral \0 in the format string, otherwise snprintf + * will think the format string is finished... */ + return nullptr; + } + + ofn.lStructSize = sizeof(ofn); + ofn.lpstrFile = path; + ofn.nMaxFile = sizeof(path); + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 1; + ofn.lpstrDefExt = extension; + + return &ofn; +} + +const char * filePathForReading(const char * extension) { + OPENFILENAME * ofn = getOFN(extension); + if (ofn != nullptr && GetOpenFileName(ofn)) { + return ofn->lpstrFile; + } + return nullptr; +} + +const char * filePathForWriting(const char * extension) { + OPENFILENAME * ofn = getOFN(extension); + if (ofn != nullptr && GetSaveFileName(ofn)) { + return ofn->lpstrFile; + } + return nullptr; +} + +} +} +}