Update to v094r13 release.

byuu says:

This version polishes up the input dialogue (reset, erase, disable
button when item not focused, split device ID from mapping name), adds
color emulation toggle, and add dummy menu items for remaining features
(to be filled in later.)

Also, it now compiles cleanly on Windows with GTK.

I didn't test with TDM-GCC-32, because for god knows what reason, the
32-bit version ships with headers from Windows 95 OSR2 only. So I built
with TDM-GCC-64 with arch=x86.

And uh, apparently, moving or resizing a window causes a Visual C++
runtime exception in the GTK+ DLLs. This doesn't happen with trance or
renshuu built with TDM-GCC-32. So, yeah, like I said, don't use -m32.
This commit is contained in:
Tim Allen 2015-03-07 21:21:47 +11:00
parent a1b2fb0124
commit b4ba95242f
33 changed files with 517 additions and 155 deletions

View File

@ -3,7 +3,7 @@
namespace Emulator { namespace Emulator {
static const char Name[] = "higan"; 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 Author[] = "byuu";
static const char License[] = "GPLv3"; static const char License[] = "GPLv3";
static const char Website[] = "http://byuu.org/"; static const char Website[] = "http://byuu.org/";

View File

@ -2,11 +2,28 @@ ifeq ($(platform),)
hiroflags = $(cppflags) $(flags) -DHIRO_REFERENCE hiroflags = $(cppflags) $(flags) -DHIRO_REFERENCE
hirolink = hirolink =
else ifeq ($(platform),windows) else ifeq ($(platform),windows)
ifeq ($(hiro),)
hiro := windows
endif
ifeq ($(hiro),windows)
hiroflags = $(cppflags) $(flags) -DHIRO_WINDOWS hiroflags = $(cppflags) $(flags) -DHIRO_WINDOWS
hirolink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi 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) else ifeq ($(platform),macosx)
ifeq ($(hiro),)
hiro := cocoa
endif
ifeq ($(hiro),cocoa)
hiroflags = $(objcppflags) $(flags) -DHIRO_COCOA hiroflags = $(objcppflags) $(flags) -DHIRO_COCOA
hirolink = -framework Cocoa -framework Carbon hirolink = -framework Cocoa -framework Carbon
endif
else else
ifeq ($(hiro),) ifeq ($(hiro),)
hiro := gtk hiro := gtk

View File

@ -1,3 +1,5 @@
#include <nall/intrinsics.hpp>
#if defined(HIRO_WINDOWS) #if defined(HIRO_WINDOWS)
#include "../windows/header.hpp" #include "../windows/header.hpp"
#elif defined(HIRO_QT) #elif defined(HIRO_QT)

View File

@ -508,6 +508,7 @@ struct mWindow : mObject {
auto setFullScreen(bool fullScreen = true) -> type&; auto setFullScreen(bool fullScreen = true) -> type&;
auto setGeometry(Geometry geometry) -> type&; auto setGeometry(Geometry geometry) -> type&;
auto setModal(bool modal = true) -> type&; auto setModal(bool modal = true) -> type&;
auto setPlacement(double x, double y) -> type&;
auto setPosition(Position position) -> type&; auto setPosition(Position position) -> type&;
auto setResizable(bool resizable = true) -> type&; auto setResizable(bool resizable = true) -> type&;
auto setSize(Size size) -> type&; auto setSize(Size size) -> type&;

View File

@ -236,6 +236,17 @@ auto mWindow::setModal(bool modal) -> type& {
return *this; 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& { auto mWindow::setPosition(Position position) -> type& {
return setGeometry({ return setGeometry({
position.x(), position.y(), position.x(), position.y(),

View File

@ -112,6 +112,7 @@ struct Window : sWindow {
auto setFullScreen(bool fullScreen = true) -> type& { return self().setFullScreen(fullScreen), *this; } auto setFullScreen(bool fullScreen = true) -> type& { return self().setFullScreen(fullScreen), *this; }
auto setGeometry(Geometry geometry) -> type& { return self().setGeometry(geometry), *this; } auto setGeometry(Geometry geometry) -> type& { return self().setGeometry(geometry), *this; }
auto setModal(bool modal = true) -> type& { return self().setModal(modal), *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 setPosition(Position position) -> type& { return self().setPosition(position), *this; }
auto setResizable(bool resizable = true) -> type& { return self().setResizable(resizable), *this; } auto setResizable(bool resizable = true) -> type& { return self().setResizable(resizable), *this; }
auto setSize(Size size) -> type& { return self().setSize(size), *this; } auto setSize(Size size) -> type& { return self().setSize(size), *this; }

View File

@ -1,6 +1,8 @@
namespace hiro { namespace hiro {
#if defined(PLATFORM_XORG)
XlibDisplay* pApplication::display = nullptr; XlibDisplay* pApplication::display = nullptr;
#endif
void pApplication::run() { void pApplication::run() {
if(Application::state.onMain) { if(Application::state.onMain) {
@ -24,10 +26,19 @@ void pApplication::processEvents() {
void pApplication::quit() { void pApplication::quit() {
//if gtk_main() was invoked, call gtk_main_quit() //if gtk_main() was invoked, call gtk_main_quit()
if(gtk_main_level()) 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() { void pApplication::initialize() {
#if defined(PLATFORM_XORG)
display = XOpenDisplay(nullptr); display = XOpenDisplay(nullptr);
#endif
settings = new Settings; settings = new Settings;
settings->load(); settings->load();
@ -48,11 +59,24 @@ void pApplication::initialize() {
strcpy(argv[1], "--g-fatal-warnings"); strcpy(argv[1], "--g-fatal-warnings");
#endif #endif
char** argvp = argv; char** argvp = argv;
gtk_init(&argc, &argvp);
gtk_init(&argc, &argvp);
GtkSettings* gtkSettings = gtk_settings_get_default(); 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); 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"( gtk_rc_parse_string(R"(
style "HiroWindow" style "HiroWindow"
{ {

View File

@ -1,7 +1,9 @@
namespace hiro { namespace hiro {
struct pApplication { struct pApplication {
#if defined(PLATFORM_XORG)
static XlibDisplay* display; static XlibDisplay* display;
#endif
static void run(); static void run();
static bool pendingEvents(); static bool pendingEvents();

View File

@ -8,6 +8,13 @@ Size pDesktop::size() {
} }
Geometry pDesktop::workspace() { 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); XlibDisplay* display = XOpenDisplay(nullptr);
int screen = DefaultScreen(display); int screen = DefaultScreen(display);
@ -35,6 +42,7 @@ Geometry pDesktop::workspace() {
gdk_screen_get_width(gdk_screen_get_default()), gdk_screen_get_width(gdk_screen_get_default()),
gdk_screen_get_height(gdk_screen_get_default()) gdk_screen_get_height(gdk_screen_get_default())
}; };
#endif
} }
} }

View File

@ -1,3 +1,32 @@
#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 <winsock2.h>
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <uxtheme.h>
#include <io.h>
#include <shlobj.h>
#include <gdk/gdk.h>
#include <gdk/gdkwin32.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <gtksourceview/gtksourceview.h>
#include <gtksourceview/gtksourcelanguagemanager.h>
#include <gtksourceview/gtksourcestyleschememanager.h>
#include <cairo.h>
#include <nall/windows/registry.hpp>
#include <nall/windows/utf8.hpp>
#endif
#if defined(PLATFORM_XORG)
#include <nall/xorg/guard.hpp> #include <nall/xorg/guard.hpp>
#include <gdk/gdk.h> #include <gdk/gdk.h>
#include <gdk/gdkx.h> #include <gdk/gdkx.h>
@ -9,3 +38,4 @@
#include <cairo.h> #include <cairo.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <nall/xorg/guard.hpp> #include <nall/xorg/guard.hpp>
#endif

View File

@ -3,7 +3,9 @@ namespace hiro {
auto pKeyboard::poll() -> vector<bool> { auto pKeyboard::poll() -> vector<bool> {
vector<bool> result; vector<bool> result;
char state[256]; char state[256];
#if defined(PLATFORM_XORG)
XQueryKeymap(pApplication::display, state); XQueryKeymap(pApplication::display, state);
#endif
for(auto& code : settings->keycodes) { for(auto& code : settings->keycodes) {
result.append(_pressed(state, code)); result.append(_pressed(state, code));
} }
@ -12,15 +14,26 @@ auto pKeyboard::poll() -> vector<bool> {
auto pKeyboard::pressed(unsigned code) -> bool { auto pKeyboard::pressed(unsigned code) -> bool {
char state[256]; char state[256];
#if defined(PLATFORM_XORG)
XQueryKeymap(pApplication::display, state); XQueryKeymap(pApplication::display, state);
#endif
return _pressed(state, code); 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 lo = code >> 0;
uint8_t hi = code >> 8; 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(lo && state[lo >> 3] & (1 << (lo & 7))) return true;
if(hi && state[hi >> 3] & (1 << (hi & 7))) return true; if(hi && state[hi >> 3] & (1 << (hi & 7))) return true;
#endif
return false; return false;
} }
@ -208,134 +221,24 @@ auto pKeyboard::_translate(unsigned code) -> signed {
auto pKeyboard::initialize() -> void { auto pKeyboard::initialize() -> void {
auto append = [](unsigned lo, unsigned hi = 0) { auto append = [](unsigned lo, unsigned hi = 0) {
#if defined(PLATFORM_XORG)
lo = lo ? (uint8_t)XKeysymToKeycode(pApplication::display, lo) : 0; lo = lo ? (uint8_t)XKeysymToKeycode(pApplication::display, lo) : 0;
hi = hi ? (uint8_t)XKeysymToKeycode(pApplication::display, hi) : 0; hi = hi ? (uint8_t)XKeysymToKeycode(pApplication::display, hi) : 0;
#endif
settings->keycodes.append(lo | (hi << 8)); settings->keycodes.append(lo | (hi << 8));
}; };
#define map(name, ...) if(key == name) { append(__VA_ARGS__); continue; } #define map(name, ...) if(key == name) { append(__VA_ARGS__); continue; }
for(auto& key : Keyboard::keys) { for(auto& key : Keyboard::keys) {
map("Escape", XK_Escape); #if defined(PLATFORM_WINDOWS)
map("F1", XK_F1); #include <hiro/platform/windows/keyboard.hpp>
map("F2", XK_F2); #endif
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); #if defined(PLATFORM_XORG)
map("ScrollLock", XK_Scroll_Lock); #include <hiro/platform/xorg/keyboard.hpp>
map("Pause", XK_Pause); #endif
map("Insert", XK_Insert); //print("[phoenix/gtk] warning: unhandled key: ", key, "\n");
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");
append(0); append(0);
} }
#undef map #undef map

View File

@ -4,7 +4,7 @@ struct pKeyboard {
static auto poll() -> vector<bool>; static auto poll() -> vector<bool>;
static auto pressed(unsigned code) -> bool; 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 _translate(unsigned code) -> signed;
static auto initialize() -> void; static auto initialize() -> void;

View File

@ -1,14 +1,31 @@
namespace hiro { namespace hiro {
auto pMouse::position() -> Position { 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; XlibWindow root, child;
int rootx, rooty, winx, winy; int rootx, rooty, winx, winy;
unsigned int mask; unsigned int mask;
XQueryPointer(pApplication::display, DefaultRootWindow(pApplication::display), &root, &child, &rootx, &rooty, &winx, &winy, &mask); XQueryPointer(pApplication::display, DefaultRootWindow(pApplication::display), &root, &child, &rootx, &rooty, &winx, &winy, &mask);
return {rootx, rooty}; return {rootx, rooty};
#endif
} }
auto pMouse::pressed(Mouse::Button button) -> bool { 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; XlibWindow root, child;
int rootx, rooty, winx, winy; int rootx, rooty, winx, winy;
unsigned int mask; unsigned int mask;
@ -18,6 +35,8 @@ auto pMouse::pressed(Mouse::Button button) -> bool {
case Mouse::Button::Middle: return mask & Button2Mask; case Mouse::Button::Middle: return mask & Button2Mask;
case Mouse::Button::Right: return mask & Button3Mask; case Mouse::Button::Right: return mask & Button3Mask;
} }
#endif
return false; return false;
} }

View File

@ -65,7 +65,13 @@ auto pViewport::destruct() -> void {
} }
auto pViewport::handle() const -> uintptr_t { 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)); return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget));
#endif
} }
auto pViewport::setDroppable(bool droppable) -> void { auto pViewport::setDroppable(bool droppable) -> void {

View File

@ -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);

View File

@ -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);

View File

@ -1,8 +1,8 @@
#define UNICODE #define UNICODE
#define WINVER 0x0501 #define WINVER 0x0601
#define _WIN32_WINNT 0x0501 #define _WIN32_WINNT WINVER
#define _WIN32_IE 0x0600 #define _WIN32_IE WINVER
#define __MSVCRT_VERSION__ 0x0601 #define __MSVCRT_VERSION__ WINVER
#define NOMINMAX #define NOMINMAX
#include <winsock2.h> #include <winsock2.h>

View File

@ -41,6 +41,7 @@ link :=
ifeq ($(compiler),) ifeq ($(compiler),)
ifeq ($(platform),windows) ifeq ($(platform),windows)
compiler := g++ compiler := g++
cppflags := -x c++ -std=gnu++14
else ifeq ($(platform),macosx) else ifeq ($(platform),macosx)
compiler := clang++ compiler := clang++
else ifeq ($(platform),bsd) else ifeq ($(platform),bsd)

View File

@ -61,10 +61,8 @@ namespace Math {
#undef interface #undef interface
#define dllexport __declspec(dllexport) #define dllexport __declspec(dllexport)
#define MSG_NOSIGNAL 0 #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 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 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 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)); } inline auto putenv(const char* value) -> int { return _wputenv(nall::utf16_t(value)); }

View File

@ -9,6 +9,8 @@ ConfigurationManager::ConfigurationManager() {
video.append(video.synchronize, "Synchronize"); video.append(video.synchronize, "Synchronize");
video.append(video.scale, "Scale"); video.append(video.scale, "Scale");
video.append(video.aspectCorrection, "AspectCorrection"); video.append(video.aspectCorrection, "AspectCorrection");
video.append(video.filter, "Filter");
video.append(video.colorEmulation, "ColorEmulation");
append(video, "Video"); append(video, "Video");
audio.append(audio.driver, "Driver"); audio.append(audio.driver, "Driver");

View File

@ -7,6 +7,8 @@ struct ConfigurationManager : Configuration::Document {
bool synchronize = false; bool synchronize = false;
string scale = "Normal"; string scale = "Normal";
bool aspectCorrection = true; bool aspectCorrection = true;
string filter = "Blur";
bool colorEmulation = true;
} video; } video;
struct Audio : Configuration::Node { struct Audio : Configuration::Node {

View File

@ -19,6 +19,8 @@ auto InputMapping::bind() -> void {
} }
auto InputMapping::bind(HID::Device& device, unsigned group, unsigned input, int16 oldValue, int16 newValue) -> bool { 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->assignment = {hex(device.id), "/", group, "/", input, "/", device.group[group].input[input].name};
this->device = &device; this->device = &device;
this->group = group; this->group = group;
@ -31,6 +33,13 @@ auto InputMapping::poll() -> int16 {
return 0; return 0;
} }
auto InputMapping::unbind() -> void {
this->assignment = "None";
this->device = nullptr;
this->group = 0;
this->input = 0;
}
// //
InputManager::InputManager() { InputManager::InputManager() {

View File

@ -2,6 +2,7 @@ struct InputMapping {
auto bind() -> void; auto bind() -> void;
auto bind(HID::Device& device, unsigned group, unsigned input, int16 oldValue, int16 newValue) -> bool; auto bind(HID::Device& device, unsigned group, unsigned input, int16 oldValue, int16 newValue) -> bool;
auto poll() -> int16; auto poll() -> int16;
auto unbind() -> void;
string name; string name;
string assignment = "None"; string assignment = "None";

View File

@ -15,7 +15,7 @@ LibraryManager::LibraryManager() {
setTitle("Library"); setTitle("Library");
setSize({640, 800}); setSize({640, 800});
setPosition({0, 0}); setPlacement(0.0, 0.0);
} }
auto LibraryManager::show(const string& type) -> void { auto LibraryManager::show(const string& type) -> void {

View File

@ -39,10 +39,22 @@ Presentation::Presentation() {
config().video.scale = "Large"; config().video.scale = "Large";
resizeViewport(); 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([&] { aspectCorrection.setText("Aspect Correction").setChecked(config().video.aspectCorrection).onToggle([&] {
config().video.aspectCorrection = aspectCorrection.checked(); config().video.aspectCorrection = aspectCorrection.checked();
resizeViewport(); resizeViewport();
}); });
maskOverscan.setText("Mask Overscan").onToggle([&] {
});
synchronizeVideo.setText("Synchronize Video").setChecked(config().video.synchronize).onToggle([&] { synchronizeVideo.setText("Synchronize Video").setChecked(config().video.synchronize).onToggle([&] {
config().video.synchronize = synchronizeVideo.checked(); config().video.synchronize = synchronizeVideo.checked();
video.set(Video::Synchronize, config().video.synchronize); video.set(Video::Synchronize, config().video.synchronize);
@ -60,7 +72,21 @@ Presentation::Presentation() {
settingsManager->setFocused(); 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")); statusBar.setFont(Font::sans(8, "Bold"));
@ -88,7 +114,7 @@ auto Presentation::resizeViewport() -> void {
} }
setSize({width, height}); setSize({width, height});
setCentered(); setPlacement(0.5, 0.5);
if(!program->activeEmulator) drawSplashScreen(); if(!program->activeEmulator) drawSplashScreen();
} }

View File

@ -18,6 +18,12 @@ struct Presentation : Window {
MenuRadioItem videoScaleLarge{&videoScaleMenu}; MenuRadioItem videoScaleLarge{&videoScaleMenu};
MenuSeparator videoScaleSeparator{&videoScaleMenu}; MenuSeparator videoScaleSeparator{&videoScaleMenu};
MenuCheckItem aspectCorrection{&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}; MenuSeparator settingsMenuSeparator1{&settingsMenu};
MenuCheckItem synchronizeVideo{&settingsMenu}; MenuCheckItem synchronizeVideo{&settingsMenu};
MenuCheckItem synchronizeAudio{&settingsMenu}; MenuCheckItem synchronizeAudio{&settingsMenu};
@ -25,6 +31,21 @@ struct Presentation : Window {
MenuSeparator settingsMenuSeparator2{&settingsMenu}; MenuSeparator settingsMenuSeparator2{&settingsMenu};
MenuItem showConfiguration{&settingsMenu}; MenuItem showConfiguration{&settingsMenu};
Menu toolsMenu{&menuBar}; 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}; VerticalLayout layout{this};
Viewport viewport{&layout, Size{~0, ~0}}; Viewport viewport{&layout, Size{~0, ~0}};

View File

@ -20,13 +20,14 @@ auto Program::loadMedia(Emulator::Interface& _emulator, Emulator::Interface::Med
mediaPaths(media.id) = location; mediaPaths(media.id) = location;
setEmulator(&_emulator); setEmulator(&_emulator);
emulator().paletteUpdate(Emulator::Interface::PaletteMode::Standard); updateVideoPalette();
emulator().load(media.id); emulator().load(media.id);
emulator().power(); emulator().power();
presentation->resizeViewport(); presentation->resizeViewport();
presentation->setTitle(emulator().title()); presentation->setTitle(emulator().title());
presentation->systemMenu.setVisible(true); presentation->systemMenu.setVisible(true);
presentation->toolsMenu.setVisible(true);
} }
auto Program::unloadMedia() -> void { auto Program::unloadMedia() -> void {
@ -37,4 +38,5 @@ auto Program::unloadMedia() -> void {
presentation->setTitle({"tomoko v", Emulator::Version}); presentation->setTitle({"tomoko v", Emulator::Version});
presentation->systemMenu.setVisible(false); presentation->systemMenu.setVisible(false);
presentation->toolsMenu.setVisible(false);
} }

View File

@ -5,6 +5,7 @@
#include <gba/interface/interface.hpp> #include <gba/interface/interface.hpp>
#include "interface.cpp" #include "interface.cpp"
#include "media.cpp" #include "media.cpp"
#include "utility.cpp"
Program* program = nullptr; Program* program = nullptr;
Program::Program() { Program::Program() {
@ -50,6 +51,8 @@ Program::Program() {
dsp.setResamplerFrequency(96000); dsp.setResamplerFrequency(96000);
presentation->drawSplashScreen(); presentation->drawSplashScreen();
updateVideoFilter();
} }
auto Program::emulator() -> Emulator::Interface& { auto Program::emulator() -> Emulator::Interface& {

View File

@ -24,6 +24,10 @@ struct Program : Emulator::Interface::Bind {
auto loadMedia(Emulator::Interface& interface, Emulator::Interface::Media& media, const string& location) -> void; auto loadMedia(Emulator::Interface& interface, Emulator::Interface::Media& media, const string& location) -> void;
auto unloadMedia() -> void; auto unloadMedia() -> void;
//utility.cpp
auto updateVideoFilter() -> void;
auto updateVideoPalette() -> void;
DSP dsp; DSP dsp;
vector<Emulator::Interface*> emulators; vector<Emulator::Interface*> emulators;

View File

@ -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
);
}

View File

@ -9,10 +9,22 @@ InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) {
emulatorList.onChange([&] { reloadPorts(); }); emulatorList.onChange([&] { reloadPorts(); });
portList.onChange([&] { reloadDevices(); }); portList.onChange([&] { reloadDevices(); });
deviceList.onChange([&] { reloadMappings(); }); deviceList.onChange([&] { reloadMappings(); });
mappingList.onActivate([&] { assignMapping(); }); mappingList.onActivate([&] { assignMapping(); }).onChange([&] {
eraseButton.setEnabled((bool)mappingList.selected());
});
mappingList.setHeaderVisible(); mappingList.setHeaderVisible();
resetButton.setText("Reset"); resetButton.setText("Reset").onActivate([&] {
eraseButton.setText("Erase"); 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(); reloadPorts();
} }
@ -45,9 +57,11 @@ auto InputSettings::reloadDevices() -> void {
} }
auto InputSettings::reloadMappings() -> void { auto InputSettings::reloadMappings() -> void {
eraseButton.setEnabled(false);
mappingList.reset(); mappingList.reset();
mappingList.append(ListViewColumn().setText("Name")); 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) { for(auto& mapping : activeDevice().mappings) {
mappingList.append(ListViewItem().setText(0, mapping->name)); mappingList.append(ListViewItem().setText(0, mapping->name));
} }
@ -57,7 +71,10 @@ auto InputSettings::reloadMappings() -> void {
auto InputSettings::refreshMappings() -> void { auto InputSettings::refreshMappings() -> void {
unsigned position = 0; unsigned position = 0;
for(auto& mapping : activeDevice().mappings) { 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(); mappingList.resizeColumns();
} }

View File

@ -10,6 +10,8 @@ SettingsManager::SettingsManager() {
statusBar.setFont(Font::sans(8, "Bold")); statusBar.setFont(Font::sans(8, "Bold"));
setTitle("Configuration Settings"); setTitle("Configuration Settings");
setPosition({0, 0});
setSize({600, 400}); setSize({600, 400});
setPlacement(0.0, 1.0);
input.mappingList.resizeColumns();
} }

View File

@ -28,7 +28,7 @@ struct AdvancedSettings : TabFrameItem {
AdvancedSettings(TabFrame*); AdvancedSettings(TabFrame*);
VerticalLayout layout{this}; VerticalLayout layout{this};
Label driverLabel{&layout, Size{~0, 0}, 0}; Label driverLabel{&layout, Size{~0, 0}, 2};
HorizontalLayout driverLayout{&layout, Size{~0, 0}}; HorizontalLayout driverLayout{&layout, Size{~0, 0}};
Label videoLabel{&driverLayout, Size{0, 0}}; Label videoLabel{&driverLayout, Size{0, 0}};
ComboButton videoDriver{&driverLayout, Size{~0, 0}}; ComboButton videoDriver{&driverLayout, Size{~0, 0}};