From 6578af4476e314bea56c373fccbe8a76ea566c0f Mon Sep 17 00:00:00 2001 From: namark <namark@disroot.org> Date: Sat, 17 Nov 2018 01:46:21 +0400 Subject: [PATCH] Initial source, more or less functional for mouse and keyboard events. --- Makefile | 75 +++ examples/00_press_any_key.cpp | 40 ++ examples/01_mouse_around.cpp | 7 + examples/Makefile | 57 ++ examples/common/sdl_input_grabber.cpp | 19 + examples/common/sdl_input_grabber.h | 26 + examples/versions/01_mouse_around_capture.cpp | 98 ++++ examples/versions/01_mouse_around_grab.cpp | 103 ++++ source/simple/interactive/codes.cpp | 16 + source/simple/interactive/codes.h | 500 ++++++++++++++++++ source/simple/interactive/event.cpp | 185 +++++++ source/simple/interactive/event.h | 168 ++++++ source/simple/interactive/initializer.cpp | 10 + source/simple/interactive/initializer.h | 18 + 14 files changed, 1322 insertions(+) create mode 100644 Makefile create mode 100644 examples/00_press_any_key.cpp create mode 100644 examples/01_mouse_around.cpp create mode 100644 examples/Makefile create mode 100644 examples/common/sdl_input_grabber.cpp create mode 100644 examples/common/sdl_input_grabber.h create mode 100644 examples/versions/01_mouse_around_capture.cpp create mode 100644 examples/versions/01_mouse_around_grab.cpp create mode 100644 source/simple/interactive/codes.cpp create mode 100644 source/simple/interactive/codes.h create mode 100644 source/simple/interactive/event.cpp create mode 100644 source/simple/interactive/event.h create mode 100644 source/simple/interactive/initializer.cpp create mode 100644 source/simple/interactive/initializer.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..80975ca --- /dev/null +++ b/Makefile @@ -0,0 +1,75 @@ +override CPPFLAGS += --std=c++1z +override CPPFLAGS += -MMD -MP +override CPPFLAGS += -I./include +override CPPFLAGS += $(shell cat .cxxflags 2> /dev/null | xargs) + +ARFLAGS := $(ARFLAGS)c + +PREFIX := $(DESTDIR)/usr/local +INCDIR := $(PREFIX)/include +LIBDIR := $(PREFIX)/lib + +SRCDIR := ./source +TEMPDIR := temp +DISTDIR := out +TARGET := libsimple_interactive.a +OUT := $(DISTDIR)/$(TARGET) +SOURCES := $(shell find -wholename "$(SRCDIR)/*.cpp") +HEADERS := $(shell find -wholename "$(SRCDIR)/*.hpp" && find -wholename "$(SRCDIR)/*.h") +INCLUDE := $(HEADERS:$(SRCDIR)/%=$(INCDIR)/%) +INCDIRS := $(shell dirname $(INCLUDE)) +OBJECTS := $(SOURCES:$(SRCDIR)/%.cpp=$(TEMPDIR)/%.o) +OBJDIRS := $(shell dirname $(OBJECTS)) +DEPENDS := $(OBJECTS:.o=.d) + + +$(OUT): $(OBJECTS) | $(DISTDIR) + $(AR) $(ARFLAGS) $@ $^ + +$(TEMPDIR)/%.o: $(SRCDIR)/%.cpp | $(TEMPDIR) + @mkdir -p $(@D) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $< + +$(TEMPDIR): + @mkdir $@ + +$(DISTDIR): + @mkdir $@ + +clean: + @rm $(DEPENDS) 2> /dev/null || true + @rm $(OBJECTS) 2> /dev/null || true + @rmdir -p $(OBJDIRS) 2> /dev/null || true + @echo Temporaries cleaned! + +distclean: clean + @rm $(OUT) 2> /dev/null || true + @rmdir $(DISTDIR) 2> /dev/null || true + @echo All clean! + +install: $(OUT) $(INCLUDE) | $(LIBDIR) + cp $(OUT) $(LIBDIR)/$(TARGET) + @echo Install complete! + +$(LIBDIR): + @mkdir $@ + +$(INCDIR)/%.h: $(SRCDIR)/%.h + @mkdir -p $(@D) + cp $< $@ + +$(INCDIR)/%.hpp: $(SRCDIR)/%.hpp + @mkdir -p $(@D) + cp $< $@ + +uninstall: + -rm $(INCLUDE) + @rmdir -p $(INCDIRS) 2> /dev/null || true + -rm $(LIBDIR)/$(TARGET) + @rmdir $(LIBDIR) 2> /dev/null || true + @echo Uninstall complete! + +-include $(DEPENDS) + +.PRECIOUS : $(OBJECTS) +.PHONY : clean distclean install uninstall diff --git a/examples/00_press_any_key.cpp b/examples/00_press_any_key.cpp new file mode 100644 index 0000000..40230b7 --- /dev/null +++ b/examples/00_press_any_key.cpp @@ -0,0 +1,40 @@ +#include <cstdio> +#include <thread> +#include <chrono> + +#include "simple/interactive/initializer.h" +#include "simple/interactive/event.h" +#include "simple/support/function_utils.hpp" +#include "simple/support/misc.hpp" +#include "common/sdl_input_grabber.h" + +#include "common/sdl_input_grabber.cpp" + +using namespace simple::interactive; +using namespace std::chrono_literals; + +int main() try +{ + + initializer init; + + sdl_input_grabber input_grabber; + std::puts("Press any key!"); + while(true) + if (auto e = next_event(); !e || !std::holds_alternative<key_pressed>(*e)) + std::this_thread::sleep_for(20ms); + else break; + + return 0; +} +catch(...) +{ + if(errno) + std::perror("ERROR"); + + const char* sdl_error = SDL_GetError(); + if(*sdl_error) + std::puts(sdl_error); + + throw; +} diff --git a/examples/01_mouse_around.cpp b/examples/01_mouse_around.cpp new file mode 100644 index 0000000..58e29b4 --- /dev/null +++ b/examples/01_mouse_around.cpp @@ -0,0 +1,7 @@ +#include "simple/interactive/initializer.h" + +#if SDL_VERSION_ATLEAST(2,0,4) +#include "versions/01_mouse_around_capture.cpp" +#else +#include "versions/01_mouse_around_grab.cpp" +#endif diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..e5e5b8d --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,57 @@ + +override CPPFLAGS += --std=c++1z +override CPPFLAGS += -MMD -MP +override CPPFLAGS += -I../source -I../include +override CPPFLAGS += $(shell cat ../.cxxflags 2> /dev/null | xargs) +override LDFLAGS += -L../out/ -L../lib/ +override LDFLAGS += $(shell cat .ldflags 2> /dev/null | xargs) + +override LDARCH += $(shell cat .ldarch 2> /dev/null | xargs) +ifeq ($(strip $(LDARCH)),) +override LDLIBS += -lsimple_sdlcore +else +override LDLIBS += $(LDARCH) +endif + +override LDLIBS += -lsimple_interactive -lSDL2main -lSDL2 + +TEMPDIR := temp +DISTDIR := out + +SOURCES := $(shell echo *.cpp) +TARGETS := $(SOURCES:%.cpp=$(DISTDIR)/%) +OBJECTS := $(SOURCES:%.cpp=$(TEMPDIR)/%.o) +DEPENDS := $(OBJECTS:.o=.d) + +build: make_parent $(TARGETS) + +make_parent: + make -C .. + +$(DISTDIR)/%: $(TEMPDIR)/%.o ../out/libsimple_interactive.a $(LDARCH) | $(DISTDIR) + $(CXX) $(LDFLAGS) $< $(LDLIBS) -o $@ + +$(TEMPDIR)/%.o: %.cpp | $(TEMPDIR) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $< + +$(TEMPDIR): + @mkdir $@ + +$(DISTDIR): + @mkdir $@ + +clean: + @rm $(DEPENDS) 2> /dev/null || true + @rm $(OBJECTS) 2> /dev/null || true + @rmdir $(TEMPDIR) 2> /dev/null || true + @echo Temporaries cleaned! + +distclean: clean + @rm $(TARGETS) 2> /dev/null || true + @rmdir $(DISTDIR) 2> /dev/null || true + @echo All clean! + +-include $(DEPENDS) + +.PRECIOUS : $(OBJECTS) +.PHONY : clean distclean make_parent diff --git a/examples/common/sdl_input_grabber.cpp b/examples/common/sdl_input_grabber.cpp new file mode 100644 index 0000000..fa74955 --- /dev/null +++ b/examples/common/sdl_input_grabber.cpp @@ -0,0 +1,19 @@ +#include "sdl_input_grabber.h" +#include "simple/sdlcore/utils.hpp" + +sdl_input_grabber::sdl_input_grabber() : + video_init( simple::sdlcore::system_flag::video ), + window(SDL_CreateWindow("input grabber", 0,0,0,0, SDL_WINDOW_BORDERLESS | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS)) +{ + simple::sdlcore::utils::throw_error(window.get()); +} + +void sdl_input_grabber::grab() noexcept +{ + SDL_SetWindowGrab(window.get(), SDL_TRUE); +} + +void sdl_input_grabber::release() noexcept +{ + SDL_SetWindowGrab(window.get(), SDL_FALSE); +} diff --git a/examples/common/sdl_input_grabber.h b/examples/common/sdl_input_grabber.h new file mode 100644 index 0000000..24411d2 --- /dev/null +++ b/examples/common/sdl_input_grabber.h @@ -0,0 +1,26 @@ +#ifndef SIMPLE_INTERACTIVE_EXAMPLES_SDL_INPUT_GRABBER_H +#define SIMPLE_INTERACTIVE_EXAMPLES_SDL_INPUT_GRABBER_H + +#include <memory> +#include "simple/sdlcore/initializer.h" +#include "simple/support/enum_flags_operators.hpp" + +class sdl_input_grabber +{ + struct sdl_window_del + { + void operator()(SDL_Window * w) noexcept + { + SDL_DestroyWindow(w); + } + }; + + simple::sdlcore::initializer video_init; + std::unique_ptr<SDL_Window, sdl_window_del> window; + public: + sdl_input_grabber(); + void grab() noexcept; + void release() noexcept; +}; + +#endif /* end of include guard */ diff --git a/examples/versions/01_mouse_around_capture.cpp b/examples/versions/01_mouse_around_capture.cpp new file mode 100644 index 0000000..125bf49 --- /dev/null +++ b/examples/versions/01_mouse_around_capture.cpp @@ -0,0 +1,98 @@ +#include <cstdio> +#include <thread> +#include <chrono> +#include <string> + +#include "simple/interactive/initializer.h" +#include "simple/interactive/event.h" +#include "simple/support/function_utils.hpp" +#include "simple/support/misc.hpp" +#include "../common/sdl_input_grabber.h" + +#include "../common/sdl_input_grabber.cpp" + +using namespace simple::interactive; +using namespace std::chrono_literals; +using namespace std::string_literals; + +void render_screen(int2 size, int2 cursor_position, char bg, char cursor, bool break_lines = false); + +int main(int argc, char const* argv[]) try +{ + + using simple::support::ston; + const int screen_size_x = argc > 1 ? ston<int>(argv[1]) : 79; + const int screen_size_y = argc > 2 ? ston<int>(argv[2]) : 23; + const std::chrono::milliseconds frametime(argc > 3 ? ston<int>(argv[3]) : 16); + const bool break_lines = argc > 4 ? "false"s != argv[4] : true; + + const float2 screen_size{float(screen_size_x), float(screen_size_y)}; + + initializer init; + sdl_input_grabber input_grabber; + require_mouse_capture(true); + + float2 cursor_position{}; + + bool run = true; + while(run) + { + while(auto e = next_event()) std::visit( simple::support::overloaded{ + [&cursor_position, &screen_size](const mouse_motion& event) + { + cursor_position = screen_size * event.screen_normalized_position().value(); + }, + [&run](mouse_up) + { + run = false; + }, + [&run](key_pressed) + { + run = false; + }, + [](auto) { } + }, *e); + + std::puts("\nPress any key or click to quit."); + render_screen(int2(screen_size), int2(cursor_position), ' ', '*', break_lines); + std::this_thread::sleep_for(frametime); + } + std::puts(""); + return 0; +} +catch(...) +{ + if(errno) + std::perror("ERROR"); + + const char* sdl_error = SDL_GetError(); + if(*sdl_error) + std::puts(sdl_error); + + throw; +} + +void render_screen(int2 size, int2 cursor_position, char bg, char cursor, bool break_lines) +{ + static std::string buffer; + int linear_size = size.y() * size.x(); + if(break_lines) + linear_size += size.y() - 1; + buffer.resize(linear_size); + + auto row = buffer.begin(); + for(int y = 0; y < size.y(); ++y) + { + row = std::fill_n(row, size.x(), bg); + if(break_lines && y != (size.y() - 1)) + *row++ = '\n'; + } + + int pitch = break_lines ? size.x() + 1 : size.x(); + int linear_cursor_position = cursor_position.y() * pitch + cursor_position.x(); + buffer[linear_cursor_position] = cursor; + + std::fputs(buffer.c_str(), stdout); + std::fflush(stdout); +} + diff --git a/examples/versions/01_mouse_around_grab.cpp b/examples/versions/01_mouse_around_grab.cpp new file mode 100644 index 0000000..78e633a --- /dev/null +++ b/examples/versions/01_mouse_around_grab.cpp @@ -0,0 +1,103 @@ +#include <cstdio> +#include <thread> +#include <chrono> +#include <string> + +#include "simple/interactive/initializer.h" +#include "simple/interactive/event.h" +#include "simple/support/function_utils.hpp" +#include "simple/support/misc.hpp" +#include "../common/sdl_input_grabber.h" + +#include "../common/sdl_input_grabber.cpp" + +using namespace simple::interactive; +using namespace std::chrono_literals; +using namespace std::string_literals; + +void render_screen(int2 size, int2 cursor_position, char bg, char cursor, bool break_lines = false); + +int main(int argc, char const* argv[]) try +{ + + using simple::support::ston; + const int screen_size_x = argc > 1 ? ston<int>(argv[1]) : 79; + const int screen_size_y = argc > 2 ? ston<int>(argv[2]) : 23; + const std::chrono::milliseconds frametime(argc > 3 ? ston<int>(argv[3]) : 16); + const bool break_lines = argc > 4 ? "false"s != argv[4] : true; + + const float2 screen_size{float(screen_size_x), float(screen_size_y)}; + + initializer init; + sdl_input_grabber input_grabber; + input_grabber.grab(); + relative_mouse_mode(true); + + float2 cursor_position{}; + + bool run = true; + while(run) + { + while(auto e = next_event()) std::visit( simple::support::overloaded{ + [&cursor_position, &screen_size](const mouse_motion& event) + { + // using value_or here since SDL sends motion events with invalid window id until window gains focus for the first time, + // and screen_normalized_motion selects the screen/display based on the window id. + const float2 motion = event.screen_normalized_motion().value_or(float2{}); + cursor_position += screen_size * motion; + cursor_position.clamp(float2::zero(), screen_size - 1); + }, + [&run](mouse_up) + { + run = false; + }, + [&run](key_pressed) + { + run = false; + }, + [](auto) { } + }, *e); + + std::puts("\nPress any key or click to quit."); + render_screen(int2(screen_size), int2(cursor_position), ' ', '*', break_lines); + std::this_thread::sleep_for(frametime); + } + std::puts(""); + return 0; +} +catch(...) +{ + if(errno) + std::perror("ERROR"); + + const char* sdl_error = SDL_GetError(); + if(*sdl_error) + std::puts(sdl_error); + + throw; +} + +void render_screen(int2 size, int2 cursor_position, char bg, char cursor, bool break_lines) +{ + static std::string buffer; + int linear_size = size.y() * size.x(); + if(break_lines) + linear_size += size.y() - 1; + buffer.resize(linear_size); + + auto row = buffer.begin(); + for(int y = 0; y < size.y(); ++y) + { + row = std::fill_n(row, size.x(), bg); + if(break_lines && y != (size.y() - 1)) + *row++ = '\n'; + } + + int pitch = break_lines ? size.x() + 1 : size.x(); + int linear_cursor_position = cursor_position.y() * pitch + cursor_position.x(); + buffer[linear_cursor_position] = cursor; + + std::fputs(buffer.c_str(), stdout); + std::fflush(stdout); +} + diff --git a/source/simple/interactive/codes.cpp b/source/simple/interactive/codes.cpp new file mode 100644 index 0000000..4b547be --- /dev/null +++ b/source/simple/interactive/codes.cpp @@ -0,0 +1,16 @@ +#include "codes.h" +#include "simple/support/enum.hpp" + +using namespace simple::interactive; +using simple::support::to_integer; + +scancode to_scancode(keycode code) noexcept +{ + return static_cast<scancode>(SDL_GetScancodeFromKey(to_integer(code))); +} + +keycode to_keycode(scancode code) noexcept +{ + return static_cast<keycode>( + SDL_GetKeyFromScancode(static_cast<SDL_Scancode>(to_integer(code))) ); +} diff --git a/source/simple/interactive/codes.h b/source/simple/interactive/codes.h new file mode 100644 index 0000000..3c969a8 --- /dev/null +++ b/source/simple/interactive/codes.h @@ -0,0 +1,500 @@ +#ifndef SIMPLE_INTERACTIVE_CODES_H +#define SIMPLE_INTERACTIVE_CODES_H +#include <SDL2/SDL.h> + +namespace simple::interactive +{ + + enum class keycode : SDL_Keycode + { + _0 = SDLK_0, + _1 = SDLK_1, + _2 = SDLK_2, + _3 = SDLK_3, + _4 = SDLK_4, + _5 = SDLK_5, + _6 = SDLK_6, + _7 = SDLK_7, + _8 = SDLK_8, + _9 = SDLK_9, + a = SDLK_a, + ac_back = SDLK_AC_BACK, + ac_bookmarks = SDLK_AC_BOOKMARKS, + ac_forward = SDLK_AC_FORWARD, + ac_home = SDLK_AC_HOME, + ac_refresh = SDLK_AC_REFRESH, + ac_search = SDLK_AC_SEARCH, + ac_stop = SDLK_AC_STOP, + again = SDLK_AGAIN, + alterase = SDLK_ALTERASE, + ampersand = SDLK_AMPERSAND, + application = SDLK_APPLICATION, + asterisk = SDLK_ASTERISK, + at = SDLK_AT, + audiomute = SDLK_AUDIOMUTE, + audionext = SDLK_AUDIONEXT, + audioplay = SDLK_AUDIOPLAY, + audioprev = SDLK_AUDIOPREV, + audiostop = SDLK_AUDIOSTOP, + b = SDLK_b, + backquote = SDLK_BACKQUOTE, + backslash = SDLK_BACKSLASH, + backspace = SDLK_BACKSPACE, + brightnessdown = SDLK_BRIGHTNESSDOWN, + brightnessup = SDLK_BRIGHTNESSUP, + c = SDLK_c, + calculator = SDLK_CALCULATOR, + cancel = SDLK_CANCEL, + capslock = SDLK_CAPSLOCK, + caret = SDLK_CARET, + clear = SDLK_CLEAR, + clearagain = SDLK_CLEARAGAIN, + colon = SDLK_COLON, + comma = SDLK_COMMA, + computer = SDLK_COMPUTER, + copy = SDLK_COPY, + crsel = SDLK_CRSEL, + currencysubunit = SDLK_CURRENCYSUBUNIT, + currencyunit = SDLK_CURRENCYUNIT, + cut = SDLK_CUT, + d = SDLK_d, + decimalseparator = SDLK_DECIMALSEPARATOR, + del = SDLK_DELETE, + displayswitch = SDLK_DISPLAYSWITCH, + dollar = SDLK_DOLLAR, + down = SDLK_DOWN, + e = SDLK_e, + eject = SDLK_EJECT, + end = SDLK_END, + equals = SDLK_EQUALS, + escape = SDLK_ESCAPE, + exclaim = SDLK_EXCLAIM, + execute = SDLK_EXECUTE, + exsel = SDLK_EXSEL, + f = SDLK_f, + f1 = SDLK_F1, + f10 = SDLK_F10, + f11 = SDLK_F11, + f12 = SDLK_F12, + f13 = SDLK_F13, + f14 = SDLK_F14, + f15 = SDLK_F15, + f16 = SDLK_F16, + f17 = SDLK_F17, + f18 = SDLK_F18, + f19 = SDLK_F19, + f2 = SDLK_F2, + f20 = SDLK_F20, + f21 = SDLK_F21, + f22 = SDLK_F22, + f23 = SDLK_F23, + f24 = SDLK_F24, + f3 = SDLK_F3, + f4 = SDLK_F4, + f5 = SDLK_F5, + f6 = SDLK_F6, + f7 = SDLK_F7, + f8 = SDLK_F8, + f9 = SDLK_F9, + find = SDLK_FIND, + g = SDLK_g, + greater = SDLK_GREATER, + h = SDLK_h, + hash = SDLK_HASH, + help = SDLK_HELP, + SDLK_HOME, + i = SDLK_i, + insert = SDLK_INSERT, + j = SDLK_j, + k = SDLK_k, + kbdillumdown = SDLK_KBDILLUMDOWN, + kbdillumtoggle = SDLK_KBDILLUMTOGGLE, + kbdillumup = SDLK_KBDILLUMUP, + kp_0 = SDLK_KP_0, + kp_00 = SDLK_KP_00, + kp_000 = SDLK_KP_000, + kp_1 = SDLK_KP_1, + kp_2 = SDLK_KP_2, + kp_3 = SDLK_KP_3, + kp_4 = SDLK_KP_4, + kp_5 = SDLK_KP_5, + kp_6 = SDLK_KP_6, + kp_7 = SDLK_KP_7, + kp_8 = SDLK_KP_8, + kp_9 = SDLK_KP_9, + kp_a = SDLK_KP_A, + kp_ampersand = SDLK_KP_AMPERSAND, + kp_at = SDLK_KP_AT, + kp_b = SDLK_KP_B, + kp_backspace = SDLK_KP_BACKSPACE, + kp_binary = SDLK_KP_BINARY, + kp_c = SDLK_KP_C, + kp_clear = SDLK_KP_CLEAR, + kp_clearentry = SDLK_KP_CLEARENTRY, + kp_colon = SDLK_KP_COLON, + kp_comma = SDLK_KP_COMMA, + kp_d = SDLK_KP_D, + kp_dblampersand = SDLK_KP_DBLAMPERSAND, + kp_dblverticalbar = SDLK_KP_DBLVERTICALBAR, + kp_decimal = SDLK_KP_DECIMAL, + kp_divide = SDLK_KP_DIVIDE, + kp_e = SDLK_KP_E, + kp_enter = SDLK_KP_ENTER, + kp_equals = SDLK_KP_EQUALS, + kp_equalsas400 = SDLK_KP_EQUALSAS400, + kp_exclam = SDLK_KP_EXCLAM, + kp_f = SDLK_KP_F, + kp_greater = SDLK_KP_GREATER, + kp_hash = SDLK_KP_HASH, + kp_hexadecimal = SDLK_KP_HEXADECIMAL, + kp_leftbrace = SDLK_KP_LEFTBRACE, + kp_leftparen = SDLK_KP_LEFTPAREN, + kp_less = SDLK_KP_LESS, + kp_memadd = SDLK_KP_MEMADD, + kp_memclear = SDLK_KP_MEMCLEAR, + kp_memdivide = SDLK_KP_MEMDIVIDE, + kp_memmultiply = SDLK_KP_MEMMULTIPLY, + kp_memrecall = SDLK_KP_MEMRECALL, + kp_memstore = SDLK_KP_MEMSTORE, + kp_memsubtract = SDLK_KP_MEMSUBTRACT, + kp_minus = SDLK_KP_MINUS, + kp_multiply = SDLK_KP_MULTIPLY, + kp_octal = SDLK_KP_OCTAL, + kp_percent = SDLK_KP_PERCENT, + kp_period = SDLK_KP_PERIOD, + kp_plus = SDLK_KP_PLUS, + kp_plusminus = SDLK_KP_PLUSMINUS, + kp_power = SDLK_KP_POWER, + kp_rightbrace = SDLK_KP_RIGHTBRACE, + kp_rightparen = SDLK_KP_RIGHTPAREN, + kp_space = SDLK_KP_SPACE, + kp_tab = SDLK_KP_TAB, + kp_verticalbar = SDLK_KP_VERTICALBAR, + kp_xor = SDLK_KP_XOR, + l = SDLK_l, + lalt = SDLK_LALT, + lctrl = SDLK_LCTRL, + left = SDLK_LEFT, + leftbracket = SDLK_LEFTBRACKET, + leftparen = SDLK_LEFTPAREN, + less = SDLK_LESS, + lgui = SDLK_LGUI, + lshift = SDLK_LSHIFT, + m = SDLK_m, + mail = SDLK_MAIL, + mediaselect = SDLK_MEDIASELECT, + menu = SDLK_MENU, + minus = SDLK_MINUS, + mode = SDLK_MODE, + mute = SDLK_MUTE, + n = SDLK_n, + numlockclear = SDLK_NUMLOCKCLEAR, + o = SDLK_o, + oper = SDLK_OPER, + out = SDLK_OUT, + p = SDLK_p, + pagedown = SDLK_PAGEDOWN, + pageup = SDLK_PAGEUP, + paste = SDLK_PASTE, + pause = SDLK_PAUSE, + percent = SDLK_PERCENT, + period = SDLK_PERIOD, + plus = SDLK_PLUS, + power = SDLK_POWER, + printscreen = SDLK_PRINTSCREEN, + prior = SDLK_PRIOR, + q = SDLK_q, + question = SDLK_QUESTION, + quote = SDLK_QUOTE, + quotedbl = SDLK_QUOTEDBL, + r = SDLK_r, + ralt = SDLK_RALT, + rctrl = SDLK_RCTRL, + enter = SDLK_RETURN, + return2 = SDLK_RETURN2, + rgui = SDLK_RGUI, + right = SDLK_RIGHT, + rightbracket = SDLK_RIGHTBRACKET, + rightparen = SDLK_RIGHTPAREN, + rshift = SDLK_RSHIFT, + s = SDLK_s, + scrolllock = SDLK_SCROLLLOCK, + select = SDLK_SELECT, + semicolon = SDLK_SEMICOLON, + separator = SDLK_SEPARATOR, + slash = SDLK_SLASH, + sleep = SDLK_SLEEP, + space = SDLK_SPACE, + stop = SDLK_STOP, + sysreq = SDLK_SYSREQ, + t = SDLK_t, + tab = SDLK_TAB, + thousandsseparator = SDLK_THOUSANDSSEPARATOR, + u = SDLK_u, + underscore = SDLK_UNDERSCORE, + undo = SDLK_UNDO, + unknown = SDLK_UNKNOWN, + up = SDLK_UP, + v = SDLK_v, + volumedown = SDLK_VOLUMEDOWN, + volumeup = SDLK_VOLUMEUP, + w = SDLK_w, + www = SDLK_WWW, + x = SDLK_x, + y = SDLK_y, + z = SDLK_z, + }; + + enum class scancode : std::underlying_type_t<SDL_Scancode> + { + _0 = SDL_SCANCODE_0, + _1 = SDL_SCANCODE_1, + _2 = SDL_SCANCODE_2, + _3 = SDL_SCANCODE_3, + _4 = SDL_SCANCODE_4, + _5 = SDL_SCANCODE_5, + _6 = SDL_SCANCODE_6, + _7 = SDL_SCANCODE_7, + _8 = SDL_SCANCODE_8, + _9 = SDL_SCANCODE_9, + a = SDL_SCANCODE_A, + ac_back = SDL_SCANCODE_AC_BACK, + ac_bookmarks = SDL_SCANCODE_AC_BOOKMARKS, + ac_forward = SDL_SCANCODE_AC_FORWARD, + ac_home = SDL_SCANCODE_AC_HOME, + ac_refresh = SDL_SCANCODE_AC_REFRESH, + ac_search = SDL_SCANCODE_AC_SEARCH, + ac_stop = SDL_SCANCODE_AC_STOP, + again = SDL_SCANCODE_AGAIN, + alterase = SDL_SCANCODE_ALTERASE, + apostrophe = SDL_SCANCODE_APOSTROPHE, + application = SDL_SCANCODE_APPLICATION, + audiomute = SDL_SCANCODE_AUDIOMUTE, + audionext = SDL_SCANCODE_AUDIONEXT, + audioplay = SDL_SCANCODE_AUDIOPLAY, + audioprev = SDL_SCANCODE_AUDIOPREV, + audiostop = SDL_SCANCODE_AUDIOSTOP, + b = SDL_SCANCODE_B, + backslash = SDL_SCANCODE_BACKSLASH, + backspace = SDL_SCANCODE_BACKSPACE, + brightnessdown = SDL_SCANCODE_BRIGHTNESSDOWN, + brightnessup = SDL_SCANCODE_BRIGHTNESSUP, + c = SDL_SCANCODE_C, + calculator = SDL_SCANCODE_CALCULATOR, + cancel = SDL_SCANCODE_CANCEL, + capslock = SDL_SCANCODE_CAPSLOCK, + clear = SDL_SCANCODE_CLEAR, + clearagain = SDL_SCANCODE_CLEARAGAIN, + comma = SDL_SCANCODE_COMMA, + computer = SDL_SCANCODE_COMPUTER, + copy = SDL_SCANCODE_COPY, + crsel = SDL_SCANCODE_CRSEL, + currencysubunit = SDL_SCANCODE_CURRENCYSUBUNIT, + currencyunit = SDL_SCANCODE_CURRENCYUNIT, + cut = SDL_SCANCODE_CUT, + d = SDL_SCANCODE_D, + decimalseparator = SDL_SCANCODE_DECIMALSEPARATOR, + del = SDL_SCANCODE_DELETE, + displayswitch = SDL_SCANCODE_DISPLAYSWITCH, + down = SDL_SCANCODE_DOWN, + e = SDL_SCANCODE_E, + eject = SDL_SCANCODE_EJECT, + end = SDL_SCANCODE_END, + equals = SDL_SCANCODE_EQUALS, + escape = SDL_SCANCODE_ESCAPE, + execute = SDL_SCANCODE_EXECUTE, + exsel = SDL_SCANCODE_EXSEL, + f = SDL_SCANCODE_F, + f1 = SDL_SCANCODE_F1, + f10 = SDL_SCANCODE_F10, + f11 = SDL_SCANCODE_F11, + f12 = SDL_SCANCODE_F12, + f13 = SDL_SCANCODE_F13, + f14 = SDL_SCANCODE_F14, + f15 = SDL_SCANCODE_F15, + f16 = SDL_SCANCODE_F16, + f17 = SDL_SCANCODE_F17, + f18 = SDL_SCANCODE_F18, + f19 = SDL_SCANCODE_F19, + f2 = SDL_SCANCODE_F2, + f20 = SDL_SCANCODE_F20, + f21 = SDL_SCANCODE_F21, + f22 = SDL_SCANCODE_F22, + f23 = SDL_SCANCODE_F23, + f24 = SDL_SCANCODE_F24, + f3 = SDL_SCANCODE_F3, + f4 = SDL_SCANCODE_F4, + f5 = SDL_SCANCODE_F5, + f6 = SDL_SCANCODE_F6, + f7 = SDL_SCANCODE_F7, + f8 = SDL_SCANCODE_F8, + f9 = SDL_SCANCODE_F9, + find = SDL_SCANCODE_FIND, + g = SDL_SCANCODE_G, + grave = SDL_SCANCODE_GRAVE, + h = SDL_SCANCODE_H, + help = SDL_SCANCODE_HELP, + home = SDL_SCANCODE_HOME, + i = SDL_SCANCODE_I, + insert = SDL_SCANCODE_INSERT, + international1 = SDL_SCANCODE_INTERNATIONAL1, + international2 = SDL_SCANCODE_INTERNATIONAL2, + international3 = SDL_SCANCODE_INTERNATIONAL3, + international4 = SDL_SCANCODE_INTERNATIONAL4, + international5 = SDL_SCANCODE_INTERNATIONAL5, + international6 = SDL_SCANCODE_INTERNATIONAL6, + international7 = SDL_SCANCODE_INTERNATIONAL7, + international8 = SDL_SCANCODE_INTERNATIONAL8, + international9 = SDL_SCANCODE_INTERNATIONAL9, + j = SDL_SCANCODE_J, + k = SDL_SCANCODE_K, + kbdillumdown = SDL_SCANCODE_KBDILLUMDOWN, + kbdillumtoggle = SDL_SCANCODE_KBDILLUMTOGGLE, + kbdillumup = SDL_SCANCODE_KBDILLUMUP, + kp_0 = SDL_SCANCODE_KP_0, + kp_00 = SDL_SCANCODE_KP_00, + kp_000 = SDL_SCANCODE_KP_000, + kp_1 = SDL_SCANCODE_KP_1, + kp_2 = SDL_SCANCODE_KP_2, + kp_3 = SDL_SCANCODE_KP_3, + kp_4 = SDL_SCANCODE_KP_4, + kp_5 = SDL_SCANCODE_KP_5, + kp_6 = SDL_SCANCODE_KP_6, + kp_7 = SDL_SCANCODE_KP_7, + kp_8 = SDL_SCANCODE_KP_8, + kp_9 = SDL_SCANCODE_KP_9, + kp_a = SDL_SCANCODE_KP_A, + kp_ampersand = SDL_SCANCODE_KP_AMPERSAND, + kp_at = SDL_SCANCODE_KP_AT, + kp_b = SDL_SCANCODE_KP_B, + kp_backspace = SDL_SCANCODE_KP_BACKSPACE, + kp_binary = SDL_SCANCODE_KP_BINARY, + kp_c = SDL_SCANCODE_KP_C, + kp_clear = SDL_SCANCODE_KP_CLEAR, + kp_clearentry = SDL_SCANCODE_KP_CLEARENTRY, + kp_colon = SDL_SCANCODE_KP_COLON, + kp_comma = SDL_SCANCODE_KP_COMMA, + kp_d = SDL_SCANCODE_KP_D, + kp_dblampersand = SDL_SCANCODE_KP_DBLAMPERSAND, + kp_dblverticalbar = SDL_SCANCODE_KP_DBLVERTICALBAR, + kp_decimal = SDL_SCANCODE_KP_DECIMAL, + kp_divide = SDL_SCANCODE_KP_DIVIDE, + kp_e = SDL_SCANCODE_KP_E, + kp_enter = SDL_SCANCODE_KP_ENTER, + kp_equals = SDL_SCANCODE_KP_EQUALS, + kp_equalsas400 = SDL_SCANCODE_KP_EQUALSAS400, + kp_exclam = SDL_SCANCODE_KP_EXCLAM, + kp_f = SDL_SCANCODE_KP_F, + kp_greater = SDL_SCANCODE_KP_GREATER, + kp_hash = SDL_SCANCODE_KP_HASH, + kp_hexadecimal = SDL_SCANCODE_KP_HEXADECIMAL, + kp_leftbrace = SDL_SCANCODE_KP_LEFTBRACE, + kp_leftparen = SDL_SCANCODE_KP_LEFTPAREN, + kp_less = SDL_SCANCODE_KP_LESS, + kp_memadd = SDL_SCANCODE_KP_MEMADD, + kp_memclear = SDL_SCANCODE_KP_MEMCLEAR, + kp_memdivide = SDL_SCANCODE_KP_MEMDIVIDE, + kp_memmultiply = SDL_SCANCODE_KP_MEMMULTIPLY, + kp_memrecall = SDL_SCANCODE_KP_MEMRECALL, + kp_memstore = SDL_SCANCODE_KP_MEMSTORE, + kp_memsubtract = SDL_SCANCODE_KP_MEMSUBTRACT, + kp_minus = SDL_SCANCODE_KP_MINUS, + kp_multiply = SDL_SCANCODE_KP_MULTIPLY, + kp_octal = SDL_SCANCODE_KP_OCTAL, + kp_percent = SDL_SCANCODE_KP_PERCENT, + kp_period = SDL_SCANCODE_KP_PERIOD, + kp_plus = SDL_SCANCODE_KP_PLUS, + kp_plusminus = SDL_SCANCODE_KP_PLUSMINUS, + kp_power = SDL_SCANCODE_KP_POWER, + kp_rightbrace = SDL_SCANCODE_KP_RIGHTBRACE, + kp_rightparen = SDL_SCANCODE_KP_RIGHTPAREN, + kp_space = SDL_SCANCODE_KP_SPACE, + kp_tab = SDL_SCANCODE_KP_TAB, + kp_verticalbar = SDL_SCANCODE_KP_VERTICALBAR, + kp_xor = SDL_SCANCODE_KP_XOR, + l = SDL_SCANCODE_L, + lalt = SDL_SCANCODE_LALT, + lang1 = SDL_SCANCODE_LANG1, + lang2 = SDL_SCANCODE_LANG2, + lang3 = SDL_SCANCODE_LANG3, + lang4 = SDL_SCANCODE_LANG4, + lang5 = SDL_SCANCODE_LANG5, + lang6 = SDL_SCANCODE_LANG6, + lang7 = SDL_SCANCODE_LANG7, + lang8 = SDL_SCANCODE_LANG8, + lang9 = SDL_SCANCODE_LANG9, + lctrl = SDL_SCANCODE_LCTRL, + left = SDL_SCANCODE_LEFT, + leftbracket = SDL_SCANCODE_LEFTBRACKET, + lgui = SDL_SCANCODE_LGUI, + // well these don't exist... wiki lies!! + // lockingcapslock = SDL_SCANCODE_LOCKINGCAPSLOCK, + // lockingnumlock = SDL_SCANCODE_LOCKINGNUMLOCK, + // lockingscrolllock = SDL_SCANCODE_LOCKINGSCROLLLOCK, + lshift = SDL_SCANCODE_LSHIFT, + m = SDL_SCANCODE_M, + mail = SDL_SCANCODE_MAIL, + mediaselect = SDL_SCANCODE_MEDIASELECT, + menu = SDL_SCANCODE_MENU, + minus = SDL_SCANCODE_MINUS, + mode = SDL_SCANCODE_MODE, + mute = SDL_SCANCODE_MUTE, + n = SDL_SCANCODE_N, + nonusbackslash = SDL_SCANCODE_NONUSBACKSLASH, + nonushash = SDL_SCANCODE_NONUSHASH, + numlockclear = SDL_SCANCODE_NUMLOCKCLEAR, + o = SDL_SCANCODE_O, + oper = SDL_SCANCODE_OPER, + out = SDL_SCANCODE_OUT, + p = SDL_SCANCODE_P, + pagedown = SDL_SCANCODE_PAGEDOWN, + pageup = SDL_SCANCODE_PAGEUP, + paste = SDL_SCANCODE_PASTE, + pause = SDL_SCANCODE_PAUSE, + period = SDL_SCANCODE_PERIOD, + power = SDL_SCANCODE_POWER, + printscreen = SDL_SCANCODE_PRINTSCREEN, + prior = SDL_SCANCODE_PRIOR, + q = SDL_SCANCODE_Q, + r = SDL_SCANCODE_R, + ralt = SDL_SCANCODE_RALT, + rctrl = SDL_SCANCODE_RCTRL, + enter = SDL_SCANCODE_RETURN, + return2 = SDL_SCANCODE_RETURN2, + rgui = SDL_SCANCODE_RGUI, + right = SDL_SCANCODE_RIGHT, + rightbracket = SDL_SCANCODE_RIGHTBRACKET, + rshift = SDL_SCANCODE_RSHIFT, + s = SDL_SCANCODE_S, + scrolllock = SDL_SCANCODE_SCROLLLOCK, + select = SDL_SCANCODE_SELECT, + semicolon = SDL_SCANCODE_SEMICOLON, + separator = SDL_SCANCODE_SEPARATOR, + slash = SDL_SCANCODE_SLASH, + sleep = SDL_SCANCODE_SLEEP, + space = SDL_SCANCODE_SPACE, + stop = SDL_SCANCODE_STOP, + sysreq = SDL_SCANCODE_SYSREQ, + t = SDL_SCANCODE_T, + tab = SDL_SCANCODE_TAB, + thousandsseparator = SDL_SCANCODE_THOUSANDSSEPARATOR, + u = SDL_SCANCODE_U, + undo = SDL_SCANCODE_UNDO, + unknown = SDL_SCANCODE_UNKNOWN, + up = SDL_SCANCODE_UP, + v = SDL_SCANCODE_V, + volumedown = SDL_SCANCODE_VOLUMEDOWN, + volumeup = SDL_SCANCODE_VOLUMEUP, + w = SDL_SCANCODE_W, + www = SDL_SCANCODE_WWW, + x = SDL_SCANCODE_X, + y = SDL_SCANCODE_Y, + z = SDL_SCANCODE_Z, + }; + + scancode to_scancode(keycode) noexcept; + keycode to_keycode(scancode) noexcept; + +} // namespace simple::interactive + +#endif /* end of include guard */ diff --git a/source/simple/interactive/event.cpp b/source/simple/interactive/event.cpp new file mode 100644 index 0000000..37a7a58 --- /dev/null +++ b/source/simple/interactive/event.cpp @@ -0,0 +1,185 @@ +#include "event.h" +#include "simple/sdlcore/utils.hpp" + +namespace simple::interactive +{ + + std::optional<event> next_event() noexcept + { + SDL_Event event; + while(SDL_PollEvent(&event)) + { + switch(event.type) + { + case SDL_KEYDOWN: + return key_pressed + { + event.key.windowID, + std::chrono::milliseconds(event.key.timestamp), + static_cast<keycode>(event.key.keysym.sym), + static_cast<scancode>(event.key.keysym.scancode), + static_cast<keystate>(event.key.state), + event.key.repeat + }; + case SDL_KEYUP: + return key_released + { + event.key.windowID, + std::chrono::milliseconds(event.key.timestamp), + static_cast<keycode>(event.key.keysym.sym), + static_cast<scancode>(event.key.keysym.scancode), + static_cast<keystate>(event.key.state), + event.key.repeat + }; + case SDL_MOUSEBUTTONDOWN: + return mouse_down + { + event.button.windowID, + std::chrono::milliseconds(event.button.timestamp), + event.button.which, + {event.button.x, event.button.y}, + static_cast<mouse_button>(event.button.button), + static_cast<keystate>(event.button.state), + event.button.clicks + }; + case SDL_MOUSEBUTTONUP: + return mouse_up + { + event.button.windowID, + std::chrono::milliseconds(event.button.timestamp), + event.button.which, + {event.button.x, event.button.y}, + static_cast<mouse_button>(event.button.button), + static_cast<keystate>(event.button.state), +#if SDL_VERSION_ATLEAST(2,0,2) + event.button.clicks +#endif + }; + case SDL_MOUSEMOTION: + return mouse_motion + { + event.motion.windowID, + std::chrono::milliseconds(event.motion.timestamp), + event.motion.which, + {event.motion.x, event.motion.y}, + {event.motion.xrel, event.motion.yrel}, + static_cast<mouse_button_mask>(event.motion.state), + }; + case SDL_MOUSEWHEEL: + return mouse_wheel + { + event.wheel.windowID, + std::chrono::milliseconds(event.wheel.timestamp), + event.wheel.which, + {event.wheel.x, event.wheel.y}, +#if SDL_VERSION_ATLEAST(2,0,4) + static_cast<wheel_direction>(event.wheel.direction), +#endif + }; + } + } + return std::nullopt; + } + +#if SDL_VERSION_ATLEAST(2,0,4) + int2 mouse_wheel::motion() const noexcept + { + return data.direction == wheel_direction::flipped ? -data.position : data.position; + } +#endif + + bool relative_mouse_mode() noexcept + { + return SDL_GetRelativeMouseMode(); + } + + bool relative_mouse_mode(bool enable) noexcept + { + return !sdlcore::utils::check_error(SDL_SetRelativeMouseMode(SDL_bool(enable))); + } + + void require_mouse_mode(bool enable) noexcept + { + sdlcore::utils::throw_error(SDL_SetRelativeMouseMode(SDL_bool(enable))); + } + + std::optional<float2> window_normalized(uint32_t window_id, int2 position) noexcept + { + float2 result = static_cast<float2>(position); + + auto window = SDL_GetWindowFromID(window_id); + if(!window) + return std::nullopt; + + int2 window_size; + SDL_GetWindowSize(window, &window_size.x(), &window_size.y()); + if( std::any_of(window_size.begin(), window_size.end(), [](auto c){ return c == 0;}) ) + return std::nullopt; + + result /= static_cast<float2>(window_size); + return result; + } + + std::optional<float2> window_normalized_position(const common_mouse_data& data) noexcept + { + return window_normalized(data.window_id, data.position); + } + + std::optional<float2> window_normalized_motion(const mouse_motion_data& data) noexcept + { + return window_normalized(data.window_id, data.motion); + } + + std::optional<float2> screen_normalized(uint32_t window_id, int2 position, bool absolute = true) noexcept + { + float2 result = static_cast<float2>(position); + + auto window = SDL_GetWindowFromID(window_id); + if(!window) + return std::nullopt; + + if(absolute) + { + int2 window_position; + SDL_GetWindowPosition(window, &window_position.x(), &window_position.y()); + result += static_cast<float2>(window_position); + } + + SDL_DisplayMode mode; + if(SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(window), &mode) < 0) + return std::nullopt; + + const int2 screen_size{mode.w, mode.h}; + + result /= static_cast<float2>(screen_size); + return result; + } + + std::optional<float2> screen_normalized_position(const common_mouse_data& data) noexcept + { + return screen_normalized(data.window_id, data.position); + } + + std::optional<float2> screen_normalized_motion(const mouse_motion_data& data) noexcept + { + return screen_normalized(data.window_id, data.motion, false); + } + +#if SDL_VERSION_ATLEAST(2,0,4) + + // better to use expected<bool, error> + bool mouse_capture(bool enable) noexcept + { + SDL_PumpEvents(); + return !sdlcore::utils::check_error(SDL_CaptureMouse(SDL_bool(enable))); + } + + void require_mouse_capture(bool enable) + { + SDL_PumpEvents(); + sdlcore::utils::throw_error(SDL_CaptureMouse(SDL_bool(enable))); + } + +#endif + +} // namespace simple::interactive diff --git a/source/simple/interactive/event.h b/source/simple/interactive/event.h new file mode 100644 index 0000000..0333883 --- /dev/null +++ b/source/simple/interactive/event.h @@ -0,0 +1,168 @@ +#ifndef SIMPLE_INTERACTIVE_EVENT_H +#define SIMPLE_INTERACTIVE_EVENT_H +#include "codes.h" +#include <chrono> +#include <variant> +#include <optional> +#include "simple/geom/vector.hpp" + +namespace simple::interactive +{ + using int2 = simple::geom::vector<int, 2>; + using float2 = simple::geom::vector<float, 2>; + + enum class keystate : uint8_t + { + pressed = SDL_PRESSED, + released = SDL_RELEASED + }; + +#if SDL_VERSION_ATLEAST(2,0,4) + enum class wheel_direction : uint32_t + { + normal = SDL_MOUSEWHEEL_NORMAL, + flipped = SDL_MOUSEWHEEL_FLIPPED + }; +#endif + + enum class mouse_button : uint8_t + { + left = SDL_BUTTON_LEFT, + right = SDL_BUTTON_RIGHT, + middle = SDL_BUTTON_MIDDLE, + x1 = SDL_BUTTON_X1, + x2 = SDL_BUTTON_X2 + }; + + enum class mouse_button_mask : uint32_t + { + left = SDL_BUTTON_LMASK, + right = SDL_BUTTON_RMASK, + middle = SDL_BUTTON_MMASK, + x1 = SDL_BUTTON_X1MASK, + x2 = SDL_BUTTON_X2MASK + }; + using ::operator |; + using ::operator &; + using ::operator &&; + + constexpr uint32_t touch_mouse_id = SDL_TOUCH_MOUSEID; + + struct common_data + { + uint32_t window_id; + std::chrono::milliseconds timestamp; + }; + + struct key_data : public common_data + { + enum keycode keycode; + enum scancode scancode; + keystate state; + uint8_t repeat; + }; + + struct common_mouse_data : public common_data + { + uint32_t mouse_id; + int2 position; + }; + + struct mouse_button_data : public common_mouse_data + { + mouse_button button; + keystate state; +#if SDL_VERSION_ATLEAST(2,0,2) + uint8_t clicks; +#endif + }; + + struct mouse_motion_data : public common_mouse_data + { + int2 motion; + mouse_button_mask button_state; + }; + + struct mouse_wheel_data : public common_mouse_data + { +#if SDL_VERSION_ATLEAST(2,0,4) + wheel_direction direction; +#endif + }; + + struct key_event + { + const key_data data; + }; + + struct key_pressed : key_event + {}; + + struct key_released : key_event + {}; + + std::optional<float2> window_normalized_position(const common_mouse_data& data) noexcept; + std::optional<float2> screen_normalized_position(const common_mouse_data& data) noexcept; + std::optional<float2> window_normalized_motion(const mouse_motion_data& data) noexcept; + std::optional<float2> screen_normalized_motion(const mouse_motion_data& data) noexcept; + + template<typename event_data> + struct mouse_position_event + { + const event_data data; + auto window_normalized_position() const noexcept { return interactive::window_normalized_position(data); } + auto screen_normalized_position() const noexcept { return interactive::screen_normalized_position(data); } + }; + + struct mouse_motion : public mouse_position_event<mouse_motion_data> + { + auto window_normalized_motion() const noexcept { return interactive::window_normalized_motion(data); } + auto screen_normalized_motion() const noexcept { return interactive::screen_normalized_motion(data); } + }; + + struct mouse_wheel + { + const mouse_wheel_data data; +#if SDL_VERSION_ATLEAST(2,0,4) + int2 motion() const noexcept; +#endif + }; + + struct mouse_button_event : public mouse_position_event<mouse_button_data> + { + }; + + struct mouse_down : public mouse_button_event + {}; + + struct mouse_up : public mouse_button_event + {}; + + using event = std::variant< + key_pressed + ,key_released + ,mouse_down + ,mouse_up + ,mouse_motion + ,mouse_wheel + >; + + std::optional<event> next_event() noexcept; + + // better to use expected<bool, error> + bool relative_mouse_mode() noexcept; + bool relative_mouse_mode(bool enable) noexcept; + void require_relative_mouse_mode(bool enable); + +#if SDL_VERSION_ATLEAST(2,0,4) + // better to use expected<bool, error> + bool mouse_capture(bool enable) noexcept; + void require_mouse_capture(bool enable); +#endif + +} // namespace simple::interactive + +template<> struct simple::support::define_enum_flags_operators<simple::interactive::mouse_button_mask> + : std::true_type {}; + +#endif /* end of include guard */ diff --git a/source/simple/interactive/initializer.cpp b/source/simple/interactive/initializer.cpp new file mode 100644 index 0000000..1948f89 --- /dev/null +++ b/source/simple/interactive/initializer.cpp @@ -0,0 +1,10 @@ +#include "initializer.h" + +using namespace simple; +using namespace simple::interactive; + +using flag = sdlcore::system_flag; + +initializer::initializer() : + sdlcore::initializer(flag::event | flag::haptic | flag::joystick | flag::game_controller) +{} diff --git a/source/simple/interactive/initializer.h b/source/simple/interactive/initializer.h new file mode 100644 index 0000000..bb2e166 --- /dev/null +++ b/source/simple/interactive/initializer.h @@ -0,0 +1,18 @@ +#ifndef SIMPLE_GRAPHICAL_INITIALIZER_H +#define SIMPLE_GRAPHICAL_INITIALIZER_H +#include <memory> +#include "simple/sdlcore/initializer.h" +#include "simple/support/enum_flags_operators.hpp" + +namespace simple::interactive +{ + + class initializer : private sdlcore::initializer + { + public: + initializer(); + }; + +} // namespace simple::graphical + +#endif /* end of include guard */ -- GitLab