diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 85460f30..2a1951f0 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { static const char Name[] = "higan"; - static const char Version[] = "094.12"; + static const char Version[] = "094.13"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; static const char Website[] = "http://byuu.org/"; diff --git a/hiro/GNUmakefile b/hiro/GNUmakefile index 1be0edb0..585eeab0 100644 --- a/hiro/GNUmakefile +++ b/hiro/GNUmakefile @@ -2,11 +2,28 @@ ifeq ($(platform),) hiroflags = $(cppflags) $(flags) -DHIRO_REFERENCE hirolink = else ifeq ($(platform),windows) - hiroflags = $(cppflags) $(flags) -DHIRO_WINDOWS - hirolink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi + ifeq ($(hiro),) + hiro := windows + endif + + ifeq ($(hiro),windows) + hiroflags = $(cppflags) $(flags) -DHIRO_WINDOWS + hirolink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi + endif + + ifeq ($(hiro),gtk) + hiroflags = $(cppflags) $(flags) -DHIRO_GTK $(shell pkg-config --cflags gtk+-2.0 gtksourceview-2.0) + hirolink = $(shell pkg-config --libs gtk+-2.0 gtksourceview-2.0) + endif else ifeq ($(platform),macosx) - hiroflags = $(objcppflags) $(flags) -DHIRO_COCOA - hirolink = -framework Cocoa -framework Carbon + ifeq ($(hiro),) + hiro := cocoa + endif + + ifeq ($(hiro),cocoa) + hiroflags = $(objcppflags) $(flags) -DHIRO_COCOA + hirolink = -framework Cocoa -framework Carbon + endif else ifeq ($(hiro),) hiro := gtk diff --git a/hiro/core/core.cpp b/hiro/core/core.cpp index 531b94d7..79011b6b 100644 --- a/hiro/core/core.cpp +++ b/hiro/core/core.cpp @@ -1,3 +1,5 @@ +#include + #if defined(HIRO_WINDOWS) #include "../windows/header.hpp" #elif defined(HIRO_QT) diff --git a/hiro/core/core.hpp b/hiro/core/core.hpp index 47e3d6e1..8a19e249 100644 --- a/hiro/core/core.hpp +++ b/hiro/core/core.hpp @@ -508,6 +508,7 @@ struct mWindow : mObject { auto setFullScreen(bool fullScreen = true) -> type&; auto setGeometry(Geometry geometry) -> type&; auto setModal(bool modal = true) -> type&; + auto setPlacement(double x, double y) -> type&; auto setPosition(Position position) -> type&; auto setResizable(bool resizable = true) -> type&; auto setSize(Size size) -> type&; diff --git a/hiro/core/window.cpp b/hiro/core/window.cpp index 964ae940..389f0c6f 100644 --- a/hiro/core/window.cpp +++ b/hiro/core/window.cpp @@ -236,6 +236,17 @@ auto mWindow::setModal(bool modal) -> type& { return *this; } +auto mWindow::setPlacement(double x, double y) -> type& { + x = max(0.0, min(1.0, x)); + y = max(0.0, min(1.0, y)); + auto workspace = Desktop::workspace(); + auto geometry = frameGeometry(); + signed left = x * (workspace.width() - geometry.width()); + signed top = y * (workspace.height() - geometry.height()); + setFramePosition({left, top}); + return *this; +} + auto mWindow::setPosition(Position position) -> type& { return setGeometry({ position.x(), position.y(), diff --git a/hiro/extension/shared.hpp b/hiro/extension/shared.hpp index 0572e862..73d065f4 100644 --- a/hiro/extension/shared.hpp +++ b/hiro/extension/shared.hpp @@ -112,6 +112,7 @@ struct Window : sWindow { auto setFullScreen(bool fullScreen = true) -> type& { return self().setFullScreen(fullScreen), *this; } auto setGeometry(Geometry geometry) -> type& { return self().setGeometry(geometry), *this; } auto setModal(bool modal = true) -> type& { return self().setModal(modal), *this; } + auto setPlacement(double x, double y) -> type& { return self().setPlacement(x, y), *this; } auto setPosition(Position position) -> type& { return self().setPosition(position), *this; } auto setResizable(bool resizable = true) -> type& { return self().setResizable(resizable), *this; } auto setSize(Size size) -> type& { return self().setSize(size), *this; } diff --git a/hiro/gtk/application.cpp b/hiro/gtk/application.cpp index 1cd3dfa9..63ad90a4 100644 --- a/hiro/gtk/application.cpp +++ b/hiro/gtk/application.cpp @@ -1,6 +1,8 @@ namespace hiro { +#if defined(PLATFORM_XORG) XlibDisplay* pApplication::display = nullptr; +#endif void pApplication::run() { if(Application::state.onMain) { @@ -24,10 +26,19 @@ void pApplication::processEvents() { void pApplication::quit() { //if gtk_main() was invoked, call gtk_main_quit() if(gtk_main_level()) gtk_main_quit(); + + #if defined(PLATFORM_XORG) + //todo: Keyboard::poll() is being called after Application::quit(); + //so if display is closed; this causes a segfault + //XCloseDisplay(display); + //display = nullptr; + #endif } void pApplication::initialize() { + #if defined(PLATFORM_XORG) display = XOpenDisplay(nullptr); + #endif settings = new Settings; settings->load(); @@ -48,11 +59,24 @@ void pApplication::initialize() { strcpy(argv[1], "--g-fatal-warnings"); #endif char** argvp = argv; - gtk_init(&argc, &argvp); + gtk_init(&argc, &argvp); GtkSettings* gtkSettings = gtk_settings_get_default(); + + //allow buttons to show icons + g_type_class_unref(g_type_class_ref(GTK_TYPE_BUTTON)); g_object_set(gtkSettings, "gtk-button-images", true, nullptr); + #if defined(PLATFORM_WINDOWS) + //there is a serious bug in GTK 2.24 for Windows with the "ime" (Windows IME) input method: + //by default, it will be impossible to type in text fields at all. + //there are various tricks to get around this; but they are unintuitive and unreliable. + //the "ime" method is chosen when various international system locales (eg Japanese) are selected. + //here, we override the default input method to use the "Simple" type instead to avoid the bug. + //obviously, this has a drawback: in-place editing for IMEs will not work in this mode. + g_object_set(gtkSettings, "gtk-im-module", "gtk-im-context-simple", nullptr); + #endif + gtk_rc_parse_string(R"( style "HiroWindow" { diff --git a/hiro/gtk/application.hpp b/hiro/gtk/application.hpp index 4fd5d573..269937ce 100644 --- a/hiro/gtk/application.hpp +++ b/hiro/gtk/application.hpp @@ -1,7 +1,9 @@ namespace hiro { struct pApplication { + #if defined(PLATFORM_XORG) static XlibDisplay* display; + #endif static void run(); static bool pendingEvents(); diff --git a/hiro/gtk/desktop.cpp b/hiro/gtk/desktop.cpp index 25b03fee..4cd551f4 100644 --- a/hiro/gtk/desktop.cpp +++ b/hiro/gtk/desktop.cpp @@ -8,6 +8,13 @@ Size pDesktop::size() { } Geometry pDesktop::workspace() { + #if defined(PLATFORM_WINDOWS) + RECT rc; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); + return {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top}; + #endif + + #if defined(PLATFORM_XORG) XlibDisplay* display = XOpenDisplay(nullptr); int screen = DefaultScreen(display); @@ -35,6 +42,7 @@ Geometry pDesktop::workspace() { gdk_screen_get_width(gdk_screen_get_default()), gdk_screen_get_height(gdk_screen_get_default()) }; + #endif } } diff --git a/hiro/gtk/header.hpp b/hiro/gtk/header.hpp index 8e691ab5..0820f9ad 100644 --- a/hiro/gtk/header.hpp +++ b/hiro/gtk/header.hpp @@ -1,11 +1,41 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#if defined(PLATFORM_WINDOWS) + #define UNICODE + #define WINVER 0x0601 + #define _WIN32_WINNT WINVER + #define _WIN32_IE WINVER + #define __MSVCRT_VERSION__ WINVER + #define NOMINMAX + #define TBS_TRANSPARENTBKGND 0x1000 + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif + +#if defined(PLATFORM_XORG) + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif diff --git a/hiro/gtk/keyboard.cpp b/hiro/gtk/keyboard.cpp index 0223ccf3..34895a1a 100644 --- a/hiro/gtk/keyboard.cpp +++ b/hiro/gtk/keyboard.cpp @@ -3,7 +3,9 @@ namespace hiro { auto pKeyboard::poll() -> vector { vector result; char state[256]; + #if defined(PLATFORM_XORG) XQueryKeymap(pApplication::display, state); + #endif for(auto& code : settings->keycodes) { result.append(_pressed(state, code)); } @@ -12,15 +14,26 @@ auto pKeyboard::poll() -> vector { auto pKeyboard::pressed(unsigned code) -> bool { char state[256]; + #if defined(PLATFORM_XORG) XQueryKeymap(pApplication::display, state); + #endif return _pressed(state, code); } -auto pKeyboard::_pressed(char* state, uint16_t code) -> bool { +auto pKeyboard::_pressed(const char* state, uint16_t code) -> bool { uint8_t lo = code >> 0; uint8_t hi = code >> 8; + + #if defined(PLATFORM_WINDOWS) + if(lo && GetAsyncKeyState(lo) & 0x8000) return true; + if(hi && GetAsyncKeyState(hi) & 0x8000) return true; + #endif + + #if defined(PLATFORM_XORG) if(lo && state[lo >> 3] & (1 << (lo & 7))) return true; if(hi && state[hi >> 3] & (1 << (hi & 7))) return true; + #endif + return false; } @@ -208,134 +221,24 @@ auto pKeyboard::_translate(unsigned code) -> signed { auto pKeyboard::initialize() -> void { auto append = [](unsigned lo, unsigned hi = 0) { + #if defined(PLATFORM_XORG) lo = lo ? (uint8_t)XKeysymToKeycode(pApplication::display, lo) : 0; hi = hi ? (uint8_t)XKeysymToKeycode(pApplication::display, hi) : 0; + #endif settings->keycodes.append(lo | (hi << 8)); }; #define map(name, ...) if(key == name) { append(__VA_ARGS__); continue; } for(auto& key : Keyboard::keys) { - map("Escape", XK_Escape); - map("F1", XK_F1); - map("F2", XK_F2); - map("F3", XK_F3); - map("F4", XK_F4); - map("F5", XK_F5); - map("F6", XK_F6); - map("F7", XK_F7); - map("F8", XK_F8); - map("F9", XK_F9); - map("F10", XK_F10); - map("F11", XK_F11); - map("F12", XK_F12); + #if defined(PLATFORM_WINDOWS) + #include + #endif - map("PrintScreen", XK_Print); - map("ScrollLock", XK_Scroll_Lock); - map("Pause", XK_Pause); + #if defined(PLATFORM_XORG) + #include + #endif - map("Insert", XK_Insert); - map("Delete", XK_Delete); - map("Home", XK_Home); - map("End", XK_End); - map("PageUp", XK_Prior); - map("PageDown", XK_Next); - - map("Up", XK_Up); - map("Down", XK_Down); - map("Left", XK_Left); - map("Right", XK_Right); - - map("Grave", XK_asciitilde); - map("1", XK_1); - map("2", XK_2); - map("3", XK_3); - map("4", XK_4); - map("5", XK_5); - map("6", XK_6); - map("7", XK_7); - map("8", XK_8); - map("9", XK_9); - map("0", XK_0); - map("Dash", XK_minus); - map("Equal", XK_equal); - map("Backspace", XK_BackSpace); - - map("Tab", XK_Tab); - map("CapsLock", XK_Caps_Lock); - map("LeftEnter", XK_Return); - map("LeftShift", XK_Shift_L); - map("RightShift", XK_Shift_R); - map("LeftControl", XK_Control_L); - map("RightControl", XK_Control_R); - map("LeftAlt", XK_Alt_L); - map("RightAlt", XK_Alt_R); - map("LeftSuper", XK_Super_L); - map("RightSuper", XK_Super_R); - map("Menu", XK_Menu); - map("Space", XK_space); - - map("OpenBracket", XK_bracketleft); - map("CloseBracket", XK_bracketright); - map("Backslash", XK_backslash); - map("Semicolon", XK_semicolon); - map("Apostrophe", XK_apostrophe); - map("Comma", XK_comma); - map("Period", XK_period); - map("Slash", XK_slash); - - map("A", XK_A); - map("B", XK_B); - map("C", XK_C); - map("D", XK_D); - map("E", XK_E); - map("F", XK_F); - map("G", XK_G); - map("H", XK_H); - map("I", XK_I); - map("J", XK_J); - map("K", XK_K); - map("L", XK_L); - map("M", XK_M); - map("N", XK_N); - map("O", XK_O); - map("P", XK_P); - map("Q", XK_Q); - map("R", XK_R); - map("S", XK_S); - map("T", XK_T); - map("U", XK_U); - map("V", XK_V); - map("W", XK_W); - map("X", XK_X); - map("Y", XK_Y); - map("Z", XK_Z); - - map("NumLock", XK_Num_Lock); - map("Divide", XK_KP_Divide); - map("Multiply", XK_KP_Multiply); - map("Subtract", XK_KP_Subtract); - map("Add", XK_KP_Add); - map("RightEnter", XK_KP_Enter); - map("Point", XK_KP_Decimal); - - map("One", XK_KP_1); - map("Two", XK_KP_2); - map("Three", XK_KP_3); - map("Four", XK_KP_4); - map("Five", XK_KP_5); - map("Six", XK_KP_6); - map("Seven", XK_KP_7); - map("Eight", XK_KP_8); - map("Nine", XK_KP_9); - map("Zero", XK_KP_0); - - map("Shift", XK_Shift_L, XK_Shift_R); - map("Control", XK_Control_L, XK_Control_R); - map("Alt", XK_Alt_L, XK_Alt_R); - map("Super", XK_Super_L, XK_Super_R); - map("Enter", XK_Return, XK_KP_Enter); - - print("[phoenix/gtk] error: unhandled key: ", key, "\n"); + //print("[phoenix/gtk] warning: unhandled key: ", key, "\n"); append(0); } #undef map diff --git a/hiro/gtk/keyboard.hpp b/hiro/gtk/keyboard.hpp index 06e5387c..9257ca92 100644 --- a/hiro/gtk/keyboard.hpp +++ b/hiro/gtk/keyboard.hpp @@ -4,7 +4,7 @@ struct pKeyboard { static auto poll() -> vector; static auto pressed(unsigned code) -> bool; - static auto _pressed(char* state, uint16_t code) -> bool; + static auto _pressed(const char* state, uint16_t code) -> bool; static auto _translate(unsigned code) -> signed; static auto initialize() -> void; diff --git a/hiro/gtk/mouse.cpp b/hiro/gtk/mouse.cpp index 0e6a6c94..ae9ab4e9 100644 --- a/hiro/gtk/mouse.cpp +++ b/hiro/gtk/mouse.cpp @@ -1,14 +1,31 @@ namespace hiro { auto pMouse::position() -> Position { + #if defined(PLATFORM_WINDOWS) + POINT point = {0}; + GetCursorPos(&point); + return {point.x, point.y}; + #endif + + #if defined(PLATFORM_XORG) XlibWindow root, child; int rootx, rooty, winx, winy; unsigned int mask; XQueryPointer(pApplication::display, DefaultRootWindow(pApplication::display), &root, &child, &rootx, &rooty, &winx, &winy, &mask); return {rootx, rooty}; + #endif } auto pMouse::pressed(Mouse::Button button) -> bool { + #if defined(PLATFORM_WINDOWS) + switch(button) { + case Mouse::Button::Left: return GetAsyncKeyState(VK_LBUTTON) & 0x8000; + case Mouse::Button::Middle: return GetAsyncKeyState(VK_MBUTTON) & 0x8000; + case Mouse::Button::Right: return GetAsyncKeyState(VK_RBUTTON) & 0x8000; + } + #endif + + #if defined(PLATFORM_XORG) XlibWindow root, child; int rootx, rooty, winx, winy; unsigned int mask; @@ -18,6 +35,8 @@ auto pMouse::pressed(Mouse::Button button) -> bool { case Mouse::Button::Middle: return mask & Button2Mask; case Mouse::Button::Right: return mask & Button3Mask; } + #endif + return false; } diff --git a/hiro/gtk/widget/viewport.cpp b/hiro/gtk/widget/viewport.cpp index f6a27c94..7a8d393a 100644 --- a/hiro/gtk/widget/viewport.cpp +++ b/hiro/gtk/widget/viewport.cpp @@ -65,7 +65,13 @@ auto pViewport::destruct() -> void { } auto pViewport::handle() const -> uintptr_t { + #if defined(PLATFORM_WINDOWS) + return (uintptr_t)GDK_WINDOW_HWND(gtk_widget_get_window(gtkWidget)); + #endif + + #if defined(PLATFORM_XORG) return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget)); + #endif } auto pViewport::setDroppable(bool droppable) -> void { diff --git a/hiro/platform/windows/keyboard.hpp b/hiro/platform/windows/keyboard.hpp new file mode 100644 index 00000000..88b914a4 --- /dev/null +++ b/hiro/platform/windows/keyboard.hpp @@ -0,0 +1,119 @@ +map("Escape", VK_ESCAPE); +map("F1", VK_F1); +map("F2", VK_F2); +map("F3", VK_F3); +map("F4", VK_F4); +map("F5", VK_F5); +map("F6", VK_F6); +map("F7", VK_F7); +map("F8", VK_F8); +map("F9", VK_F9); +map("F10", VK_F10); +map("F11", VK_F11); +map("F12", VK_F12); + +map("PrintScreen", VK_SNAPSHOT); +map("ScrollLock", VK_SCROLL); +map("Pause", VK_PAUSE); + +map("Insert", VK_INSERT); +map("Delete", VK_DELETE); +map("Home", VK_HOME); +map("End", VK_END); +map("PageUp", VK_PRIOR); +map("PageDown", VK_NEXT); + +map("Up", VK_UP); +map("Down", VK_DOWN); +map("Left", VK_LEFT); +map("Right", VK_RIGHT); + +map("Grave", VK_OEM_3); +map("1", '1'); +map("2", '2'); +map("3", '3'); +map("4", '4'); +map("5", '5'); +map("6", '6'); +map("7", '7'); +map("8", '8'); +map("9", '9'); +map("0", '0'); +map("Dash", VK_OEM_MINUS); +map("Equal", VK_OEM_PLUS); +map("Backspace", VK_BACK); + +map("Tab", VK_TAB); +map("CapsLock", VK_CAPITAL); +map("LeftEnter", VK_RETURN); +map("LeftShift", VK_LSHIFT); +map("RightShift", VK_RSHIFT); +map("LeftControl", VK_LCONTROL); +map("RightControl", VK_RCONTROL); +map("LeftAlt", VK_LMENU); +map("RightAlt", VK_RMENU); +map("LeftSuper", VK_LWIN); +map("RightSuper", VK_RWIN); +map("Menu", VK_APPS); +map("Space", VK_SPACE); + +map("OpenBracket", VK_OEM_4); +map("CloseBracket", VK_OEM_6); +map("Backslash", VK_OEM_5); +map("Semicolon", VK_OEM_1); +map("Apostrophe", VK_OEM_7); +map("Comma", VK_OEM_COMMA); +map("Period", VK_OEM_PERIOD); +map("Slash", VK_OEM_2); + +map("A", 'A'); +map("B", 'B'); +map("C", 'C'); +map("D", 'D'); +map("E", 'E'); +map("F", 'F'); +map("G", 'G'); +map("H", 'H'); +map("I", 'I'); +map("J", 'J'); +map("K", 'K'); +map("L", 'L'); +map("M", 'M'); +map("N", 'N'); +map("O", 'O'); +map("P", 'P'); +map("Q", 'Q'); +map("R", 'R'); +map("S", 'S'); +map("T", 'T'); +map("U", 'U'); +map("V", 'V'); +map("W", 'W'); +map("X", 'X'); +map("Y", 'Y'); +map("Z", 'Z'); + +map("NumLock", VK_NUMLOCK); +map("Divide", VK_DIVIDE); +map("Multiply", VK_MULTIPLY); +map("Subtract", VK_SUBTRACT); +map("Add", VK_ADD); +//map("RightEnter", ...); +map("Point", VK_DECIMAL); + +map("One", VK_NUMPAD1); +map("Two", VK_NUMPAD2); +map("Three", VK_NUMPAD3); +map("Four", VK_NUMPAD4); +map("Five", VK_NUMPAD5); +map("Six", VK_NUMPAD6); +map("Seven", VK_NUMPAD7); +map("Eight", VK_NUMPAD8); +map("Nine", VK_NUMPAD9); +map("Zero", VK_NUMPAD0); + +map("Shift", VK_LSHIFT, VK_RSHIFT); +map("Control", VK_LCONTROL, VK_RCONTROL); +map("Alt", VK_LMENU, VK_RMENU); +map("Super", VK_LWIN, VK_RWIN); +map("Enter", VK_RETURN); diff --git a/hiro/platform/xorg/keyboard.hpp b/hiro/platform/xorg/keyboard.hpp new file mode 100644 index 00000000..3a0fb676 --- /dev/null +++ b/hiro/platform/xorg/keyboard.hpp @@ -0,0 +1,119 @@ +map("Escape", XK_Escape); +map("F1", XK_F1); +map("F2", XK_F2); +map("F3", XK_F3); +map("F4", XK_F4); +map("F5", XK_F5); +map("F6", XK_F6); +map("F7", XK_F7); +map("F8", XK_F8); +map("F9", XK_F9); +map("F10", XK_F10); +map("F11", XK_F11); +map("F12", XK_F12); + +map("PrintScreen", XK_Print); +map("ScrollLock", XK_Scroll_Lock); +map("Pause", XK_Pause); + +map("Insert", XK_Insert); +map("Delete", XK_Delete); +map("Home", XK_Home); +map("End", XK_End); +map("PageUp", XK_Prior); +map("PageDown", XK_Next); + +map("Up", XK_Up); +map("Down", XK_Down); +map("Left", XK_Left); +map("Right", XK_Right); + +map("Grave", XK_asciitilde); +map("1", XK_1); +map("2", XK_2); +map("3", XK_3); +map("4", XK_4); +map("5", XK_5); +map("6", XK_6); +map("7", XK_7); +map("8", XK_8); +map("9", XK_9); +map("0", XK_0); +map("Dash", XK_minus); +map("Equal", XK_equal); +map("Backspace", XK_BackSpace); + +map("Tab", XK_Tab); +map("CapsLock", XK_Caps_Lock); +map("LeftEnter", XK_Return); +map("LeftShift", XK_Shift_L); +map("RightShift", XK_Shift_R); +map("LeftControl", XK_Control_L); +map("RightControl", XK_Control_R); +map("LeftAlt", XK_Alt_L); +map("RightAlt", XK_Alt_R); +map("LeftSuper", XK_Super_L); +map("RightSuper", XK_Super_R); +map("Menu", XK_Menu); +map("Space", XK_space); + +map("OpenBracket", XK_bracketleft); +map("CloseBracket", XK_bracketright); +map("Backslash", XK_backslash); +map("Semicolon", XK_semicolon); +map("Apostrophe", XK_apostrophe); +map("Comma", XK_comma); +map("Period", XK_period); +map("Slash", XK_slash); + +map("A", XK_A); +map("B", XK_B); +map("C", XK_C); +map("D", XK_D); +map("E", XK_E); +map("F", XK_F); +map("G", XK_G); +map("H", XK_H); +map("I", XK_I); +map("J", XK_J); +map("K", XK_K); +map("L", XK_L); +map("M", XK_M); +map("N", XK_N); +map("O", XK_O); +map("P", XK_P); +map("Q", XK_Q); +map("R", XK_R); +map("S", XK_S); +map("T", XK_T); +map("U", XK_U); +map("V", XK_V); +map("W", XK_W); +map("X", XK_X); +map("Y", XK_Y); +map("Z", XK_Z); + +map("NumLock", XK_Num_Lock); +map("Divide", XK_KP_Divide); +map("Multiply", XK_KP_Multiply); +map("Subtract", XK_KP_Subtract); +map("Add", XK_KP_Add); +map("RightEnter", XK_KP_Enter); +map("Point", XK_KP_Decimal); + +map("One", XK_KP_1); +map("Two", XK_KP_2); +map("Three", XK_KP_3); +map("Four", XK_KP_4); +map("Five", XK_KP_5); +map("Six", XK_KP_6); +map("Seven", XK_KP_7); +map("Eight", XK_KP_8); +map("Nine", XK_KP_9); +map("Zero", XK_KP_0); + +map("Shift", XK_Shift_L, XK_Shift_R); +map("Control", XK_Control_L, XK_Control_R); +map("Alt", XK_Alt_L, XK_Alt_R); +map("Super", XK_Super_L, XK_Super_R); +map("Enter", XK_Return, XK_KP_Enter); diff --git a/hiro/windows/header.hpp b/hiro/windows/header.hpp index 43717c23..d50ce963 100644 --- a/hiro/windows/header.hpp +++ b/hiro/windows/header.hpp @@ -1,8 +1,8 @@ #define UNICODE -#define WINVER 0x0501 -#define _WIN32_WINNT 0x0501 -#define _WIN32_IE 0x0600 -#define __MSVCRT_VERSION__ 0x0601 +#define WINVER 0x0601 +#define _WIN32_WINNT WINVER +#define _WIN32_IE WINVER +#define __MSVCRT_VERSION__ WINVER #define NOMINMAX #include diff --git a/nall/GNUmakefile b/nall/GNUmakefile index e51a20a8..efcc3bff 100644 --- a/nall/GNUmakefile +++ b/nall/GNUmakefile @@ -41,6 +41,7 @@ link := ifeq ($(compiler),) ifeq ($(platform),windows) compiler := g++ + cppflags := -x c++ -std=gnu++14 else ifeq ($(platform),macosx) compiler := clang++ else ifeq ($(platform),bsd) diff --git a/nall/platform.hpp b/nall/platform.hpp index 2cc2c0c0..717cd4a6 100644 --- a/nall/platform.hpp +++ b/nall/platform.hpp @@ -61,10 +61,8 @@ namespace Math { #undef interface #define dllexport __declspec(dllexport) #define MSG_NOSIGNAL 0 - __declspec(dllimport) auto _fileno(FILE*) -> int; inline auto access(const char* path, int amode) -> int { return _waccess(nall::utf16_t(path), amode); } - inline auto fileno(FILE* stream) -> int { return _fileno(stream); } inline auto getcwd(char* buf, size_t size) -> char* { wchar_t wpath[PATH_MAX] = L""; if(!_wgetcwd(wpath, size)) return nullptr; strcpy(buf, nall::utf8_t(wpath)); return buf; } inline auto mkdir(const char* path, int mode) -> int { return _wmkdir(nall::utf16_t(path)); } inline auto putenv(const char* value) -> int { return _wputenv(nall::utf16_t(value)); } diff --git a/target-tomoko/configuration/configuration.cpp b/target-tomoko/configuration/configuration.cpp index 63e1f1af..6c289e19 100644 --- a/target-tomoko/configuration/configuration.cpp +++ b/target-tomoko/configuration/configuration.cpp @@ -9,6 +9,8 @@ ConfigurationManager::ConfigurationManager() { video.append(video.synchronize, "Synchronize"); video.append(video.scale, "Scale"); video.append(video.aspectCorrection, "AspectCorrection"); + video.append(video.filter, "Filter"); + video.append(video.colorEmulation, "ColorEmulation"); append(video, "Video"); audio.append(audio.driver, "Driver"); diff --git a/target-tomoko/configuration/configuration.hpp b/target-tomoko/configuration/configuration.hpp index 31be1576..0f4015a2 100644 --- a/target-tomoko/configuration/configuration.hpp +++ b/target-tomoko/configuration/configuration.hpp @@ -7,6 +7,8 @@ struct ConfigurationManager : Configuration::Document { bool synchronize = false; string scale = "Normal"; bool aspectCorrection = true; + string filter = "Blur"; + bool colorEmulation = true; } video; struct Audio : Configuration::Node { diff --git a/target-tomoko/input/input.cpp b/target-tomoko/input/input.cpp index 1020455b..9097c8dd 100644 --- a/target-tomoko/input/input.cpp +++ b/target-tomoko/input/input.cpp @@ -19,6 +19,8 @@ auto InputMapping::bind() -> void { } auto InputMapping::bind(HID::Device& device, unsigned group, unsigned input, int16 oldValue, int16 newValue) -> bool { + if(device.group[group].input[input].name == "Escape") return unbind(), true; + this->assignment = {hex(device.id), "/", group, "/", input, "/", device.group[group].input[input].name}; this->device = &device; this->group = group; @@ -31,6 +33,13 @@ auto InputMapping::poll() -> int16 { return 0; } +auto InputMapping::unbind() -> void { + this->assignment = "None"; + this->device = nullptr; + this->group = 0; + this->input = 0; +} + // InputManager::InputManager() { diff --git a/target-tomoko/input/input.hpp b/target-tomoko/input/input.hpp index 83e528d3..f749a57e 100644 --- a/target-tomoko/input/input.hpp +++ b/target-tomoko/input/input.hpp @@ -2,6 +2,7 @@ struct InputMapping { auto bind() -> void; auto bind(HID::Device& device, unsigned group, unsigned input, int16 oldValue, int16 newValue) -> bool; auto poll() -> int16; + auto unbind() -> void; string name; string assignment = "None"; diff --git a/target-tomoko/library/manager.cpp b/target-tomoko/library/manager.cpp index 731469a7..57a488b9 100644 --- a/target-tomoko/library/manager.cpp +++ b/target-tomoko/library/manager.cpp @@ -15,7 +15,7 @@ LibraryManager::LibraryManager() { setTitle("Library"); setSize({640, 800}); - setPosition({0, 0}); + setPlacement(0.0, 0.0); } auto LibraryManager::show(const string& type) -> void { diff --git a/target-tomoko/presentation/presentation.cpp b/target-tomoko/presentation/presentation.cpp index 1f95b30e..f5d6f421 100644 --- a/target-tomoko/presentation/presentation.cpp +++ b/target-tomoko/presentation/presentation.cpp @@ -39,10 +39,22 @@ Presentation::Presentation() { config().video.scale = "Large"; resizeViewport(); }); + videoFilterMenu.setText("Video Filter"); + MenuRadioItem::group({videoFilterNone, videoFilterBlur}); + if(config().video.filter == "None") videoFilterNone.setChecked(); + if(config().video.filter == "Blur") videoFilterBlur.setChecked(); + videoFilterNone.setText("None").onActivate([&] { config().video.filter = "None"; program->updateVideoFilter(); }); + videoFilterBlur.setText("Blur").onActivate([&] { config().video.filter = "Blur"; program->updateVideoFilter(); }); + colorEmulation.setText("Color Emulation").setChecked(config().video.colorEmulation).onToggle([&] { + config().video.colorEmulation = colorEmulation.checked(); + program->updateVideoPalette(); + }); aspectCorrection.setText("Aspect Correction").setChecked(config().video.aspectCorrection).onToggle([&] { config().video.aspectCorrection = aspectCorrection.checked(); resizeViewport(); }); + maskOverscan.setText("Mask Overscan").onToggle([&] { + }); synchronizeVideo.setText("Synchronize Video").setChecked(config().video.synchronize).onToggle([&] { config().video.synchronize = synchronizeVideo.checked(); video.set(Video::Synchronize, config().video.synchronize); @@ -60,7 +72,21 @@ Presentation::Presentation() { settingsManager->setFocused(); }); - toolsMenu.setText("Tools"); + toolsMenu.setText("Tools").setVisible(false); + saveStateMenu.setText("Save State"); + saveSlot1.setText("Slot 1").onActivate([&] {}); + saveSlot2.setText("Slot 2").onActivate([&] {}); + saveSlot3.setText("Slot 3").onActivate([&] {}); + saveSlot4.setText("Slot 4").onActivate([&] {}); + saveSlot5.setText("Slot 5").onActivate([&] {}); + loadStateMenu.setText("Load State"); + loadSlot1.setText("Slot 1").onActivate([&] {}); + loadSlot2.setText("Slot 2").onActivate([&] {}); + loadSlot3.setText("Slot 3").onActivate([&] {}); + loadSlot4.setText("Slot 4").onActivate([&] {}); + loadSlot5.setText("Slot 5").onActivate([&] {}); + stateManager.setText("State Manager").onActivate([&] {}); + cheatEditor.setText("Cheat Editor").onActivate([&] {}); statusBar.setFont(Font::sans(8, "Bold")); @@ -88,7 +114,7 @@ auto Presentation::resizeViewport() -> void { } setSize({width, height}); - setCentered(); + setPlacement(0.5, 0.5); if(!program->activeEmulator) drawSplashScreen(); } diff --git a/target-tomoko/presentation/presentation.hpp b/target-tomoko/presentation/presentation.hpp index a27fbe16..26b77993 100644 --- a/target-tomoko/presentation/presentation.hpp +++ b/target-tomoko/presentation/presentation.hpp @@ -18,6 +18,12 @@ struct Presentation : Window { MenuRadioItem videoScaleLarge{&videoScaleMenu}; MenuSeparator videoScaleSeparator{&videoScaleMenu}; MenuCheckItem aspectCorrection{&videoScaleMenu}; + MenuCheckItem maskOverscan{&videoScaleMenu}; + Menu videoFilterMenu{&settingsMenu}; + MenuRadioItem videoFilterNone{&videoFilterMenu}; + MenuRadioItem videoFilterBlur{&videoFilterMenu}; + MenuSeparator videoFilterSeparator{&videoFilterMenu}; + MenuCheckItem colorEmulation{&videoFilterMenu}; MenuSeparator settingsMenuSeparator1{&settingsMenu}; MenuCheckItem synchronizeVideo{&settingsMenu}; MenuCheckItem synchronizeAudio{&settingsMenu}; @@ -25,6 +31,21 @@ struct Presentation : Window { MenuSeparator settingsMenuSeparator2{&settingsMenu}; MenuItem showConfiguration{&settingsMenu}; Menu toolsMenu{&menuBar}; + Menu saveStateMenu{&toolsMenu}; + MenuItem saveSlot1{&saveStateMenu}; + MenuItem saveSlot2{&saveStateMenu}; + MenuItem saveSlot3{&saveStateMenu}; + MenuItem saveSlot4{&saveStateMenu}; + MenuItem saveSlot5{&saveStateMenu}; + Menu loadStateMenu{&toolsMenu}; + MenuItem loadSlot1{&loadStateMenu}; + MenuItem loadSlot2{&loadStateMenu}; + MenuItem loadSlot3{&loadStateMenu}; + MenuItem loadSlot4{&loadStateMenu}; + MenuItem loadSlot5{&loadStateMenu}; + MenuSeparator toolsMenuSeparator{&toolsMenu}; + MenuItem stateManager{&toolsMenu}; + MenuItem cheatEditor{&toolsMenu}; VerticalLayout layout{this}; Viewport viewport{&layout, Size{~0, ~0}}; diff --git a/target-tomoko/program/media.cpp b/target-tomoko/program/media.cpp index f03390ca..a2aae4d7 100644 --- a/target-tomoko/program/media.cpp +++ b/target-tomoko/program/media.cpp @@ -20,13 +20,14 @@ auto Program::loadMedia(Emulator::Interface& _emulator, Emulator::Interface::Med mediaPaths(media.id) = location; setEmulator(&_emulator); - emulator().paletteUpdate(Emulator::Interface::PaletteMode::Standard); + updateVideoPalette(); emulator().load(media.id); emulator().power(); presentation->resizeViewport(); presentation->setTitle(emulator().title()); presentation->systemMenu.setVisible(true); + presentation->toolsMenu.setVisible(true); } auto Program::unloadMedia() -> void { @@ -37,4 +38,5 @@ auto Program::unloadMedia() -> void { presentation->setTitle({"tomoko v", Emulator::Version}); presentation->systemMenu.setVisible(false); + presentation->toolsMenu.setVisible(false); } diff --git a/target-tomoko/program/program.cpp b/target-tomoko/program/program.cpp index 456516d3..0412e336 100644 --- a/target-tomoko/program/program.cpp +++ b/target-tomoko/program/program.cpp @@ -5,6 +5,7 @@ #include #include "interface.cpp" #include "media.cpp" +#include "utility.cpp" Program* program = nullptr; Program::Program() { @@ -50,6 +51,8 @@ Program::Program() { dsp.setResamplerFrequency(96000); presentation->drawSplashScreen(); + + updateVideoFilter(); } auto Program::emulator() -> Emulator::Interface& { diff --git a/target-tomoko/program/program.hpp b/target-tomoko/program/program.hpp index 0c3cb313..14b54589 100644 --- a/target-tomoko/program/program.hpp +++ b/target-tomoko/program/program.hpp @@ -24,6 +24,10 @@ struct Program : Emulator::Interface::Bind { auto loadMedia(Emulator::Interface& interface, Emulator::Interface::Media& media, const string& location) -> void; auto unloadMedia() -> void; + //utility.cpp + auto updateVideoFilter() -> void; + auto updateVideoPalette() -> void; + DSP dsp; vector emulators; diff --git a/target-tomoko/program/utility.cpp b/target-tomoko/program/utility.cpp new file mode 100644 index 00000000..815c3227 --- /dev/null +++ b/target-tomoko/program/utility.cpp @@ -0,0 +1,12 @@ +auto Program::updateVideoFilter() -> void { + if(config().video.filter == "None") video.set(Video::Filter, Video::FilterNearest); + if(config().video.filter == "Blur") video.set(Video::Filter, Video::FilterLinear); +} + +auto Program::updateVideoPalette() -> void { + if(!activeEmulator) return; + emulator().paletteUpdate(config().video.colorEmulation + ? Emulator::Interface::PaletteMode::Emulation + : Emulator::Interface::PaletteMode::Standard + ); +} diff --git a/target-tomoko/settings/input.cpp b/target-tomoko/settings/input.cpp index 1db9df71..a74b9e51 100644 --- a/target-tomoko/settings/input.cpp +++ b/target-tomoko/settings/input.cpp @@ -9,10 +9,22 @@ InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) { emulatorList.onChange([&] { reloadPorts(); }); portList.onChange([&] { reloadDevices(); }); deviceList.onChange([&] { reloadMappings(); }); - mappingList.onActivate([&] { assignMapping(); }); + mappingList.onActivate([&] { assignMapping(); }).onChange([&] { + eraseButton.setEnabled((bool)mappingList.selected()); + }); mappingList.setHeaderVisible(); - resetButton.setText("Reset"); - eraseButton.setText("Erase"); + resetButton.setText("Reset").onActivate([&] { + if(MessageDialog("Are you sure you want to erase all mappings for this device?").setParent(*settingsManager).question() == 0) { + for(auto& mapping : activeDevice().mappings) mapping->unbind(); + refreshMappings(); + } + }); + eraseButton.setText("Erase").onActivate([&] { + if(auto mapping = mappingList.selected()) { + activeDevice().mappings[mapping->offset()]->unbind(); + refreshMappings(); + } + }); reloadPorts(); } @@ -45,9 +57,11 @@ auto InputSettings::reloadDevices() -> void { } auto InputSettings::reloadMappings() -> void { + eraseButton.setEnabled(false); mappingList.reset(); mappingList.append(ListViewColumn().setText("Name")); - mappingList.append(ListViewColumn().setText("Mapping")); + mappingList.append(ListViewColumn().setText("Mapping").setWidth(~0)); + mappingList.append(ListViewColumn().setText("Device")); for(auto& mapping : activeDevice().mappings) { mappingList.append(ListViewItem().setText(0, mapping->name)); } @@ -57,7 +71,10 @@ auto InputSettings::reloadMappings() -> void { auto InputSettings::refreshMappings() -> void { unsigned position = 0; for(auto& mapping : activeDevice().mappings) { - mappingList.item(position++)->setText(1, mapping->assignment); + auto path = mapping->assignment.split("/"); + string assignment = path.takeLast(); + string device = path(0); + mappingList.item(position++)->setText(1, assignment).setText(2, device); } mappingList.resizeColumns(); } diff --git a/target-tomoko/settings/settings.cpp b/target-tomoko/settings/settings.cpp index 3edb4f1c..4ad76e16 100644 --- a/target-tomoko/settings/settings.cpp +++ b/target-tomoko/settings/settings.cpp @@ -10,6 +10,8 @@ SettingsManager::SettingsManager() { statusBar.setFont(Font::sans(8, "Bold")); setTitle("Configuration Settings"); - setPosition({0, 0}); setSize({600, 400}); + setPlacement(0.0, 1.0); + + input.mappingList.resizeColumns(); } diff --git a/target-tomoko/settings/settings.hpp b/target-tomoko/settings/settings.hpp index 947b41be..fa394c02 100644 --- a/target-tomoko/settings/settings.hpp +++ b/target-tomoko/settings/settings.hpp @@ -28,7 +28,7 @@ struct AdvancedSettings : TabFrameItem { AdvancedSettings(TabFrame*); VerticalLayout layout{this}; - Label driverLabel{&layout, Size{~0, 0}, 0}; + Label driverLabel{&layout, Size{~0, 0}, 2}; HorizontalLayout driverLayout{&layout, Size{~0, 0}}; Label videoLabel{&driverLayout, Size{0, 0}}; ComboButton videoDriver{&driverLayout, Size{~0, 0}};