diff --git a/src/base.hpp b/src/base.hpp
index 3eb4587b..e3e936cb 100644
--- a/src/base.hpp
+++ b/src/base.hpp
@@ -1,4 +1,4 @@
-static const char bsnesVersion[] = "0.055";
+static const char bsnesVersion[] = "0.056";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSaveStateVersion = 3;
diff --git a/src/chip/supergameboy/supergameboy.cpp b/src/chip/supergameboy/supergameboy.cpp
index 5f6b43ab..85591d0d 100644
--- a/src/chip/supergameboy/supergameboy.cpp
+++ b/src/chip/supergameboy/supergameboy.cpp
@@ -15,7 +15,11 @@ void SuperGameBoy::enter() {
while(true) {
unsigned samples = sgb_run(samplebuffer, 16);
for(unsigned i = 0; i < samples; i++) {
- audio.coprocessor_sample(samplebuffer[i] >> 0, samplebuffer[i] >> 16);
+ int16 left = samplebuffer[i] >> 0;
+ int16 right = samplebuffer[i] >> 16;
+
+ //SNES audio is notoriously quiet; lower Game Boy samples to match SGB sound effects
+ audio.coprocessor_sample(left / 3, right / 3);
}
scheduler.addclocks_cop(samples * 10);
scheduler.sync_copcpu();
@@ -65,18 +69,19 @@ void SuperGameBoy::write(unsigned addr, uint8 data) {
void SuperGameBoy::init() {
if(open("supergameboy")) {
- sgb_rom = sym("sgb_rom");
- sgb_ram = sym("sgb_ram");
- sgb_rtc = sym("sgb_rtc");
- sgb_init = sym("sgb_init");
- sgb_term = sym("sgb_term");
- sgb_power = sym("sgb_power");
- sgb_reset = sym("sgb_reset");
- sgb_row = sym("sgb_row");
- sgb_read = sym("sgb_read");
- sgb_write = sym("sgb_write");
- sgb_run = sym("sgb_run");
- sgb_save = sym("sgb_save");
+ sgb_rom = sym("sgb_rom");
+ sgb_ram = sym("sgb_ram");
+ sgb_rtc = sym("sgb_rtc");
+ sgb_init = sym("sgb_init");
+ sgb_term = sym("sgb_term");
+ sgb_power = sym("sgb_power");
+ sgb_reset = sym("sgb_reset");
+ sgb_row = sym("sgb_row");
+ sgb_read = sym("sgb_read");
+ sgb_write = sym("sgb_write");
+ sgb_run = sym("sgb_run");
+ sgb_save = sym("sgb_save");
+ sgb_serialize = sym("sgb_serialize");
}
}
@@ -114,4 +119,9 @@ void SuperGameBoy::unload() {
if(sgb_term) sgb_term();
}
+void SuperGameBoy::serialize(serializer &s) {
+ s.integer(row);
+ if(sgb_serialize) sgb_serialize(s);
+}
+
}
diff --git a/src/chip/supergameboy/supergameboy.hpp b/src/chip/supergameboy/supergameboy.hpp
index ab195723..d3095c9b 100644
--- a/src/chip/supergameboy/supergameboy.hpp
+++ b/src/chip/supergameboy/supergameboy.hpp
@@ -15,6 +15,8 @@ public:
void reset();
void unload();
+ void serialize(serializer&);
+
private:
uint32_t samplebuffer[4096];
unsigned row;
@@ -32,6 +34,7 @@ private:
function sgb_write;
function sgb_run;
function sgb_save;
+ function sgb_serialize;
};
extern SuperGameBoy supergameboy;
diff --git a/src/lib/nall/input.hpp b/src/lib/nall/input.hpp
index 033c26be..b3ce9ebf 100644
--- a/src/lib/nall/input.hpp
+++ b/src/lib/nall/input.hpp
@@ -6,258 +6,381 @@
#include
#include
+#include
namespace nall {
- enum { input_none = 0 };
- template struct keyboard {
- enum {
- none = keyboard::limit,
- escape, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12,
- print_screen, scroll_lock, pause, tilde,
- num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0,
- dash, equal, backspace,
- insert, delete_, home, end, page_up, page_down,
- a, b, c, d, e, f, g, h, i, j, k, l, m,
- n, o, p, q, r, s, t, u, v, w, x, y, z,
- lbracket, rbracket, backslash, semicolon, apostrophe, comma, period, slash,
- pad_1, pad_2, pad_3, pad_4, pad_5, pad_6, pad_7, pad_8, pad_9, pad_0,
- point, enter, add, subtract, multiply, divide,
- num_lock, caps_lock,
- up, down, left, right,
- tab, return_, spacebar,
- lctrl, rctrl, lalt, ralt, lshift, rshift, lsuper, rsuper, menu,
- limit,
- };
+struct Keyboard;
+Keyboard& keyboard(unsigned = 0);
+
+static const char KeyboardScancodeName[][64] = {
+ "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
+ "PrintScreen", "ScrollLock", "Pause", "Tilde",
+ "Num1", "Num2", "Num3", "Num4", "Num5", "Num6", "Num7", "Num8", "Num9", "Num0",
+ "Dash", "Equal", "Backspace",
+ "Insert", "Delete", "Home", "End", "PageUp", "PageDown",
+ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
+ "LeftBracket", "RightBracket", "Backslash", "Semicolon", "Apostrophe", "Comma", "Period", "Slash",
+ "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "Keypad0",
+ "Point", "Enter", "Add", "Subtract", "Multiply", "Divide",
+ "NumLock", "CapsLock",
+ "Up", "Down", "Left", "Right",
+ "Tab", "Return", "Spacebar", "Menu",
+ "Shift", "Control", "Alt", "Super",
+};
+
+struct Keyboard {
+ const unsigned ID;
+ enum { Base = 1 };
+ enum { Count = 8, Size = 128 };
+
+ enum Scancode {
+ Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
+ PrintScreen, ScrollLock, Pause, Tilde,
+ Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
+ Dash, Equal, Backspace,
+ Insert, Delete, Home, End, PageUp, PageDown,
+ A, B, C, D, E, F, G, H, I, J, K, L, M,
+ N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
+ LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash,
+ Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0,
+ Point, Enter, Add, Subtract, Multiply, Divide,
+ NumLock, CapsLock,
+ Up, Down, Left, Right,
+ Tab, Return, Spacebar, Menu,
+ Shift, Control, Alt, Super,
+ Limit,
};
- template<> struct keyboard<-1> {
- enum { count = 16 };
- enum {
- none,
- escape, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12,
- print_screen, scroll_lock, pause, tilde,
- num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0,
- dash, equal, backspace,
- insert, delete_, home, end, page_up, page_down,
- a, b, c, d, e, f, g, h, i, j, k, l, m,
- n, o, p, q, r, s, t, u, v, w, x, y, z,
- lbracket, rbracket, backslash, semicolon, apostrophe, comma, period, slash,
- pad_1, pad_2, pad_3, pad_4, pad_5, pad_6, pad_7, pad_8, pad_9, pad_0,
- point, enter, add, subtract, multiply, divide,
- num_lock, caps_lock,
- up, down, left, right,
- tab, return_, spacebar,
- lctrl, rctrl, lalt, ralt, lshift, rshift, lsuper, rsuper, menu,
- length, //number of syms per keyboard
- limit = 0,
- };
-
- static uint16_t index(unsigned keyboard_number, unsigned keyboard_enum) {
- if(keyboard_number >= count) return input_none;
- return limit + keyboard_number * length + keyboard_enum;
+ static signed numberDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).belongsTo(scancode)) return i;
}
- };
-
- template struct mouse {
- enum { buttons = 8 };
- enum {
- none = mouse::limit,
- x, y, z,
- button,
- limit = button + buttons,
- };
- };
-
- template<> struct mouse<-1> {
- enum { count = 16, buttons = 8 };
- enum {
- none,
- x, y, z,
- button,
- length = button + buttons - none, //number of syms per mouse
- limit = keyboard::count - 1>::limit,
- };
-
- static uint16_t index(unsigned mouse_number, unsigned mouse_enum) {
- if(mouse_number >= count) return input_none;
- return limit + mouse_number * length + mouse_enum;
- }
- };
-
- template struct joypad {
- enum { hats = 8, axes = 32, buttons = 96 };
- enum {
- none = joypad::limit,
- hat,
- axis = hat + hats,
- button = axis + axes,
- limit = button + buttons,
- };
- };
-
- template<> struct joypad<-1> {
- enum { count = 16, hats = 8, axes = 32, buttons = 96 };
- enum { hat_center = 0, hat_up = 1, hat_right = 2, hat_down = 4, hat_left = 8 };
- enum {
- none,
- hat,
- axis = hat + hats,
- button = axis + axes,
- length = button + buttons - none, //number of syms per joypad
- limit = mouse::count - 1>::limit,
- };
-
- static uint16_t index(unsigned joypad_number, unsigned joypad_enum) {
- if(joypad_number >= count) return input_none;
- return limit + joypad_number * length + joypad_enum;
- }
- };
-
- enum { input_limit = joypad::count - 1>::limit };
-
- static const char keysym[][64] = {
- "none",
- "escape", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12",
- "print_screen", "scroll_lock", "pause", "tilde",
- "num_1", "num_2", "num_3", "num_4", "num_5", "num_6", "num_7", "num_8", "num_9", "num_0",
- "dash", "equal", "backspace",
- "insert", "delete", "home", "end", "page_up", "page_down",
- "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
- "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
- "lbracket", "rbracket", "backslash", "semicolon", "apostrophe", "comma", "period", "slash",
- "pad_1", "pad_2", "pad_3", "pad_4", "pad_5", "pad_6", "pad_7", "pad_8", "pad_9", "pad_0",
- "point", "enter", "add", "subtract", "multiply", "divide",
- "num_lock", "caps_lock",
- "up", "down", "left", "right",
- "tab", "return", "spacebar",
- "lctrl", "rctrl", "lalt", "ralt", "lshift", "rshift", "lsuper", "rsuper", "menu",
- "limit",
- };
-
- static const char* input_find(uint16_t key) {
- static char buffer[64];
-
- for(unsigned k = 0; k < keyboard<>::count; k++) {
- if(key >= keyboard<>::index(k, keyboard<>::none) && key < keyboard<>::index(k, keyboard<>::length)) {
- sprintf(buffer, "keyboard%.2d.%s", k, keysym[key - keyboard<>::index(k, keyboard<>::none)]);
- return buffer;
- }
- }
-
- for(unsigned m = 0; m < mouse<>::count; m++) {
- if(key == mouse<>::index(m, mouse<>::x)) { sprintf(buffer, "mouse%.2d.x", m); return buffer; }
- if(key == mouse<>::index(m, mouse<>::y)) { sprintf(buffer, "mouse%.2d.y", m); return buffer; }
- if(key == mouse<>::index(m, mouse<>::z)) { sprintf(buffer, "mouse%.2d.z", m); return buffer; }
-
- if(key >= mouse<>::index(m, mouse<>::button + 0)
- && key < mouse<>::index(m, mouse<>::button + mouse<>::buttons)) {
- sprintf(buffer, "mouse%.2d.button%.2d", m, key - mouse<>::index(m, mouse<>::button));
- return buffer;
- }
- }
-
- for(unsigned j = 0; j < joypad<>::count; j++) {
- if(key >= joypad<>::index(j, joypad<>::hat + 0)
- && key < joypad<>::index(j, joypad<>::hat + joypad<>::hats)) {
- sprintf(buffer, "joypad%.2d.hat%.2d", j, key - joypad<>::index(j, joypad<>::hat));
- return buffer;
- }
-
- if(key >= joypad<>::index(j, joypad<>::axis + 0)
- && key < joypad<>::index(j, joypad<>::axis + joypad<>::axes)) {
- sprintf(buffer, "joypad%.2d.axis%.2d", j, key - joypad<>::index(j, joypad<>::axis));
- return buffer;
- }
-
- if(key >= joypad<>::index(j, joypad<>::button + 0)
- && key < joypad<>::index(j, joypad<>::button + joypad<>::buttons)) {
- sprintf(buffer, "joypad%.2d.button%.2d", j, key - joypad<>::index(j, joypad<>::button));
- return buffer;
- }
- }
-
- return "none";
+ return -1;
}
- static char* input_find(char *out, uint16_t key) {
- strcpy(out, input_find(key));
- return out;
+ static signed keyDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).isKey(scancode)) return scancode - keyboard(i).key(Escape);
+ }
+ return -1;
}
- static uint16_t input_find(const char *key) {
- if(!memcmp(key, "keyboard", 8)) {
- key += 8;
- if(!*key || !*(key + 1)) return input_none;
- uint8_t k = (*key - '0') * 10 + (*(key + 1) - '0');
- if(k >= keyboard<>::count) return input_none;
- key += 2;
+ static signed modifierDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).isModifier(scancode)) return scancode - keyboard(i).key(Shift);
+ }
+ return -1;
+ }
- if(*key++ != '.') return input_none;
+ static bool isAnyKey(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).isKey(scancode)) return true;
+ }
+ return false;
+ }
- for(unsigned i = 0; i < keyboard<>::length; i++) {
- if(!strcmp(key, keysym[i])) return keyboard<>::index(k, i);
+ static bool isAnyModifier(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).isModifier(scancode)) return true;
+ }
+ return false;
+ }
+
+ static uint16_t decode(const char *name) {
+ string s(name);
+ if(!strbegin(name, "KB")) return 0;
+ ltrim(s, "KB");
+ unsigned id = strunsigned(s);
+ int pos = strpos(s, "::");
+ if(pos < 0) return 0;
+ s = substr(s, pos + 2);
+ for(unsigned i = 0; i < Limit; i++) {
+ if(s == KeyboardScancodeName[i]) return Base + Size * id + i;
+ }
+ return 0;
+ }
+
+ string encode(uint16_t code) const {
+ unsigned index = 0;
+ for(unsigned i = 0; i < Count; i++) {
+ if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
+ index = code - (Base + Size * i);
+ break;
}
}
+ return string() << "KB" << ID << "::" << KeyboardScancodeName[index];
+ }
- if(!memcmp(key, "mouse", 5)) {
- key += 5;
- if(!*key || !*(key + 1)) return input_none;
- uint8_t m = (*key - '0') * 10 + (*(key + 1) - '0');
- if(m >= mouse<>::count) return input_none;
- key += 2;
+ uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
+ uint16_t key(unsigned id) const { return Base + Size * ID + id; }
+ bool isKey(unsigned id) const { return id >= key(Escape) && id <= key(Menu); }
+ bool isModifier(unsigned id) const { return id >= key(Shift) && id <= key(Super); }
+ bool belongsTo(uint16_t scancode) const { return isKey(scancode) || isModifier(scancode); }
- if(!strcmp(key, ".x")) return mouse<>::index(m, mouse<>::x);
- if(!strcmp(key, ".y")) return mouse<>::index(m, mouse<>::y);
- if(!strcmp(key, ".z")) return mouse<>::index(m, mouse<>::z);
+ Keyboard(unsigned ID_) : ID(ID_) {}
+};
- if(!memcmp(key, ".button", 7)) {
- key += 7;
- if(!*key || !*(key + 1)) return input_none;
- uint8_t button = (*key - '0') * 10 + (*(key + 1) - '0');
- if(button >= mouse<>::buttons) return input_none;
- return mouse<>::index(m, mouse<>::button + button);
- }
-
- return input_none;
- }
-
- if(!memcmp(key, "joypad", 6)) {
- key += 6;
- if(!*key || !*(key + 1)) return input_none;
- uint8_t j = (*key - '0') * 10 + (*(key + 1) - '0');
- if(j >= joypad<>::count) return input_none;
- key += 2;
-
- if(!memcmp(key, ".hat", 4)) {
- key += 4;
- if(!*key || !*(key + 1)) return input_none;
- uint8_t hat = (*key - '0') * 10 + (*(key + 1) - '0');
- if(hat >= joypad<>::hats) return input_none;
- return joypad<>::index(j, joypad<>::hat + hat);
- }
-
- if(!memcmp(key, ".axis", 5)) {
- key += 5;
- if(!*key || !*(key + 1)) return input_none;
- uint8_t axis = (*key - '0') * 10 + (*(key + 1) - '0');
- if(axis >= joypad<>::axes) return input_none;
- return joypad<>::index(j, joypad<>::axis + axis);
- }
-
- if(!memcmp(key, ".button", 7)) {
- key += 7;
- if(!*key || !*(key + 1)) return input_none;
- uint8_t button = (*key - '0') * 10 + (*(key + 1) - '0');
- if(button >= joypad<>::buttons) return input_none;
- return joypad<>::index(j, joypad<>::button + button);
- }
-
- return input_none;
- }
-
- return input_none;
+inline Keyboard& keyboard(unsigned id) {
+ static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
+ switch(id) { default:
+ case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
+ case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
}
}
+static const char MouseScancodeName[][64] = {
+ "Xaxis", "Yaxis", "Zaxis",
+ "Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
+};
+
+struct Mouse;
+Mouse& mouse(unsigned = 0);
+
+struct Mouse {
+ const unsigned ID;
+ enum { Base = Keyboard::Base + Keyboard::Size * Keyboard::Count };
+ enum { Count = 8, Size = 16 };
+ enum { Axes = 3, Buttons = 8 };
+
+ enum Scancode {
+ Xaxis, Yaxis, Zaxis,
+ Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
+ Limit,
+ };
+
+ static signed numberDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).belongsTo(scancode)) return i;
+ }
+ return -1;
+ }
+
+ static signed axisDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).isAxis(scancode)) return scancode - mouse(i).axis(0);
+ }
+ return -1;
+ }
+
+ static signed buttonDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).isButton(scancode)) return scancode - mouse(i).button(0);
+ }
+ return -1;
+ }
+
+ static bool isAnyAxis(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).isAxis(scancode)) return true;
+ }
+ return false;
+ }
+
+ static bool isAnyButton(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).isButton(scancode)) return true;
+ }
+ return false;
+ }
+
+ static uint16_t decode(const char *name) {
+ string s(name);
+ if(!strbegin(name, "MS")) return 0;
+ ltrim(s, "MS");
+ unsigned id = strunsigned(s);
+ int pos = strpos(s, "::");
+ if(pos < 0) return 0;
+ s = substr(s, pos + 2);
+ for(unsigned i = 0; i < Limit; i++) {
+ if(s == MouseScancodeName[i]) return Base + Size * id + i;
+ }
+ return 0;
+ }
+
+ string encode(uint16_t code) const {
+ unsigned index = 0;
+ for(unsigned i = 0; i < Count; i++) {
+ if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
+ index = code - (Base + Size * i);
+ break;
+ }
+ }
+ return string() << "MS" << ID << "::" << MouseScancodeName[index];
+ }
+
+ uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
+ uint16_t axis(unsigned id) const { return Base + Size * ID + Xaxis + id; }
+ uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
+ bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(2); }
+ bool isButton(unsigned id) const { return id >= button(0) && id <= button(7); }
+ bool belongsTo(uint16_t scancode) const { return isAxis(scancode) || isButton(scancode); }
+
+ Mouse(unsigned ID_) : ID(ID_) {}
+};
+
+inline Mouse& mouse(unsigned id) {
+ static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
+ switch(id) { default:
+ case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
+ case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
+ }
+}
+
+static const char JoypadScancodeName[][64] = {
+ "Hat0", "Hat1", "Hat2", "Hat3", "Hat4", "Hat5", "Hat6", "Hat7",
+ "Axis0", "Axis1", "Axis2", "Axis3", "Axis4", "Axis5", "Axis6", "Axis7",
+ "Axis8", "Axis9", "Axis10", "Axis11", "Axis12", "Axis13", "Axis14", "Axis15",
+ "Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
+ "Button8", "Button9", "Button10", "Button11", "Button12", "Button13", "Button14", "Button15",
+ "Button16", "Button17", "Button18", "Button19", "Button20", "Button21", "Button22", "Button23",
+ "Button24", "Button25", "Button26", "Button27", "Button28", "Button29", "Button30", "Button31",
+};
+
+struct Joypad;
+Joypad& joypad(unsigned = 0);
+
+struct Joypad {
+ const unsigned ID;
+ enum { Base = Mouse::Base + Mouse::Size * Mouse::Count };
+ enum { Count = 8, Size = 64 };
+ enum { Hats = 8, Axes = 16, Buttons = 32 };
+
+ enum Scancode {
+ Hat0, Hat1, Hat2, Hat3, Hat4, Hat5, Hat6, Hat7,
+ Axis0, Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7,
+ Axis8, Axis9, Axis10, Axis11, Axis12, Axis13, Axis14, Axis15,
+ Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
+ Button8, Button9, Button10, Button11, Button12, Button13, Button14, Button15,
+ Button16, Button17, Button18, Button19, Button20, Button21, Button22, Button23,
+ Button24, Button25, Button26, Button27, Button28, Button29, Button30, Button31,
+ Limit,
+ };
+
+ enum Hat { HatCenter = 0, HatUp = 1, HatRight = 2, HatDown = 4, HatLeft = 8 };
+
+ static signed numberDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).belongsTo(scancode)) return i;
+ }
+ return -1;
+ }
+
+ static signed hatDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isHat(scancode)) return scancode - joypad(i).hat(0);
+ }
+ return -1;
+ }
+
+ static signed axisDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isAxis(scancode)) return scancode - joypad(i).axis(0);
+ }
+ return -1;
+ }
+
+ static signed buttonDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isButton(scancode)) return scancode - joypad(i).button(0);
+ }
+ return -1;
+ }
+
+ static bool isAnyHat(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isHat(scancode)) return true;
+ }
+ return false;
+ }
+
+ static bool isAnyAxis(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isAxis(scancode)) return true;
+ }
+ return false;
+ }
+
+ static bool isAnyButton(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isButton(scancode)) return true;
+ }
+ return false;
+ }
+
+ static uint16_t decode(const char *name) {
+ string s(name);
+ if(!strbegin(name, "JP")) return 0;
+ ltrim(s, "JP");
+ unsigned id = strunsigned(s);
+ int pos = strpos(s, "::");
+ if(pos < 0) return 0;
+ s = substr(s, pos + 2);
+ for(unsigned i = 0; i < Limit; i++) {
+ if(s == JoypadScancodeName[i]) return Base + Size * id + i;
+ }
+ return 0;
+ }
+
+ string encode(uint16_t code) const {
+ unsigned index = 0;
+ for(unsigned i = 0; i < Count; i++) {
+ if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
+ index = code - (Base + Size * i);
+ }
+ }
+ return string() << "JP" << ID << "::" << JoypadScancodeName[index];
+ }
+
+ uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
+ uint16_t hat(unsigned id) const { return Base + Size * ID + Hat0 + id; }
+ uint16_t axis(unsigned id) const { return Base + Size * ID + Axis0 + id; }
+ uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
+ bool isHat(unsigned id) const { return id >= hat(0) && id <= hat(7); }
+ bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(15); }
+ bool isButton(unsigned id) const { return id >= button(0) && id <= button(31); }
+ bool belongsTo(uint16_t scancode) const { return isHat(scancode) || isAxis(scancode) || isButton(scancode); }
+
+ Joypad(unsigned ID_) : ID(ID_) {}
+};
+
+inline Joypad& joypad(unsigned id) {
+ static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
+ switch(id) { default:
+ case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
+ case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
+ }
+}
+
+struct Scancode {
+ enum { None = 0, Limit = Joypad::Base + Joypad::Size * Joypad::Count };
+
+ static uint16_t decode(const char *name) {
+ uint16_t code;
+ code = Keyboard::decode(name);
+ if(code) return code;
+ code = Mouse::decode(name);
+ if(code) return code;
+ code = Joypad::decode(name);
+ if(code) return code;
+ return None;
+ }
+
+ static string encode(uint16_t code) {
+ for(unsigned i = 0; i < Keyboard::Count; i++) {
+ if(keyboard(i).belongsTo(code)) return keyboard(i).encode(code);
+ }
+ for(unsigned i = 0; i < Mouse::Count; i++) {
+ if(mouse(i).belongsTo(code)) return mouse(i).encode(code);
+ }
+ for(unsigned i = 0; i < Joypad::Count; i++) {
+ if(joypad(i).belongsTo(code)) return joypad(i).encode(code);
+ }
+ return "None";
+ }
+};
+
+}
+
#endif
diff --git a/src/lib/nall/serializer.hpp b/src/lib/nall/serializer.hpp
index 4357f831..521e7d2e 100644
--- a/src/lib/nall/serializer.hpp
+++ b/src/lib/nall/serializer.hpp
@@ -20,6 +20,12 @@ namespace nall {
class serializer {
public:
+ enum mode_t { Load, Save, Size };
+
+ mode_t mode() const {
+ return imode;
+ }
+
const uint8_t* data() const {
return idata;
}
@@ -37,9 +43,9 @@ namespace nall {
//this is rather dangerous, and not cross-platform safe;
//but there is no standardized way to export FP-values
uint8_t *p = (uint8_t*)&value;
- if(mode == Save) {
+ if(imode == Save) {
for(unsigned n = 0; n < size; n++) idata[isize++] = p[n];
- } else if(mode == Load) {
+ } else if(imode == Load) {
for(unsigned n = 0; n < size; n++) p[n] = idata[isize++];
} else {
isize += size;
@@ -48,12 +54,12 @@ namespace nall {
template void integer(T &value) {
enum { size = is_bool::value ? 1 : sizeof(T) };
- if(mode == Save) {
+ if(imode == Save) {
for(unsigned n = 0; n < size; n++) idata[isize++] = value >> (n << 3);
- } else if(mode == Load) {
+ } else if(imode == Load) {
value = 0;
for(unsigned n = 0; n < size; n++) value |= idata[isize++] << (n << 3);
- } else if(mode == Size) {
+ } else if(imode == Size) {
isize += size;
}
}
@@ -70,7 +76,7 @@ namespace nall {
serializer& operator=(const serializer &s) {
if(idata) delete[] idata;
- mode = s.mode;
+ imode = s.imode;
idata = new uint8_t[s.icapacity];
isize = s.isize;
icapacity = s.icapacity;
@@ -84,20 +90,20 @@ namespace nall {
}
serializer() {
- mode = Size;
+ imode = Size;
idata = 0;
isize = 0;
}
serializer(unsigned capacity) {
- mode = Save;
+ imode = Save;
idata = new uint8_t[capacity]();
isize = 0;
icapacity = capacity;
}
serializer(const uint8_t *data, unsigned capacity) {
- mode = Load;
+ imode = Load;
idata = new uint8_t[capacity];
isize = 0;
icapacity = capacity;
@@ -109,7 +115,7 @@ namespace nall {
}
private:
- enum mode_t { Load, Save, Size } mode;
+ mode_t imode;
uint8_t *idata;
unsigned isize;
unsigned icapacity;
diff --git a/src/lib/nall/string/base.hpp b/src/lib/nall/string/base.hpp
index e620bff3..24a5b1d4 100644
--- a/src/lib/nall/string/base.hpp
+++ b/src/lib/nall/string/base.hpp
@@ -80,6 +80,11 @@ namespace nall {
protected:
char *data;
size_t size;
+
+ #if defined(QT_CORE_LIB)
+ public:
+ inline operator QString() const;
+ #endif
};
class lstring : public vector {
diff --git a/src/lib/nall/string/cast.hpp b/src/lib/nall/string/cast.hpp
index 08e366ea..0b490917 100644
--- a/src/lib/nall/string/cast.hpp
+++ b/src/lib/nall/string/cast.hpp
@@ -20,6 +20,11 @@ namespace nall {
operator[](size()).assign(to_string(value));
return *this;
}
+
+ #if defined(QT_CORE_LIB)
+ template<> inline string to_string(const QString &v) { return v.toUtf8().constData(); }
+ string::operator QString() const { return QString::fromUtf8(*this); }
+ #endif
};
#endif
diff --git a/src/lib/ruby/input/carbon.cpp b/src/lib/ruby/input/carbon.cpp
index 65706b24..c5191f4b 100644
--- a/src/lib/ruby/input/carbon.cpp
+++ b/src/lib/ruby/input/carbon.cpp
@@ -19,129 +19,126 @@ public:
bool acquired() { return false; }
bool poll(int16_t *table) {
- memset(table, 0, nall::input_limit * sizeof(int16_t));
+ memset(table, 0, Scancode::Limit * sizeof(int16_t));
KeyMap keys;
GetKeys(keys);
uint8_t *keymap = (uint8_t*)keys;
- #define map(id, name) table[keyboard<0>::name] = (bool)(keymap[id >> 3] & (1 << (id & 7)))
- map(0x35, escape);
+ #define map(id, name) table[keyboard(0)[name]] = (bool)(keymap[id >> 3] & (1 << (id & 7)))
+ map(0x35, Keyboard::Escape);
- map(0x7a, f1);
- map(0x78, f2);
- map(0x63, f3);
- map(0x76, f4);
- map(0x60, f5);
- map(0x61, f6);
- map(0x62, f7);
- map(0x64, f8);
- map(0x65, f9);
- map(0x6d, f10);
- map(0x67, f11);
- //map(0x??, f12);
+ map(0x7a, Keyboard::F1);
+ map(0x78, Keyboard::F2);
+ map(0x63, Keyboard::F3);
+ map(0x76, Keyboard::F4);
+ map(0x60, Keyboard::F5);
+ map(0x61, Keyboard::F6);
+ map(0x62, Keyboard::F7);
+ map(0x64, Keyboard::F8);
+ map(0x65, Keyboard::F9);
+ map(0x6d, Keyboard::F10);
+ map(0x67, Keyboard::F11);
+ //map(0x??, Keyboard::F12);
- map(0x69, print_screen);
- //map(0x??, scroll_lock);
- map(0x71, pause);
+ map(0x69, Keyboard::PrintScreen);
+ //map(0x??, Keyboard::ScrollLock);
+ map(0x71, Keyboard::Pause);
- map(0x32, tilde);
- map(0x12, num_1);
- map(0x13, num_2);
- map(0x14, num_3);
- map(0x15, num_4);
- map(0x17, num_5);
- map(0x16, num_6);
- map(0x1a, num_7);
- map(0x1c, num_8);
- map(0x19, num_9);
- map(0x1d, num_0);
+ map(0x32, Keyboard::Tilde);
+ map(0x12, Keyboard::Num1);
+ map(0x13, Keyboard::Num2);
+ map(0x14, Keyboard::Num3);
+ map(0x15, Keyboard::Num4);
+ map(0x17, Keyboard::Num5);
+ map(0x16, Keyboard::Num6);
+ map(0x1a, Keyboard::Num7);
+ map(0x1c, Keyboard::Num8);
+ map(0x19, Keyboard::Num9);
+ map(0x1d, Keyboard::Num0);
- map(0x1b, dash);
- map(0x18, equal);
- map(0x33, backspace);
+ map(0x1b, Keyboard::Dash);
+ map(0x18, Keyboard::Equal);
+ map(0x33, Keyboard::Backspace);
- map(0x72, insert);
- map(0x75, delete_);
- map(0x73, home);
- map(0x77, end);
- map(0x74, page_up);
- map(0x79, page_down);
+ map(0x72, Keyboard::Insert);
+ map(0x75, Keyboard::Delete);
+ map(0x73, Keyboard::Home);
+ map(0x77, Keyboard::End);
+ map(0x74, Keyboard::PageUp);
+ map(0x79, Keyboard::PageDown);
- map(0x00, a);
- map(0x0b, b);
- map(0x08, c);
- map(0x02, d);
- map(0x0e, e);
- map(0x03, f);
- map(0x05, g);
- map(0x04, h);
- map(0x22, i);
- map(0x26, j);
- map(0x28, k);
- map(0x25, l);
- map(0x2e, m);
- map(0x2d, n);
- map(0x1f, o);
- map(0x23, p);
- map(0x0c, q);
- map(0x0f, r);
- map(0x01, s);
- map(0x11, t);
- map(0x20, u);
- map(0x09, v);
- map(0x0d, w);
- map(0x07, x);
- map(0x10, y);
- map(0x06, z);
+ map(0x00, Keyboard::A);
+ map(0x0b, Keyboard::B);
+ map(0x08, Keyboard::C);
+ map(0x02, Keyboard::D);
+ map(0x0e, Keyboard::E);
+ map(0x03, Keyboard::F);
+ map(0x05, Keyboard::G);
+ map(0x04, Keyboard::H);
+ map(0x22, Keyboard::I);
+ map(0x26, Keyboard::J);
+ map(0x28, Keyboard::K);
+ map(0x25, Keyboard::L);
+ map(0x2e, Keyboard::M);
+ map(0x2d, Keyboard::N);
+ map(0x1f, Keyboard::O);
+ map(0x23, Keyboard::P);
+ map(0x0c, Keyboard::Q);
+ map(0x0f, Keyboard::R);
+ map(0x01, Keyboard::S);
+ map(0x11, Keyboard::T);
+ map(0x20, Keyboard::U);
+ map(0x09, Keyboard::V);
+ map(0x0d, Keyboard::W);
+ map(0x07, Keyboard::X);
+ map(0x10, Keyboard::Y);
+ map(0x06, Keyboard::Z);
- map(0x21, lbracket);
- map(0x1e, rbracket);
- map(0x2a, backslash);
- map(0x29, semicolon);
- map(0x27, apostrophe);
- map(0x2b, comma);
- map(0x2f, period);
- map(0x2c, slash);
+ map(0x21, Keyboard::LeftBracket);
+ map(0x1e, Keyboard::RightBracket);
+ map(0x2a, Keyboard::Backslash);
+ map(0x29, Keyboard::Semicolon);
+ map(0x27, Keyboard::Apostrophe);
+ map(0x2b, Keyboard::Comma);
+ map(0x2f, Keyboard::Period);
+ map(0x2c, Keyboard::Slash);
- map(0x52, pad_0);
- map(0x53, pad_1);
- map(0x54, pad_2);
- map(0x55, pad_3);
- map(0x56, pad_4);
- map(0x57, pad_5);
- map(0x58, pad_6);
- map(0x59, pad_7);
- map(0x5b, pad_8);
- map(0x5c, pad_9);
+ map(0x53, Keyboard::Keypad1);
+ map(0x54, Keyboard::Keypad2);
+ map(0x55, Keyboard::Keypad3);
+ map(0x56, Keyboard::Keypad4);
+ map(0x57, Keyboard::Keypad5);
+ map(0x58, Keyboard::Keypad6);
+ map(0x59, Keyboard::Keypad7);
+ map(0x5b, Keyboard::Keypad8);
+ map(0x5c, Keyboard::Keypad9);
+ map(0x52, Keyboard::Keypad0);
- map(0x45, add);
- map(0x4e, subtract);
- map(0x43, multiply);
- map(0x4b, divide);
- map(0x4c, enter);
+ //map(0x??, Keyboard::Point);
+ map(0x4c, Keyboard::Enter);
+ map(0x45, Keyboard::Add);
+ map(0x4e, Keyboard::Subtract);
+ map(0x43, Keyboard::Multiply);
+ map(0x4b, Keyboard::Divide);
- map(0x47, num_lock);
- //map(0x39, caps_lock);
+ map(0x47, Keyboard::NumLock);
+ //map(0x39, Keyboard::CapsLock);
- map(0x7e, up);
- map(0x7d, down);
- map(0x7b, left);
- map(0x7c, right);
+ map(0x7e, Keyboard::Up);
+ map(0x7d, Keyboard::Down);
+ map(0x7b, Keyboard::Left);
+ map(0x7c, Keyboard::Right);
- map(0x30, tab);
- map(0x24, return_);
- map(0x31, spacebar);
+ map(0x30, Keyboard::Tab);
+ map(0x24, Keyboard::Return);
+ map(0x31, Keyboard::Spacebar);
+ //map(0x??, Keyboard::Menu);
- map(0x3b, lctrl);
- //map(0x3b, rctrl);
- map(0x3a, lalt);
- //map(0x3a, ralt);
- map(0x38, lshift);
- //map(0x38, rshift);
- map(0x37, lsuper);
- //map(0x37, rsuper);
- //map(0x??, menu);
+ map(0x38, Keyboard::Shift);
+ map(0x3b, Keyboard::Control);
+ map(0x3a, Keyboard::Alt);
+ map(0x37, Keyboard::Super);
#undef map
return true;
diff --git a/src/lib/ruby/input/directinput.cpp b/src/lib/ruby/input/directinput.cpp
index 339c9f20..cb0da3c2 100644
--- a/src/lib/ruby/input/directinput.cpp
+++ b/src/lib/ruby/input/directinput.cpp
@@ -14,7 +14,7 @@ public:
LPDIRECTINPUT8 context;
LPDIRECTINPUTDEVICE8 keyboard;
LPDIRECTINPUTDEVICE8 mouse;
- LPDIRECTINPUTDEVICE8 gamepad[joypad<>::count];
+ LPDIRECTINPUTDEVICE8 gamepad[Joypad::Count];
bool mouseacquired;
} device;
@@ -45,7 +45,7 @@ public:
}
bool poll(int16_t *table) {
- memset(table, 0, nall::input_limit * sizeof(int16_t));
+ memset(table, 0, Scancode::Limit * sizeof(int16_t));
//========
//Keyboard
@@ -60,122 +60,122 @@ public:
}
}
- table[keyboard<0>::escape] = (bool)(state[0x01] & 0x80);
- table[keyboard<0>::f1 ] = (bool)(state[0x3b] & 0x80);
- table[keyboard<0>::f2 ] = (bool)(state[0x3c] & 0x80);
- table[keyboard<0>::f3 ] = (bool)(state[0x3d] & 0x80);
- table[keyboard<0>::f4 ] = (bool)(state[0x3e] & 0x80);
- table[keyboard<0>::f5 ] = (bool)(state[0x3f] & 0x80);
- table[keyboard<0>::f6 ] = (bool)(state[0x40] & 0x80);
- table[keyboard<0>::f7 ] = (bool)(state[0x41] & 0x80);
- table[keyboard<0>::f8 ] = (bool)(state[0x42] & 0x80);
- table[keyboard<0>::f9 ] = (bool)(state[0x43] & 0x80);
- table[keyboard<0>::f10 ] = (bool)(state[0x44] & 0x80);
- table[keyboard<0>::f11 ] = (bool)(state[0x57] & 0x80);
- table[keyboard<0>::f12 ] = (bool)(state[0x58] & 0x80);
+ #define key(id) table[keyboard(0)[id]]
- table[keyboard<0>::print_screen] = (bool)(state[0xb7] & 0x80);
- table[keyboard<0>::scroll_lock ] = (bool)(state[0x46] & 0x80);
- table[keyboard<0>::pause ] = (bool)(state[0xc5] & 0x80);
- table[keyboard<0>::tilde ] = (bool)(state[0x29] & 0x80);
+ key(Keyboard::Escape) = (bool)(state[0x01] & 0x80);
+ key(Keyboard::F1 ) = (bool)(state[0x3b] & 0x80);
+ key(Keyboard::F2 ) = (bool)(state[0x3c] & 0x80);
+ key(Keyboard::F3 ) = (bool)(state[0x3d] & 0x80);
+ key(Keyboard::F4 ) = (bool)(state[0x3e] & 0x80);
+ key(Keyboard::F5 ) = (bool)(state[0x3f] & 0x80);
+ key(Keyboard::F6 ) = (bool)(state[0x40] & 0x80);
+ key(Keyboard::F7 ) = (bool)(state[0x41] & 0x80);
+ key(Keyboard::F8 ) = (bool)(state[0x42] & 0x80);
+ key(Keyboard::F9 ) = (bool)(state[0x43] & 0x80);
+ key(Keyboard::F10 ) = (bool)(state[0x44] & 0x80);
+ key(Keyboard::F11 ) = (bool)(state[0x57] & 0x80);
+ key(Keyboard::F12 ) = (bool)(state[0x58] & 0x80);
- table[keyboard<0>::num_1] = (bool)(state[0x02] & 0x80);
- table[keyboard<0>::num_2] = (bool)(state[0x03] & 0x80);
- table[keyboard<0>::num_3] = (bool)(state[0x04] & 0x80);
- table[keyboard<0>::num_4] = (bool)(state[0x05] & 0x80);
- table[keyboard<0>::num_5] = (bool)(state[0x06] & 0x80);
- table[keyboard<0>::num_6] = (bool)(state[0x07] & 0x80);
- table[keyboard<0>::num_7] = (bool)(state[0x08] & 0x80);
- table[keyboard<0>::num_8] = (bool)(state[0x09] & 0x80);
- table[keyboard<0>::num_9] = (bool)(state[0x0a] & 0x80);
- table[keyboard<0>::num_0] = (bool)(state[0x0b] & 0x80);
+ key(Keyboard::PrintScreen) = (bool)(state[0xb7] & 0x80);
+ key(Keyboard::ScrollLock ) = (bool)(state[0x46] & 0x80);
+ key(Keyboard::Pause ) = (bool)(state[0xc5] & 0x80);
+ key(Keyboard::Tilde ) = (bool)(state[0x29] & 0x80);
- table[keyboard<0>::dash ] = (bool)(state[0x0c] & 0x80);
- table[keyboard<0>::equal ] = (bool)(state[0x0d] & 0x80);
- table[keyboard<0>::backspace] = (bool)(state[0x0e] & 0x80);
+ key(Keyboard::Num1) = (bool)(state[0x02] & 0x80);
+ key(Keyboard::Num2) = (bool)(state[0x03] & 0x80);
+ key(Keyboard::Num3) = (bool)(state[0x04] & 0x80);
+ key(Keyboard::Num4) = (bool)(state[0x05] & 0x80);
+ key(Keyboard::Num5) = (bool)(state[0x06] & 0x80);
+ key(Keyboard::Num6) = (bool)(state[0x07] & 0x80);
+ key(Keyboard::Num7) = (bool)(state[0x08] & 0x80);
+ key(Keyboard::Num8) = (bool)(state[0x09] & 0x80);
+ key(Keyboard::Num9) = (bool)(state[0x0a] & 0x80);
+ key(Keyboard::Num0) = (bool)(state[0x0b] & 0x80);
- table[keyboard<0>::insert ] = (bool)(state[0xd2] & 0x80);
- table[keyboard<0>::delete_ ] = (bool)(state[0xd3] & 0x80);
- table[keyboard<0>::home ] = (bool)(state[0xc7] & 0x80);
- table[keyboard<0>::end ] = (bool)(state[0xcf] & 0x80);
- table[keyboard<0>::page_up ] = (bool)(state[0xc9] & 0x80);
- table[keyboard<0>::page_down] = (bool)(state[0xd1] & 0x80);
+ key(Keyboard::Dash ) = (bool)(state[0x0c] & 0x80);
+ key(Keyboard::Equal ) = (bool)(state[0x0d] & 0x80);
+ key(Keyboard::Backspace) = (bool)(state[0x0e] & 0x80);
- table[keyboard<0>::a] = (bool)(state[0x1e] & 0x80);
- table[keyboard<0>::b] = (bool)(state[0x30] & 0x80);
- table[keyboard<0>::c] = (bool)(state[0x2e] & 0x80);
- table[keyboard<0>::d] = (bool)(state[0x20] & 0x80);
- table[keyboard<0>::e] = (bool)(state[0x12] & 0x80);
- table[keyboard<0>::f] = (bool)(state[0x21] & 0x80);
- table[keyboard<0>::g] = (bool)(state[0x22] & 0x80);
- table[keyboard<0>::h] = (bool)(state[0x23] & 0x80);
- table[keyboard<0>::i] = (bool)(state[0x17] & 0x80);
- table[keyboard<0>::j] = (bool)(state[0x24] & 0x80);
- table[keyboard<0>::k] = (bool)(state[0x25] & 0x80);
- table[keyboard<0>::l] = (bool)(state[0x26] & 0x80);
- table[keyboard<0>::m] = (bool)(state[0x32] & 0x80);
- table[keyboard<0>::n] = (bool)(state[0x31] & 0x80);
- table[keyboard<0>::o] = (bool)(state[0x18] & 0x80);
- table[keyboard<0>::p] = (bool)(state[0x19] & 0x80);
- table[keyboard<0>::q] = (bool)(state[0x10] & 0x80);
- table[keyboard<0>::r] = (bool)(state[0x13] & 0x80);
- table[keyboard<0>::s] = (bool)(state[0x1f] & 0x80);
- table[keyboard<0>::t] = (bool)(state[0x14] & 0x80);
- table[keyboard<0>::u] = (bool)(state[0x16] & 0x80);
- table[keyboard<0>::v] = (bool)(state[0x2f] & 0x80);
- table[keyboard<0>::w] = (bool)(state[0x11] & 0x80);
- table[keyboard<0>::x] = (bool)(state[0x2d] & 0x80);
- table[keyboard<0>::y] = (bool)(state[0x15] & 0x80);
- table[keyboard<0>::z] = (bool)(state[0x2c] & 0x80);
+ key(Keyboard::Insert ) = (bool)(state[0xd2] & 0x80);
+ key(Keyboard::Delete ) = (bool)(state[0xd3] & 0x80);
+ key(Keyboard::Home ) = (bool)(state[0xc7] & 0x80);
+ key(Keyboard::End ) = (bool)(state[0xcf] & 0x80);
+ key(Keyboard::PageUp ) = (bool)(state[0xc9] & 0x80);
+ key(Keyboard::PageDown) = (bool)(state[0xd1] & 0x80);
- table[keyboard<0>::lbracket ] = (bool)(state[0x1a] & 0x80);
- table[keyboard<0>::rbracket ] = (bool)(state[0x1b] & 0x80);
- table[keyboard<0>::backslash ] = (bool)(state[0x2b] & 0x80);
- table[keyboard<0>::semicolon ] = (bool)(state[0x27] & 0x80);
- table[keyboard<0>::apostrophe] = (bool)(state[0x28] & 0x80);
- table[keyboard<0>::comma ] = (bool)(state[0x33] & 0x80);
- table[keyboard<0>::period ] = (bool)(state[0x34] & 0x80);
- table[keyboard<0>::slash ] = (bool)(state[0x35] & 0x80);
+ key(Keyboard::A) = (bool)(state[0x1e] & 0x80);
+ key(Keyboard::B) = (bool)(state[0x30] & 0x80);
+ key(Keyboard::C) = (bool)(state[0x2e] & 0x80);
+ key(Keyboard::D) = (bool)(state[0x20] & 0x80);
+ key(Keyboard::E) = (bool)(state[0x12] & 0x80);
+ key(Keyboard::F) = (bool)(state[0x21] & 0x80);
+ key(Keyboard::G) = (bool)(state[0x22] & 0x80);
+ key(Keyboard::H) = (bool)(state[0x23] & 0x80);
+ key(Keyboard::I) = (bool)(state[0x17] & 0x80);
+ key(Keyboard::J) = (bool)(state[0x24] & 0x80);
+ key(Keyboard::K) = (bool)(state[0x25] & 0x80);
+ key(Keyboard::L) = (bool)(state[0x26] & 0x80);
+ key(Keyboard::M) = (bool)(state[0x32] & 0x80);
+ key(Keyboard::N) = (bool)(state[0x31] & 0x80);
+ key(Keyboard::O) = (bool)(state[0x18] & 0x80);
+ key(Keyboard::P) = (bool)(state[0x19] & 0x80);
+ key(Keyboard::Q) = (bool)(state[0x10] & 0x80);
+ key(Keyboard::R) = (bool)(state[0x13] & 0x80);
+ key(Keyboard::S) = (bool)(state[0x1f] & 0x80);
+ key(Keyboard::T) = (bool)(state[0x14] & 0x80);
+ key(Keyboard::U) = (bool)(state[0x16] & 0x80);
+ key(Keyboard::V) = (bool)(state[0x2f] & 0x80);
+ key(Keyboard::W) = (bool)(state[0x11] & 0x80);
+ key(Keyboard::X) = (bool)(state[0x2d] & 0x80);
+ key(Keyboard::Y) = (bool)(state[0x15] & 0x80);
+ key(Keyboard::Z) = (bool)(state[0x2c] & 0x80);
- table[keyboard<0>::pad_0] = (bool)(state[0x4f] & 0x80);
- table[keyboard<0>::pad_1] = (bool)(state[0x50] & 0x80);
- table[keyboard<0>::pad_2] = (bool)(state[0x51] & 0x80);
- table[keyboard<0>::pad_3] = (bool)(state[0x4b] & 0x80);
- table[keyboard<0>::pad_4] = (bool)(state[0x4c] & 0x80);
- table[keyboard<0>::pad_5] = (bool)(state[0x4d] & 0x80);
- table[keyboard<0>::pad_6] = (bool)(state[0x47] & 0x80);
- table[keyboard<0>::pad_7] = (bool)(state[0x48] & 0x80);
- table[keyboard<0>::pad_8] = (bool)(state[0x49] & 0x80);
- table[keyboard<0>::pad_9] = (bool)(state[0x52] & 0x80);
- table[keyboard<0>::point] = (bool)(state[0x53] & 0x80);
+ key(Keyboard::LeftBracket ) = (bool)(state[0x1a] & 0x80);
+ key(Keyboard::RightBracket) = (bool)(state[0x1b] & 0x80);
+ key(Keyboard::Backslash ) = (bool)(state[0x2b] & 0x80);
+ key(Keyboard::Semicolon ) = (bool)(state[0x27] & 0x80);
+ key(Keyboard::Apostrophe ) = (bool)(state[0x28] & 0x80);
+ key(Keyboard::Comma ) = (bool)(state[0x33] & 0x80);
+ key(Keyboard::Period ) = (bool)(state[0x34] & 0x80);
+ key(Keyboard::Slash ) = (bool)(state[0x35] & 0x80);
- table[keyboard<0>::add] = (bool)(state[0x4e] & 0x80);
- table[keyboard<0>::subtract] = (bool)(state[0x4a] & 0x80);
- table[keyboard<0>::multiply] = (bool)(state[0x37] & 0x80);
- table[keyboard<0>::divide] = (bool)(state[0xb5] & 0x80);
- table[keyboard<0>::enter] = (bool)(state[0x9c] & 0x80);
+ key(Keyboard::Keypad0) = (bool)(state[0x4f] & 0x80);
+ key(Keyboard::Keypad1) = (bool)(state[0x50] & 0x80);
+ key(Keyboard::Keypad2) = (bool)(state[0x51] & 0x80);
+ key(Keyboard::Keypad3) = (bool)(state[0x4b] & 0x80);
+ key(Keyboard::Keypad4) = (bool)(state[0x4c] & 0x80);
+ key(Keyboard::Keypad5) = (bool)(state[0x4d] & 0x80);
+ key(Keyboard::Keypad6) = (bool)(state[0x47] & 0x80);
+ key(Keyboard::Keypad7) = (bool)(state[0x48] & 0x80);
+ key(Keyboard::Keypad8) = (bool)(state[0x49] & 0x80);
+ key(Keyboard::Keypad9) = (bool)(state[0x52] & 0x80);
+ key(Keyboard::Point ) = (bool)(state[0x53] & 0x80);
- table[keyboard<0>::num_lock ] = (bool)(state[0x45] & 0x80);
- table[keyboard<0>::caps_lock] = (bool)(state[0x3a] & 0x80);
+ key(Keyboard::Add ) = (bool)(state[0x4e] & 0x80);
+ key(Keyboard::Subtract) = (bool)(state[0x4a] & 0x80);
+ key(Keyboard::Multiply) = (bool)(state[0x37] & 0x80);
+ key(Keyboard::Divide ) = (bool)(state[0xb5] & 0x80);
+ key(Keyboard::Enter ) = (bool)(state[0x9c] & 0x80);
- table[keyboard<0>::up ] = (bool)(state[0xc8] & 0x80);
- table[keyboard<0>::down ] = (bool)(state[0xd0] & 0x80);
- table[keyboard<0>::left ] = (bool)(state[0xcb] & 0x80);
- table[keyboard<0>::right] = (bool)(state[0xcd] & 0x80);
+ key(Keyboard::NumLock ) = (bool)(state[0x45] & 0x80);
+ key(Keyboard::CapsLock) = (bool)(state[0x3a] & 0x80);
- table[keyboard<0>::tab ] = (bool)(state[0x0f] & 0x80);
- table[keyboard<0>::return_ ] = (bool)(state[0x1c] & 0x80);
- table[keyboard<0>::spacebar] = (bool)(state[0x39] & 0x80);
+ key(Keyboard::Up ) = (bool)(state[0xc8] & 0x80);
+ key(Keyboard::Down ) = (bool)(state[0xd0] & 0x80);
+ key(Keyboard::Left ) = (bool)(state[0xcb] & 0x80);
+ key(Keyboard::Right) = (bool)(state[0xcd] & 0x80);
- table[keyboard<0>::lctrl ] = (bool)(state[0x1d] & 0x80);
- table[keyboard<0>::rctrl ] = (bool)(state[0x9d] & 0x80);
- table[keyboard<0>::lalt ] = (bool)(state[0x38] & 0x80);
- table[keyboard<0>::ralt ] = (bool)(state[0xb8] & 0x80);
- table[keyboard<0>::lshift] = (bool)(state[0x2a] & 0x80);
- table[keyboard<0>::rshift] = (bool)(state[0x36] & 0x80);
- table[keyboard<0>::lsuper] = (bool)(state[0xdb] & 0x80);
- table[keyboard<0>::rsuper] = (bool)(state[0xdc] & 0x80);
- table[keyboard<0>::menu ] = (bool)(state[0xdd] & 0x80);
+ key(Keyboard::Tab ) = (bool)(state[0x0f] & 0x80);
+ key(Keyboard::Return ) = (bool)(state[0x1c] & 0x80);
+ key(Keyboard::Spacebar) = (bool)(state[0x39] & 0x80);
+ key(Keyboard::Menu ) = (bool)(state[0xdd] & 0x80);
+
+ key(Keyboard::Shift ) = (bool)(state[0x2a] & 0x80) || (bool)(state[0x36] & 0x80);
+ key(Keyboard::Control) = (bool)(state[0x1d] & 0x80) || (bool)(state[0x9d] & 0x80);
+ key(Keyboard::Alt ) = (bool)(state[0x38] & 0x80) || (bool)(state[0xb8] & 0x80);
+ key(Keyboard::Super ) = (bool)(state[0xdb] & 0x80) || (bool)(state[0xdc] & 0x80);
+
+ #undef key
}
//=====
@@ -191,27 +191,26 @@ public:
}
}
- table[mouse<0>::x] = state.lX;
- table[mouse<0>::y] = state.lY;
- table[mouse<0>::z] = state.lZ / WHEEL_DELTA;
- for(unsigned n = 0; n < mouse<>::buttons; n++) {
- table[mouse<0>::button + n] = (bool)state.rgbButtons[n];
+ table[mouse(0).axis(0)] = state.lX;
+ table[mouse(0).axis(1)] = state.lY;
+ table[mouse(0).axis(2)] = state.lZ / WHEEL_DELTA;
+ for(unsigned n = 0; n < Mouse::Buttons; n++) {
+ table[mouse(0).button(n)] = (bool)state.rgbButtons[n];
}
//on Windows, 0 = left, 1 = right, 2 = middle
//swap middle and right buttons for consistency with Linux
- int16_t temp = table[mouse<0>::button + 1];
- table[mouse<0>::button + 1] = table[mouse<0>::button + 2];
- table[mouse<0>::button + 2] = temp;
+ int16_t temp = table[mouse(0).button(1)];
+ table[mouse(0).button(1)] = table[mouse(0).button(2)];
+ table[mouse(0).button(2)] = temp;
}
//=========
//Joypad(s)
//=========
- for(unsigned i = 0; i < joypad<>::count; i++) {
+ for(unsigned i = 0; i < Joypad::Count; i++) {
if(!device.gamepad[i]) continue;
- unsigned index = joypad<>::index(i, joypad<>::none);
if(FAILED(device.gamepad[i]->Poll())) {
device.gamepad[i]->Acquire();
@@ -222,30 +221,30 @@ public:
device.gamepad[i]->GetDeviceState(sizeof(DIJOYSTATE2), &state);
//POV hats
- for(unsigned n = 0; n < min((unsigned)joypad<>::hats, 4); n++) {
+ for(unsigned n = 0; n < min((unsigned)Joypad::Hats, 4); n++) {
//POV value is in clockwise-hundredth degree units.
unsigned pov = state.rgdwPOV[n];
//some drivers report a centered POV hat as -1U, others as 65535U.
//>= 36000 will match both, as well as invalid ranges.
if(pov < 36000) {
- if(pov >= 31500 || pov <= 4500) table[index + joypad<>::hat + n] |= joypad<>::hat_up;
- if(pov >= 4500 && pov <= 13500) table[index + joypad<>::hat + n] |= joypad<>::hat_right;
- if(pov >= 13500 && pov <= 22500) table[index + joypad<>::hat + n] |= joypad<>::hat_down;
- if(pov >= 22500 && pov <= 31500) table[index + joypad<>::hat + n] |= joypad<>::hat_left;
+ if(pov >= 31500 || pov <= 4500) table[joypad(i).hat(n)] |= Joypad::HatUp;
+ if(pov >= 4500 && pov <= 13500) table[joypad(i).hat(n)] |= Joypad::HatRight;
+ if(pov >= 13500 && pov <= 22500) table[joypad(i).hat(n)] |= Joypad::HatDown;
+ if(pov >= 22500 && pov <= 31500) table[joypad(i).hat(n)] |= Joypad::HatLeft;
}
}
//axes
- table[index + joypad<>::axis + 0] = state.lX;
- table[index + joypad<>::axis + 1] = state.lY;
- table[index + joypad<>::axis + 2] = state.lZ;
- table[index + joypad<>::axis + 3] = state.lRx;
- table[index + joypad<>::axis + 4] = state.lRy;
- table[index + joypad<>::axis + 5] = state.lRz;
+ table[joypad(i).axis(0)] = state.lX;
+ table[joypad(i).axis(1)] = state.lY;
+ table[joypad(i).axis(2)] = state.lZ;
+ table[joypad(i).axis(3)] = state.lRx;
+ table[joypad(i).axis(4)] = state.lRy;
+ table[joypad(i).axis(5)] = state.lRz;
//buttons
- for(unsigned n = 0; n < min((unsigned)joypad<>::buttons, 128); n++) {
- table[index + joypad<>::button + n] = (bool)state.rgbButtons[n];
+ for(unsigned n = 0; n < min((unsigned)Joypad::Buttons, 128); n++) {
+ table[joypad(i).button(n)] = (bool)state.rgbButtons[n];
}
}
@@ -254,8 +253,8 @@ public:
bool init_joypad(const DIDEVICEINSTANCE *instance) {
unsigned n;
- for(n = 0; n < joypad<>::count; n++) { if(!device.gamepad[n]) break; }
- if(n >= joypad<>::count) return DIENUM_STOP;
+ for(n = 0; n < Joypad::Count; n++) { if(!device.gamepad[n]) break; }
+ if(n >= Joypad::Count) return DIENUM_STOP;
if(FAILED(device.context->CreateDevice(instance->guidInstance, &device.gamepad[n], 0))) {
return DIENUM_CONTINUE; //continue and try next gamepad
@@ -270,7 +269,7 @@ public:
bool init_axis(const DIDEVICEOBJECTINSTANCE *instance) {
signed n;
- for(n = joypad<>::count - 1; n >= 0; n--) { if(device.gamepad[n]) break; }
+ for(n = Joypad::Count - 1; n >= 0; n--) { if(device.gamepad[n]) break; }
if(n < 0) return DIENUM_STOP;
DIPROPRANGE range;
@@ -289,7 +288,7 @@ public:
device.context = 0;
device.keyboard = 0;
device.mouse = 0;
- for(unsigned i = 0; i < joypad<>::count; i++) device.gamepad[i] = 0;
+ for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0;
device.mouseacquired = false;
DirectInput8Create(GetModuleHandle(0), 0x0800, IID_IDirectInput8, (void**)&device.context, 0);
@@ -322,7 +321,7 @@ public:
device.mouse = 0;
}
- for(unsigned i = 0; i < joypad<>::count; i++) {
+ for(unsigned i = 0; i < Joypad::Count; i++) {
if(device.gamepad[i]) {
device.gamepad[i]->Unacquire();
device.gamepad[i]->Release();
@@ -366,7 +365,7 @@ public:
device.context = 0;
device.keyboard = 0;
device.mouse = 0;
- for(unsigned i = 0; i < joypad<>::count; i++) device.gamepad[i] = 0;
+ for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0;
device.mouseacquired = false;
settings.handle = 0;
diff --git a/src/lib/ruby/input/rawinput.cpp b/src/lib/ruby/input/rawinput.cpp
index d2d9e2a8..fa3951fe 100644
--- a/src/lib/ruby/input/rawinput.cpp
+++ b/src/lib/ruby/input/rawinput.cpp
@@ -39,139 +39,151 @@ public:
};
struct Keyboard : Device {
- bool state[keyboard<>::length];
+ bool state[nall::Keyboard::Size];
void update(RAWINPUT *input) {
unsigned code = input->data.keyboard.MakeCode;
unsigned flags = input->data.keyboard.Flags;
#define map(id, flag, name) if(code == id) state[name] = (bool)(flags == flag);
- map(0x0001, 0, keyboard<>::escape)
- map(0x003b, 0, keyboard<>::f1)
- map(0x003c, 0, keyboard<>::f2)
- map(0x003d, 0, keyboard<>::f3)
- map(0x003e, 0, keyboard<>::f4)
- map(0x003f, 0, keyboard<>::f5)
- map(0x0040, 0, keyboard<>::f6)
- map(0x0041, 0, keyboard<>::f7)
- map(0x0042, 0, keyboard<>::f8)
- map(0x0043, 0, keyboard<>::f9)
- map(0x0044, 0, keyboard<>::f10)
- map(0x0057, 0, keyboard<>::f11)
- map(0x0058, 0, keyboard<>::f12)
+ map(0x0001, 0, nall::Keyboard::Escape)
+ map(0x003b, 0, nall::Keyboard::F1)
+ map(0x003c, 0, nall::Keyboard::F2)
+ map(0x003d, 0, nall::Keyboard::F3)
+ map(0x003e, 0, nall::Keyboard::F4)
+ map(0x003f, 0, nall::Keyboard::F5)
+ map(0x0040, 0, nall::Keyboard::F6)
+ map(0x0041, 0, nall::Keyboard::F7)
+ map(0x0042, 0, nall::Keyboard::F8)
+ map(0x0043, 0, nall::Keyboard::F9)
+ map(0x0044, 0, nall::Keyboard::F10)
+ map(0x0057, 0, nall::Keyboard::F11)
+ map(0x0058, 0, nall::Keyboard::F12)
- map(0x0037, 2, keyboard<>::print_screen)
- map(0x0046, 0, keyboard<>::scroll_lock)
- map(0x001d, 4, keyboard<>::pause)
- map(0x0029, 0, keyboard<>::tilde)
+ map(0x0037, 2, nall::Keyboard::PrintScreen)
+ map(0x0046, 0, nall::Keyboard::ScrollLock)
+ map(0x001d, 4, nall::Keyboard::Pause)
+ map(0x0029, 0, nall::Keyboard::Tilde)
- map(0x0002, 0, keyboard<>::num_1)
- map(0x0003, 0, keyboard<>::num_2)
- map(0x0004, 0, keyboard<>::num_3)
- map(0x0005, 0, keyboard<>::num_4)
- map(0x0006, 0, keyboard<>::num_5)
- map(0x0007, 0, keyboard<>::num_6)
- map(0x0008, 0, keyboard<>::num_7)
- map(0x0009, 0, keyboard<>::num_8)
- map(0x000a, 0, keyboard<>::num_9)
- map(0x000b, 0, keyboard<>::num_0)
+ map(0x0002, 0, nall::Keyboard::Num1)
+ map(0x0003, 0, nall::Keyboard::Num2)
+ map(0x0004, 0, nall::Keyboard::Num3)
+ map(0x0005, 0, nall::Keyboard::Num4)
+ map(0x0006, 0, nall::Keyboard::Num5)
+ map(0x0007, 0, nall::Keyboard::Num6)
+ map(0x0008, 0, nall::Keyboard::Num7)
+ map(0x0009, 0, nall::Keyboard::Num8)
+ map(0x000a, 0, nall::Keyboard::Num9)
+ map(0x000b, 0, nall::Keyboard::Num0)
- map(0x000c, 0, keyboard<>::dash)
- map(0x000d, 0, keyboard<>::equal)
- map(0x000e, 0, keyboard<>::backspace)
+ map(0x000c, 0, nall::Keyboard::Dash)
+ map(0x000d, 0, nall::Keyboard::Equal)
+ map(0x000e, 0, nall::Keyboard::Backspace)
- map(0x0052, 2, keyboard<>::insert)
- map(0x0053, 2, keyboard<>::delete_)
- map(0x0047, 2, keyboard<>::home)
- map(0x004f, 2, keyboard<>::end)
- map(0x0049, 2, keyboard<>::page_up)
- map(0x0051, 2, keyboard<>::page_down)
+ map(0x0052, 2, nall::Keyboard::Insert)
+ map(0x0053, 2, nall::Keyboard::Delete)
+ map(0x0047, 2, nall::Keyboard::Home)
+ map(0x004f, 2, nall::Keyboard::End)
+ map(0x0049, 2, nall::Keyboard::PageUp)
+ map(0x0051, 2, nall::Keyboard::PageDown)
- map(0x001e, 0, keyboard<>::a)
- map(0x0030, 0, keyboard<>::b)
- map(0x002e, 0, keyboard<>::c)
- map(0x0020, 0, keyboard<>::d)
- map(0x0012, 0, keyboard<>::e)
- map(0x0021, 0, keyboard<>::f)
- map(0x0022, 0, keyboard<>::g)
- map(0x0023, 0, keyboard<>::h)
- map(0x0017, 0, keyboard<>::i)
- map(0x0024, 0, keyboard<>::j)
- map(0x0025, 0, keyboard<>::k)
- map(0x0026, 0, keyboard<>::l)
- map(0x0032, 0, keyboard<>::m)
- map(0x0031, 0, keyboard<>::n)
- map(0x0018, 0, keyboard<>::o)
- map(0x0019, 0, keyboard<>::p)
- map(0x0010, 0, keyboard<>::q)
- map(0x0013, 0, keyboard<>::r)
- map(0x001f, 0, keyboard<>::s)
- map(0x0014, 0, keyboard<>::t)
- map(0x0016, 0, keyboard<>::u)
- map(0x002f, 0, keyboard<>::v)
- map(0x0011, 0, keyboard<>::w)
- map(0x002d, 0, keyboard<>::x)
- map(0x0015, 0, keyboard<>::y)
- map(0x002c, 0, keyboard<>::z)
+ map(0x001e, 0, nall::Keyboard::A)
+ map(0x0030, 0, nall::Keyboard::B)
+ map(0x002e, 0, nall::Keyboard::C)
+ map(0x0020, 0, nall::Keyboard::D)
+ map(0x0012, 0, nall::Keyboard::E)
+ map(0x0021, 0, nall::Keyboard::F)
+ map(0x0022, 0, nall::Keyboard::G)
+ map(0x0023, 0, nall::Keyboard::H)
+ map(0x0017, 0, nall::Keyboard::I)
+ map(0x0024, 0, nall::Keyboard::J)
+ map(0x0025, 0, nall::Keyboard::K)
+ map(0x0026, 0, nall::Keyboard::L)
+ map(0x0032, 0, nall::Keyboard::M)
+ map(0x0031, 0, nall::Keyboard::N)
+ map(0x0018, 0, nall::Keyboard::O)
+ map(0x0019, 0, nall::Keyboard::P)
+ map(0x0010, 0, nall::Keyboard::Q)
+ map(0x0013, 0, nall::Keyboard::R)
+ map(0x001f, 0, nall::Keyboard::S)
+ map(0x0014, 0, nall::Keyboard::T)
+ map(0x0016, 0, nall::Keyboard::U)
+ map(0x002f, 0, nall::Keyboard::V)
+ map(0x0011, 0, nall::Keyboard::W)
+ map(0x002d, 0, nall::Keyboard::X)
+ map(0x0015, 0, nall::Keyboard::Y)
+ map(0x002c, 0, nall::Keyboard::Z)
- map(0x001a, 0, keyboard<>::lbracket)
- map(0x001b, 0, keyboard<>::rbracket)
- map(0x002b, 0, keyboard<>::backslash)
- map(0x0027, 0, keyboard<>::semicolon)
- map(0x0028, 0, keyboard<>::apostrophe)
- map(0x0033, 0, keyboard<>::comma)
- map(0x0034, 0, keyboard<>::period)
- map(0x0035, 0, keyboard<>::slash)
+ map(0x001a, 0, nall::Keyboard::LeftBracket)
+ map(0x001b, 0, nall::Keyboard::RightBracket)
+ map(0x002b, 0, nall::Keyboard::Backslash)
+ map(0x0027, 0, nall::Keyboard::Semicolon)
+ map(0x0028, 0, nall::Keyboard::Apostrophe)
+ map(0x0033, 0, nall::Keyboard::Comma)
+ map(0x0034, 0, nall::Keyboard::Period)
+ map(0x0035, 0, nall::Keyboard::Slash)
- map(0x004f, 0, keyboard<>::pad_1)
- map(0x0050, 0, keyboard<>::pad_2)
- map(0x0051, 0, keyboard<>::pad_3)
- map(0x004b, 0, keyboard<>::pad_4)
- map(0x004c, 0, keyboard<>::pad_5)
- map(0x004d, 0, keyboard<>::pad_6)
- map(0x0047, 0, keyboard<>::pad_7)
- map(0x0048, 0, keyboard<>::pad_8)
- map(0x0049, 0, keyboard<>::pad_9)
- map(0x0052, 0, keyboard<>::pad_0)
+ map(0x004f, 0, nall::Keyboard::Keypad1)
+ map(0x0050, 0, nall::Keyboard::Keypad2)
+ map(0x0051, 0, nall::Keyboard::Keypad3)
+ map(0x004b, 0, nall::Keyboard::Keypad4)
+ map(0x004c, 0, nall::Keyboard::Keypad5)
+ map(0x004d, 0, nall::Keyboard::Keypad6)
+ map(0x0047, 0, nall::Keyboard::Keypad7)
+ map(0x0048, 0, nall::Keyboard::Keypad8)
+ map(0x0049, 0, nall::Keyboard::Keypad9)
+ map(0x0052, 0, nall::Keyboard::Keypad0)
- map(0x0053, 0, keyboard<>::point)
- map(0x001c, 2, keyboard<>::enter)
- map(0x004e, 0, keyboard<>::add)
- map(0x004a, 0, keyboard<>::subtract)
- map(0x0037, 0, keyboard<>::multiply)
- map(0x0035, 2, keyboard<>::divide)
+ map(0x0053, 0, nall::Keyboard::Point)
+ map(0x001c, 2, nall::Keyboard::Enter)
+ map(0x004e, 0, nall::Keyboard::Add)
+ map(0x004a, 0, nall::Keyboard::Subtract)
+ map(0x0037, 0, nall::Keyboard::Multiply)
+ map(0x0035, 2, nall::Keyboard::Divide)
- map(0x0045, 0, keyboard<>::num_lock)
- map(0x003a, 0, keyboard<>::caps_lock)
+ map(0x0045, 0, nall::Keyboard::NumLock)
+ map(0x003a, 0, nall::Keyboard::CapsLock)
- //pause signals 0x1d:4 + 0x45:0, whereas num_lock signals only 0x45:0.
- //this makes it impractical to detect both pause+num_lock independently.
- //workaround: always detect pause; detect num_lock only when pause is released.
- if(state[keyboard<>::pause]) state[keyboard<>::num_lock] = false;
+ //Pause signals 0x1d:4 + 0x45:0, whereas NumLock signals only 0x45:0.
+ //this makes it impractical to detect both Pause+NumLock independently.
+ //workaround: always detect Pause; detect NumLock only when Pause is released.
+ if(state[nall::Keyboard::Pause]) state[nall::Keyboard::NumLock] = false;
- map(0x0048, 2, keyboard<>::up)
- map(0x0050, 2, keyboard<>::down)
- map(0x004b, 2, keyboard<>::left)
- map(0x004d, 2, keyboard<>::right)
+ map(0x0048, 2, nall::Keyboard::Up)
+ map(0x0050, 2, nall::Keyboard::Down)
+ map(0x004b, 2, nall::Keyboard::Left)
+ map(0x004d, 2, nall::Keyboard::Right)
- map(0x000f, 0, keyboard<>::tab)
- map(0x001c, 0, keyboard<>::return_)
- map(0x0039, 0, keyboard<>::spacebar)
+ map(0x000f, 0, nall::Keyboard::Tab)
+ map(0x001c, 0, nall::Keyboard::Return)
+ map(0x0039, 0, nall::Keyboard::Spacebar)
+ map(0x005d, 2, nall::Keyboard::Menu)
- map(0x001d, 0, keyboard<>::lctrl)
- map(0x001d, 2, keyboard<>::rctrl)
- map(0x0038, 0, keyboard<>::lalt)
- map(0x0038, 2, keyboard<>::ralt)
- map(0x002a, 0, keyboard<>::lshift)
- map(0x0036, 0, keyboard<>::rshift)
- map(0x005b, 2, keyboard<>::lsuper)
- map(0x005c, 2, keyboard<>::rsuper)
- map(0x005d, 2, keyboard<>::menu)
+ //merge left and right modifiers to one ID
+ if(code == 0x002a && flags == 0) state[nall::Keyboard::Shift] = 1; //left shift
+ if(code == 0x002a && flags == 1) state[nall::Keyboard::Shift] = 0;
+ if(code == 0x0036 && flags == 0) state[nall::Keyboard::Shift] = 1; //right shift
+ if(code == 0x0036 && flags == 1) state[nall::Keyboard::Shift] = 0;
+
+ if(code == 0x001d && flags == 0) state[nall::Keyboard::Control] = 1; //left control
+ if(code == 0x001d && flags == 1) state[nall::Keyboard::Control] = 0;
+ if(code == 0x001d && flags == 2) state[nall::Keyboard::Control] = 1; //right control
+ if(code == 0x001d && flags == 3) state[nall::Keyboard::Control] = 0;
+
+ if(code == 0x0038 && flags == 0) state[nall::Keyboard::Alt] = 1; //left alt
+ if(code == 0x0038 && flags == 1) state[nall::Keyboard::Alt] = 0;
+ if(code == 0x0038 && flags == 2) state[nall::Keyboard::Alt] = 1; //right alt
+ if(code == 0x0038 && flags == 3) state[nall::Keyboard::Alt] = 0;
+
+ if(code == 0x005b && flags == 2) state[nall::Keyboard::Super] = 1; //left super
+ if(code == 0x005b && flags == 3) state[nall::Keyboard::Super] = 0;
+ if(code == 0x005c && flags == 2) state[nall::Keyboard::Super] = 1; //right super
+ if(code == 0x005c && flags == 3) state[nall::Keyboard::Super] = 0;
#undef map
}
Keyboard() {
- for(unsigned i = 0; i < keyboard<>::length; i++) state[i] = false;
+ for(unsigned i = 0; i < nall::Keyboard::Size; i++) state[i] = false;
}
};
@@ -390,11 +402,11 @@ public:
bool button[10];
void poll(XINPUT_STATE &state) {
- hat = joypad<>::hat_center;
- if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ) hat |= joypad<>::hat_up;
- if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= joypad<>::hat_right;
- if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) hat |= joypad<>::hat_down;
- if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) hat |= joypad<>::hat_left;
+ hat = Joypad::HatCenter;
+ if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ) hat |= Joypad::HatUp;
+ if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= Joypad::HatRight;
+ if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) hat |= Joypad::HatDown;
+ if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) hat |= Joypad::HatLeft;
axis[0] = (int16_t)state.Gamepad.sThumbLX;
axis[1] = (int16_t)state.Gamepad.sThumbLY;
@@ -426,7 +438,7 @@ public:
}
Gamepad() {
- hat = joypad<>::hat_center;
+ hat = Joypad::HatCenter;
for(unsigned n = 0; n < 6; n++) axis[n] = 0;
for(unsigned n = 0; n < 10; n++) button[n] = false;
}
@@ -490,7 +502,7 @@ public:
void poll(DIJOYSTATE2 &state) {
//POV hats
for(unsigned n = 0; n < 4; n++) {
- hat[n] = joypad<>::hat_center;
+ hat[n] = Joypad::HatCenter;
//POV value is in clockwise-hundredth degree units
unsigned pov = state.rgdwPOV[n];
@@ -499,10 +511,10 @@ public:
//>= 36000 will match both, as well as invalid ranges.
if(pov >= 36000) continue;
- if(pov >= 31500 || pov <= 4500) hat[n] |= joypad<>::hat_up;
- if(pov >= 4500 && pov <= 13500) hat[n] |= joypad<>::hat_right;
- if(pov >= 13500 && pov <= 22500) hat[n] |= joypad<>::hat_down;
- if(pov >= 22500 && pov <= 31500) hat[n] |= joypad<>::hat_left;
+ if(pov >= 31500 || pov <= 4500) hat[n] |= Joypad::HatUp;
+ if(pov >= 4500 && pov <= 13500) hat[n] |= Joypad::HatRight;
+ if(pov >= 13500 && pov <= 22500) hat[n] |= Joypad::HatDown;
+ if(pov >= 22500 && pov <= 31500) hat[n] |= Joypad::HatLeft;
}
//axes
@@ -521,7 +533,7 @@ public:
Gamepad() {
handle = 0;
- for(unsigned n = 0; n < 4; n++) hat[n] = joypad<>::hat_center;
+ for(unsigned n = 0; n < 4; n++) hat[n] = Joypad::HatCenter;
for(unsigned n = 0; n < 6; n++) axis[n] = 0;
for(unsigned n = 0; n < 128; n++) button[n] = false;
}
@@ -672,33 +684,29 @@ public:
}
bool poll(int16_t *table) {
- memset(table, 0, nall::input_limit * sizeof(int16_t));
+ memset(table, 0, Scancode::Limit * sizeof(int16_t));
WaitForSingleObject(rawinput.mutex, INFINITE);
//=========
//Keyboards
//=========
- for(unsigned i = 0; i < min(rawinput.lkeyboard.size(), (unsigned)keyboard<>::count); i++) {
- unsigned index = keyboard<>::index(i, keyboard<>::none);
-
- for(unsigned n = 0; n < keyboard<>::length; n++) {
- table[index + n] = rawinput.lkeyboard[i].state[n];
+ for(unsigned i = 0; i < min(rawinput.lkeyboard.size(), (unsigned)Keyboard::Count); i++) {
+ for(unsigned n = 0; n < nall::Keyboard::Size; n++) {
+ table[keyboard(i).key(n)] = rawinput.lkeyboard[i].state[n];
}
}
//====
//Mice
//====
- for(unsigned i = 0; i < min(rawinput.lmouse.size(), (unsigned)mouse<>::count); i++) {
- unsigned index = mouse<>::index(i, mouse<>::none);
+ for(unsigned i = 0; i < min(rawinput.lmouse.size(), (unsigned)Mouse::Count); i++) {
+ table[mouse(i).axis(0)] = rawinput.lmouse[i].xDistance;
+ table[mouse(i).axis(1)] = rawinput.lmouse[i].yDistance;
+ table[mouse(i).axis(2)] = rawinput.lmouse[i].zDistance;
- table[index + mouse<>::x] = rawinput.lmouse[i].xDistance;
- table[index + mouse<>::y] = rawinput.lmouse[i].yDistance;
- table[index + mouse<>::z] = rawinput.lmouse[i].zDistance;
-
- for(unsigned n = 0; n < min(5U, (unsigned)mouse<>::buttons); n++) {
- table[index + mouse<>::button + n] = (bool)(rawinput.lmouse[i].buttonState & (1 << n));
+ for(unsigned n = 0; n < min(5U, (unsigned)Mouse::Buttons); n++) {
+ table[mouse(i).button(n)] = (bool)(rawinput.lmouse[i].buttonState & (1 << n));
}
rawinput.lmouse[i].sync();
@@ -713,17 +721,16 @@ public:
//==================
xinput.poll();
for(unsigned i = 0; i < xinput.lgamepad.size(); i++) {
- if(joy >= joypad<>::count) break;
- unsigned index = joypad<>::index(joy++, joypad<>::none);
+ if(joy >= Joypad::Count) break;
- table[index + joypad<>::hat + 0] = xinput.lgamepad[i].hat;
+ table[joypad(i).hat(0)] = xinput.lgamepad[i].hat;
- for(unsigned axis = 0; axis < min(6U, (unsigned)joypad<>::axes); axis++) {
- table[index + joypad<>::axis + axis] = xinput.lgamepad[i].axis[axis];
+ for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) {
+ table[joypad(i).axis(axis)] = xinput.lgamepad[i].axis[axis];
}
- for(unsigned button = 0; button < min(10U, (unsigned)joypad<>::buttons); button++) {
- table[index + joypad<>::button + button] = xinput.lgamepad[i].button[button];
+ for(unsigned button = 0; button < min(10U, (unsigned)Joypad::Buttons); button++) {
+ table[joypad(i).button(button)] = xinput.lgamepad[i].button[button];
}
}
@@ -732,19 +739,18 @@ public:
//=======================
dinput.poll();
for(unsigned i = 0; i < dinput.lgamepad.size(); i++) {
- if(joy >= joypad<>::count) break;
- unsigned index = joypad<>::index(joy++, joypad<>::none);
+ if(joy >= Joypad::Count) break;
- for(unsigned hat = 0; hat < min(4U, (unsigned)joypad<>::hats); hat++) {
- table[index + joypad<>::hat + hat] = dinput.lgamepad[i].hat[hat];
+ for(unsigned hat = 0; hat < min(4U, (unsigned)Joypad::Hats); hat++) {
+ table[joypad(i).hat(hat)] = dinput.lgamepad[i].hat[hat];
}
- for(unsigned axis = 0; axis < min(6U, (unsigned)joypad<>::axes); axis++) {
- table[index + joypad<>::axis + axis] = dinput.lgamepad[i].axis[axis];
+ for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) {
+ table[joypad(i).axis(axis)] = dinput.lgamepad[i].axis[axis];
}
- for(unsigned button = 0; button < min(128U, (unsigned)joypad<>::buttons); button++) {
- table[index + joypad<>::button + button] = dinput.lgamepad[i].button[button];
+ for(unsigned button = 0; button < min(128U, (unsigned)Joypad::Buttons); button++) {
+ table[joypad(i).button(button)] = dinput.lgamepad[i].button[button];
}
}
diff --git a/src/lib/ruby/input/sdl.cpp b/src/lib/ruby/input/sdl.cpp
index 2b5e3d27..9986a007 100644
--- a/src/lib/ruby/input/sdl.cpp
+++ b/src/lib/ruby/input/sdl.cpp
@@ -18,7 +18,7 @@ struct pInputSDL {
Display *display;
Window rootwindow;
Cursor InvisibleCursor;
- SDL_Joystick *gamepad[joypad<>::count];
+ SDL_Joystick *gamepad[Joypad::Count];
unsigned screenwidth, screenheight;
unsigned relativex, relativey;
@@ -91,20 +91,13 @@ struct pInputSDL {
}
bool poll(int16_t *table) {
- memset(table, 0, nall::input_limit * sizeof(int16_t));
+ memset(table, 0, Scancode::Limit * sizeof(int16_t));
//========
//Keyboard
//========
- char state[32];
- XQueryKeymap(device.display, state);
-
- for(unsigned i = 0; i < keyboard<>::length; i++) {
- uint8_t code = keycode[i];
- if(code == 0) continue; //unmapped
- table[i] = (bool)(state[code >> 3] & (1 << (code & 7)));
- }
+ x_poll(table);
//=====
//Mouse
@@ -123,56 +116,55 @@ struct pInputSDL {
XGetWindowAttributes(device.display, settings.handle, &attributes);
//absolute -> relative conversion
- table[mouse<0>::x] = (int16_t)(root_x_return - device.screenwidth / 2);
- table[mouse<0>::y] = (int16_t)(root_y_return - device.screenheight / 2);
+ table[mouse(0).axis(0)] = (int16_t)(root_x_return - device.screenwidth / 2);
+ table[mouse(0).axis(1)] = (int16_t)(root_y_return - device.screenheight / 2);
- if(table[mouse<0>::x] != 0 || table[mouse<0>::y] != 0) {
+ if(table[mouse(0).axis(0)] != 0 || table[mouse(0).axis(1)] != 0) {
//if mouse movement occurred, re-center mouse for next poll
XWarpPointer(device.display, None, device.rootwindow, 0, 0, 0, 0, device.screenwidth / 2, device.screenheight / 2);
}
} else {
- table[mouse<0>::x] = (int16_t)(root_x_return - device.relativex);
- table[mouse<0>::y] = (int16_t)(root_y_return - device.relativey);
+ table[mouse(0).axis(0)] = (int16_t)(root_x_return - device.relativex);
+ table[mouse(0).axis(1)] = (int16_t)(root_y_return - device.relativey);
device.relativex = root_x_return;
device.relativey = root_y_return;
}
//manual device polling is limited to only five buttons ...
- table[mouse<0>::button + 0] = (bool)(mask_return & Button1Mask);
- table[mouse<0>::button + 1] = (bool)(mask_return & Button2Mask);
- table[mouse<0>::button + 2] = (bool)(mask_return & Button3Mask);
- table[mouse<0>::button + 3] = (bool)(mask_return & Button4Mask);
- table[mouse<0>::button + 4] = (bool)(mask_return & Button5Mask);
+ table[mouse(0).button(0)] = (bool)(mask_return & Button1Mask);
+ table[mouse(0).button(1)] = (bool)(mask_return & Button2Mask);
+ table[mouse(0).button(2)] = (bool)(mask_return & Button3Mask);
+ table[mouse(0).button(3)] = (bool)(mask_return & Button4Mask);
+ table[mouse(0).button(4)] = (bool)(mask_return & Button5Mask);
//=========
//Joypad(s)
//=========
SDL_JoystickUpdate();
- for(unsigned i = 0; i < joypad<>::count; i++) {
+ for(unsigned i = 0; i < Joypad::Count; i++) {
if(!device.gamepad[i]) continue;
- unsigned index = joypad<>::index(i, joypad<>::none);
//POV hats
- unsigned hats = min((unsigned)joypad<>::hats, SDL_JoystickNumHats(device.gamepad[i]));
+ unsigned hats = min((unsigned)Joypad::Hats, SDL_JoystickNumHats(device.gamepad[i]));
for(unsigned hat = 0; hat < hats; hat++) {
uint8_t state = SDL_JoystickGetHat(device.gamepad[i], hat);
- if(state & SDL_HAT_UP ) table[index + joypad<>::hat + hat] |= joypad<>::hat_up;
- if(state & SDL_HAT_RIGHT) table[index + joypad<>::hat + hat] |= joypad<>::hat_right;
- if(state & SDL_HAT_DOWN ) table[index + joypad<>::hat + hat] |= joypad<>::hat_down;
- if(state & SDL_HAT_LEFT ) table[index + joypad<>::hat + hat] |= joypad<>::hat_left;
+ if(state & SDL_HAT_UP ) table[joypad(i).hat(hat)] |= Joypad::HatUp;
+ if(state & SDL_HAT_RIGHT) table[joypad(i).hat(hat)] |= Joypad::HatRight;
+ if(state & SDL_HAT_DOWN ) table[joypad(i).hat(hat)] |= Joypad::HatDown;
+ if(state & SDL_HAT_LEFT ) table[joypad(i).hat(hat)] |= Joypad::HatLeft;
}
//axes
- unsigned axes = min((unsigned)joypad<>::axes, SDL_JoystickNumAxes(device.gamepad[i]));
+ unsigned axes = min((unsigned)Joypad::Axes, SDL_JoystickNumAxes(device.gamepad[i]));
for(unsigned axis = 0; axis < axes; axis++) {
- table[index + joypad<>::axis + axis] = (int16_t)SDL_JoystickGetAxis(device.gamepad[i], axis);
+ table[joypad(i).axis(axis)] = (int16_t)SDL_JoystickGetAxis(device.gamepad[i], axis);
}
//buttons
- for(unsigned button = 0; button < joypad<>::buttons; button++) {
- table[index + joypad<>::button + button] = (bool)SDL_JoystickGetButton(device.gamepad[i], button);
+ for(unsigned button = 0; button < Joypad::Buttons; button++) {
+ table[joypad(i).button(button)] = (bool)SDL_JoystickGetButton(device.gamepad[i], button);
}
}
@@ -180,7 +172,7 @@ struct pInputSDL {
}
bool init() {
- init_keycodes();
+ x_init();
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
SDL_JoystickEventState(SDL_IGNORE);
@@ -208,7 +200,7 @@ struct pInputSDL {
device.relativex = 0;
device.relativey = 0;
- unsigned joypads = min((unsigned)joypad<>::count, SDL_NumJoysticks());
+ unsigned joypads = min((unsigned)Joypad::Count, SDL_NumJoysticks());
for(unsigned i = 0; i < joypads; i++) device.gamepad[i] = SDL_JoystickOpen(i);
return true;
@@ -218,7 +210,7 @@ struct pInputSDL {
unacquire();
XFreeCursor(device.display, device.InvisibleCursor);
- for(unsigned i = 0; i < joypad<>::count; i++) {
+ for(unsigned i = 0; i < Joypad::Count; i++) {
if(device.gamepad[i]) SDL_JoystickClose(device.gamepad[i]);
device.gamepad[i] = 0;
}
@@ -228,7 +220,7 @@ struct pInputSDL {
}
pInputSDL() {
- for(unsigned i = 0; i < joypad<>::count; i++) device.gamepad[i] = 0;
+ for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0;
settings.handle = 0;
}
};
diff --git a/src/lib/ruby/input/x.cpp b/src/lib/ruby/input/x.cpp
index 734974df..fe1440a8 100644
--- a/src/lib/ruby/input/x.cpp
+++ b/src/lib/ruby/input/x.cpp
@@ -29,22 +29,13 @@ public:
bool acquired() { return false; }
bool poll(int16_t *table) {
- memset(table, 0, input_limit * sizeof(int16_t));
-
- char state[32];
- XQueryKeymap(display, state);
-
- for(unsigned i = 0; i < keyboard<>::length; i++) {
- uint8_t code = keycode[i];
- if(code == 0) continue; //unmapped
- table[i] = (bool)(state[code >> 3] & (1 << (code & 7)));
- }
-
+ memset(table, 0, Scancode::Limit * sizeof(int16_t));
+ x_poll(table);
return true;
}
bool init() {
- init_keycodes();
+ x_init();
display = XOpenDisplay(0);
return true;
}
diff --git a/src/lib/ruby/input/xlibkeys.hpp b/src/lib/ruby/input/xlibkeys.hpp
index bb5c0103..770de16d 100644
--- a/src/lib/ruby/input/xlibkeys.hpp
+++ b/src/lib/ruby/input/xlibkeys.hpp
@@ -1,137 +1,263 @@
-//shared keycode lookup table + initialization routine:
-//#include inside a class interface to use
+uint8_t scancode[256];
-//Xlib keycodes for each key can vary between platforms, so this header file
-//will lookup keycodes from static keysyms, and map them to nall/input.hpp's
-//keyboard identifiers.
-//
-//this allows input capture routine to iterate quickly over all keycodes and
-//map their states to ruby's input state table.
+enum XScancode {
+ Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
+ ScrollLock, Pause, Tilde,
+ Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
+ Dash, Equal, Backspace,
+ Insert, Delete, Home, End, PageUp, PageDown,
+ A, B, C, D, E, F, G, H, I, J, K, L, M,
+ N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
+ LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash,
+ Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0,
+ Point, Enter, Add, Subtract, Multiply, Divide,
+ Up, Down, Left, Right,
+ Tab, Return, Spacebar, Menu,
+ LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt, LeftSuper, RightSuper,
+};
-uint8_t keycode[256];
-
-void init_keycodes() {
+void x_poll(int16_t *table) {
+ char state[32];
Display *display = XOpenDisplay(0);
- memset(&keycode, 0, sizeof keycode);
+ XQueryKeymap(display, state);
+ XCloseDisplay(display);
- #define assign(x, y) keycode[x] = XKeysymToKeycode(display, y)
- assign(keyboard<0>::escape, XK_Escape);
+ #define key(id) table[keyboard(0)[id]]
+ #define pressed(id) (bool)(state[scancode[id] >> 3] & (1 << (scancode[id] & 7)))
- assign(keyboard<0>::f1, XK_F1);
- assign(keyboard<0>::f2, XK_F2);
- assign(keyboard<0>::f3, XK_F3);
- assign(keyboard<0>::f4, XK_F4);
- assign(keyboard<0>::f5, XK_F5);
- assign(keyboard<0>::f6, XK_F6);
- assign(keyboard<0>::f7, XK_F7);
- assign(keyboard<0>::f8, XK_F8);
- assign(keyboard<0>::f9, XK_F9);
- assign(keyboard<0>::f10, XK_F10);
- assign(keyboard<0>::f11, XK_F11);
- assign(keyboard<0>::f12, XK_F12);
+ key(Keyboard::Escape) = pressed(Escape);
- //assign(keyboard<0>::print_screen, XK_???);
- assign(keyboard<0>::scroll_lock, XK_Scroll_Lock);
- assign(keyboard<0>::pause, XK_Pause);
+ key(Keyboard::F1) = pressed(F1);
+ key(Keyboard::F2) = pressed(F2);
+ key(Keyboard::F3) = pressed(F3);
+ key(Keyboard::F4) = pressed(F4);
+ key(Keyboard::F5) = pressed(F5);
+ key(Keyboard::F6) = pressed(F6);
+ key(Keyboard::F7) = pressed(F7);
+ key(Keyboard::F8) = pressed(F8);
+ key(Keyboard::F9) = pressed(F9);
+ key(Keyboard::F10) = pressed(F10);
+ key(Keyboard::F11) = pressed(F11);
+ key(Keyboard::F12) = pressed(F12);
- assign(keyboard<0>::tilde, XK_asciitilde);
+ key(Keyboard::ScrollLock) = pressed(ScrollLock);
+ key(Keyboard::Pause) = pressed(Pause);
+ key(Keyboard::Tilde) = pressed(Tilde);
- assign(keyboard<0>::num_0, XK_0);
- assign(keyboard<0>::num_1, XK_1);
- assign(keyboard<0>::num_2, XK_2);
- assign(keyboard<0>::num_3, XK_3);
- assign(keyboard<0>::num_4, XK_4);
- assign(keyboard<0>::num_5, XK_5);
- assign(keyboard<0>::num_6, XK_6);
- assign(keyboard<0>::num_7, XK_7);
- assign(keyboard<0>::num_8, XK_8);
- assign(keyboard<0>::num_9, XK_9);
+ key(Keyboard::Num1) = pressed(Num1);
+ key(Keyboard::Num2) = pressed(Num2);
+ key(Keyboard::Num3) = pressed(Num3);
+ key(Keyboard::Num4) = pressed(Num4);
+ key(Keyboard::Num5) = pressed(Num5);
+ key(Keyboard::Num6) = pressed(Num6);
+ key(Keyboard::Num7) = pressed(Num7);
+ key(Keyboard::Num8) = pressed(Num8);
+ key(Keyboard::Num9) = pressed(Num9);
+ key(Keyboard::Num0) = pressed(Num0);
- assign(keyboard<0>::dash, XK_minus);
- assign(keyboard<0>::equal, XK_equal);
- assign(keyboard<0>::backspace, XK_BackSpace);
+ key(Keyboard::Dash) = pressed(Dash);
+ key(Keyboard::Equal) = pressed(Equal);
+ key(Keyboard::Backspace) = pressed(Backspace);
- assign(keyboard<0>::insert, XK_Insert);
- assign(keyboard<0>::delete_, XK_Delete);
- assign(keyboard<0>::home, XK_Home);
- assign(keyboard<0>::end, XK_End);
- assign(keyboard<0>::page_up, XK_Prior);
- assign(keyboard<0>::page_down, XK_Next);
+ key(Keyboard::Insert) = pressed(Insert);
+ key(Keyboard::Delete) = pressed(Delete);
+ key(Keyboard::Home) = pressed(Home);
+ key(Keyboard::End) = pressed(End);
+ key(Keyboard::PageUp) = pressed(PageUp);
+ key(Keyboard::PageDown) = pressed(PageDown);
- assign(keyboard<0>::a, XK_A);
- assign(keyboard<0>::b, XK_B);
- assign(keyboard<0>::c, XK_C);
- assign(keyboard<0>::d, XK_D);
- assign(keyboard<0>::e, XK_E);
- assign(keyboard<0>::f, XK_F);
- assign(keyboard<0>::g, XK_G);
- assign(keyboard<0>::h, XK_H);
- assign(keyboard<0>::i, XK_I);
- assign(keyboard<0>::j, XK_J);
- assign(keyboard<0>::k, XK_K);
- assign(keyboard<0>::l, XK_L);
- assign(keyboard<0>::m, XK_M);
- assign(keyboard<0>::n, XK_N);
- assign(keyboard<0>::o, XK_O);
- assign(keyboard<0>::p, XK_P);
- assign(keyboard<0>::q, XK_Q);
- assign(keyboard<0>::r, XK_R);
- assign(keyboard<0>::s, XK_S);
- assign(keyboard<0>::t, XK_T);
- assign(keyboard<0>::u, XK_U);
- assign(keyboard<0>::v, XK_V);
- assign(keyboard<0>::w, XK_W);
- assign(keyboard<0>::x, XK_X);
- assign(keyboard<0>::y, XK_Y);
- assign(keyboard<0>::z, XK_Z);
+ key(Keyboard::A) = pressed(A);
+ key(Keyboard::B) = pressed(B);
+ key(Keyboard::C) = pressed(C);
+ key(Keyboard::D) = pressed(D);
+ key(Keyboard::E) = pressed(E);
+ key(Keyboard::F) = pressed(F);
+ key(Keyboard::G) = pressed(G);
+ key(Keyboard::H) = pressed(H);
+ key(Keyboard::I) = pressed(I);
+ key(Keyboard::J) = pressed(J);
+ key(Keyboard::K) = pressed(K);
+ key(Keyboard::L) = pressed(L);
+ key(Keyboard::M) = pressed(M);
+ key(Keyboard::N) = pressed(N);
+ key(Keyboard::O) = pressed(O);
+ key(Keyboard::P) = pressed(P);
+ key(Keyboard::Q) = pressed(Q);
+ key(Keyboard::R) = pressed(R);
+ key(Keyboard::S) = pressed(S);
+ key(Keyboard::T) = pressed(T);
+ key(Keyboard::U) = pressed(U);
+ key(Keyboard::V) = pressed(V);
+ key(Keyboard::W) = pressed(W);
+ key(Keyboard::X) = pressed(X);
+ key(Keyboard::Y) = pressed(Y);
+ key(Keyboard::Z) = pressed(Z);
- assign(keyboard<0>::lbracket, XK_bracketleft);
- assign(keyboard<0>::rbracket, XK_bracketright);
- assign(keyboard<0>::backslash, XK_backslash);
- assign(keyboard<0>::semicolon, XK_semicolon);
- assign(keyboard<0>::apostrophe, XK_apostrophe);
- assign(keyboard<0>::comma, XK_comma);
- assign(keyboard<0>::period, XK_period);
- assign(keyboard<0>::slash, XK_slash);
+ key(Keyboard::LeftBracket) = pressed(LeftBracket);
+ key(Keyboard::RightBracket) = pressed(RightBracket);
+ key(Keyboard::Backslash) = pressed(Backslash);
+ key(Keyboard::Semicolon) = pressed(Semicolon);
+ key(Keyboard::Apostrophe) = pressed(Apostrophe);
+ key(Keyboard::Comma) = pressed(Comma);
+ key(Keyboard::Period) = pressed(Period);
+ key(Keyboard::Slash) = pressed(Slash);
- assign(keyboard<0>::pad_0, XK_KP_0);
- assign(keyboard<0>::pad_1, XK_KP_1);
- assign(keyboard<0>::pad_2, XK_KP_2);
- assign(keyboard<0>::pad_3, XK_KP_3);
- assign(keyboard<0>::pad_4, XK_KP_4);
- assign(keyboard<0>::pad_5, XK_KP_5);
- assign(keyboard<0>::pad_6, XK_KP_6);
- assign(keyboard<0>::pad_7, XK_KP_7);
- assign(keyboard<0>::pad_8, XK_KP_8);
- assign(keyboard<0>::pad_9, XK_KP_9);
+ key(Keyboard::Keypad1) = pressed(Keypad1);
+ key(Keyboard::Keypad2) = pressed(Keypad2);
+ key(Keyboard::Keypad3) = pressed(Keypad3);
+ key(Keyboard::Keypad4) = pressed(Keypad4);
+ key(Keyboard::Keypad5) = pressed(Keypad5);
+ key(Keyboard::Keypad6) = pressed(Keypad6);
+ key(Keyboard::Keypad7) = pressed(Keypad7);
+ key(Keyboard::Keypad8) = pressed(Keypad8);
+ key(Keyboard::Keypad9) = pressed(Keypad9);
+ key(Keyboard::Keypad0) = pressed(Keypad0);
- assign(keyboard<0>::add, XK_KP_Add);
- assign(keyboard<0>::subtract, XK_KP_Subtract);
- assign(keyboard<0>::multiply, XK_KP_Multiply);
- assign(keyboard<0>::divide, XK_KP_Divide);
- assign(keyboard<0>::enter, XK_KP_Enter);
+ key(Keyboard::Point) = pressed(Point);
+ key(Keyboard::Enter) = pressed(Enter);
+ key(Keyboard::Add) = pressed(Add);
+ key(Keyboard::Subtract) = pressed(Subtract);
+ key(Keyboard::Multiply) = pressed(Multiply);
+ key(Keyboard::Divide) = pressed(Divide);
- //assign(keyboard<0>::num_lock, XK_???);
- //assign(keyboard<0>::caps_lock, XK_???);
+ key(Keyboard::Up) = pressed(Up);
+ key(Keyboard::Down) = pressed(Down);
+ key(Keyboard::Left) = pressed(Left);
+ key(Keyboard::Right) = pressed(Right);
- assign(keyboard<0>::up, XK_Up);
- assign(keyboard<0>::down, XK_Down);
- assign(keyboard<0>::left, XK_Left);
- assign(keyboard<0>::right, XK_Right);
+ key(Keyboard::Tab) = pressed(Tab);
+ key(Keyboard::Return) = pressed(Return);
+ key(Keyboard::Spacebar) = pressed(Spacebar);
+ key(Keyboard::Menu) = pressed(Menu);
- assign(keyboard<0>::tab, XK_Tab);
- assign(keyboard<0>::return_, XK_Return);
- assign(keyboard<0>::spacebar, XK_space);
+ key(Keyboard::Shift) = pressed(LeftShift) || pressed(RightShift);
+ key(Keyboard::Control) = pressed(LeftControl) || pressed(RightControl);
+ key(Keyboard::Alt) = pressed(LeftAlt) || pressed(RightAlt);
+ key(Keyboard::Super) = pressed(LeftSuper) || pressed(RightSuper);
+
+ #undef key
+ #undef pressed
+}
+
+void x_init() {
+ Display *display = XOpenDisplay(0);
+ memset(&scancode, 0, sizeof scancode);
+
+ #define assign(x, y) scancode[x] = XKeysymToKeycode(display, y)
+ assign(Escape, XK_Escape);
+
+ assign(F1, XK_F1);
+ assign(F2, XK_F2);
+ assign(F3, XK_F3);
+ assign(F4, XK_F4);
+ assign(F5, XK_F5);
+ assign(F6, XK_F6);
+ assign(F7, XK_F7);
+ assign(F8, XK_F8);
+ assign(F9, XK_F9);
+ assign(F10, XK_F10);
+ assign(F11, XK_F11);
+ assign(F12, XK_F12);
+
+ assign(ScrollLock, XK_Scroll_Lock);
+ assign(Pause, XK_Pause);
+
+ assign(Tilde, XK_asciitilde);
+
+ assign(Num0, XK_0);
+ assign(Num1, XK_1);
+ assign(Num2, XK_2);
+ assign(Num3, XK_3);
+ assign(Num4, XK_4);
+ assign(Num5, XK_5);
+ assign(Num6, XK_6);
+ assign(Num7, XK_7);
+ assign(Num8, XK_8);
+ assign(Num9, XK_9);
+
+ assign(Dash, XK_minus);
+ assign(Equal, XK_equal);
+ assign(Backspace, XK_BackSpace);
+
+ assign(Insert, XK_Insert);
+ assign(Delete, XK_Delete);
+ assign(Home, XK_Home);
+ assign(End, XK_End);
+ assign(PageUp, XK_Prior);
+ assign(PageDown, XK_Next);
+
+ assign(A, XK_A);
+ assign(B, XK_B);
+ assign(C, XK_C);
+ assign(D, XK_D);
+ assign(E, XK_E);
+ assign(F, XK_F);
+ assign(G, XK_G);
+ assign(H, XK_H);
+ assign(I, XK_I);
+ assign(J, XK_J);
+ assign(K, XK_K);
+ assign(L, XK_L);
+ assign(M, XK_M);
+ assign(N, XK_N);
+ assign(O, XK_O);
+ assign(P, XK_P);
+ assign(Q, XK_Q);
+ assign(R, XK_R);
+ assign(S, XK_S);
+ assign(T, XK_T);
+ assign(U, XK_U);
+ assign(V, XK_V);
+ assign(W, XK_W);
+ assign(X, XK_X);
+ assign(Y, XK_Y);
+ assign(Z, XK_Z);
+
+ assign(LeftBracket, XK_bracketleft);
+ assign(RightBracket, XK_bracketright);
+ assign(Backslash, XK_backslash);
+ assign(Semicolon, XK_semicolon);
+ assign(Apostrophe, XK_apostrophe);
+ assign(Comma, XK_comma);
+ assign(Period, XK_period);
+ assign(Slash, XK_slash);
+
+ assign(Keypad0, XK_KP_0);
+ assign(Keypad1, XK_KP_1);
+ assign(Keypad2, XK_KP_2);
+ assign(Keypad3, XK_KP_3);
+ assign(Keypad4, XK_KP_4);
+ assign(Keypad5, XK_KP_5);
+ assign(Keypad6, XK_KP_6);
+ assign(Keypad7, XK_KP_7);
+ assign(Keypad8, XK_KP_8);
+ assign(Keypad9, XK_KP_9);
+
+ assign(Add, XK_KP_Add);
+ assign(Subtract, XK_KP_Subtract);
+ assign(Multiply, XK_KP_Multiply);
+ assign(Divide, XK_KP_Divide);
+ assign(Enter, XK_KP_Enter);
+
+ assign(Up, XK_Up);
+ assign(Down, XK_Down);
+ assign(Left, XK_Left);
+ assign(Right, XK_Right);
+
+ assign(Tab, XK_Tab);
+ assign(Return, XK_Return);
+ assign(Spacebar, XK_space);
+
+ assign(LeftControl, XK_Control_L);
+ assign(RightControl, XK_Control_R);
+ assign(LeftAlt, XK_Alt_L);
+ assign(RightAlt, XK_Alt_R);
+ assign(LeftShift, XK_Shift_L);
+ assign(RightShift, XK_Shift_R);
+ assign(LeftSuper, XK_Super_L);
+ assign(RightSuper, XK_Super_R);
+ assign(Menu, XK_Menu);
- assign(keyboard<0>::lctrl, XK_Control_L);
- assign(keyboard<0>::rctrl, XK_Control_R);
- assign(keyboard<0>::lalt, XK_Alt_L);
- assign(keyboard<0>::ralt, XK_Alt_R);
- assign(keyboard<0>::lshift, XK_Shift_L);
- assign(keyboard<0>::rshift, XK_Shift_R);
- assign(keyboard<0>::lsuper, XK_Super_L);
- assign(keyboard<0>::rsuper, XK_Super_R);
- assign(keyboard<0>::menu, XK_Menu);
#undef assign
XCloseDisplay(display);
diff --git a/src/lib/ruby/ruby.cpp b/src/lib/ruby/ruby.cpp
index 0e6adff1..cb8a4baa 100644
--- a/src/lib/ruby/ruby.cpp
+++ b/src/lib/ruby/ruby.cpp
@@ -14,6 +14,9 @@ InputInterface input;
const char *Video::Handle = "Handle";
const char *Video::Synchronize = "Synchronize";
const char *Video::Filter = "Filter";
+const char *Video::GLSL = "GLSL";
+const char *Video::FragmentShader = "FragmentShader";
+const char *Video::VertexShader = "VertexShader";
void VideoInterface::driver(const char *driver) {
if(p) term();
diff --git a/src/lib/ruby/video.hpp b/src/lib/ruby/video.hpp
index c4aa3cfb..561be802 100644
--- a/src/lib/ruby/video.hpp
+++ b/src/lib/ruby/video.hpp
@@ -3,6 +3,9 @@ public:
static const char *Handle;
static const char *Synchronize;
static const char *Filter;
+ static const char *GLSL;
+ static const char *FragmentShader;
+ static const char *VertexShader;
enum Filter {
FilterPoint,
diff --git a/src/lib/ruby/video/glx.cpp b/src/lib/ruby/video/glx.cpp
index 31e76073..30c3720b 100644
--- a/src/lib/ruby/video/glx.cpp
+++ b/src/lib/ruby/video/glx.cpp
@@ -60,6 +60,9 @@ public:
if(name == Video::Handle) return true;
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
+ if(name == Video::GLSL) return true;
+ if(name == Video::FragmentShader) return true;
+ if(name == Video::VertexShader) return true;
return false;
}
@@ -89,6 +92,16 @@ public:
return true;
}
+ if(name == Video::FragmentShader) {
+ OpenGL::set_fragment_shader(any_cast(value));
+ return true;
+ }
+
+ if(name == Video::VertexShader) {
+ OpenGL::set_vertex_shader(any_cast(value));
+ return true;
+ }
+
return false;
}
@@ -175,6 +188,16 @@ public:
OpenGL::init();
settings.width = 256;
settings.height = 256;
+
+ //vertical synchronization
+ int (*glSwapInterval)(int);
+ glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalEXT");
+ if(glSwapInterval) glSwapInterval(settings.synchronize);
+ glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
+ if(glSwapInterval) glSwapInterval(settings.synchronize);
+ glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
+ if(glSwapInterval) glSwapInterval(settings.synchronize);
+
return true;
}
diff --git a/src/lib/ruby/video/opengl.hpp b/src/lib/ruby/video/opengl.hpp
index 4fe893e7..46e51653 100644
--- a/src/lib/ruby/video/opengl.hpp
+++ b/src/lib/ruby/video/opengl.hpp
@@ -2,15 +2,36 @@
#if defined(PLATFORM_X)
#include
+ #define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name))
#elif defined(PLATFORM_WIN)
#include
+ #define glGetProcAddress(name) wglGetProcAddress(name)
#else
#error "ruby::OpenGL: unsupported platform"
#endif
+PFNGLCREATEPROGRAMPROC glCreateProgram = 0;
+PFNGLUSEPROGRAMPROC glUseProgram = 0;
+PFNGLCREATESHADERPROC glCreateShader = 0;
+PFNGLDELETESHADERPROC glDeleteShader = 0;
+PFNGLSHADERSOURCEPROC glShaderSource = 0;
+PFNGLCOMPILESHADERPROC glCompileShader = 0;
+PFNGLATTACHSHADERPROC glAttachShader = 0;
+PFNGLDETACHSHADERPROC glDetachShader = 0;
+PFNGLLINKPROGRAMPROC glLinkProgram = 0;
+PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = 0;
+PFNGLUNIFORM1IPROC glUniform1i = 0;
+PFNGLUNIFORM2FVPROC glUniform2fv = 0;
+PFNGLUNIFORM4FVPROC glUniform4fv = 0;
+
class OpenGL {
public:
GLuint gltexture;
+ GLuint glprogram;
+ GLuint fragmentshader;
+ GLuint vertexshader;
+ bool shader_support;
+
uint32_t *buffer;
unsigned iwidth, iheight;
@@ -45,6 +66,23 @@ public:
}
void refresh(bool smooth, unsigned inwidth, unsigned inheight, unsigned outwidth, unsigned outheight) {
+ if(shader_support) {
+ glUseProgram(glprogram);
+ GLint location;
+
+ float inputSize[2] = { inwidth, inheight };
+ location = glGetUniformLocation(glprogram, "rubyInputSize");
+ glUniform2fv(location, 1, inputSize);
+
+ float outputSize[2] = { outwidth, outheight };
+ location = glGetUniformLocation(glprogram, "rubyOutputSize");
+ glUniform2fv(location, 1, outputSize);
+
+ float textureSize[2] = { iwidth, iheight };
+ location = glGetUniformLocation(glprogram, "rubyTextureSize");
+ glUniform2fv(location, 1, textureSize);
+ }
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
@@ -78,6 +116,48 @@ public:
glEnd();
glFlush();
+
+ if(shader_support) {
+ glUseProgram(0);
+ }
+ }
+
+ void set_fragment_shader(const char *source) {
+ if(!shader_support) return;
+
+ if(fragmentshader) {
+ glDetachShader(glprogram, fragmentshader);
+ glDeleteShader(fragmentshader);
+ fragmentshader = 0;
+ }
+
+ if(source) {
+ fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragmentshader, 1, &source, 0);
+ glCompileShader(fragmentshader);
+ glAttachShader(glprogram, fragmentshader);
+ }
+
+ glLinkProgram(glprogram);
+ }
+
+ void set_vertex_shader(const char *source) {
+ if(!shader_support) return;
+
+ if(vertexshader) {
+ glDetachShader(glprogram, vertexshader);
+ glDeleteShader(vertexshader);
+ vertexshader = 0;
+ }
+
+ if(source) {
+ vertexshader = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vertexshader, 1, &source, 0);
+ glCompileShader(vertexshader);
+ glAttachShader(glprogram, vertexshader);
+ }
+
+ glLinkProgram(glprogram);
}
void init() {
@@ -92,6 +172,28 @@ public:
glEnable(GL_DITHER);
glEnable(GL_TEXTURE_2D);
+ //bind shader functions
+ glCreateProgram = (PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgram");
+ glUseProgram = (PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgram");
+ glCreateShader = (PFNGLCREATESHADERPROC)glGetProcAddress("glCreateShader");
+ glDeleteShader = (PFNGLDELETESHADERPROC)glGetProcAddress("glDeleteShader");
+ glShaderSource = (PFNGLSHADERSOURCEPROC)glGetProcAddress("glShaderSource");
+ glCompileShader = (PFNGLCOMPILESHADERPROC)glGetProcAddress("glCompileShader");
+ glAttachShader = (PFNGLATTACHSHADERPROC)glGetProcAddress("glAttachShader");
+ glDetachShader = (PFNGLDETACHSHADERPROC)glGetProcAddress("glDetachShader");
+ glLinkProgram = (PFNGLLINKPROGRAMPROC)glGetProcAddress("glLinkProgram");
+ glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)glGetProcAddress("glGetUniformLocation");
+ glUniform1i = (PFNGLUNIFORM1IPROC)glGetProcAddress("glUniform1i");
+ glUniform2fv = (PFNGLUNIFORM2FVPROC)glGetProcAddress("glUniform2fv");
+ glUniform4fv = (PFNGLUNIFORM4FVPROC)glGetProcAddress("glUniform4fv");
+
+ shader_support = glCreateProgram && glUseProgram && glCreateShader
+ && glDeleteShader && glShaderSource && glCompileShader && glAttachShader
+ && glDetachShader && glLinkProgram && glGetUniformLocation
+ && glUniform1i && glUniform2fv && glUniform4fv;
+
+ if(shader_support) glprogram = glCreateProgram();
+
//create surface texture
resize(256, 256);
}
@@ -112,6 +214,10 @@ public:
OpenGL() {
gltexture = 0;
+ glprogram = 0;
+ fragmentshader = 0;
+ vertexshader = 0;
+
buffer = 0;
iwidth = 0;
iheight = 0;
diff --git a/src/lib/ruby/video/wgl.cpp b/src/lib/ruby/video/wgl.cpp
index c53e7d78..72527f2f 100644
--- a/src/lib/ruby/video/wgl.cpp
+++ b/src/lib/ruby/video/wgl.cpp
@@ -27,6 +27,9 @@ public:
if(name == Video::Handle) return true;
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
+ if(name == Video::GLSL) return true;
+ if(name == Video::FragmentShader) return true;
+ if(name == Video::VertexShader) return true;
return false;
}
@@ -55,6 +58,16 @@ public:
return true;
}
+ if(name == Video::FragmentShader) {
+ OpenGL::set_fragment_shader(any_cast(value));
+ return true;
+ }
+
+ if(name == Video::VertexShader) {
+ OpenGL::set_vertex_shader(any_cast(value));
+ return true;
+ }
+
return false;
}
@@ -105,6 +118,12 @@ public:
OpenGL::init();
settings.width = 256;
settings.height = 256;
+
+ //vertical synchronization
+ BOOL (APIENTRY *glSwapInterval)(int);
+ glSwapInterval = (BOOL (APIENTRY*)(int))glGetProcAddress("wglSwapIntervalEXT");
+ if(glSwapInterval) glSwapInterval(settings.synchronize);
+
return true;
}
diff --git a/src/system/audio/audio.cpp b/src/system/audio/audio.cpp
index bd47ee66..e2c6ec07 100644
--- a/src/system/audio/audio.cpp
+++ b/src/system/audio/audio.cpp
@@ -9,7 +9,7 @@ void Audio::coprocessor_enable(bool state) {
dsp_wroffset = cop_wroffset = 0;
dsp_length = cop_length = 0;
- for(unsigned i = 0; i < 4; i++) r_left[i] = r_right[i] = 0;
+ r_sum_l = r_sum_r = 0;
}
void Audio::coprocessor_frequency(double input_frequency) {
@@ -24,72 +24,45 @@ void Audio::coprocessor_frequency(double input_frequency) {
r_frac = 0;
}
-void Audio::sample(uint16 left, uint16 right) {
+void Audio::sample(int16 left, int16 right) {
if(coprocessor == false) {
system.interface->audio_sample(left, right);
} else {
- dsp_buffer[dsp_wroffset] = (left << 0) + (right << 16);
+ dsp_buffer[dsp_wroffset] = ((uint16)left << 0) + ((uint16)right << 16);
dsp_wroffset = (dsp_wroffset + 1) & 32767;
dsp_length = (dsp_length + 1) & 32767;
flush();
}
}
-void Audio::coprocessor_sample(uint16 left, uint16 right) {
- r_left [0] = r_left [1];
- r_left [1] = r_left [2];
- r_left [2] = r_left [3];
- r_left [3] = (int16)left;
-
- r_right[0] = r_right[1];
- r_right[1] = r_right[2];
- r_right[2] = r_right[3];
- r_right[3] = (int16)right;
-
- while(r_frac <= 1.0) {
- left = sclamp<16>(hermite(r_frac, r_left [0], r_left [1], r_left [2], r_left [3]));
- right = sclamp<16>(hermite(r_frac, r_right[0], r_right[1], r_right[2], r_right[3]));
- r_frac += r_step;
-
- cop_buffer[cop_wroffset] = (left << 0) + (right << 16);
- cop_wroffset = (cop_wroffset + 1) & 32767;
- cop_length = (cop_length + 1) & 32767;
- flush();
+void Audio::coprocessor_sample(int16 left, int16 right) {
+ if(r_frac >= 1.0) {
+ r_frac -= 1.0;
+ r_sum_l += left;
+ r_sum_r += right;
+ return;
}
- r_frac -= 1.0;
+ r_sum_l += left * r_frac;
+ r_sum_r += right * r_frac;
+
+ uint16 output_left = sclamp<16>(int(r_sum_l / r_step));
+ uint16 output_right = sclamp<16>(int(r_sum_r / r_step));
+
+ double first = 1.0 - r_frac;
+ r_sum_l = left * first;
+ r_sum_r = right * first;
+ r_frac = r_step - first;
+
+ cop_buffer[cop_wroffset] = (output_left << 0) + (output_right << 16);
+ cop_wroffset = (cop_wroffset + 1) & 32767;
+ cop_length = (cop_length + 1) & 32767;
+ flush();
}
void Audio::init() {
}
-//========
-//private:
-//========
-
-//4-tap hermite interpolation
-double Audio::hermite(double mu1, double a, double b, double c, double d) {
- const double tension = 0.0; //-1 = low, 0 = normal, 1 = high
- const double bias = 0.0; //-1 = left, 0 = even, 1 = right
-
- double mu2, mu3, m0, m1, a0, a1, a2, a3;
-
- mu2 = mu1 * mu1;
- mu3 = mu2 * mu1;
-
- m0 = (b - a) * (1 + bias) * (1 - tension) / 2;
- m0 += (c - b) * (1 - bias) * (1 - tension) / 2;
- m1 = (c - b) * (1 + bias) * (1 - tension) / 2;
- m1 += (d - c) * (1 - bias) * (1 - tension) / 2;
-
- a0 = +2 * mu3 - 3 * mu2 + 1;
- a1 = mu3 - 2 * mu2 + mu1;
- a2 = mu3 - mu2;
- a3 = -2 * mu3 + 3 * mu2;
-
- return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c);
-}
-
void Audio::flush() {
while(dsp_length > 0 && cop_length > 0) {
uint32 dsp_sample = dsp_buffer[dsp_rdoffset];
diff --git a/src/system/audio/audio.hpp b/src/system/audio/audio.hpp
index 616c2e45..3cd522fa 100644
--- a/src/system/audio/audio.hpp
+++ b/src/system/audio/audio.hpp
@@ -2,8 +2,8 @@ class Audio {
public:
void coprocessor_enable(bool state);
void coprocessor_frequency(double frequency);
- void sample(uint16 left, uint16 right);
- void coprocessor_sample(uint16 left, uint16 right);
+ void sample(int16 left, int16 right);
+ void coprocessor_sample(int16 left, int16 right);
void init();
private:
@@ -13,9 +13,8 @@ private:
unsigned dsp_wroffset, cop_wroffset;
unsigned dsp_length, cop_length;
- double hermite(double mu, double a, double b, double c, double d);
double r_step, r_frac;
- int r_left[4], r_right[4];
+ int r_sum_l, r_sum_r;
void flush();
};
diff --git a/src/system/input/input.cpp b/src/system/input/input.cpp
index d56b1900..afa60d80 100644
--- a/src/system/input/input.cpp
+++ b/src/system/input/input.cpp
@@ -8,58 +8,40 @@ uint8 Input::port_read(bool portnumber) {
switch(p.device) {
case DeviceJoypad: {
if(p.counter0 >= 16) return 1;
- unsigned deviceid = (portnumber == 0 ? DeviceIDJoypad1 : DeviceIDJoypad2);
- return system.interface->input_poll(deviceid, p.counter0++);
+ return system.interface->input_poll(portnumber, p.device, 0, p.counter0++);
} //case DeviceJoypad
case DeviceMultitap: {
if(cpu.joylatch()) return 2; //when latch is high -- data2 = 1, data1 = 0
- unsigned deviceidx, deviceid0, deviceid1;
- if(portnumber == 0) {
- if(cpu.pio() & 0x40) {
- deviceidx = p.counter0;
- if(deviceidx >= 16) return 3;
- p.counter0++;
+ unsigned deviceidx, deviceindex0, deviceindex1;
+ uint8 mask = (portnumber == 0 ? 0x40 : 0x80);
- deviceid0 = DeviceIDMultitap1A;
- deviceid1 = DeviceIDMultitap1B;
- } else {
- deviceidx = p.counter1;
- if(deviceidx >= 16) return 3;
- p.counter1++;
+ if(cpu.pio() & mask) {
+ deviceidx = p.counter0;
+ if(deviceidx >= 16) return 3;
+ p.counter0++;
- deviceid0 = DeviceIDMultitap1C;
- deviceid1 = DeviceIDMultitap1D;
- }
+ deviceindex0 = 0; //controller 1
+ deviceindex1 = 1; //controller 2
} else {
- if(cpu.pio() & 0x80) {
- deviceidx = p.counter0;
- if(deviceidx >= 16) return 3;
- p.counter0++;
+ deviceidx = p.counter1;
+ if(deviceidx >= 16) return 3;
+ p.counter1++;
- deviceid0 = DeviceIDMultitap2A;
- deviceid1 = DeviceIDMultitap2B;
- } else {
- deviceidx = p.counter1;
- if(deviceidx >= 16) return 3;
- p.counter1++;
-
- deviceid0 = DeviceIDMultitap2C;
- deviceid1 = DeviceIDMultitap2D;
- }
+ deviceindex0 = 2; //controller 3
+ deviceindex1 = 3; //controller 4
}
- return (system.interface->input_poll(deviceid0, deviceidx) << 0)
- | (system.interface->input_poll(deviceid1, deviceidx) << 1);
+ return (system.interface->input_poll(portnumber, p.device, deviceindex0, deviceidx) << 0)
+ | (system.interface->input_poll(portnumber, p.device, deviceindex1, deviceidx) << 1);
} //case DeviceMultitap
case DeviceMouse: {
if(p.counter0 >= 32) return 1;
- unsigned deviceid = (portnumber == 0 ? DeviceIDMouse1 : DeviceIDMouse2);
- int position_x = system.interface->input_poll(deviceid, MouseX); //-n = left, 0 = center, +n = right
- int position_y = system.interface->input_poll(deviceid, MouseY); //-n = up, 0 = center, +n = right
+ int position_x = system.interface->input_poll(portnumber, p.device, 0, MouseX); //-n = left, 0 = center, +n = right
+ int position_y = system.interface->input_poll(portnumber, p.device, 0, MouseY); //-n = up, 0 = center, +n = right
bool direction_x = position_x < 0; //0 = right, 1 = left
bool direction_y = position_y < 0; //0 = down, 1 = up
@@ -80,8 +62,8 @@ uint8 Input::port_read(bool portnumber) {
case 6: return 0;
case 7: return 0;
- case 8: return system.interface->input_poll(deviceid, MouseRight);
- case 9: return system.interface->input_poll(deviceid, MouseLeft);
+ case 8: return system.interface->input_poll(portnumber, p.device, 0, MouseRight);
+ case 9: return system.interface->input_poll(portnumber, p.device, 0, MouseLeft);
case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
case 11: return 0; // ||
@@ -116,7 +98,7 @@ uint8 Input::port_read(bool portnumber) {
if(p.counter0 == 0) {
//turbo is a switch; toggle is edge sensitive
- bool turbo = system.interface->input_poll(DeviceIDSuperScope, SuperScopeTurbo);
+ bool turbo = system.interface->input_poll(portnumber, p.device, 0, SuperScopeTurbo);
if(turbo && !p.superscope.turbolock) {
p.superscope.turbo = !p.superscope.turbo; //toggle state
p.superscope.turbolock = true;
@@ -127,7 +109,7 @@ uint8 Input::port_read(bool portnumber) {
//trigger is a button
//if turbo is active, trigger is level sensitive; otherwise it is edge sensitive
p.superscope.trigger = false;
- bool trigger = system.interface->input_poll(DeviceIDSuperScope, SuperScopeTrigger);
+ bool trigger = system.interface->input_poll(portnumber, p.device, 0, SuperScopeTrigger);
if(trigger && (p.superscope.turbo || !p.superscope.triggerlock)) {
p.superscope.trigger = true;
p.superscope.triggerlock = true;
@@ -136,11 +118,11 @@ uint8 Input::port_read(bool portnumber) {
}
//cursor is a button; it is always level sensitive
- p.superscope.cursor = system.interface->input_poll(DeviceIDSuperScope, SuperScopeCursor);
+ p.superscope.cursor = system.interface->input_poll(portnumber, p.device, 0, SuperScopeCursor);
//pause is a button; it is always edge sensitive
p.superscope.pause = false;
- bool pause = system.interface->input_poll(DeviceIDSuperScope, SuperScopePause);
+ bool pause = system.interface->input_poll(portnumber, p.device, 0, SuperScopePause);
if(pause && !p.superscope.pauselock) {
p.superscope.pause = true;
p.superscope.pauselock = true;
@@ -171,12 +153,12 @@ uint8 Input::port_read(bool portnumber) {
if(p.counter0 >= 32) return 1;
if(p.counter0 == 0) {
- p.justifier.trigger1 = system.interface->input_poll(DeviceIDJustifier1, JustifierTrigger);
- p.justifier.start1 = system.interface->input_poll(DeviceIDJustifier1, JustifierStart);
+ p.justifier.trigger1 = system.interface->input_poll(portnumber, p.device, 0, JustifierTrigger);
+ p.justifier.start1 = system.interface->input_poll(portnumber, p.device, 0, JustifierStart);
if(p.device == DeviceJustifiers) {
- p.justifier.trigger2 = system.interface->input_poll(DeviceIDJustifier2, JustifierTrigger);
- p.justifier.start2 = system.interface->input_poll(DeviceIDJustifier2, JustifierStart);
+ p.justifier.trigger2 = system.interface->input_poll(portnumber, p.device, 1, JustifierTrigger);
+ p.justifier.start2 = system.interface->input_poll(portnumber, p.device, 1, JustifierStart);
} else {
p.justifier.x2 = -1;
p.justifier.y2 = -1;
@@ -238,8 +220,8 @@ void Input::update() {
switch(p.device) {
case DeviceSuperScope: {
- int x = system.interface->input_poll(DeviceIDSuperScope, SuperScopeX);
- int y = system.interface->input_poll(DeviceIDSuperScope, SuperScopeY);
+ int x = system.interface->input_poll(1, p.device, 0, SuperScopeX);
+ int y = system.interface->input_poll(1, p.device, 0, SuperScopeY);
x += p.superscope.x;
y += p.superscope.y;
p.superscope.x = max(-16, min(256 + 16, x));
@@ -251,15 +233,15 @@ void Input::update() {
case DeviceJustifier:
case DeviceJustifiers: {
- int x1 = system.interface->input_poll(DeviceIDJustifier1, JustifierX);
- int y1 = system.interface->input_poll(DeviceIDJustifier1, JustifierY);
+ int x1 = system.interface->input_poll(1, p.device, 0, JustifierX);
+ int y1 = system.interface->input_poll(1, p.device, 0, JustifierY);
x1 += p.justifier.x1;
y1 += p.justifier.y1;
p.justifier.x1 = max(-16, min(256 + 16, x1));
p.justifier.y1 = max(-16, min(240 + 16, y1));
- int x2 = system.interface->input_poll(DeviceIDJustifier2, JustifierX);
- int y2 = system.interface->input_poll(DeviceIDJustifier2, JustifierY);
+ int x2 = system.interface->input_poll(1, p.device, 1, JustifierX);
+ int y2 = system.interface->input_poll(1, p.device, 1, JustifierY);
x2 += p.justifier.x2;
y2 += p.justifier.y2;
p.justifier.x2 = max(-16, min(256 + 16, x2));
diff --git a/src/system/input/input.hpp b/src/system/input/input.hpp
index 00e10be8..80d8d4ad 100644
--- a/src/system/input/input.hpp
+++ b/src/system/input/input.hpp
@@ -10,32 +10,13 @@ public:
DeviceJustifiers,
};
- enum DeviceID {
- DeviceIDNone,
- DeviceIDJoypad1,
- DeviceIDJoypad2,
- DeviceIDMultitap1A,
- DeviceIDMultitap1B,
- DeviceIDMultitap1C,
- DeviceIDMultitap1D,
- DeviceIDMultitap2A,
- DeviceIDMultitap2B,
- DeviceIDMultitap2C,
- DeviceIDMultitap2D,
- DeviceIDMouse1,
- DeviceIDMouse2,
- DeviceIDSuperScope,
- DeviceIDJustifier1,
- DeviceIDJustifier2,
- };
-
enum JoypadID {
- JoypadB = 0, JoypadY = 1,
- JoypadSelect = 2, JoypadStart = 3,
- JoypadUp = 4, JoypadDown = 5,
- JoypadLeft = 6, JoypadRight = 7,
- JoypadA = 8, JoypadX = 9,
- JoypadL = 10, JoypadR = 11,
+ JoypadB = 0, JoypadY = 1,
+ JoypadSelect = 2, JoypadStart = 3,
+ JoypadUp = 4, JoypadDown = 5,
+ JoypadLeft = 6, JoypadRight = 7,
+ JoypadA = 8, JoypadX = 9,
+ JoypadL = 10, JoypadR = 11,
};
enum MouseID {
diff --git a/src/system/interface/interface.hpp b/src/system/interface/interface.hpp
index bc1ce15d..49518709 100644
--- a/src/system/interface/interface.hpp
+++ b/src/system/interface/interface.hpp
@@ -3,5 +3,5 @@ public:
virtual void video_refresh(uint16_t *data, unsigned pitch, unsigned *line, unsigned width, unsigned height) {}
virtual void audio_sample(uint16_t l_sample, uint16_t r_sample) {}
virtual void input_poll() {}
- virtual int16_t input_poll(unsigned deviceid, unsigned id) { return 0; }
+ virtual int16_t input_poll(bool port, unsigned device, unsigned index, unsigned id) { return 0; }
};
diff --git a/src/system/serialization.cpp b/src/system/serialization.cpp
index a5ac8570..0ffafb0f 100644
--- a/src/system/serialization.cpp
+++ b/src/system/serialization.cpp
@@ -51,6 +51,8 @@ void System::serialize_all(serializer &s) {
ppu.serialize(s);
dsp.serialize(s);
+ if(cartridge.mode() == Cartridge::ModeSuperGameBoy) supergameboy.serialize(s);
+
if(cartridge.has_srtc()) srtc.serialize(s);
if(cartridge.has_sdd1()) sdd1.serialize(s);
if(cartridge.has_spc7110()) spc7110.serialize(s);
diff --git a/src/ui_qt/application/application.cpp b/src/ui_qt/application/application.cpp
index 746fba7c..1985d1ab 100644
--- a/src/ui_qt/application/application.cpp
+++ b/src/ui_qt/application/application.cpp
@@ -15,30 +15,30 @@ void Application::initPaths(const char *basename) {
}
if(strend(temp, "/") == false) strcat(temp, "/");
- config.path.base = temp;
+ config().path.base = temp;
} else {
- config.path.base = "";
+ config().path.base = "";
}
if(userpath(temp)) {
strtr(temp, "\\", "/");
if(strend(temp, "/") == false) strcat(temp, "/");
- config.path.user = temp;
+ config().path.user = temp;
} else {
- config.path.user = "";
+ config().path.user = "";
}
char cwd[PATH_MAX];
- config.path.current = getcwd(cwd);
+ config().path.startup = getcwd(cwd);
}
void Application::locateFile(string &filename, bool createDataDirectory) {
//first, check if file exists in executable directory (single-user mode)
- string temp = string() << config.path.base << filename;
+ string temp = string() << config().path.base << filename;
if(file::exists(temp) == false) {
//if not, use user data path (multi-user mode)
- temp = config.path.user;
+ temp = config().path.user;
temp << ".bsnes";
if(createDataDirectory) mkdir(temp); //ensure directory exists
temp << "/" << filename;
@@ -66,7 +66,8 @@ int Application::main(int &argc, char **argv) {
app->setStyleSheet(defaultStylesheet);
}
- config.load(configFilename);
+ config().load(configFilename);
+ mapper().bind();
init();
SNES::system.init(&interface);
mainWindow->system_loadSpecial_superGameBoy->setVisible(SNES::supergameboy.opened());
@@ -87,7 +88,7 @@ int Application::main(int &argc, char **argv) {
}
utility.unloadCartridge();
- config.save(configFilename);
+ config().save(configFilename);
return 0;
}
@@ -100,9 +101,9 @@ void Application::run() {
QApplication::processEvents();
utility.updateSystemState();
- inputManager.refresh();
+ mapper().poll();
- if(config.input.focusPolicy == Configuration::Input::FocusPolicyPauseEmulation) {
+ if(config().input.focusPolicy == Configuration::Input::FocusPolicyPauseEmulation) {
bool active = mainWindow->isActive();
if(!autopause && !active) {
autopause = true;
@@ -135,7 +136,7 @@ void Application::run() {
if(autosaveTime >= CLOCKS_PER_SEC * 60) {
//auto-save RAM once per minute in case of emulator crash
autosaveTime = 0;
- if(config.system.autoSaveMemory == true) utility.saveMemory();
+ if(config().system.autoSaveMemory == true) utility.saveMemory();
}
if(screensaverTime >= CLOCKS_PER_SEC * 30) {
diff --git a/src/ui_qt/application/init.cpp b/src/ui_qt/application/init.cpp
index a7c1c805..e1c6b6b1 100644
--- a/src/ui_qt/application/init.cpp
+++ b/src/ui_qt/application/init.cpp
@@ -17,9 +17,9 @@
#include "../tools/tools.cpp"
void Application::init() {
- if(config.system.crashedOnLastRun == true) {
+ if(config().system.crashedOnLastRun == true) {
//emulator crashed on last run, disable all drivers
- QMessageBox::warning(0, "bsnes Crash Notification", utf8() <<
+ QMessageBox::warning(0, "bsnes Crash Notification", string() <<
"Warning:
bsnes crashed while attempting to initialize device "
"drivers the last time it was run.
"
"To prevent this from occurring again, all drivers have been disabled. Please "
@@ -27,19 +27,19 @@ void Application::init() {
"restart the emulator for the changes to take effect. Video, audio and input "
"will not work until you do this!
"
"Settings that caused failure on last run:
"
- << "Video driver: " << config.system.video << "
"
- << "Audio driver: " << config.system.audio << "
"
- << "Input driver: " << config.system.input << "
"
+ << "Video driver: " << config().system.video << "
"
+ << "Audio driver: " << config().system.audio << "
"
+ << "Input driver: " << config().system.input << "
"
);
- config.system.video = "None";
- config.system.audio = "None";
- config.system.input = "None";
+ config().system.video = "None";
+ config().system.audio = "None";
+ config().system.input = "None";
}
- if(config.system.video == "") config.system.video = video.default_driver();
- if(config.system.audio == "") config.system.audio = audio.default_driver();
- if(config.system.input == "") config.system.input = input.default_driver();
+ if(config().system.video == "") config().system.video = video.default_driver();
+ if(config().system.audio == "") config().system.audio = audio.default_driver();
+ if(config().system.input == "") config().system.input = input.default_driver();
mainWindow = new MainWindow;
loaderWindow = new LoaderWindow;
@@ -59,15 +59,15 @@ void Application::init() {
//if emulator crashes while initializing drivers, next run will disable them all.
//this will allow user to choose different driver settings.
- config.system.crashedOnLastRun = true;
- config.save(configFilename);
+ config().system.crashedOnLastRun = true;
+ config().save(configFilename);
- video.driver(config.system.video);
+ video.driver(config().system.video);
video.set(Video::Handle, (uintptr_t)mainWindow->canvas->winId());
video.set("QWidget", (QWidget*)mainWindow->canvas);
if(video.init() == false) {
- QMessageBox::warning(0, "bsnes", utf8() <<
- "Warning: " << config.system.video << " video driver failed to initialize. "
+ QMessageBox::warning(0, "bsnes", string() <<
+ "
Warning: " << config().system.video << " video driver failed to initialize. "
"Video driver has been disabled.
"
"Please go to Settings->Configuration->Advanced and choose a different driver, and "
"then restart the emulator for the changes to take effect.
"
@@ -76,14 +76,14 @@ void Application::init() {
video.init();
}
- audio.driver(config.system.audio);
+ audio.driver(config().system.audio);
audio.set(Audio::Handle, (uintptr_t)mainWindow->canvas->winId());
- audio.set(Audio::Frequency, config.audio.outputFrequency);
- audio.set(Audio::Latency, config.audio.latency);
- audio.set(Audio::Volume, config.audio.volume);
+ audio.set(Audio::Frequency, config().audio.outputFrequency);
+ audio.set(Audio::Latency, config().audio.latency);
+ audio.set(Audio::Volume, config().audio.volume);
if(audio.init() == false) {
- QMessageBox::warning(0, "bsnes", utf8() <<
- "Warning: " << config.system.audio << " audio driver failed to initialize. "
+ QMessageBox::warning(0, "bsnes", string() <<
+ "
Warning: " << config().system.audio << " audio driver failed to initialize. "
"Audio driver has been disabled.
"
"Please go to Settings->Configuration->Advanced and choose a different driver, and "
"then restart the emulator for the changes to take effect.
"
@@ -92,11 +92,11 @@ void Application::init() {
audio.init();
}
- input.driver(config.system.input);
+ input.driver(config().system.input);
input.set("Handle", (uintptr_t)mainWindow->canvas->winId());
if(input.init() == false) {
- QMessageBox::warning(0, "bsnes", utf8() <<
- "Warning: " << config.system.input << " input driver failed to initialize. "
+ QMessageBox::warning(0, "bsnes", string() <<
+ "
Warning: " << config().system.input << " input driver failed to initialize. "
"Input driver has been disabled.
"
"Please go to Settings->Configuration->Advanced and choose a different driver, and "
"then restart the emulator for the changes to take effect.
"
@@ -106,18 +106,17 @@ void Application::init() {
}
//didn't crash, note this in the config file now in case a different kind of crash occurs later
- config.system.crashedOnLastRun = false;
- config.save(configFilename);
+ config().system.crashedOnLastRun = false;
+ config().save(configFilename);
- inputManager.bind();
- inputManager.refresh();
- inputManager.refresh();
- inputManager.onInput = bind(&Utility::inputEvent, &utility);
+ //no sense showing unusable options ...
+ pixelShaderWindow->setVisible(video.cap(Video::FragmentShader) || video.cap(Video::VertexShader));
utility.resizeMainWindow();
utility.updateAvSync();
utility.updateVideoMode();
utility.updateColorFilter();
+ utility.updatePixelShader();
utility.updateHardwareFilter();
utility.updateSoftwareFilter();
utility.updateEmulationSpeed();
diff --git a/src/ui_qt/application/qb.cpp b/src/ui_qt/application/qb.cpp
index f1cddbb9..6ce65dee 100644
--- a/src/ui_qt/application/qb.cpp
+++ b/src/ui_qt/application/qb.cpp
@@ -1,8 +1,10 @@
void QbWindow::shrink() {
- for(unsigned i = 0; i < 2; i++) {
- resize(0, 0);
- usleep(2000);
- QApplication::processEvents();
+ if(config().video.isFullscreen == false) {
+ for(unsigned i = 0; i < 2; i++) {
+ resize(0, 0);
+ usleep(2000);
+ QApplication::processEvents();
+ }
}
}
diff --git a/src/ui_qt/base/about.cpp b/src/ui_qt/base/about.cpp
index 662d7cb7..b7a15eb8 100644
--- a/src/ui_qt/base/about.cpp
+++ b/src/ui_qt/base/about.cpp
@@ -1,4 +1,4 @@
-AboutWindow::AboutWindow() : QbWindow(config.geometry.aboutWindow) {
+AboutWindow::AboutWindow() : QbWindow(config().geometry.aboutWindow) {
setObjectName("about-window");
setWindowTitle("About bsnes ...");
@@ -12,7 +12,7 @@ AboutWindow::AboutWindow() : QbWindow(config.geometry.aboutWindow) {
logo->setFixedSize(600, 106);
layout->addWidget(logo);
- info = new QLabel(utf8() <<
+ info = new QLabel(string() <<
""
"Version: | " << bsnesVersion << " |
"
"Author: | byuu |
"
diff --git a/src/ui_qt/base/diskbrowser.cpp b/src/ui_qt/base/diskbrowser.cpp
index a1b557e2..54ae457f 100644
--- a/src/ui_qt/base/diskbrowser.cpp
+++ b/src/ui_qt/base/diskbrowser.cpp
@@ -2,7 +2,7 @@
//FolderCreator
//=============
-FolderCreator::FolderCreator() : QbWindow(config.geometry.folderCreator) {
+FolderCreator::FolderCreator() : QbWindow(config().geometry.folderCreator) {
setObjectName("folder-creator");
setWindowTitle("Create New Folder");
@@ -89,7 +89,7 @@ void DiskBrowserView::currentChanged(const QModelIndex ¤t, const QModelInd
void DiskBrowserImage::paintEvent(QPaintEvent*) {
QPainter painter(this);
if(name != "") {
- QImage image(name);
+ QImage image(QString::fromUtf8(name));
painter.drawImage(0, 0, image);
}
}
@@ -98,81 +98,160 @@ void DiskBrowserImage::paintEvent(QPaintEvent*) {
//DiskBrowser
//===========
-void DiskBrowser::chooseFolder(PathSettingWidget *widget, const char *title) {
+void DiskBrowser::inputEvent(uint16_t scancode) {
+ if(!isActiveWindow() || isMinimized()) return;
+
+ //provide very simple support for controlling the window via gamepads
+ if(Joypad::isAnyHat(scancode)) {
+ int16_t state = mapper().state(scancode);
+
+ if(state == Joypad::HatUp) {
+ QKeyEvent event((QEvent::Type)6, Qt::Key_Up, Qt::NoModifier);
+ view->keyPressEvent(&event);
+ }
+
+ if(state == Joypad::HatDown) {
+ QKeyEvent event((QEvent::Type)6, Qt::Key_Down, Qt::NoModifier);
+ view->keyPressEvent(&event);
+ }
+
+ if(state == Joypad::HatLeft) {
+ QKeyEvent event((QEvent::Type)6, Qt::Key_Backspace, Qt::NoModifier);
+ view->keyPressEvent(&event);
+ }
+
+ if(state == Joypad::HatRight) {
+ QKeyEvent event((QEvent::Type)6, Qt::Key_Return, Qt::NoModifier);
+ view->keyPressEvent(&event);
+ }
+ }
+}
+
+void DiskBrowser::chooseFolder(const function &callback_, string ¤tPath_, const char *title) {
+ callback = callback_;
+ currentPath = ¤tPath_;
browseMode = Folder;
- activePath = widget;
+
hide();
group->hide();
ok->setText("Choose");
- setWindowTitle(utf8() << title);
- setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
+ setWindowTitle(string() << title);
+ setPath(*currentPath);
setNameFilters("Folders ()");
show();
}
-void DiskBrowser::loadCartridge() {
- browseMode = Cartridge;
+void DiskBrowser::chooseFile(const function &callback_, string ¤tPath_, const char *title) {
+ callback = callback_;
+ currentPath = ¤tPath_;
+ browseMode = File;
+
hide();
- group->setVisible(config.diskBrowser.showPanel);
+ group->hide();
+ ok->setText("Choose");
+ setWindowTitle(string() << title);
+ setPath(*currentPath);
+ setNameFilters("All Files (*)");
+ show();
+}
+
+void DiskBrowser::loadCartridge() {
+ currentPath = &config().path.current.cartridge;
+ browseMode = Cartridge;
+
+ hide();
+ group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
setWindowTitle("Load Cartridge");
- setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
- setNameFilters(utf8() << "SNES cartridges (*.sfc" << reader.filterList << ");;All files (*)");
+ setPath(config().path.rom == "" ? *currentPath : config().path.rom);
+ setNameFilters(string()
+ << "SNES cartridges (*.sfc" << reader.extensionList << reader.compressionList << ");;"
+ << "BS-X cartridges (*.bs" << reader.compressionList << ");;"
+ << "Sufami Turbo cartridges (*.st" << reader.compressionList << ");;"
+ << "Game Boy cartridges (*.gb *.sgb *.gbc" << reader.compressionList << ");;"
+ << "All files (*)"
+ );
+ filter->setCurrentIndex(config().path.current.filter);
show();
}
void DiskBrowser::loadBaseCartridge() {
+ currentPath = &config().path.current.cartridge;
browseMode = BaseCartridge;
+
hide();
- group->setVisible(config.diskBrowser.showPanel);
+ group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
setWindowTitle("Load Base Cartridge");
- setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
- setNameFilters(utf8() << "SNES cartridges (*.sfc" << reader.filterList << ");;All files (*)");
+ setPath(config().path.rom == "" ? *currentPath : config().path.rom);
+ setNameFilters(string()
+ << "SNES cartridges (*.sfc" << reader.extensionList << reader.compressionList << ");;"
+ << "All files (*)"
+ );
show();
}
void DiskBrowser::loadBsxCartridge() {
+ currentPath = &config().path.current.bsx;
browseMode = BsxCartridge;
+
hide();
- group->setVisible(config.diskBrowser.showPanel);
+ group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
setWindowTitle("Load BS-X Cartridge");
- setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
- setNameFilters(utf8() << "BS-X cartridges (*.bs" << reader.filterList << ");;All files (*)");
+ setPath(config().path.rom == "" ? *currentPath : config().path.rom);
+ setNameFilters(string()
+ << "BS-X cartridges (*.bs" << reader.compressionList << ");;"
+ << "All files (*)"
+ );
show();
}
void DiskBrowser::loadSufamiTurboCartridge1() {
+ currentPath = &config().path.current.st;
browseMode = SufamiTurboCartridge1;
+
hide();
- group->setVisible(config.diskBrowser.showPanel);
+ group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
setWindowTitle("Load Slot-A Sufami Turbo Cartridge");
- setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
- setNameFilters(utf8() << "Sufami Turbo cartridges (*.st" << reader.filterList << ");;All files (*)");
+ setPath(config().path.rom == "" ? *currentPath : config().path.rom);
+ setNameFilters(string()
+ << "Sufami Turbo cartridges (*.st" << reader.compressionList << ");;"
+ << "All files (*)"
+ );
show();
}
void DiskBrowser::loadSufamiTurboCartridge2() {
+ currentPath = &config().path.current.st;
browseMode = SufamiTurboCartridge2;
+
hide();
- group->setVisible(config.diskBrowser.showPanel);
+ group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
setWindowTitle("Load Slot-B Sufami Turbo Cartridge");
- setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
- setNameFilters(utf8() << "Sufami Turbo Cartridges (*.st" << reader.filterList << ");;All files (*)");
+ setPath(config().path.rom == "" ? *currentPath : config().path.rom);
+ setNameFilters(string()
+ << "Sufami Turbo Cartridges (*.st" << reader.compressionList << ");;"
+ << "All files (*)"
+ );
show();
}
void DiskBrowser::loadSuperGameBoyCartridge() {
+ currentPath = &config().path.current.sgb;
browseMode = SuperGameBoyCartridge;
+
hide();
- group->setVisible(config.diskBrowser.showPanel);
+ group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
setWindowTitle("Load Super Game Boy Cartridge");
- setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
- setNameFilters(utf8() << "Game Boy cartridges (*.gb *.gbc" << reader.filterList << ");;All files (*)");
+ setPath(config().path.rom == "" ? *currentPath : config().path.rom);
+ setNameFilters(string()
+ << "Game Boy cartridges (*.gb *.sgb *.gbc" << reader.compressionList << ");;"
+ << "All files (*)"
+ );
show();
}
@@ -219,7 +298,7 @@ void DiskBrowser::changeItem(const QModelIndex &item) {
ok->setEnabled(true);
image->name = nall::basename(filename) << ".png";
if(file::exists(image->name) == false) image->name = "";
- info->setText(utf8() << queryImageInformation());
+ info->setText(string() << queryImageInformation());
string patch = nall::basename(filename) << ".ups";
applyPatch->setVisible(file::exists(patch));
}
@@ -234,17 +313,48 @@ void DiskBrowser::loadSelected() {
if(browseMode == Folder || loadable == true) {
QModelIndex item = view->currentIndex();
- config.path.current = dir(model->filePath(item).toUtf8().constData());
+ if(currentPath) *currentPath = dir(model->filePath(item).toUtf8().constData());
hide();
- switch(browseMode) { default:
- case Folder: activePath->selectPath(filename); break;
- case Cartridge: utility.loadCartridgeNormal(filename); break;
- case BaseCartridge: loaderWindow->selectBaseCartridge(filename); break;
- case BsxCartridge: loaderWindow->selectSlot1Cartridge(filename); break;
- case SufamiTurboCartridge1: loaderWindow->selectSlot1Cartridge(filename); break;
- case SufamiTurboCartridge2: loaderWindow->selectSlot2Cartridge(filename); break;
- case SuperGameBoyCartridge: loaderWindow->selectSlot1Cartridge(filename); break;
+ if(browseMode == Folder || browseMode == File) {
+ callback(filename);
+ } else if(browseMode == Cartridge) {
+ //quick-loading mode: determine load type via active filter
+ config().path.current.filter = filter->currentIndex();
+
+ if(config().path.current.filter == 1) { //"BS-X cartridges"
+ if(config().path.bsx == "") {
+ loaderWindow->loadBsxCartridge("", filename);
+ } else {
+ utility.loadCartridgeBsx(config().path.bsx, filename);
+ }
+ } else if(config().path.current.filter == 2) { //"Sufami Turbo cartridges"
+ if(config().path.st == "") {
+ loaderWindow->loadSufamiTurboCartridge("", filename, "");
+ } else {
+ utility.loadCartridgeSufamiTurbo(config().path.st, filename, "");
+ }
+ } else if(config().path.current.filter == 3) { //"Game Boy cartridges"
+ if(SNES::supergameboy.opened() == false) {
+ QMessageBox::warning(0, "Warning", "Super Game Boy support missing - cartridge cannot be loaded.");
+ } else if(config().path.sgb == "") {
+ loaderWindow->loadSuperGameBoyCartridge("", filename);
+ } else {
+ utility.loadCartridgeSuperGameBoy(config().path.sgb, filename);
+ }
+ } else { //"SNES cartridges" (0) or "All files" (4)
+ utility.loadCartridgeNormal(filename);
+ }
+ } else if(browseMode == BaseCartridge) {
+ loaderWindow->selectBaseCartridge(filename);
+ } else if(browseMode == BsxCartridge) {
+ loaderWindow->selectSlot1Cartridge(filename);
+ } else if(browseMode == SufamiTurboCartridge1) {
+ loaderWindow->selectSlot1Cartridge(filename);
+ } else if(browseMode == SufamiTurboCartridge2) {
+ loaderWindow->selectSlot2Cartridge(filename);
+ } else if(browseMode == SuperGameBoyCartridge) {
+ loaderWindow->selectSlot1Cartridge(filename);
}
} else {
//this is a standard folder in ROM loading mode; enter into the folder
@@ -259,6 +369,9 @@ void DiskBrowser::setPath(const QString &reqPath) {
disconnect(path, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePath()));
QString effectivePath = reqPath;
+ if(effectivePath == "") {
+ effectivePath = QString::fromUtf8(config().path.startup);
+ }
if(effectivePath == "" || QDir(reqPath).exists() == false) {
effectivePath = "";
newFolder->setEnabled(false);
@@ -294,7 +407,7 @@ void DiskBrowser::setNameFilters(const QString &filters) {
filterPart.split(";;", filterData);
for(unsigned i = 0; i < filterPart.size(); i++) {
- filter->addItem(utf8() << filterPart[i]);
+ filter->addItem(filterPart[i]);
}
connect(filter, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFilter()));
@@ -337,7 +450,7 @@ bool DiskBrowser::currentFilename(string &filename) {
if(browseMode != Folder) {
if(model->isDir(item) == true) {
- QDir directory(utf8() << filename);
+ QDir directory(filename);
directory.setNameFilters(QStringList() << "*.sfc");
QStringList list = directory.entryList(QDir::Files | QDir::NoDotAndDotDot);
if(list.count() == 1) {
@@ -354,11 +467,11 @@ bool DiskBrowser::currentFilename(string &filename) {
void DiskBrowser::toggleShowPanel() {
showPanel->setChecked(!showPanel->isChecked());
- config.diskBrowser.showPanel = showPanel->isChecked();
- group->setVisible(config.diskBrowser.showPanel);
+ config().diskBrowser.showPanel = showPanel->isChecked();
+ group->setVisible(config().diskBrowser.showPanel);
}
-DiskBrowser::DiskBrowser() : QbWindow(config.geometry.diskBrowser) {
+DiskBrowser::DiskBrowser() : QbWindow(config().geometry.diskBrowser) {
setObjectName("disk-browser");
resize(720, 480);
@@ -434,7 +547,7 @@ DiskBrowser::DiskBrowser() : QbWindow(config.geometry.diskBrowser) {
options->setMenu(menu);
menu->addAction(showPanel = new QbCheckAction("Show Side Panel", 0));
- showPanel->setChecked(config.diskBrowser.showPanel);
+ showPanel->setChecked(config().diskBrowser.showPanel);
ok = new QPushButton("Ok");
ok->setEnabled(false);
diff --git a/src/ui_qt/base/diskbrowser.moc.hpp b/src/ui_qt/base/diskbrowser.moc.hpp
index c42edf93..47422830 100644
--- a/src/ui_qt/base/diskbrowser.moc.hpp
+++ b/src/ui_qt/base/diskbrowser.moc.hpp
@@ -1,5 +1,3 @@
-class PathSettingWidget;
-
class FolderCreator : public QbWindow {
Q_OBJECT
@@ -62,18 +60,22 @@ public:
QPushButton *ok;
QPushButton *cancel;
QFileSystemModel *model;
- PathSettingWidget *activePath;
QMenu *menu;
QbCheckAction *showPanel;
- void chooseFolder(PathSettingWidget*, const char*);
+ void inputEvent(uint16_t scancode);
+
+ void chooseFolder(const function&, string&, const char*);
+ void chooseFile(const function&, string&, const char*);
+
void loadCartridge();
void loadBaseCartridge();
void loadBsxCartridge();
void loadSufamiTurboCartridge1();
void loadSufamiTurboCartridge2();
void loadSuperGameBoyCartridge();
+
string queryImageInformation();
void setPath(const QString&);
@@ -92,8 +94,12 @@ public slots:
void toggleShowPanel();
private:
+ function callback;
+ string *currentPath;
+
enum BrowseMode {
Folder,
+ File,
Cartridge,
BaseCartridge,
BsxCartridge,
diff --git a/src/ui_qt/base/htmlviewer.cpp b/src/ui_qt/base/htmlviewer.cpp
index 4a633c12..7ffcb987 100644
--- a/src/ui_qt/base/htmlviewer.cpp
+++ b/src/ui_qt/base/htmlviewer.cpp
@@ -1,4 +1,4 @@
-HtmlViewerWindow::HtmlViewerWindow() : QbWindow(config.geometry.htmlViewerWindow) {
+HtmlViewerWindow::HtmlViewerWindow() : QbWindow(config().geometry.htmlViewerWindow) {
setObjectName("html-window");
resize(560, 480);
@@ -12,7 +12,7 @@ HtmlViewerWindow::HtmlViewerWindow() : QbWindow(config.geometry.htmlViewerWindow
}
void HtmlViewerWindow::show(const char *title, const char *htmlData) {
- document->setHtml(utf8() << htmlData);
+ document->setHtml(string() << htmlData);
setWindowTitle(title);
QbWindow::show();
}
diff --git a/src/ui_qt/base/loader.cpp b/src/ui_qt/base/loader.cpp
index 82e3b2ac..7575bc91 100644
--- a/src/ui_qt/base/loader.cpp
+++ b/src/ui_qt/base/loader.cpp
@@ -1,4 +1,4 @@
-LoaderWindow::LoaderWindow() : QbWindow(config.geometry.loaderWindow) {
+LoaderWindow::LoaderWindow() : QbWindow(config().geometry.loaderWindow) {
setObjectName("loader-window");
setMinimumWidth(520);
@@ -145,17 +145,17 @@ void LoaderWindow::showWindow(const char *title) {
}
void LoaderWindow::selectBaseCartridge(const char *filename) {
- baseFile->setText(utf8() << filename);
+ baseFile->setText(string() << filename);
syncUi();
}
void LoaderWindow::selectSlot1Cartridge(const char *filename) {
- slot1File->setText(utf8() << filename);
+ slot1File->setText(string() << filename);
syncUi();
}
void LoaderWindow::selectSlot2Cartridge(const char *filename) {
- slot2File->setText(utf8() << filename);
+ slot2File->setText(string() << filename);
syncUi();
}
@@ -209,17 +209,17 @@ void LoaderWindow::onLoad() {
} break;
case SNES::Cartridge::ModeBsx: {
- config.path.bsx = base;
+ config().path.bsx = base;
utility.loadCartridgeBsx(base, slot1);
} break;
case SNES::Cartridge::ModeSufamiTurbo: {
- config.path.st = base;
+ config().path.st = base;
utility.loadCartridgeSufamiTurbo(base, slot1, slot2);
} break;
case SNES::Cartridge::ModeSuperGameBoy: {
- config.path.sgb = base;
+ config().path.sgb = base;
utility.loadCartridgeSuperGameBoy(base, slot1);
} break;
}
diff --git a/src/ui_qt/base/main.cpp b/src/ui_qt/base/main.cpp
index ccd61d4b..31b3ec08 100644
--- a/src/ui_qt/base/main.cpp
+++ b/src/ui_qt/base/main.cpp
@@ -1,6 +1,6 @@
-MainWindow::MainWindow() : QbWindow(config.geometry.mainWindow) {
+MainWindow::MainWindow() : QbWindow(config().geometry.mainWindow) {
setObjectName("main-window");
- setWindowTitle(utf8() << bsnesTitle << " v" << bsnesVersion);
+ setWindowTitle(string() << bsnesTitle << " v" << bsnesVersion);
//menu bar
#if defined(PLATFORM_OSX)
@@ -9,126 +9,176 @@ MainWindow::MainWindow() : QbWindow(config.geometry.mainWindow) {
menuBar = new QMenuBar;
#endif
- system = menuBar->addMenu("System");
- system_load = system->addAction("Load Cartridge ...");
- system_load->setIcon(QIcon(":/16x16/document-open.png"));
- system_loadSpecial = system->addMenu("Load Special");
- system_loadSpecial->setIcon(QIcon(":/16x16/document-open.png"));
- system_loadSpecial_bsxSlotted = system_loadSpecial->addAction("Load BS-X Slotted Cartridge ...");
- system_loadSpecial_bsxSlotted->setIcon(QIcon(":/16x16/document-open.png"));
- system_loadSpecial_bsx = system_loadSpecial->addAction("Load BS-X Cartridge ...");
- system_loadSpecial_bsx->setIcon(QIcon(":/16x16/document-open.png"));
- system_loadSpecial_sufamiTurbo = system_loadSpecial->addAction("Load Sufami Turbo Cartridge ...");
- system_loadSpecial_sufamiTurbo->setIcon(QIcon(":/16x16/document-open.png"));
- system_loadSpecial_superGameBoy = system_loadSpecial->addAction("Load Super Game Boy Cartridge ...");
- system_loadSpecial_superGameBoy->setIcon(QIcon(":/16x16/document-open.png"));
- system->addSeparator();
- system->addAction(system_power = new QbCheckAction("Power", 0));
- system_reset = system->addAction("Reset");
- system_reset->setIcon(QIcon(":/16x16/view-refresh.png"));
- system->addSeparator();
- system_port1 = system->addMenu("Controller Port 1");
- system_port1->setIcon(QIcon(":/16x16/input-gaming.png"));
- system_port1->addAction(system_port1_none = new QbRadioAction("None", 0));
- system_port1->addAction(system_port1_joypad = new QbRadioAction("Joypad", 0));
- system_port1->addAction(system_port1_multitap = new QbRadioAction("Multitap", 0));
- system_port1->addAction(system_port1_mouse = new QbRadioAction("Mouse", 0));
- system_port2 = system->addMenu("Controller Port 2");
- system_port2->setIcon(QIcon(":/16x16/input-gaming.png"));
- system_port2->addAction(system_port2_none = new QbRadioAction("None", 0));
- system_port2->addAction(system_port2_joypad = new QbRadioAction("Joypad", 0));
- system_port2->addAction(system_port2_multitap = new QbRadioAction("Multitap", 0));
- system_port2->addAction(system_port2_mouse = new QbRadioAction("Mouse", 0));
- system_port2->addAction(system_port2_superscope = new QbRadioAction("Super Scope", 0));
- system_port2->addAction(system_port2_justifier = new QbRadioAction("Justifier", 0));
- system_port2->addAction(system_port2_justifiers = new QbRadioAction("Two Justifiers", 0));
- #if !defined(PLATFORM_OSX)
- system->addSeparator();
- #endif
- system_exit = system->addAction("Exit");
- system_exit->setIcon(QIcon(":/16x16/process-stop.png"));
- system_exit->setMenuRole(QAction::QuitRole);
+ system = menuBar->addMenu("&System");
- settings = menuBar->addMenu("Settings");
- settings_videoMode = settings->addMenu("Video Mode");
- settings_videoMode->setIcon(QIcon(":/16x16/video-display.png"));
- settings_videoMode->addAction(settings_videoMode_1x = new QbRadioAction("Scale 1x", 0));
- settings_videoMode->addAction(settings_videoMode_2x = new QbRadioAction("Scale 2x", 0));
- settings_videoMode->addAction(settings_videoMode_3x = new QbRadioAction("Scale 3x", 0));
- settings_videoMode->addAction(settings_videoMode_4x = new QbRadioAction("Scale 4x", 0));
- settings_videoMode->addAction(settings_videoMode_max = new QbRadioAction("Scale Max", 0));
- settings_videoMode->addSeparator();
- settings_videoMode->addAction(settings_videoMode_correctAspectRatio = new QbCheckAction("Correct Aspect Ratio", 0));
- settings_videoMode->addAction(settings_videoMode_fullscreen = new QbCheckAction("Fullscreen", 0));
- settings_videoMode->addSeparator();
- settings_videoMode->addAction(settings_videoMode_ntsc = new QbRadioAction("NTSC", 0));
- settings_videoMode->addAction(settings_videoMode_pal = new QbRadioAction("PAL", 0));
+ system_load = system->addAction("Load &Cartridge ...");
+ system_load->setIcon(QIcon(":/16x16/document-open.png"));
- if(filter.opened()) {
- settings_videoFilter = settings->addMenu("Video Filter");
- settings_videoFilter->setIcon(QIcon(":/16x16/image-x-generic.png"));
+ system_loadSpecial = system->addMenu("Load &Special");
+ system_loadSpecial->setIcon(QIcon(":/16x16/document-open.png"));
- settings_videoFilter_configure = settings_videoFilter->addAction("Configure Active Filter ...");
- settings_videoFilter_configure->setIcon(QIcon(":/16x16/preferences-desktop.png"));
- settings_videoFilter->addSeparator();
+ system_loadSpecial_bsxSlotted = system_loadSpecial->addAction("Load BS-X &Slotted Cartridge ...");
+ system_loadSpecial_bsxSlotted->setIcon(QIcon(":/16x16/document-open.png"));
- settings_videoFilter->addAction(settings_videoFilter_none = new QbRadioAction("None", 0));
- settings_videoFilter_list.add(settings_videoFilter_none);
+ system_loadSpecial_bsx = system_loadSpecial->addAction("Load &BS-X Cartridge ...");
+ system_loadSpecial_bsx->setIcon(QIcon(":/16x16/document-open.png"));
- lstring filterlist;
- filterlist.split(";", filter.dl_supported());
- for(unsigned i = 0; i < filterlist.size(); i++) {
- QbRadioAction *action = new QbRadioAction(utf8() << filterlist[i], 0);
- settings_videoFilter->addAction(action);
- settings_videoFilter_list.add(action);
- }
+ system_loadSpecial_sufamiTurbo = system_loadSpecial->addAction("Load Sufami &Turbo Cartridge ...");
+ system_loadSpecial_sufamiTurbo->setIcon(QIcon(":/16x16/document-open.png"));
+
+ system_loadSpecial_superGameBoy = system_loadSpecial->addAction("Load Super &Game Boy Cartridge ...");
+ system_loadSpecial_superGameBoy->setIcon(QIcon(":/16x16/document-open.png"));
+
+ system->addSeparator();
+
+ system->addAction(system_power = new QbCheckAction("&Power", 0));
+
+ system_reset = system->addAction("&Reset");
+ system_reset->setIcon(QIcon(":/16x16/view-refresh.png"));
+
+ system->addSeparator();
+
+ system_port1 = system->addMenu("Controller Port &1");
+ system_port1->setIcon(QIcon(":/16x16/input-gaming.png"));
+ system_port1->addAction(system_port1_none = new QbRadioAction("&None", 0));
+ system_port1->addAction(system_port1_gamepad = new QbRadioAction("&Gamepad", 0));
+ system_port1->addAction(system_port1_asciipad = new QbRadioAction("&asciiPad", 0));
+ system_port1->addAction(system_port1_multitap = new QbRadioAction("&Multitap", 0));
+ system_port1->addAction(system_port1_mouse = new QbRadioAction("&Mouse", 0));
+
+ system_port2 = system->addMenu("Controller Port &2");
+ system_port2->setIcon(QIcon(":/16x16/input-gaming.png"));
+ system_port2->addAction(system_port2_none = new QbRadioAction("&None", 0));
+ system_port2->addAction(system_port2_gamepad = new QbRadioAction("&Gamepad", 0));
+ system_port2->addAction(system_port2_asciipad = new QbRadioAction("&asciiPad", 0));
+ system_port2->addAction(system_port2_multitap = new QbRadioAction("&Multitap", 0));
+ system_port2->addAction(system_port2_mouse = new QbRadioAction("&Mouse", 0));
+ system_port2->addAction(system_port2_superscope = new QbRadioAction("&Super Scope", 0));
+ system_port2->addAction(system_port2_justifier = new QbRadioAction("&Justifier", 0));
+ system_port2->addAction(system_port2_justifiers = new QbRadioAction("Two &Justifiers", 0));
+
+ #if !defined(PLATFORM_OSX)
+ system->addSeparator();
+ #endif
+
+ system_exit = system->addAction("E&xit");
+ system_exit->setIcon(QIcon(":/16x16/process-stop.png"));
+ system_exit->setMenuRole(QAction::QuitRole);
+
+ settings = menuBar->addMenu("S&ettings");
+
+ settings_videoMode = settings->addMenu("Video &Mode");
+ settings_videoMode->setIcon(QIcon(":/16x16/video-display.png"));
+
+ settings_videoMode->addAction(settings_videoMode_1x = new QbRadioAction("Scale &1x", 0));
+
+ settings_videoMode->addAction(settings_videoMode_2x = new QbRadioAction("Scale &2x", 0));
+
+ settings_videoMode->addAction(settings_videoMode_3x = new QbRadioAction("Scale &3x", 0));
+
+ settings_videoMode->addAction(settings_videoMode_4x = new QbRadioAction("Scale &4x", 0));
+
+ settings_videoMode->addAction(settings_videoMode_5x = new QbRadioAction("Scale &5x", 0));
+
+ settings_videoMode->addSeparator();
+
+ settings_videoMode->addAction(settings_videoMode_correctAspectRatio = new QbCheckAction("Correct &Aspect Ratio", 0));
+
+ settings_videoMode->addAction(settings_videoMode_fullscreen = new QbCheckAction("&Fullscreen", 0));
+
+ settings_videoMode->addSeparator();
+
+ settings_videoMode->addAction(settings_videoMode_ntsc = new QbRadioAction("&NTSC", 0));
+ settings_videoMode->addAction(settings_videoMode_pal = new QbRadioAction("&PAL", 0));
+
+ if(filter.opened()) {
+ settings_videoFilter = settings->addMenu("Video &Filter");
+ settings_videoFilter->setIcon(QIcon(":/16x16/image-x-generic.png"));
+
+ settings_videoFilter_configure = settings_videoFilter->addAction("&Configure Active Filter ...");
+ settings_videoFilter_configure->setIcon(QIcon(":/16x16/preferences-desktop.png"));
+ settings_videoFilter->addSeparator();
+
+ settings_videoFilter->addAction(settings_videoFilter_none = new QbRadioAction("&None", 0));
+ settings_videoFilter_list.add(settings_videoFilter_none);
+
+ lstring filterlist;
+ filterlist.split(";", filter.dl_supported());
+ for(unsigned i = 0; i < filterlist.size(); i++) {
+ QbRadioAction *action = new QbRadioAction(filterlist[i], 0);
+ settings_videoFilter->addAction(action);
+ settings_videoFilter_list.add(action);
}
+ }
- settings->addAction(settings_smoothVideo = new QbCheckAction("Smooth Video Output", 0));
- settings->addSeparator();
- settings->addAction(settings_muteAudio = new QbCheckAction("Mute Audio Output", 0));
- settings->addSeparator();
- settings_emulationSpeed = settings->addMenu("Emulation Speed");
- settings_emulationSpeed->setIcon(QIcon(":/16x16/appointment-new.png"));
- settings_emulationSpeed->addAction(settings_emulationSpeed_slowest = new QbRadioAction("50%", 0));
- settings_emulationSpeed->addAction(settings_emulationSpeed_slow = new QbRadioAction("75%", 0));
- settings_emulationSpeed->addAction(settings_emulationSpeed_normal = new QbRadioAction("100%", 0));
- settings_emulationSpeed->addAction(settings_emulationSpeed_fast = new QbRadioAction("150%", 0));
- settings_emulationSpeed->addAction(settings_emulationSpeed_fastest = new QbRadioAction("200%", 0));
- settings_emulationSpeed->addSeparator();
- settings_emulationSpeed->addAction(settings_emulationSpeed_syncVideo = new QbCheckAction("Sync Video", 0));
- settings_emulationSpeed->addAction(settings_emulationSpeed_syncAudio = new QbCheckAction("Sync Audio", 0));
- settings_configuration = settings->addAction("Configuration ...");
- settings_configuration->setIcon(QIcon(":/16x16/preferences-desktop.png"));
- settings_configuration->setMenuRole(QAction::PreferencesRole);
+ settings->addAction(settings_smoothVideo = new QbCheckAction("&Smooth Video Output", 0));
- tools = menuBar->addMenu("Tools");
- tools_cheatEditor = tools->addAction("Cheat Editor ...");
- tools_cheatEditor->setIcon(QIcon(":/16x16/accessories-text-editor.png"));
- tools_cheatFinder = tools->addAction("Cheat Finder ...");
- tools_cheatFinder->setIcon(QIcon(":/16x16/system-search.png"));
- tools_stateManager = tools->addAction("State Manager ...");
- tools_stateManager->setIcon(QIcon(":/16x16/system-file-manager.png"));
- tools->addSeparator();
- tools_captureScreenshot = tools->addAction("Capture Screenshot");
- tools_captureScreenshot->setIcon(QIcon(":/16x16/image-x-generic.png"));
- tools_debugger = tools->addAction("Debugger ...");
- tools_debugger->setIcon(QIcon(":/16x16/utilities-terminal.png"));
- #if !defined(DEBUGGER)
- tools_debugger->setVisible(false);
- #endif
+ settings->addSeparator();
- help = menuBar->addMenu("Help");
- help_documentation = help->addAction("Documentation ...");
- help_documentation->setIcon(QIcon(":/16x16/text-x-generic.png"));
- help_license = help->addAction("License ...");
- help_license->setIcon(QIcon(":/16x16/text-x-generic.png"));
- #if !defined(PLATFORM_OSX)
- help->addSeparator();
- #endif
- help_about = help->addAction("About ...");
- help_about->setIcon(QIcon(":/16x16/help-browser.png"));
- help_about->setMenuRole(QAction::AboutRole);
+ settings->addAction(settings_muteAudio = new QbCheckAction("&Mute Audio Output", 0));
+
+ settings->addSeparator();
+
+ settings_emulationSpeed = settings->addMenu("Emulation &Speed");
+ settings_emulationSpeed->setIcon(QIcon(":/16x16/appointment-new.png"));
+
+ settings_emulationSpeed->addAction(settings_emulationSpeed_slowest = new QbRadioAction("50%", 0));
+
+ settings_emulationSpeed->addAction(settings_emulationSpeed_slow = new QbRadioAction("75%", 0));
+
+ settings_emulationSpeed->addAction(settings_emulationSpeed_normal = new QbRadioAction("100%", 0));
+
+ settings_emulationSpeed->addAction(settings_emulationSpeed_fast = new QbRadioAction("150%", 0));
+
+ settings_emulationSpeed->addAction(settings_emulationSpeed_fastest = new QbRadioAction("200%", 0));
+
+ settings_emulationSpeed->addSeparator();
+
+ settings_emulationSpeed->addAction(settings_emulationSpeed_syncVideo = new QbCheckAction("Sync &Video", 0));
+
+ settings_emulationSpeed->addAction(settings_emulationSpeed_syncAudio = new QbCheckAction("Sync &Audio", 0));
+
+ settings_configuration = settings->addAction("&Configuration ...");
+ settings_configuration->setIcon(QIcon(":/16x16/preferences-desktop.png"));
+ settings_configuration->setMenuRole(QAction::PreferencesRole);
+
+ tools = menuBar->addMenu("&Tools");
+
+ tools_cheatEditor = tools->addAction("Cheat &Editor ...");
+ tools_cheatEditor->setIcon(QIcon(":/16x16/accessories-text-editor.png"));
+
+ tools_cheatFinder = tools->addAction("Cheat &Finder ...");
+ tools_cheatFinder->setIcon(QIcon(":/16x16/system-search.png"));
+
+ tools_stateManager = tools->addAction("&State Manager ...");
+ tools_stateManager->setIcon(QIcon(":/16x16/system-file-manager.png"));
+
+ tools->addSeparator();
+
+ tools_captureScreenshot = tools->addAction("&Capture Screenshot");
+ tools_captureScreenshot->setIcon(QIcon(":/16x16/image-x-generic.png"));
+
+ tools_debugger = tools->addAction("&Debugger ...");
+ tools_debugger->setIcon(QIcon(":/16x16/utilities-terminal.png"));
+ #if !defined(DEBUGGER)
+ tools_debugger->setVisible(false);
+ #endif
+
+ help = menuBar->addMenu("&Help");
+
+ help_documentation = help->addAction("&Documentation ...");
+ help_documentation->setIcon(QIcon(":/16x16/text-x-generic.png"));
+
+ help_license = help->addAction("&License ...");
+ help_license->setIcon(QIcon(":/16x16/text-x-generic.png"));
+
+ #if !defined(PLATFORM_OSX)
+ help->addSeparator();
+ #endif
+
+ help_about = help->addAction("&About ...");
+ help_about->setIcon(QIcon(":/16x16/help-browser.png"));
+ help_about->setMenuRole(QAction::AboutRole);
//canvas
canvasContainer = new CanvasObject;
@@ -180,11 +230,13 @@ MainWindow::MainWindow() : QbWindow(config.geometry.mainWindow) {
connect(system_power, SIGNAL(triggered()), this, SLOT(power()));
connect(system_reset, SIGNAL(triggered()), this, SLOT(reset()));
connect(system_port1_none, SIGNAL(triggered()), this, SLOT(setPort1None()));
- connect(system_port1_joypad, SIGNAL(triggered()), this, SLOT(setPort1Joypad()));
+ connect(system_port1_gamepad, SIGNAL(triggered()), this, SLOT(setPort1Gamepad()));
+ connect(system_port1_asciipad, SIGNAL(triggered()), this, SLOT(setPort1Asciipad()));
connect(system_port1_multitap, SIGNAL(triggered()), this, SLOT(setPort1Multitap()));
connect(system_port1_mouse, SIGNAL(triggered()), this, SLOT(setPort1Mouse()));
connect(system_port2_none, SIGNAL(triggered()), this, SLOT(setPort2None()));
- connect(system_port2_joypad, SIGNAL(triggered()), this, SLOT(setPort2Joypad()));
+ connect(system_port2_gamepad, SIGNAL(triggered()), this, SLOT(setPort2Gamepad()));
+ connect(system_port2_asciipad, SIGNAL(triggered()), this, SLOT(setPort2Asciipad()));
connect(system_port2_multitap, SIGNAL(triggered()), this, SLOT(setPort2Multitap()));
connect(system_port2_mouse, SIGNAL(triggered()), this, SLOT(setPort2Mouse()));
connect(system_port2_superscope, SIGNAL(triggered()), this, SLOT(setPort2SuperScope()));
@@ -195,7 +247,7 @@ MainWindow::MainWindow() : QbWindow(config.geometry.mainWindow) {
connect(settings_videoMode_2x, SIGNAL(triggered()), this, SLOT(setVideoMode2x()));
connect(settings_videoMode_3x, SIGNAL(triggered()), this, SLOT(setVideoMode3x()));
connect(settings_videoMode_4x, SIGNAL(triggered()), this, SLOT(setVideoMode4x()));
- connect(settings_videoMode_max, SIGNAL(triggered()), this, SLOT(setVideoModeMax()));
+ connect(settings_videoMode_5x, SIGNAL(triggered()), this, SLOT(setVideoMode5x()));
connect(settings_videoMode_correctAspectRatio, SIGNAL(triggered()), this, SLOT(toggleAspectCorrection()));
connect(settings_videoMode_fullscreen, SIGNAL(triggered()), this, SLOT(toggleFullscreen()));
connect(settings_videoMode_ntsc, SIGNAL(triggered()), this, SLOT(setVideoNtsc()));
@@ -234,49 +286,52 @@ void MainWindow::syncUi() {
system_power->setEnabled(SNES::cartridge.loaded());
system_reset->setEnabled(SNES::cartridge.loaded() && application.power);
- system_port1_none->setChecked (SNES::config.controller_port1 == SNES::Input::DeviceNone);
- system_port1_joypad->setChecked (SNES::config.controller_port1 == SNES::Input::DeviceJoypad);
- system_port1_multitap->setChecked (SNES::config.controller_port1 == SNES::Input::DeviceMultitap);
- system_port1_mouse->setChecked (SNES::config.controller_port1 == SNES::Input::DeviceMouse);
- system_port2_none->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceNone);
- system_port2_joypad->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceJoypad);
- system_port2_multitap->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceMultitap);
- system_port2_mouse->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceMouse);
- system_port2_superscope->setChecked(SNES::config.controller_port2 == SNES::Input::DeviceSuperScope);
- system_port2_justifier->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceJustifier);
- system_port2_justifiers->setChecked(SNES::config.controller_port2 == SNES::Input::DeviceJustifiers);
+ system_port1_none->setChecked (config().input.port1 == ControllerPort1::None);
+ system_port1_gamepad->setChecked (config().input.port1 == ControllerPort1::Gamepad);
+ system_port1_asciipad->setChecked (config().input.port1 == ControllerPort1::Asciipad);
+ system_port1_multitap->setChecked (config().input.port1 == ControllerPort1::Multitap);
+ system_port1_mouse->setChecked (config().input.port1 == ControllerPort1::Mouse);
- settings_videoMode_1x->setChecked (config.video.context->multiplier == 1);
- settings_videoMode_2x->setChecked (config.video.context->multiplier == 2);
- settings_videoMode_3x->setChecked (config.video.context->multiplier == 3);
- settings_videoMode_4x->setChecked (config.video.context->multiplier == 4);
- settings_videoMode_max->setChecked(config.video.context->multiplier >= 5);
+ system_port2_none->setChecked (config().input.port2 == ControllerPort2::None);
+ system_port2_gamepad->setChecked (config().input.port2 == ControllerPort2::Gamepad);
+ system_port2_asciipad->setChecked (config().input.port2 == ControllerPort2::Asciipad);
+ system_port2_multitap->setChecked (config().input.port2 == ControllerPort2::Multitap);
+ system_port2_mouse->setChecked (config().input.port2 == ControllerPort2::Mouse);
+ system_port2_superscope->setChecked(config().input.port2 == ControllerPort2::SuperScope);
+ system_port2_justifier->setChecked (config().input.port2 == ControllerPort2::Justifier);
+ system_port2_justifiers->setChecked(config().input.port2 == ControllerPort2::Justifiers);
- settings_videoMode_correctAspectRatio->setChecked(config.video.context->correctAspectRatio);
- settings_videoMode_fullscreen->setChecked(config.video.isFullscreen);
- settings_videoMode_ntsc->setChecked(config.video.context->region == 0);
- settings_videoMode_pal->setChecked (config.video.context->region == 1);
+ settings_videoMode_1x->setChecked(config().video.context->multiplier == 1);
+ settings_videoMode_2x->setChecked(config().video.context->multiplier == 2);
+ settings_videoMode_3x->setChecked(config().video.context->multiplier == 3);
+ settings_videoMode_4x->setChecked(config().video.context->multiplier == 4);
+ settings_videoMode_5x->setChecked(config().video.context->multiplier == 5);
+
+ settings_videoMode_correctAspectRatio->setChecked(config().video.context->correctAspectRatio);
+ settings_videoMode_fullscreen->setChecked(config().video.isFullscreen);
+ settings_videoMode_ntsc->setChecked(config().video.context->region == 0);
+ settings_videoMode_pal->setChecked (config().video.context->region == 1);
if(filter.opened()) {
//only enable configuration option if the active filter supports it ...
settings_videoFilter_configure->setEnabled(filter.settings());
for(unsigned i = 0; i < settings_videoFilter_list.size(); i++) {
- settings_videoFilter_list[i]->setChecked(config.video.context->swFilter == i);
+ settings_videoFilter_list[i]->setChecked(config().video.context->swFilter == i);
}
}
- settings_smoothVideo->setChecked(config.video.context->hwFilter == 1);
- settings_muteAudio->setChecked(config.audio.mute);
+ settings_smoothVideo->setChecked(config().video.context->hwFilter == 1);
+ settings_muteAudio->setChecked(config().audio.mute);
- settings_emulationSpeed_slowest->setChecked(config.system.speed == 0);
- settings_emulationSpeed_slow->setChecked (config.system.speed == 1);
- settings_emulationSpeed_normal->setChecked (config.system.speed == 2);
- settings_emulationSpeed_fast->setChecked (config.system.speed == 3);
- settings_emulationSpeed_fastest->setChecked(config.system.speed == 4);
+ settings_emulationSpeed_slowest->setChecked(config().system.speed == 0);
+ settings_emulationSpeed_slow->setChecked (config().system.speed == 1);
+ settings_emulationSpeed_normal->setChecked (config().system.speed == 2);
+ settings_emulationSpeed_fast->setChecked (config().system.speed == 3);
+ settings_emulationSpeed_fastest->setChecked(config().system.speed == 4);
- settings_emulationSpeed_syncVideo->setChecked(config.video.synchronize);
- settings_emulationSpeed_syncAudio->setChecked(config.audio.synchronize);
+ settings_emulationSpeed_syncVideo->setChecked(config().video.synchronize);
+ settings_emulationSpeed_syncAudio->setChecked(config().audio.synchronize);
}
bool MainWindow::isActive() {
@@ -292,15 +347,15 @@ void MainWindow::loadBsxSlottedCartridge() {
}
void MainWindow::loadBsxCartridge() {
- loaderWindow->loadBsxCartridge(config.path.bsx, "");
+ loaderWindow->loadBsxCartridge(config().path.bsx, "");
}
void MainWindow::loadSufamiTurboCartridge() {
- loaderWindow->loadSufamiTurboCartridge(config.path.st, "", "");
+ loaderWindow->loadSufamiTurboCartridge(config().path.st, "", "");
}
void MainWindow::loadSuperGameBoyCartridge() {
- loaderWindow->loadSuperGameBoyCartridge(config.path.sgb, "");
+ loaderWindow->loadSuperGameBoyCartridge(config().path.sgb, "");
}
void MainWindow::power() {
@@ -316,52 +371,102 @@ void MainWindow::reset() {
utility.modifySystemState(Utility::Reset);
}
-void MainWindow::setPort1None() { SNES::config.controller_port1 = SNES::Input::DeviceNone; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort1Joypad() { SNES::config.controller_port1 = SNES::Input::DeviceJoypad; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort1Multitap() { SNES::config.controller_port1 = SNES::Input::DeviceMultitap; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort1Mouse() { SNES::config.controller_port1 = SNES::Input::DeviceMouse; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort2None() { SNES::config.controller_port2 = SNES::Input::DeviceNone; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort2Joypad() { SNES::config.controller_port2 = SNES::Input::DeviceJoypad; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort2Multitap() { SNES::config.controller_port2 = SNES::Input::DeviceMultitap; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort2Mouse() { SNES::config.controller_port2 = SNES::Input::DeviceMouse; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort2SuperScope() { SNES::config.controller_port2 = SNES::Input::DeviceSuperScope; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort2Justifier() { SNES::config.controller_port2 = SNES::Input::DeviceJustifier; utility.updateControllers(); syncUi(); }
-void MainWindow::setPort2Justifiers() { SNES::config.controller_port2 = SNES::Input::DeviceJustifiers; utility.updateControllers(); syncUi(); }
+void MainWindow::setPort1None() {
+ config().input.port1 = ControllerPort1::None;
+ SNES::config.controller_port1 = SNES::Input::DeviceNone;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort1Gamepad() {
+ config().input.port1 = ControllerPort1::Gamepad;
+ SNES::config.controller_port1 = SNES::Input::DeviceJoypad;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort1Asciipad() {
+ config().input.port1 = ControllerPort1::Asciipad;
+ SNES::config.controller_port1 = SNES::Input::DeviceJoypad;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort1Multitap() {
+ config().input.port1 = ControllerPort1::Multitap;
+ SNES::config.controller_port1 = SNES::Input::DeviceMultitap;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort1Mouse() {
+ config().input.port1 = ControllerPort1::Mouse;
+ SNES::config.controller_port1 = SNES::Input::DeviceMouse;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort2None() {
+ config().input.port2 = ControllerPort2::None;
+ SNES::config.controller_port2 = SNES::Input::DeviceNone;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort2Gamepad() {
+ config().input.port2 = ControllerPort2::Gamepad;
+ SNES::config.controller_port2 = SNES::Input::DeviceJoypad;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort2Asciipad() {
+ config().input.port2 = ControllerPort2::Asciipad;
+ SNES::config.controller_port2 = SNES::Input::DeviceJoypad;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort2Multitap() {
+ config().input.port2 = ControllerPort2::Multitap;
+ SNES::config.controller_port2 = SNES::Input::DeviceMultitap;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort2Mouse() {
+ config().input.port2 = ControllerPort2::Mouse;
+ SNES::config.controller_port2 = SNES::Input::DeviceMouse;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort2SuperScope() {
+ config().input.port2 = ControllerPort2::SuperScope;
+ SNES::config.controller_port2 = SNES::Input::DeviceSuperScope;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort2Justifier() {
+ config().input.port2 = ControllerPort2::Justifier;
+ SNES::config.controller_port2 = SNES::Input::DeviceJustifier;
+ utility.updateControllers();
+}
+
+void MainWindow::setPort2Justifiers() {
+ config().input.port2 = ControllerPort2::Justifiers;
+ SNES::config.controller_port2 = SNES::Input::DeviceJustifiers;
+ utility.updateControllers();
+}
void MainWindow::quit() {
hide();
application.terminate = true;
}
-void MainWindow::setVideoMode1x() { config.video.context->multiplier = 1; utility.resizeMainWindow(); syncUi(); }
-void MainWindow::setVideoMode2x() { config.video.context->multiplier = 2; utility.resizeMainWindow(); syncUi(); }
-void MainWindow::setVideoMode3x() { config.video.context->multiplier = 3; utility.resizeMainWindow(); syncUi(); }
-void MainWindow::setVideoMode4x() { config.video.context->multiplier = 4; utility.resizeMainWindow(); syncUi(); }
-void MainWindow::setVideoModeMax() { config.video.context->multiplier = 9; utility.resizeMainWindow(); syncUi(); }
+void MainWindow::setVideoMode1x() { utility.setScale(1); }
+void MainWindow::setVideoMode2x() { utility.setScale(2); }
+void MainWindow::setVideoMode3x() { utility.setScale(3); }
+void MainWindow::setVideoMode4x() { utility.setScale(4); }
+void MainWindow::setVideoMode5x() { utility.setScale(5); }
-void MainWindow::toggleAspectCorrection() {
- settings_videoMode_correctAspectRatio->toggleChecked();
- config.video.context->correctAspectRatio = settings_videoMode_correctAspectRatio->isChecked();
- utility.resizeMainWindow();
-}
+void MainWindow::toggleAspectCorrection() { utility.toggleAspectCorrection(); }
+void MainWindow::toggleFullscreen() { utility.toggleFullscreen(); }
-void MainWindow::toggleFullscreen() {
- settings_videoMode_fullscreen->toggleChecked();
- config.video.isFullscreen = settings_videoMode_fullscreen->isChecked();
- utility.updateFullscreenState();
- utility.resizeMainWindow();
- syncUi();
-}
+void MainWindow::setVideoNtsc() { utility.setNtscMode(); }
+void MainWindow::setVideoPal() { utility.setPalMode(); }
-void MainWindow::setVideoNtsc() { config.video.context->region = 0; utility.updateVideoMode(); utility.resizeMainWindow(); syncUi(); }
-void MainWindow::setVideoPal() { config.video.context->region = 1; utility.updateVideoMode(); utility.resizeMainWindow(); syncUi(); }
-
-void MainWindow::toggleSmoothVideo() {
- settings_smoothVideo->toggleChecked();
- config.video.context->hwFilter = settings_smoothVideo->isChecked();
- utility.updateHardwareFilter();
- syncUi();
-}
+void MainWindow::toggleSmoothVideo() { utility.toggleSmoothVideoOutput(); }
void MainWindow::configureFilter() {
QWidget *widget = filter.settings();
@@ -375,7 +480,7 @@ void MainWindow::configureFilter() {
void MainWindow::setFilter() {
for(unsigned i = 0; i < settings_videoFilter_list.size(); i++) {
if(sender() == settings_videoFilter_list[i]) {
- config.video.context->swFilter = i;
+ config().video.context->swFilter = i;
utility.updateSoftwareFilter();
syncUi();
return;
@@ -385,26 +490,17 @@ void MainWindow::setFilter() {
void MainWindow::muteAudio() {
settings_muteAudio->toggleChecked();
- config.audio.mute = settings_muteAudio->isChecked();
+ config().audio.mute = settings_muteAudio->isChecked();
}
-void MainWindow::setSpeedSlowest() { config.system.speed = 0; utility.updateEmulationSpeed(); syncUi(); }
-void MainWindow::setSpeedSlow() { config.system.speed = 1; utility.updateEmulationSpeed(); syncUi(); }
-void MainWindow::setSpeedNormal() { config.system.speed = 2; utility.updateEmulationSpeed(); syncUi(); }
-void MainWindow::setSpeedFast() { config.system.speed = 3; utility.updateEmulationSpeed(); syncUi(); }
-void MainWindow::setSpeedFastest() { config.system.speed = 4; utility.updateEmulationSpeed(); syncUi(); }
+void MainWindow::setSpeedSlowest() { config().system.speed = 0; utility.updateEmulationSpeed(); syncUi(); }
+void MainWindow::setSpeedSlow() { config().system.speed = 1; utility.updateEmulationSpeed(); syncUi(); }
+void MainWindow::setSpeedNormal() { config().system.speed = 2; utility.updateEmulationSpeed(); syncUi(); }
+void MainWindow::setSpeedFast() { config().system.speed = 3; utility.updateEmulationSpeed(); syncUi(); }
+void MainWindow::setSpeedFastest() { config().system.speed = 4; utility.updateEmulationSpeed(); syncUi(); }
-void MainWindow::syncVideo() {
- settings_emulationSpeed_syncVideo->toggleChecked();
- config.video.synchronize = settings_emulationSpeed_syncVideo->isChecked();
- utility.updateAvSync();
-}
-
-void MainWindow::syncAudio() {
- settings_emulationSpeed_syncAudio->toggleChecked();
- config.audio.synchronize = settings_emulationSpeed_syncAudio->isChecked();
- utility.updateAvSync();
-}
+void MainWindow::syncVideo() { utility.toggleSynchronizeVideo(); }
+void MainWindow::syncAudio() { utility.toggleSynchronizeAudio(); }
void MainWindow::showConfigWindow() { settingsWindow->show(); }
diff --git a/src/ui_qt/base/main.moc.hpp b/src/ui_qt/base/main.moc.hpp
index 338683e5..b717752c 100644
--- a/src/ui_qt/base/main.moc.hpp
+++ b/src/ui_qt/base/main.moc.hpp
@@ -31,12 +31,14 @@ public:
QAction *system_reset;
QMenu *system_port1;
QbRadioAction *system_port1_none;
- QbRadioAction *system_port1_joypad;
+ QbRadioAction *system_port1_gamepad;
+ QbRadioAction *system_port1_asciipad;
QbRadioAction *system_port1_multitap;
QbRadioAction *system_port1_mouse;
QMenu *system_port2;
QbRadioAction *system_port2_none;
- QbRadioAction *system_port2_joypad;
+ QbRadioAction *system_port2_gamepad;
+ QbRadioAction *system_port2_asciipad;
QbRadioAction *system_port2_multitap;
QbRadioAction *system_port2_mouse;
QbRadioAction *system_port2_superscope;
@@ -49,7 +51,7 @@ public:
QbRadioAction *settings_videoMode_2x;
QbRadioAction *settings_videoMode_3x;
QbRadioAction *settings_videoMode_4x;
- QbRadioAction *settings_videoMode_max;
+ QbRadioAction *settings_videoMode_5x;
QbCheckAction *settings_videoMode_correctAspectRatio;
QbCheckAction *settings_videoMode_fullscreen;
QbRadioAction *settings_videoMode_ntsc;
@@ -79,10 +81,10 @@ public:
QAction *help_documentation;
QAction *help_license;
QAction *help_about;
- //
+
CanvasObject *canvasContainer;
- QVBoxLayout *canvasLayout;
- CanvasWidget *canvas;
+ QVBoxLayout *canvasLayout;
+ CanvasWidget *canvas;
QLabel *systemState;
void syncUi();
@@ -99,11 +101,13 @@ public slots:
void power();
void reset();
void setPort1None();
- void setPort1Joypad();
+ void setPort1Gamepad();
+ void setPort1Asciipad();
void setPort1Multitap();
void setPort1Mouse();
void setPort2None();
- void setPort2Joypad();
+ void setPort2Gamepad();
+ void setPort2Asciipad();
void setPort2Multitap();
void setPort2Mouse();
void setPort2SuperScope();
@@ -114,7 +118,7 @@ public slots:
void setVideoMode2x();
void setVideoMode3x();
void setVideoMode4x();
- void setVideoModeMax();
+ void setVideoMode5x();
void toggleAspectCorrection();
void toggleFullscreen();
void setVideoNtsc();
diff --git a/src/ui_qt/config.cpp b/src/ui_qt/config.cpp
index c6f3bd15..17d70617 100644
--- a/src/ui_qt/config.cpp
+++ b/src/ui_qt/config.cpp
@@ -1,3 +1,8 @@
+Configuration &config() {
+ static Configuration configuration;
+ return configuration;
+}
+
bool Configuration::load(const char *filename) {
if(configuration::load(filename) == false) return false;
SNES::config.superfx.speed = max(0, min(2, SNES::config.superfx.speed));
@@ -5,21 +10,6 @@ bool Configuration::load(const char *filename) {
return true;
}
-void Configuration::attachJoypad(Configuration::Input::Joypad &joypad, const char *name) {
- attach(joypad.up = "none", string() << name << ".up");
- attach(joypad.down = "none", string() << name << ".down");
- attach(joypad.left = "none", string() << name << ".left");
- attach(joypad.right = "none", string() << name << ".right");
- attach(joypad.a = "none", string() << name << ".a");
- attach(joypad.b = "none", string() << name << ".b");
- attach(joypad.x = "none", string() << name << ".x");
- attach(joypad.y = "none", string() << name << ".y");
- attach(joypad.l = "none", string() << name << ".l");
- attach(joypad.r = "none", string() << name << ".r");
- attach(joypad.select = "none", string() << name << ".select");
- attach(joypad.start = "none", string() << name << ".start");
-}
-
Configuration::Configuration() {
//========
//external
@@ -62,16 +52,25 @@ Configuration::Configuration() {
attach(file.autodetect_type = false, "file.autodetectType");
attach(file.bypass_patch_crc32 = false, "file.bypassPatchCrc32");
- attach(path.current = "", "path.current");
- attach(path.rom = "", "path.rom");
- attach(path.save = "", "path.save");
- attach(path.state = "", "path.state");
- attach(path.patch = "", "path.patch");
- attach(path.cheat = "", "path.cheat");
- attach(path.data = "", "path.data");
- attach(path.bsx = "", "path.bsx");
- attach(path.st = "", "path.st");
- attach(path.sgb = "", "path.sgb");
+ attach(path.rom = "", "path.rom");
+ attach(path.save = "", "path.save");
+ attach(path.state = "", "path.state");
+ attach(path.patch = "", "path.patch");
+ attach(path.cheat = "", "path.cheat");
+ attach(path.data = "", "path.data");
+ attach(path.bsx = "", "path.bsx");
+ attach(path.st = "", "path.st");
+ attach(path.sgb = "", "path.sgb");
+ attach(path.fragmentShader = "", "path.fragmentShader");
+ attach(path.vertexShader = "", "path.vertexShader");
+
+ attach(path.current.folder = "", "path.current.folder");
+ attach(path.current.shader = "", "path.current.shader");
+ attach(path.current.cartridge = "", "path.current.cartridge");
+ attach(path.current.bsx = "", "path.current.bsx");
+ attach(path.current.st = "", "path.current.st");
+ attach(path.current.sgb = "", "path.current.sgb");
+ attach(path.current.filter = 0, "path.current.filter");
video.context = &video.windowed;
attach(video.isFullscreen = false, "video.isFullscreen");
@@ -80,6 +79,7 @@ Configuration::Configuration() {
attach(video.contrastAdjust = 0, "video.contrastAdjust");
attach(video.brightnessAdjust = 0, "video.brightnessAdjust");
attach(video.gammaAdjust = 0, "video.gammaAdjust");
+ attach(video.scanlineAdjust = 100, "video.scanlineAdjust");
attach(video.enableGammaRamp = true, "video.enableGammaRamp");
attach(video.ntscAspectRatio = 54.0 / 47.0, "video.ntscAspectRatio", "NTSC aspect ratio (x / y)");
@@ -107,98 +107,21 @@ Configuration::Configuration() {
attach(audio.outputFrequency = 48000, "audio.outputFrequency");
attach(audio.inputFrequency = 32000, "audio.inputFrequency");
+ attach(input.port1 = ControllerPort1::Gamepad, "input.port1");
+ attach(input.port2 = ControllerPort2::Gamepad, "input.port2");
attach(input.focusPolicy = Input::FocusPolicyIgnoreInput, "input.focusPolicy");
attach(input.allowInvalidInput = false, "input.allowInvalidInput", "Allow up+down / left+right combinations; may trigger bugs in some games");
- attach(input.joypad1.up = "keyboard00.up", "input.joypad1.up");
- attach(input.joypad1.down = "keyboard00.down", "input.joypad1.down");
- attach(input.joypad1.left = "keyboard00.left", "input.joypad1.left");
- attach(input.joypad1.right = "keyboard00.right", "input.joypad1.right");
- attach(input.joypad1.a = "keyboard00.x", "input.joypad1.a");
- attach(input.joypad1.b = "keyboard00.z", "input.joypad1.b");
- attach(input.joypad1.x = "keyboard00.s", "input.joypad1.x");
- attach(input.joypad1.y = "keyboard00.a", "input.joypad1.y");
- attach(input.joypad1.l = "keyboard00.d", "input.joypad1.l");
- attach(input.joypad1.r = "keyboard00.c", "input.joypad1.r");
- attach(input.joypad1.select = "keyboard00.rshift", "input.joypad1.select");
- attach(input.joypad1.start = "keyboard00.return", "input.joypad1.start");
-
- //these are all mapped to "none" by default
- attachJoypad(input.joypad2, "input.joypad2");
- attachJoypad(input.multitap1a, "input.multitap1a");
- attachJoypad(input.multitap1b, "input.multitap1b");
- attachJoypad(input.multitap1c, "input.multitap1c");
- attachJoypad(input.multitap1d, "input.multitap1d");
- attachJoypad(input.multitap2a, "input.multitap2a");
- attachJoypad(input.multitap2b, "input.multitap2b");
- attachJoypad(input.multitap2c, "input.multitap2c");
- attachJoypad(input.multitap2d, "input.multitap2d");
-
- attach(input.mouse1.x = "mouse00.x", "input.mouse1.x");
- attach(input.mouse1.y = "mouse00.y", "input.mouse1.y");
- attach(input.mouse1.left = "mouse00.button00", "input.mouse1.left");
- attach(input.mouse1.right = "mouse00.button02", "input.mouse1.right");
-
- //more likely a user will only use one mouse at a time, than for a system to have two mice
- attach(input.mouse2.x = "mouse00.x", "input.mouse2.x");
- attach(input.mouse2.y = "mouse00.y", "input.mouse2.y");
- attach(input.mouse2.left = "mouse00.button00", "input.mouse2.left");
- attach(input.mouse2.right = "mouse00.button02", "input.mouse2.right");
-
- //unlikely a user will have a five-button mouse for turbo / pause mapping
- attach(input.superscope.x = "mouse00.x", "input.superscope.x");
- attach(input.superscope.y = "mouse00.y", "input.superscope.y");
- attach(input.superscope.trigger = "mouse00.button00", "input.superscope.trigger");
- attach(input.superscope.cursor = "mouse00.button02", "input.superscope.cursor");
- attach(input.superscope.turbo = "keyboard00.t", "input.superscope.turbo");
- attach(input.superscope.pause = "keyboard00.p", "input.superscope.pause");
-
- attach(input.justifier1.x = "mouse00.x", "input.justifier1.x");
- attach(input.justifier1.y = "mouse00.y", "input.justifier1.y");
- attach(input.justifier1.trigger = "mouse00.button00", "input.justifier1.trigger");
- attach(input.justifier1.start = "mouse00.button02", "input.jusitifer1.start");
-
- attach(input.justifier2.x = "mouse01.x", "input.justifier2.x");
- attach(input.justifier2.y = "mouse01.y", "input.justifier2.y");
- attach(input.justifier2.trigger = "mouse01.button00", "input.justifier2.trigger");
- attach(input.justifier2.start = "mouse01.button02", "input.justifier2.start");
-
- attach(input.uiGeneral.loadCartridge = "none", "input.uiGeneral.loadCartridge");
- attach(input.uiGeneral.pauseEmulation = "keyboard00.pause", "input.uiGeneral.pauseEmulation");
- attach(input.uiGeneral.resetSystem = "none", "input.uiGeneral.resetSystem");
- attach(input.uiGeneral.powerCycleSystem = "none", "input.uiGeneral.powerCycleSystem");
-
- attach(input.uiGeneral.captureScreenshot = "none", "input.uiGeneral.captureScreenshot");
- attach(input.uiGeneral.showStateManager = "keyboard00.f3", "input.uiGeneral.showStateManager");
-
- attach(input.uiGeneral.quickLoad1 = "keyboard00.f4", "input.uiGeneral.quickLoad1");
- attach(input.uiGeneral.quickLoad2 = "none", "input.uiGeneral.quickLoad2");
- attach(input.uiGeneral.quickLoad3 = "none", "input.uiGeneral.quickLoad3");
- attach(input.uiGeneral.quickSave1 = "keyboard00.f2", "input.uiGeneral.quickSave1");
- attach(input.uiGeneral.quickSave2 = "none", "input.uiGeneral.quickSave2");
- attach(input.uiGeneral.quickSave3 = "none", "input.uiGeneral.quickSave3");
-
- attach(input.uiGeneral.lowerSpeed = "keyboard00.divide", "input.uiGeneral.lowerSpeed");
- attach(input.uiGeneral.raiseSpeed = "keyboard00.multiply", "input.uiGeneral.raiseSpeed");
- attach(input.uiGeneral.toggleCheatSystem = "none", "input.uiGeneral.toggleCheatSystem");
- attach(input.uiGeneral.toggleFullscreen = "keyboard00.f11", "input.uiGeneral.toggleFullscreen");
- attach(input.uiGeneral.toggleMenu = "keyboard00.escape", "input.uiGeneral.toggleMenu");
- attach(input.uiGeneral.toggleStatus = "keyboard00.escape", "input.uiGeneral.toggleStatus");
- attach(input.uiGeneral.exitEmulator = "none", "input.uiGeneral.exitEmulator");
-
- attach(geometry.mainWindow = "", "geometry.mainWindow");
- attach(geometry.loaderWindow = "", "geometry.loaderWindow");
- attach(geometry.htmlViewerWindow = "", "geometry.htmlViewerWindow");
- attach(geometry.aboutWindow = "", "geometry.aboutWindow");
- attach(geometry.diskBrowser = "", "geometry.diskBrowser");
- attach(geometry.folderCreator = "", "geometry.folderCreator");
- attach(geometry.settingsWindow = "", "geometry.settingsWindow");
- attach(geometry.inputCaptureWindow = "", "geometry.inputCaptureWindow");
- attach(geometry.inputMouseCaptureWindow = "", "geometry.inputMouseCaptureWindow");
- attach(geometry.inputCalibrationWindow = "", "geometry.inputCalibrationWindow");
- attach(geometry.toolsWindow = "", "geometry.toolsWindow");
- attach(geometry.debugger = "", "geometry.debugger");
- attach(geometry.breakpointEditor = "", "geometry.breakpointEditor");
- attach(geometry.memoryEditor = "", "geometry.memoryEditor");
- attach(geometry.vramViewer = "", "geometry.vramViewer");
+ attach(geometry.mainWindow = "", "geometry.mainWindow");
+ attach(geometry.loaderWindow = "", "geometry.loaderWindow");
+ attach(geometry.htmlViewerWindow = "", "geometry.htmlViewerWindow");
+ attach(geometry.aboutWindow = "", "geometry.aboutWindow");
+ attach(geometry.diskBrowser = "", "geometry.diskBrowser");
+ attach(geometry.folderCreator = "", "geometry.folderCreator");
+ attach(geometry.settingsWindow = "", "geometry.settingsWindow");
+ attach(geometry.toolsWindow = "", "geometry.toolsWindow");
+ attach(geometry.debugger = "", "geometry.debugger");
+ attach(geometry.breakpointEditor = "", "geometry.breakpointEditor");
+ attach(geometry.memoryEditor = "", "geometry.memoryEditor");
+ attach(geometry.vramViewer = "", "geometry.vramViewer");
}
diff --git a/src/ui_qt/config.hpp b/src/ui_qt/config.hpp
index b6239923..7765c306 100644
--- a/src/ui_qt/config.hpp
+++ b/src/ui_qt/config.hpp
@@ -20,15 +20,21 @@ public:
struct Path {
string base; //binary path
string user; //user profile path (bsnes.cfg, ...)
- string current; //current working directory (path to currently loaded cartridge)
+ string startup; //startup path
string rom, save, state, patch, cheat, data;
string bsx, st, sgb;
+ string fragmentShader, vertexShader;
+
+ struct Current {
+ string folder, shader, cartridge, bsx, st, sgb;
+ unsigned filter; //current active filter for "Load Cartridge"
+ } current;
} path;
struct Video {
bool isFullscreen;
bool synchronize;
- signed contrastAdjust, brightnessAdjust, gammaAdjust;
+ signed contrastAdjust, brightnessAdjust, gammaAdjust, scanlineAdjust;
bool enableGammaRamp;
double ntscAspectRatio, palAspectRatio;
@@ -46,49 +52,11 @@ public:
} audio;
struct Input {
+ unsigned port1;
+ unsigned port2;
enum policy_t { FocusPolicyPauseEmulation, FocusPolicyIgnoreInput, FocusPolicyAllowInput };
unsigned focusPolicy;
bool allowInvalidInput;
-
- struct Joypad {
- string up, down, left, right, a, b, x, y, l, r, select, start;
- } joypad1, joypad2,
- multitap1a, multitap1b, multitap1c, multitap1d,
- multitap2a, multitap2b, multitap2c, multitap2d;
-
- struct Mouse {
- string x, y, left, right;
- } mouse1, mouse2;
-
- struct SuperScope {
- string x, y, trigger, turbo, cursor, pause;
- } superscope;
-
- struct Justifier {
- string x, y, trigger, start;
- } justifier1, justifier2;
-
- struct UiGeneral {
- string loadCartridge;
- string pauseEmulation;
- string resetSystem;
- string powerCycleSystem;
- string captureScreenshot;
- string showStateManager;
- string quickLoad1;
- string quickLoad2;
- string quickLoad3;
- string quickSave1;
- string quickSave2;
- string quickSave3;
- string lowerSpeed;
- string raiseSpeed;
- string toggleCheatSystem;
- string toggleFullscreen;
- string toggleMenu;
- string toggleStatus;
- string exitEmulator;
- } uiGeneral;
} input;
struct Geometry {
@@ -98,14 +66,8 @@ public:
string aboutWindow;
string diskBrowser;
string folderCreator;
-
string settingsWindow;
- string inputCaptureWindow;
- string inputMouseCaptureWindow;
- string inputCalibrationWindow;
-
string toolsWindow;
-
string debugger;
string breakpointEditor;
string memoryEditor;
@@ -113,6 +75,7 @@ public:
} geometry;
bool load(const char *filename);
- void attachJoypad(Configuration::Input::Joypad &joypad, const char *name);
Configuration();
-} config;
+};
+
+Configuration &config();
diff --git a/src/ui_qt/debugger/breakpoint.cpp b/src/ui_qt/debugger/breakpoint.cpp
index ee0f2d36..53ffdb0b 100644
--- a/src/ui_qt/debugger/breakpoint.cpp
+++ b/src/ui_qt/debugger/breakpoint.cpp
@@ -58,7 +58,7 @@ void BreakpointItem::toggle() {
}
}
-BreakpointEditor::BreakpointEditor() : QbWindow(config.geometry.breakpointEditor) {
+BreakpointEditor::BreakpointEditor() : QbWindow(config().geometry.breakpointEditor) {
setObjectName("breakpoint-editor");
setWindowTitle("Breakpoint Editor");
diff --git a/src/ui_qt/debugger/debugger.cpp b/src/ui_qt/debugger/debugger.cpp
index fc86e059..ba0af784 100644
--- a/src/ui_qt/debugger/debugger.cpp
+++ b/src/ui_qt/debugger/debugger.cpp
@@ -3,7 +3,7 @@
#include "memory.cpp"
#include "vramviewer.cpp"
-Debugger::Debugger() : QbWindow(config.geometry.debugger) {
+Debugger::Debugger() : QbWindow(config().geometry.debugger) {
setObjectName("debugger");
setWindowTitle("Debugger");
@@ -133,7 +133,7 @@ void Debugger::stepAction() {
void Debugger::tracerUpdate() {
if(SNES::debugger.trace_cpu || SNES::debugger.trace_smp) {
if(SNES::debugger.tracefile.open() == false) {
- SNES::debugger.tracefile.open(utf8() << config.path.data << "trace.log", file::mode_write);
+ SNES::debugger.tracefile.open(string() << config().path.data << "trace.log", file::mode_write);
}
} else if(!SNES::debugger.trace_cpu && !SNES::debugger.trace_smp) {
if(SNES::debugger.tracefile.open() == true) {
@@ -158,19 +158,19 @@ void Debugger::event() {
switch(SNES::debugger.break_event) {
case SNES::Debugger::BreakpointHit: {
unsigned n = SNES::debugger.breakpoint_hit;
- echo(utf8() << "Breakpoint " << n << " hit (" << SNES::debugger.breakpoint[n].counter << ").
");
+ echo(string() << "Breakpoint " << n << " hit (" << SNES::debugger.breakpoint[n].counter << ").
");
if(SNES::debugger.breakpoint[n].mode == SNES::Debugger::Breakpoint::Exec) {
if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::CPUBus) {
SNES::debugger.step_cpu = true;
SNES::cpu.disassemble_opcode(t);
- echo(utf8() << t << "
");
+ echo(string() << t << "
");
}
if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::APURAM) {
SNES::debugger.step_smp = true;
SNES::smp.disassemble_opcode(t);
- echo(utf8() << t << "
");
+ echo(string() << t << "
");
}
}
} break;
@@ -179,14 +179,14 @@ void Debugger::event() {
SNES::cpu.disassemble_opcode(t);
string s = t;
s.replace(" ", " ");
- echo(utf8() << "" << s << "
");
+ echo(string() << "" << s << "
");
} break;
case SNES::Debugger::SMPStep: {
SNES::smp.disassemble_opcode(t);
string s = t;
s.replace(" ", " ");
- echo(utf8() << "" << s << "
");
+ echo(string() << "" << s << "
");
} break;
}
}
diff --git a/src/ui_qt/debugger/hexeditor.cpp b/src/ui_qt/debugger/hexeditor.cpp
index 0d1413cd..4be791ae 100644
--- a/src/ui_qt/debugger/hexeditor.cpp
+++ b/src/ui_qt/debugger/hexeditor.cpp
@@ -78,7 +78,7 @@ void HexEditor::update() {
if(y != 15) output << "
";
}
- setHtml(utf8() << output);
+ setHtml(output);
}
void HexEditor::sliderMoved() {
diff --git a/src/ui_qt/debugger/memory.cpp b/src/ui_qt/debugger/memory.cpp
index 0f846290..89b1b0aa 100644
--- a/src/ui_qt/debugger/memory.cpp
+++ b/src/ui_qt/debugger/memory.cpp
@@ -1,4 +1,4 @@
-MemoryEditor::MemoryEditor() : QbWindow(config.geometry.memoryEditor) {
+MemoryEditor::MemoryEditor() : QbWindow(config().geometry.memoryEditor) {
setObjectName("memory-editor");
setWindowTitle("Memory Editor");
diff --git a/src/ui_qt/debugger/vramviewer.cpp b/src/ui_qt/debugger/vramviewer.cpp
index cb5d0b8f..21603d38 100644
--- a/src/ui_qt/debugger/vramviewer.cpp
+++ b/src/ui_qt/debugger/vramviewer.cpp
@@ -1,4 +1,4 @@
-VramViewer::VramViewer() : QbWindow(config.geometry.vramViewer) {
+VramViewer::VramViewer() : QbWindow(config().geometry.vramViewer) {
setObjectName("vram-viewer");
setWindowTitle("Video RAM Viewer");
diff --git a/src/ui_qt/input/controller.cpp b/src/ui_qt/input/controller.cpp
new file mode 100644
index 00000000..53237497
--- /dev/null
+++ b/src/ui_qt/input/controller.cpp
@@ -0,0 +1,372 @@
+namespace Controllers {
+
+void TurboInput::cache() {
+ if(state) {
+ cachedState = (counter < holdHi ? state : 0);
+ if(++counter >= holdHi + holdLo) counter = 0;
+ } else {
+ cachedState = 0;
+ counter = 0;
+ }
+}
+
+TurboInput::TurboInput(const char *label, const char *configName) :
+DigitalInput(label, configName) {
+ holdHi = 2;
+ holdLo = 2;
+ counter = 0;
+}
+
+int16_t Gamepad::status(unsigned index, unsigned id) const {
+ switch(id) {
+ case SNES::Input::JoypadUp: return up.cachedState;
+ case SNES::Input::JoypadDown: return down.cachedState;
+ case SNES::Input::JoypadLeft: return left.cachedState;
+ case SNES::Input::JoypadRight: return right.cachedState;
+ case SNES::Input::JoypadA: return a.cachedState | turboA.cachedState;
+ case SNES::Input::JoypadB: return b.cachedState | turboB.cachedState;
+ case SNES::Input::JoypadX: return x.cachedState | turboX.cachedState;
+ case SNES::Input::JoypadY: return y.cachedState | turboY.cachedState;
+ case SNES::Input::JoypadL: return l.cachedState | turboL.cachedState;
+ case SNES::Input::JoypadR: return r.cachedState | turboR.cachedState;
+ case SNES::Input::JoypadSelect: return select.cachedState;
+ case SNES::Input::JoypadStart: return start.cachedState;
+ }
+ return 0;
+}
+
+Gamepad::Gamepad(unsigned category, const char *label, const char *configName) :
+InputGroup(category, label),
+up("Up", string() << "input." << configName << ".up"),
+down("Down", string() << "input." << configName << ".down"),
+left("Left", string() << "input." << configName << ".left"),
+right("Right", string() << "input." << configName << ".right"),
+b("B", string() << "input." << configName << ".b"),
+a("A", string() << "input." << configName << ".a"),
+y("Y", string() << "input." << configName << ".y"),
+x("X", string() << "input." << configName << ".x"),
+l("L", string() << "input." << configName << ".l"),
+r("R", string() << "input." << configName << ".r"),
+select("Select", string() << "input." << configName << ".select"),
+start("Start", string() << "input." << configName << ".start"),
+turboB("Turbo B", string() << "input." << configName << ".turboB"),
+turboA("Turbo A", string() << "input." << configName << ".turboA"),
+turboY("Turbo Y", string() << "input." << configName << ".turboY"),
+turboX("Turbo X", string() << "input." << configName << ".turboX"),
+turboL("Turbo L", string() << "input." << configName << ".turboL"),
+turboR("Turbo R", string() << "input." << configName << ".turboR") {
+ attach(&up); attach(&down); attach(&left); attach(&right);
+ attach(&b); attach(&a); attach(&y); attach(&x);
+ attach(&l); attach(&r); attach(&select); attach(&start);
+ attach(&turboB); attach(&turboA); attach(&turboY); attach(&turboX);
+ attach(&turboL); attach(&turboR);
+
+ if(this == &gamepad1) {
+ up.name = "KB0::Up";
+ down.name = "KB0::Down";
+ left.name = "KB0::Left";
+ right.name = "KB0::Right";
+ b.name = "KB0::Z";
+ a.name = "KB0::X";
+ y.name = "KB0::A";
+ x.name = "KB0::S";
+ l.name = "KB0::D";
+ r.name = "KB0::C";
+ select.name = "KB0::Apostrophe";
+ start.name = "KB0::Return";
+ }
+}
+
+//
+
+int16_t Multitap::status(unsigned index, unsigned id) const {
+ switch(index & 3) { default:
+ case 0: return port1.status(index, id);
+ case 1: return port2.status(index, id);
+ case 2: return port3.status(index, id);
+ case 3: return port4.status(index, id);
+ }
+}
+
+Multitap::Multitap(Gamepad &port1_, Gamepad &port2_, Gamepad &port3_, Gamepad &port4_) :
+InputGroup(InputCategory::Hidden, "Multitap"),
+port1(port1_), port2(port2_), port3(port3_), port4(port4_) {
+}
+
+//
+
+void AsciiSwitch::poll() {
+ DigitalInput::poll();
+
+ //only change state when controller is active
+ if(!parent) return;
+ if(parent->category == InputCategory::Port1 && mapper().port1 != parent) return;
+ if(parent->category == InputCategory::Port2 && mapper().port2 != parent) return;
+
+ if(previousState != state && state) {
+ switch(mode) {
+ case Off: mode = Turbo; utility.showMessage(string() << label << " set to turbo."); break;
+ case Turbo: mode = Auto; utility.showMessage(string() << label << " set to auto."); break;
+ case Auto: mode = Off; utility.showMessage(string() << label << " set to off."); break;
+ }
+ }
+}
+
+AsciiSwitch::AsciiSwitch(const char *label, const char *configName) :
+DigitalInput(label, configName) {
+ mode = Off;
+}
+
+void AsciiInput::cache() {
+ if(asciiSwitch->mode == AsciiSwitch::Off) {
+ cachedState = state;
+ } else if(asciiSwitch->mode == AsciiSwitch::Turbo) {
+ if(state) {
+ cachedState = (counter < holdHi ? state : 0);
+ if(++counter >= holdHi + holdLo) counter = 0;
+ } else {
+ cachedState = 0;
+ counter = 0;
+ }
+ } else if(asciiSwitch->mode == AsciiSwitch::Auto) {
+ cachedState = (counter < holdHi);
+ if(++counter >= holdHi + holdLo) counter = 0;
+ }
+}
+
+AsciiInput::AsciiInput(const char *label, const char *configName) :
+DigitalInput(label, configName) {
+ holdHi = 2;
+ holdLo = 2;
+ counter = 0;
+}
+
+void AsciiSlowMotion::poll() {
+ DigitalInput::poll();
+
+ //only change state when controller is active
+ if(!parent) return;
+ if(parent->category == InputCategory::Port1 && mapper().port1 != parent) return;
+ if(parent->category == InputCategory::Port2 && mapper().port2 != parent) return;
+
+ if(previousState != state && state) {
+ if(enabled == false) {
+ enabled = true;
+ utility.showMessage(string() << label << " enabled.");
+ } else {
+ enabled = false;
+ utility.showMessage(string() << label << " disabled.");
+ }
+ }
+}
+
+void AsciiSlowMotion::cache() {
+ if(enabled == false) {
+ cachedState = 0;
+ } else {
+ cachedState = counter < holdHi;
+ if(++counter >= holdHi + holdLo) counter = 0;
+ }
+}
+
+AsciiSlowMotion::AsciiSlowMotion(const char *label, const char *configName) :
+DigitalInput(label, configName) {
+ enabled = false;
+ holdHi = 2;
+ holdLo = 2;
+}
+
+int16_t Asciipad::status(unsigned index, unsigned id) const {
+ switch(id) {
+ case SNES::Input::JoypadUp: return up.cachedState;
+ case SNES::Input::JoypadDown: return down.cachedState;
+ case SNES::Input::JoypadLeft: return left.cachedState;
+ case SNES::Input::JoypadRight: return right.cachedState;
+ case SNES::Input::JoypadA: return a.cachedState;
+ case SNES::Input::JoypadB: return b.cachedState;
+ case SNES::Input::JoypadX: return x.cachedState;
+ case SNES::Input::JoypadY: return y.cachedState;
+ case SNES::Input::JoypadL: return l.cachedState;
+ case SNES::Input::JoypadR: return r.cachedState;
+ case SNES::Input::JoypadSelect: return select.cachedState;
+ case SNES::Input::JoypadStart: return start.cachedState | slowMotion.cachedState;
+ }
+ return 0;
+}
+
+Asciipad::Asciipad(unsigned category, const char *label, const char *configName) :
+InputGroup(category, label),
+up("Up", string() << "input." << configName << ".up"),
+down("Down", string() << "input." << configName << ".down"),
+left("Left", string() << "input." << configName << ".left"),
+right("Right", string() << "input." << configName << ".right"),
+b("B", string() << "input." << configName << ".b"),
+a("A", string() << "input." << configName << ".a"),
+y("Y", string() << "input." << configName << ".y"),
+x("X", string() << "input." << configName << ".x"),
+l("L", string() << "input." << configName << ".l"),
+r("R", string() << "input." << configName << ".r"),
+select("Select", string() << "input." << configName << ".select"),
+start("Start", string() << "input." << configName << ".start"),
+switchB("B Switch", string() << "input." << configName << ".bSwitch"),
+switchA("A Switch", string() << "input." << configName << ".aSwitch"),
+switchY("Y Switch", string() << "input." << configName << ".ySwitch"),
+switchX("X Switch", string() << "input." << configName << ".xSwitch"),
+switchL("L Switch", string() << "input." << configName << ".lSwitch"),
+switchR("R Switch", string() << "input." << configName << ".rSwitch"),
+slowMotion("Slow Motion", string() << "input." << configName << ".slowMotion") {
+ b.asciiSwitch = &switchB;
+ a.asciiSwitch = &switchA;
+ y.asciiSwitch = &switchY;
+ x.asciiSwitch = &switchX;
+ l.asciiSwitch = &switchL;
+ r.asciiSwitch = &switchR;
+
+ attach(&up); attach(&down); attach(&left); attach(&right);
+ attach(&b); attach(&a); attach(&y); attach(&x);
+ attach(&l); attach(&r); attach(&select); attach(&start);
+ attach(&switchB); attach(&switchA); attach(&switchY); attach(&switchX);
+ attach(&switchL); attach(&switchR); attach(&slowMotion);
+
+ if(this == &asciipad1) {
+ up.name = "KB0::Up";
+ down.name = "KB0::Down";
+ left.name = "KB0::Left";
+ right.name = "KB0::Right";
+ b.name = "KB0::Z";
+ a.name = "KB0::X";
+ y.name = "KB0::A";
+ x.name = "KB0::S";
+ l.name = "KB0::D";
+ r.name = "KB0::C";
+ select.name = "KB0::Apostrophe";
+ start.name = "KB0::Return";
+ }
+}
+
+//
+
+int16_t Mouse::status(unsigned index, unsigned id) const {
+ switch(id) {
+ case SNES::Input::MouseX: return x.cachedState;
+ case SNES::Input::MouseY: return y.cachedState;
+ case SNES::Input::MouseLeft: return left.cachedState;
+ case SNES::Input::MouseRight: return right.cachedState;
+ }
+ return 0;
+}
+
+Mouse::Mouse(unsigned category, const char *label, const char *configName) :
+InputGroup(category, label),
+x("X-axis", string() << "input." << configName << ".x"),
+y("Y-axis", string() << "input." << configName << ".y"),
+left("Left Button", string() << "input." << configName << ".left"),
+right("Right Button", string() << "input." << configName << ".right") {
+ attach(&x); attach(&y); attach(&left); attach(&right);
+
+ x.name = "MS0::Xaxis";
+ y.name = "MS0::Yaxis";
+ left.name = "MS0::Button0";
+ right.name = "MS0::Button2";
+}
+
+//
+
+int16_t SuperScope::status(unsigned index, unsigned id) const {
+ switch(id) {
+ case SNES::Input::SuperScopeX: return x.cachedState;
+ case SNES::Input::SuperScopeY: return y.cachedState;
+ case SNES::Input::SuperScopeTrigger: return trigger.cachedState;
+ case SNES::Input::SuperScopeCursor: return cursor.cachedState;
+ case SNES::Input::SuperScopeTurbo: return turbo.cachedState;
+ case SNES::Input::SuperScopePause: return pause.cachedState;
+ }
+ return 0;
+}
+
+SuperScope::SuperScope(unsigned category, const char *label, const char *configName) :
+InputGroup(category, label),
+x("X-axis", string() << "input." << configName << ".x"),
+y("Y-axis", string() << "input." << configName << ".y"),
+trigger("Trigger", string() << "input." << configName << ".trigger"),
+cursor("Cursor", string() << "input." << configName << ".cursor"),
+turbo("Turbo", string() << "input." << configName << ".turbo"),
+pause("Pause", string() << "input." << configName << ".pause") {
+ attach(&x); attach(&y); attach(&trigger); attach(&cursor);
+ attach(&turbo); attach(&pause);
+
+ x.name = "MS0::Xaxis";
+ y.name = "MS0::Yaxis";
+ trigger.name = "MS0::Button0";
+ cursor.name = "MS0::Button2";
+ turbo.name = "KB0::T";
+ pause.name = "KB0::P";
+}
+
+//
+
+int16_t Justifier::status(unsigned index, unsigned id) const {
+ switch(id) {
+ case SNES::Input::JustifierX: return x.cachedState;
+ case SNES::Input::JustifierY: return y.cachedState;
+ case SNES::Input::JustifierTrigger: return trigger.cachedState;
+ case SNES::Input::JustifierStart: return start.cachedState;
+ }
+ return 0;
+}
+
+Justifier::Justifier(unsigned category, const char *label, const char *configName) :
+InputGroup(category, label),
+x("X-axis", string() << "input." << configName << ".x"),
+y("Y-axis", string() << "input." << configName << ".y"),
+trigger("Trigger", string() << "input." << configName << ".trigger"),
+start("Start", string() << "input." << configName << ".start") {
+ attach(&x); attach(&y); attach(&trigger); attach(&start);
+
+ if(this == &justifier1) {
+ x.name = "MS0::Xaxis";
+ y.name = "MS0::Yaxis";
+ trigger.name = "MS0::Button0";
+ start.name = "MS0::Button2";
+ }
+}
+
+//
+
+int16_t Justifiers::status(unsigned index, unsigned id) const {
+ switch(index & 1) { default:
+ case 0: return port1.status(index, id);
+ case 1: return port2.status(index, id);
+ }
+}
+
+Justifiers::Justifiers(Justifier &port1_, Justifier &port2_) :
+InputGroup(InputCategory::Hidden, "Justifiers"),
+port1(port1_), port2(port2_) {
+}
+
+//
+
+Gamepad gamepad1(InputCategory::Port1, "Gamepad", "gamepad1");
+Asciipad asciipad1(InputCategory::Port1, "asciiPad", "asciipad1");
+Gamepad multitap1a(InputCategory::Port1, "Multitap - Port 1", "multitap1a");
+Gamepad multitap1b(InputCategory::Port1, "Multitap - Port 2", "multitap1b");
+Gamepad multitap1c(InputCategory::Port1, "Multitap - Port 3", "multitap1c");
+Gamepad multitap1d(InputCategory::Port1, "Multitap - Port 4", "multitap1d");
+Multitap multitap1(multitap1a, multitap1b, multitap1c, multitap1d);
+Mouse mouse1(InputCategory::Port1, "Mouse", "mouse1");
+
+Gamepad gamepad2(InputCategory::Port2, "Gamepad", "gamepad2");
+Asciipad asciipad2(InputCategory::Port2, "asciiPad", "asciipad2");
+Gamepad multitap2a(InputCategory::Port2, "Multitap - Port 1", "multitap2a");
+Gamepad multitap2b(InputCategory::Port2, "Multitap - Port 2", "multitap2b");
+Gamepad multitap2c(InputCategory::Port2, "Multitap - Port 3", "multitap2c");
+Gamepad multitap2d(InputCategory::Port2, "Multitap - Port 4", "multitap2d");
+Multitap multitap2(multitap2a, multitap2b, multitap2c, multitap2d);
+Mouse mouse2(InputCategory::Port2, "Mouse", "mouse2");
+SuperScope superscope(InputCategory::Port2, "Super Scope", "superscope");
+Justifier justifier1(InputCategory::Port2, "Justifier 1", "justifier1");
+Justifier justifier2(InputCategory::Port2, "Justifier 2", "justifier2");
+Justifiers justifiers(justifier1, justifier2);
+
+}
diff --git a/src/ui_qt/input/controller.hpp b/src/ui_qt/input/controller.hpp
new file mode 100644
index 00000000..e7920bef
--- /dev/null
+++ b/src/ui_qt/input/controller.hpp
@@ -0,0 +1,112 @@
+struct ControllerPort1 { enum { None, Gamepad, Asciipad, Multitap, Mouse }; };
+struct ControllerPort2 { enum { None, Gamepad, Asciipad, Multitap, Mouse, SuperScope, Justifier, Justifiers }; };
+
+namespace Controllers {
+
+struct TurboInput : DigitalInput {
+ unsigned holdHi;
+ unsigned holdLo;
+ unsigned counter;
+ void cache();
+ TurboInput(const char*, const char*);
+};
+
+struct Gamepad : InputGroup {
+ DigitalInput up, down, left, right, b, a, y, x, l, r, select, start;
+ TurboInput turboB, turboA, turboY, turboX, turboL, turboR;
+ int16_t status(unsigned, unsigned) const;
+ Gamepad(unsigned, const char*, const char*);
+};
+
+struct Multitap : InputGroup {
+ Gamepad &port1, &port2, &port3, &port4;
+ int16_t status(unsigned, unsigned) const;
+ Multitap(Gamepad&, Gamepad&, Gamepad&, Gamepad&);
+};
+
+struct AsciiSwitch : DigitalInput {
+ enum Mode { Off, Turbo, Auto } mode;
+ void poll();
+ AsciiSwitch(const char*, const char*);
+};
+
+struct AsciiSlowMotion : DigitalInput {
+ bool enabled;
+ unsigned holdHi;
+ unsigned holdLo;
+ unsigned counter;
+ void poll();
+ void cache();
+ AsciiSlowMotion(const char*, const char*);
+};
+
+struct AsciiInput : DigitalInput {
+ AsciiSwitch *asciiSwitch;
+ unsigned holdHi;
+ unsigned holdLo;
+ unsigned counter;
+ void cache();
+ AsciiInput(const char*, const char*);
+};
+
+struct Asciipad : InputGroup {
+ DigitalInput up, down, left, right;
+ AsciiInput b, a, y, x, l, r;
+ DigitalInput select, start;
+ AsciiSwitch switchB, switchA, switchY, switchX, switchL, switchR;
+ AsciiSlowMotion slowMotion;
+ int16_t status(unsigned, unsigned) const;
+ Asciipad(unsigned, const char*, const char*);
+};
+
+struct Mouse : InputGroup {
+ AnalogInput x, y;
+ DigitalInput left, right;
+ int16_t status(unsigned, unsigned) const;
+ Mouse(unsigned, const char*, const char*);
+};
+
+struct SuperScope : InputGroup {
+ AnalogInput x, y;
+ DigitalInput trigger, cursor, turbo, pause;
+ int16_t status(unsigned, unsigned) const;
+ SuperScope(unsigned, const char*, const char*);
+};
+
+struct Justifier : InputGroup {
+ AnalogInput x, y;
+ DigitalInput trigger, start;
+ int16_t status(unsigned, unsigned) const;
+ Justifier(unsigned, const char*, const char*);
+};
+
+struct Justifiers : InputGroup {
+ Justifier &port1;
+ Justifier &port2;
+ int16_t status(unsigned, unsigned) const;
+ Justifiers(Justifier&, Justifier&);
+};
+
+extern Gamepad gamepad1;
+extern Asciipad asciipad1;
+extern Gamepad multitap1a;
+extern Gamepad multitap1b;
+extern Gamepad multitap1c;
+extern Gamepad multitap1d;
+extern Multitap multitap1;
+extern Mouse mouse1;
+
+extern Gamepad gamepad2;
+extern Asciipad asciipad2;
+extern Gamepad multitap2a;
+extern Gamepad multitap2b;
+extern Gamepad multitap2c;
+extern Gamepad multitap2d;
+extern Multitap multitap2;
+extern Mouse mouse2;
+extern SuperScope superscope;
+extern Justifier justifier1;
+extern Justifier justifier2;
+extern Justifiers justifiers;
+
+}
diff --git a/src/ui_qt/input/device.cpp b/src/ui_qt/input/device.cpp
deleted file mode 100644
index 7fb09e3f..00000000
--- a/src/ui_qt/input/device.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-//===========
-//InputDevice
-//===========
-
-InputDevice::InputDevice(SNES::Input::DeviceID i, bool p, const char *n) : InputGroup(n), id(i), port(p) {
-}
-
-//======
-//Joypad
-//======
-
-int16_t Joypad::state(unsigned index) const {
- if(config.input.allowInvalidInput == false) {
- //SNES D-pads have central pivot point, making up+down or left+right combinations impossible.
- //some software programs rely on this, and will crash if these combinations are allowed.
- if(index == SNES::Input::JoypadDown && up.state ) return 0;
- if(index == SNES::Input::JoypadRight && left.state) return 0;
- }
-
- switch(index) {
- case SNES::Input::JoypadUp: return up.state;
- case SNES::Input::JoypadDown: return down.state;
- case SNES::Input::JoypadLeft: return left.state;
- case SNES::Input::JoypadRight: return right.state;
- case SNES::Input::JoypadA: return a.state;
- case SNES::Input::JoypadB: return b.state;
- case SNES::Input::JoypadX: return x.state;
- case SNES::Input::JoypadY: return y.state;
- case SNES::Input::JoypadL: return l.state;
- case SNES::Input::JoypadR: return r.state;
- case SNES::Input::JoypadSelect: return select.state;
- case SNES::Input::JoypadStart: return start.state;
- }
-
- return 0;
-}
-
-Joypad::Joypad(SNES::Input::DeviceID id, bool port, const char *name,
-string &up_t, string &down_t, string &left_t, string &right_t, string &a_t, string &b_t,
-string &x_t, string &y_t, string &l_t, string &r_t, string &select_t, string &start_t
-) :
-InputDevice(id, port, name),
-up (InputObject::Button, "Up", up_t),
-down (InputObject::Button, "Down", down_t),
-left (InputObject::Button, "Left", left_t),
-right (InputObject::Button, "Right", right_t),
-a (InputObject::Button, "A", a_t),
-b (InputObject::Button, "B", b_t),
-x (InputObject::Button, "X", x_t),
-y (InputObject::Button, "Y", y_t),
-l (InputObject::Button, "L", l_t),
-r (InputObject::Button, "R", r_t),
-select(InputObject::Button, "Select", select_t),
-start (InputObject::Button, "Start", start_t) {
- attach(up); attach(down); attach(left); attach(right); attach(a); attach(b);
- attach(x); attach(y); attach(l); attach(r); attach(select); attach(start);
-}
-
-//=====
-//Mouse
-//=====
-
-int16_t Mouse::state(unsigned index) const {
- switch(index) {
- case SNES::Input::MouseX: return x.state;
- case SNES::Input::MouseY: return y.state;
- case SNES::Input::MouseLeft: return left.state;
- case SNES::Input::MouseRight: return right.state;
- }
-
- return 0;
-}
-
-Mouse::Mouse(SNES::Input::DeviceID id, bool port, const char *name,
-string &x_t, string &y_t, string &left_t, string &right_t
-) :
-InputDevice(id, port, name),
-x (InputObject::Axis, "X-axis", x_t),
-y (InputObject::Axis, "Y-axis", y_t),
-left (InputObject::Button, "Left button", left_t),
-right(InputObject::Button, "Right button", right_t) {
- attach(x); attach(y); attach(left); attach(right);
-}
-
-//==========
-//SuperScope
-//==========
-
-int16_t SuperScope::state(unsigned index) const {
- switch(index) {
- case SNES::Input::SuperScopeX: return x.state;
- case SNES::Input::SuperScopeY: return y.state;
- case SNES::Input::SuperScopeTrigger: return trigger.state;
- case SNES::Input::SuperScopeCursor: return cursor.state;
- case SNES::Input::SuperScopeTurbo: return turbo.state;
- case SNES::Input::SuperScopePause: return pause.state;
- }
-
- return 0;
-}
-
-SuperScope::SuperScope(SNES::Input::DeviceID id, bool port, const char *name,
-string &x_t, string &y_t, string &trigger_t, string &cursor_t, string &turbo_t, string &pause_t
-) :
-InputDevice(id, port, name),
-x (InputObject::Axis, "X-axis", x_t),
-y (InputObject::Axis, "Y-axis", y_t),
-trigger(InputObject::Button, "Trigger", trigger_t),
-cursor (InputObject::Button, "Cursor", cursor_t),
-turbo (InputObject::Button, "Turbo", turbo_t),
-pause (InputObject::Button, "Pause", pause_t) {
- attach(x); attach(y); attach(trigger); attach(cursor); attach(turbo); attach(pause);
-}
-
-//=========
-//Justifier
-//=========
-
-int16_t Justifier::state(unsigned index) const {
- switch(index) {
- case SNES::Input::JustifierX: return x.state;
- case SNES::Input::JustifierY: return y.state;
- case SNES::Input::JustifierTrigger: return trigger.state;
- case SNES::Input::JustifierStart: return start.state;
- }
-
- return 0;
-}
-
-Justifier::Justifier(SNES::Input::DeviceID id, bool port, const char *name,
-string &x_t, string &y_t, string &trigger_t, string &start_t
-) :
-InputDevice(id, port, name),
-x (InputObject::Axis, "X-axis", x_t),
-y (InputObject::Axis, "Y-axis", y_t),
-trigger(InputObject::Button, "Trigger", trigger_t),
-start (InputObject::Button, "Start", start_t) {
- attach(x); attach(y); attach(trigger); attach(start);
-}
-
-//===============
-//InputDevicePool
-//===============
-
-void InputDevicePool::attach(InputDevice &device) {
- list.add(&device);
-}
-
-void InputDevicePool::bind() {
- for(unsigned i = 0; i < list.size(); i++) list[i]->bind();
-}
-
-void InputDevicePool::clear() {
- for(unsigned i = 0; i < list.size(); i++) list[i]->clear();
-}
-
-void InputDevicePool::poll(const int16_t *table) {
- for(unsigned i = 0; i < list.size(); i++) list[i]->poll(table);
-}
-
-InputDevice* InputDevicePool::find(SNES::Input::DeviceID id) {
- for(unsigned i = 0; i < list.size(); i++) {
- if(list[i]->id == id) return list[i];
- }
-
- return 0;
-}
-
-InputDevicePool::InputDevicePool() : list(*this) {
-}
-
-//
-
-Joypad joypad1(SNES::Input::DeviceIDJoypad1, InputDevice::Port1, "Joypad",
-config.input.joypad1.up, config.input.joypad1.down, config.input.joypad1.left, config.input.joypad1.right,
-config.input.joypad1.a, config.input.joypad1.b, config.input.joypad1.x, config.input.joypad1.y,
-config.input.joypad1.l, config.input.joypad1.r, config.input.joypad1.select, config.input.joypad1.start);
-
-Joypad joypad2(SNES::Input::DeviceIDJoypad2, InputDevice::Port2, "Joypad",
-config.input.joypad2.up, config.input.joypad2.down, config.input.joypad2.left, config.input.joypad2.right,
-config.input.joypad2.a, config.input.joypad2.b, config.input.joypad2.x, config.input.joypad2.y,
-config.input.joypad2.l, config.input.joypad2.r, config.input.joypad2.select, config.input.joypad2.start);
-
-Joypad multitap1a(SNES::Input::DeviceIDMultitap1A, InputDevice::Port1, "Multitap - Port 1",
-config.input.multitap1a.up, config.input.multitap1a.down, config.input.multitap1a.left, config.input.multitap1a.right,
-config.input.multitap1a.a, config.input.multitap1a.b, config.input.multitap1a.x, config.input.multitap1a.y,
-config.input.multitap1a.l, config.input.multitap1a.r, config.input.multitap1a.select, config.input.multitap1a.start);
-
-Joypad multitap1b(SNES::Input::DeviceIDMultitap1B, InputDevice::Port1, "Multitap - Port 2",
-config.input.multitap1b.up, config.input.multitap1b.down, config.input.multitap1b.left, config.input.multitap1b.right,
-config.input.multitap1b.a, config.input.multitap1b.b, config.input.multitap1b.x, config.input.multitap1b.y,
-config.input.multitap1b.l, config.input.multitap1b.r, config.input.multitap1b.select, config.input.multitap1b.start);
-
-Joypad multitap1c(SNES::Input::DeviceIDMultitap1C, InputDevice::Port1, "Multitap - Port 3",
-config.input.multitap1c.up, config.input.multitap1c.down, config.input.multitap1c.left, config.input.multitap1c.right,
-config.input.multitap1c.a, config.input.multitap1c.b, config.input.multitap1c.x, config.input.multitap1c.y,
-config.input.multitap1c.l, config.input.multitap1c.r, config.input.multitap1c.select, config.input.multitap1c.start);
-
-Joypad multitap1d(SNES::Input::DeviceIDMultitap1D, InputDevice::Port1, "Multitap - Port 4",
-config.input.multitap1d.up, config.input.multitap1d.down, config.input.multitap1d.left, config.input.multitap1d.right,
-config.input.multitap1d.a, config.input.multitap1d.b, config.input.multitap1d.x, config.input.multitap1d.y,
-config.input.multitap1d.l, config.input.multitap1d.r, config.input.multitap1d.select, config.input.multitap1d.start);
-
-Joypad multitap2a(SNES::Input::DeviceIDMultitap2A, InputDevice::Port2, "Multitap - Port 1",
-config.input.multitap2a.up, config.input.multitap2a.down, config.input.multitap2a.left, config.input.multitap2a.right,
-config.input.multitap2a.a, config.input.multitap2a.b, config.input.multitap2a.x, config.input.multitap2a.y,
-config.input.multitap2a.l, config.input.multitap2a.r, config.input.multitap2a.select, config.input.multitap2a.start);
-
-Joypad multitap2b(SNES::Input::DeviceIDMultitap2B, InputDevice::Port2, "Multitap - Port 2",
-config.input.multitap2b.up, config.input.multitap2b.down, config.input.multitap2b.left, config.input.multitap2b.right,
-config.input.multitap2b.a, config.input.multitap2b.b, config.input.multitap2b.x, config.input.multitap2b.y,
-config.input.multitap2b.l, config.input.multitap2b.r, config.input.multitap2b.select, config.input.multitap2b.start);
-
-Joypad multitap2c(SNES::Input::DeviceIDMultitap2C, InputDevice::Port2, "Multitap - Port 3",
-config.input.multitap2c.up, config.input.multitap2c.down, config.input.multitap2c.left, config.input.multitap2c.right,
-config.input.multitap2c.a, config.input.multitap2c.b, config.input.multitap2c.x, config.input.multitap2c.y,
-config.input.multitap2c.l, config.input.multitap2c.r, config.input.multitap2c.select, config.input.multitap2c.start);
-
-Joypad multitap2d(SNES::Input::DeviceIDMultitap2D, InputDevice::Port2, "Multitap - Port 4",
-config.input.multitap2d.up, config.input.multitap2d.down, config.input.multitap2d.left, config.input.multitap2d.right,
-config.input.multitap2d.a, config.input.multitap2d.b, config.input.multitap2d.x, config.input.multitap2d.y,
-config.input.multitap2d.l, config.input.multitap2d.r, config.input.multitap2d.select, config.input.multitap2d.start);
-
-Mouse mouse1(SNES::Input::DeviceIDMouse1, InputDevice::Port1, "Mouse",
-config.input.mouse1.x, config.input.mouse1.y, config.input.mouse1.left, config.input.mouse1.right);
-
-Mouse mouse2(SNES::Input::DeviceIDMouse2, InputDevice::Port2, "Mouse",
-config.input.mouse2.x, config.input.mouse2.y, config.input.mouse2.left, config.input.mouse2.right);
-
-SuperScope superscope(SNES::Input::DeviceIDSuperScope, InputDevice::Port2, "Super Scope",
-config.input.superscope.x, config.input.superscope.y,
-config.input.superscope.trigger, config.input.superscope.cursor,
-config.input.superscope.turbo, config.input.superscope.pause);
-
-Justifier justifier1(SNES::Input::DeviceIDJustifier1, InputDevice::Port2, "Justifier 1",
-config.input.justifier1.x, config.input.justifier1.y,
-config.input.justifier1.trigger, config.input.justifier1.start);
-
-Justifier justifier2(SNES::Input::DeviceIDJustifier2, InputDevice::Port2, "Justifier 2",
-config.input.justifier2.x, config.input.justifier2.y,
-config.input.justifier2.trigger, config.input.justifier2.start);
-
-InputSnesDevicePool inputPool;
-
-InputSnesDevicePool::InputSnesDevicePool() {
- attach(joypad1);
- attach(joypad2);
- attach(multitap1a);
- attach(multitap1b);
- attach(multitap1c);
- attach(multitap1d);
- attach(multitap2a);
- attach(multitap2b);
- attach(multitap2c);
- attach(multitap2d);
- attach(mouse1);
- attach(mouse2);
- attach(superscope);
- attach(justifier1);
- attach(justifier2);
-}
diff --git a/src/ui_qt/input/device.hpp b/src/ui_qt/input/device.hpp
deleted file mode 100644
index 7675b101..00000000
--- a/src/ui_qt/input/device.hpp
+++ /dev/null
@@ -1,73 +0,0 @@
-struct InputDevice : InputGroup {
- SNES::Input::DeviceID id;
- enum Port { Port1, Port2 };
- const bool port;
-
- InputDevice(SNES::Input::DeviceID i, bool p, const char *n);
-};
-
-struct Joypad : InputDevice {
- InputObject up, down, left, right, a, b, x, y, l, r, select, start;
-
- int16_t state(unsigned index) const;
- Joypad(SNES::Input::DeviceID id, bool port, const char *name,
- string&, string&, string&, string&, string&, string&,
- string&, string&, string&, string&, string&, string&);
-};
-
-struct Mouse : InputDevice {
- InputObject x, y, left, right;
-
- int16_t state(unsigned index) const;
- Mouse(SNES::Input::DeviceID id, bool port, const char *name,
- string&, string&, string&, string&);
-};
-
-struct SuperScope : InputDevice {
- InputObject x, y, trigger, cursor, turbo, pause;
-
- int16_t state(unsigned index) const;
- SuperScope(SNES::Input::DeviceID id, bool port, const char *name,
- string&, string&, string&, string&, string&, string&);
-};
-
-struct Justifier : InputDevice {
- InputObject x, y, trigger, start;
-
- int16_t state(unsigned index) const;
- Justifier(SNES::Input::DeviceID id, bool port, const char *name,
- string&, string&, string&, string&);
-};
-
-struct InputDevicePool : public array {
- void attach(InputDevice &device);
- void bind();
- void clear();
- void poll(const int16_t *table);
- InputDevice* find(SNES::Input::DeviceID id);
- InputDevicePool();
-
-private:
- array &list;
-};
-
-struct InputSnesDevicePool : public InputDevicePool {
- InputSnesDevicePool();
-};
-
-extern Joypad joypad1;
-extern Joypad joypad2;
-extern Joypad multitap1a;
-extern Joypad multitap1b;
-extern Joypad multitap1c;
-extern Joypad multitap1d;
-extern Joypad multitap2a;
-extern Joypad multitap2b;
-extern Joypad multitap2c;
-extern Joypad multitap2d;
-extern Mouse mouse1;
-extern Mouse mouse2;
-extern SuperScope superscope;
-extern Justifier justifier1;
-extern Justifier justifier2;
-extern InputSnesDevicePool inputPool;
diff --git a/src/ui_qt/input/input.cpp b/src/ui_qt/input/input.cpp
index b1749295..36d48a9c 100644
--- a/src/ui_qt/input/input.cpp
+++ b/src/ui_qt/input/input.cpp
@@ -1,269 +1,260 @@
-#include "device.cpp"
-#include "userinterface.cpp"
+#include "controller.cpp"
+#include "userinterface-general.cpp"
+#include "userinterface-system.cpp"
+#include "userinterface-emulationspeed.cpp"
+#include "userinterface-states.cpp"
+#include "userinterface-videosettings.cpp"
-//=========
-//InputCode
-//=========
-
-InputCode::type_t InputCode::type(uint16_t code) {
- for(unsigned i = 0; i < keyboard<>::count; i++) {
- unsigned index = keyboard<>::index(i, keyboard<>::none);
- if(code >= index && code < index + keyboard<>::length) return KeyboardButton;
- }
-
- for(unsigned i = 0; i < mouse<>::count; i++) {
- unsigned index = mouse<>::index(i, mouse<>::none);
- if(code == index + mouse<>::x) return MouseAxis;
- if(code == index + mouse<>::y) return MouseAxis;
- if(code == index + mouse<>::z) return MouseAxis;
-
- index = mouse<>::index(i, mouse<>::button);
- if(code >= index && code < index + mouse<>::buttons) return MouseButton;
- }
-
- for(unsigned i = 0; i < joypad<>::count; i++) {
- unsigned index;
-
- index = joypad<>::index(i, joypad<>::hat);
- if(code >= index && code < index + joypad<>::hats) return JoypadHat;
-
- index = joypad<>::index(i, joypad<>::axis);
- if(code >= index && code < index + joypad<>::axes) return JoypadAxis;
-
- index = joypad<>::index(i, joypad<>::button);
- if(code >= index && code < index + joypad<>::buttons) return JoypadButton;
- }
-
- return Unknown;
-}
-
-InputCode::axistype_t InputCode::axisType(uint16_t code) {
- for(unsigned i = 0; i < joypad<>::count; i++) {
- unsigned index = joypad<>::index(i, joypad<>::axis);
- if(code >= index && code < index + joypad<>::axes) {
- return (InputCode::axistype_t)inputManager.axisType(i, code - index);
- }
- }
- return InvalidAxis;
-}
-
-//finds what mouse# is associated with code, returns -1 if not a mouse code
-int InputCode::mouseNumber(uint16_t code) {
- for(unsigned i = 0; i < mouse<>::count; i++) {
- unsigned index = mouse<>::index(i, mouse<>::none);
- if(code >= index && code < index + mouse<>::length) return i;
- }
- return -1;
-}
-
-//finds what joypad# is associated with code, returns -1 if not a joypad code
-int InputCode::joypadNumber(uint16_t code) {
- for(unsigned i = 0; i < joypad<>::count; i++) {
- unsigned index = joypad<>::index(i, joypad<>::none);
- if(code >= index && code < index + joypad<>::length) return i;
- }
- return -1;
-}
-
-//============
-//InputManager
-//============
-
-void InputManager::bind() {
- inputPool.bind();
- inputUiPool.bind();
-}
-
-void InputManager::poll() {
- if(config.input.focusPolicy == Configuration::Input::FocusPolicyIgnoreInput
- && mainWindow->isActive() == false) {
- inputPool.clear();
- } else {
- inputPool.poll(stateTable[activeState]);
- }
-}
-
-void InputManager::clear() {
- inputPool.clear();
-}
-
-void InputManager::flush() {
- for(unsigned i = 0; i < nall::input_limit; i++) {
- stateTable[0][i] = 0;
- stateTable[1][i] = 0;
- }
-}
-
-int16_t InputManager::state(uint16_t code) const {
- return stateTable[ activeState][code];
-}
-
-int16_t InputManager::lastState(uint16_t code) const {
- return stateTable[!activeState][code];
-}
-
-int16_t InputManager::getStatus(unsigned deviceid, unsigned id) const {
- InputDevice *device = inputPool.find((SNES::Input::DeviceID)deviceid);
- if(device) return device->state(id);
- return 0;
-}
-
-void InputManager::refresh() {
- bool last = activeState;
- activeState = !activeState;
- bool next = activeState;
-
- input.poll(stateTable[next]);
- for(unsigned i = 0; i < nall::input_limit; i++) {
- //alert via callback whenever input state changes for any ID ...
- if(onInput && stateTable[last][i] != stateTable[next][i]) onInput(i);
- }
-}
-
-void InputManager::calibrate(unsigned joy) {
- unsigned index = joypad<>::index(joy, joypad<>::none);
-
- for(unsigned axis = 0; axis < joypad<>::axes; axis++) {
- int16_t value = state(index + joypad<>::axis + axis);
- pad[joy].axis[axis] = (value >= -16384 && value <= +16384) ? InputCode::Stick : InputCode::Trigger;
- }
-
- pad[joy].calibrated = true;
-}
-
-bool InputManager::calibrated(unsigned joy) const {
- return pad[joy].calibrated;
-}
-
-InputCode::axistype_t InputManager::axisType(unsigned joy, unsigned axis) const {
- return pad[joy].axis[axis];
-}
-
-InputManager::InputManager() {
- activeState = 0;
- flush();
-
- for(unsigned i = 0; i < joypad<>::count; i++) {
- pad[i].calibrated = false;
- for(unsigned n = 0; n < joypad<>::axes; n++) pad[i].axis[n] = InputCode::InvalidAxis;
- }
-}
-
-//===========
-//InputObject
-//===========
-
-void InputObject::bind() {
+void MappedInput::bind() {
lstring part;
- part.split("::", id);
+ part.split("+", name);
- code = nall::input_find((const char*)part[0]);
- codetype = InputCode::type(code);
-
- modifier = None;
- if(part.size() > 1) {
- if(part[1] == "up" ) modifier = Up;
- if(part[1] == "down" ) modifier = Down;
- if(part[1] == "left" ) modifier = Left;
- if(part[1] == "right" ) modifier = Right;
- if(part[1] == "lo" ) modifier = Lo;
- if(part[1] == "hi" ) modifier = Hi;
- if(part[1] == "trigger") modifier = Trigger;
+ modifier = InputModifier::None;
+ for(unsigned i = 0; i < part.size(); i++) {
+ if(part[i] == "Shift") modifier |= InputModifier::Shift;
+ if(part[i] == "Control") modifier |= InputModifier::Control;
+ if(part[i] == "Alt") modifier |= InputModifier::Alt;
+ if(part[i] == "Super") modifier |= InputModifier::Super;
}
- if(code == nall::input_none) id = "none";
+ string temp = part[part.size() - 1];
+ part.split(".", temp);
+ scancode = Scancode::decode(part[0]);
+ specifier = InputSpecifier::None;
+ if(part[1] == "Up") specifier = InputSpecifier::Up;
+ if(part[1] == "Down") specifier = InputSpecifier::Down;
+ if(part[1] == "Left") specifier = InputSpecifier::Left;
+ if(part[1] == "Right") specifier = InputSpecifier::Right;
+ if(part[1] == "Lo") specifier = InputSpecifier::Lo;
+ if(part[1] == "Hi") specifier = InputSpecifier::Hi;
+ if(part[1] == "Trigger") specifier = InputSpecifier::Trigger;
+
+ //re-encode name, in case previous name was invalid
+ name = "";
+ if(modifier & InputModifier::Shift) name << "Shift+";
+ if(modifier & InputModifier::Control) name << "Control+";
+ if(modifier & InputModifier::Alt) name << "Alt+";
+ if(modifier & InputModifier::Super) name << "Super+";
+ name << Scancode::encode(scancode);
+ if(specifier == InputSpecifier::Up) name << ".Up";
+ if(specifier == InputSpecifier::Down) name << ".Down";
+ if(specifier == InputSpecifier::Left) name << ".Left";
+ if(specifier == InputSpecifier::Right) name << ".Right";
+ if(specifier == InputSpecifier::Lo) name << ".Lo";
+ if(specifier == InputSpecifier::Hi) name << ".Hi";
+ if(specifier == InputSpecifier::Trigger) name << ".Trigger";
}
-void InputObject::bind(uint16_t newCode) {
- code = newCode;
- codetype = InputCode::type(code);
-
- id = nall::input_find(newCode);
- modifier = None;
-
- if(type == Button && codetype == InputCode::JoypadHat) {
- switch(inputManager.state(code)) {
- case joypad<>::hat_up: id << "::up"; modifier = Up; break;
- case joypad<>::hat_down: id << "::down"; modifier = Down; break;
- case joypad<>::hat_left: id << "::left"; modifier = Left; break;
- case joypad<>::hat_right: id << "::right"; modifier = Right; break;
- }
- } else if(type == Button && codetype == InputCode::JoypadAxis) {
- InputCode::axistype_t type = InputCode::axisType(code);
- int16_t state = inputManager.state(code);
-
- if(type == InputCode::Stick) {
- if(state < 0) {
- id << "::lo";
- modifier = Lo;
- } else {
- id << "::hi";
- modifier = Hi;
- }
- } else if(type == InputCode::Trigger) {
- id << "::trigger";
- modifier = Trigger;
- }
- }
+void MappedInput::cache() {
+ cachedState = state;
}
-void InputObject::poll(int16_t newState) {
- if(type == Button && codetype == InputCode::JoypadHat) {
- //map 4-way hat input to button state
- state = (modifier == Up && (newState & joypad<>::hat_up ))
- || (modifier == Down && (newState & joypad<>::hat_down ))
- || (modifier == Left && (newState & joypad<>::hat_left ))
- || (modifier == Right && (newState & joypad<>::hat_right));
- } else if(type == Button && codetype == InputCode::JoypadAxis) {
- //convert analog input to button state
- state = (modifier == Lo && newState < -16384)
- || (modifier == Hi && newState > +16384)
- || (modifier == Trigger && newState < 0);
- } else if(codetype == InputCode::MouseAxis && !input.acquired()) {
- //mouse must be acquired (locked to window) to move axes
- state = 0;
- } else if(0 && codetype == InputCode::MouseButton && !input.acquired()) {
- //same for buttons
- //note: disabled for now ... requiring exclusive access makes it much more difficult
- //to utilize mouse buttons for eg SNES joypad input.
- state = 0;
- } else if(codetype == InputCode::JoypadAxis) {
- //joypad axis range = -32768 to +32767, scale to -8 to +7 to roughly match mouse delta
- //todo: scale mouse up instead of joypad down? (would require mouse DPI / resolution)
- state = newState / 4096;
+MappedInput::MappedInput(const char *label_, const char *configName) : parent(0), label(label_) {
+ specifier = InputSpecifier::None;
+ state = 0;
+ previousState = 0;
+ cachedState = 0;
+ config().attach(name = "None", configName);
+}
+
+//
+
+void DigitalInput::poll() {
+ previousState = state;
+ if(modifier == mapper().modifier) {
+ if(specifier == InputSpecifier::None) {
+ state = mapper().state(scancode);
+ } else if(specifier == InputSpecifier::Up) {
+ state = (bool)(mapper().state(scancode) & Joypad::HatUp);
+ } else if(specifier == InputSpecifier::Down) {
+ state = (bool)(mapper().state(scancode) & Joypad::HatDown);
+ } else if(specifier == InputSpecifier::Left) {
+ state = (bool)(mapper().state(scancode) & Joypad::HatLeft);
+ } else if(specifier == InputSpecifier::Right) {
+ state = (bool)(mapper().state(scancode) & Joypad::HatRight);
+ } else if(specifier == InputSpecifier::Lo) {
+ state = mapper().state(scancode) < -16384;
+ } else if(specifier == InputSpecifier::Hi) {
+ state = mapper().state(scancode) > +16384;
+ } else if(specifier == InputSpecifier::Trigger) {
+ state = mapper().state(scancode) < 0;
+ }
} else {
- state = newState;
+ state = 0;
}
}
-InputObject::InputObject(InputObject::type_t t, const char *n, string &s) : parent(0), type(t), name(n), id(s) {
+bool DigitalInput::isPressed() const { return state; }
+bool DigitalInput::wasPressed() const { return previousState; }
+
+DigitalInput::DigitalInput(const char *label, const char *configName) : MappedInput(label, configName) {
}
-//==========
-//InputGroup
-//==========
+//
-void InputGroup::attach(InputObject &object) {
- list.add(&object);
- object.parent = this;
+void AnalogInput::poll() {
+ previousState = state;
+ if(Mouse::isAnyAxis(scancode)) {
+ if(input.acquired()) {
+ state = mapper().state(scancode);
+ } else {
+ state = 0;
+ }
+ } else if(Joypad::isAnyAxis(scancode)) {
+ state = mapper().state(scancode) / 8192;
+ }
+}
+
+AnalogInput::AnalogInput(const char *label, const char *configName) : MappedInput(label, configName) {
+}
+
+//
+
+void HotkeyInput::poll() {
+ DigitalInput::poll();
+ if(state && state != previousState && mainWindow->isActive()) pressed();
+}
+
+HotkeyInput::HotkeyInput(const char *label, const char *configName) : DigitalInput(label, configName) {
+}
+
+//
+
+void InputGroup::attach(MappedInput *input) {
+ input->parent = this;
+ add(input);
}
void InputGroup::bind() {
- for(unsigned i = 0; i < list.size(); i++) list[i]->bind();
+ for(unsigned i = 0; i < size(); i++) {
+ (*this)[i]->bind();
+ }
}
-void InputGroup::clear() {
- for(unsigned i = 0; i < list.size(); i++) list[i]->state = 0;
+void InputGroup::poll() {
+ for(unsigned i = 0; i < size(); i++) {
+ (*this)[i]->poll();
+ }
}
-void InputGroup::poll(const int16_t *table) {
- for(unsigned i = 0; i < list.size(); i++) list[i]->poll(table[list[i]->code]);
+void InputGroup::cache() {
+ for(unsigned i = 0; i < size(); i++) {
+ (*this)[i]->cache();
+ }
}
-int16_t InputGroup::state(unsigned index) const {
- if(index < list.size()) return list[index]->state;
+void InputGroup::flushCache() {
+ for(unsigned i = 0; i < size(); i++) {
+ MappedInput &input = *((*this)[i]);
+ input.cachedState = 0;
+ }
+}
+
+InputGroup::InputGroup(unsigned category_, const char *label_) : category(category_), label(label_) {
+ mapper().add(this);
+}
+
+//
+
+InputMapper& mapper() {
+ static InputMapper mapper;
+ return mapper;
+}
+
+void InputMapper::calibrate() {
+ calibrated = true;
+ audio.clear();
+ QMessageBox::information(settingsWindow, "Joypad Calibration",
+ "Joypads must be calibrated prior to mapping. Please ensure that "
+ "all axes and analog buttons are not pressed or moved in any specific "
+ "direction, and then press ok."
+ );
+
+ poll();
+ for(unsigned i = 0; i < Joypad::Count; i++) {
+ for(unsigned axis = 0; axis < Joypad::Axes; axis++) {
+ int16_t n = state(joypad(i).axis(axis));
+ isTrigger[i][axis] = n < -16384 || n > +16384;
+ }
+ }
+}
+
+void InputMapper::bind() {
+ for(unsigned i = 0; i < size(); i++) {
+ (*this)[i]->bind();
+ }
+}
+
+void InputMapper::poll() {
+ activeState = !activeState;
+ input.poll(stateTable[activeState]);
+
+ modifier = 0;
+ for(unsigned i = 0; i < Keyboard::Count; i++) {
+ if(state(keyboard(i)[Keyboard::Shift])) modifier |= InputModifier::Shift;
+ if(state(keyboard(i)[Keyboard::Control])) modifier |= InputModifier::Control;
+ if(state(keyboard(i)[Keyboard::Alt])) modifier |= InputModifier::Alt;
+ if(state(keyboard(i)[Keyboard::Super])) modifier |= InputModifier::Super;
+ }
+
+ for(unsigned i = 0; i < size(); i++) {
+ (*this)[i]->poll();
+ }
+
+ for(unsigned i = 0; i < Scancode::Limit; i++) {
+ if(state(i) != previousState(i)) {
+ utility.inputEvent(i);
+ diskBrowser->inputEvent(i);
+ inputSettingsWindow->inputEvent(i);
+ }
+ }
+}
+
+void InputMapper::cache() {
+ if(config().input.focusPolicy == Configuration::Input::FocusPolicyIgnoreInput && !mainWindow->isActive()) {
+ for(unsigned i = 0; i < size(); i++) {
+ InputGroup &group = *((*this)[i]);
+ group.flushCache();
+ }
+ } else {
+ for(unsigned i = 0; i < size(); i++) {
+ InputGroup &group = *((*this)[i]);
+ if(group.category == InputCategory::Port1 || group.category == InputCategory::Port2) {
+ group.cache();
+ }
+ }
+ }
+}
+
+int16_t InputMapper::status(bool port, unsigned device, unsigned index, unsigned id) {
+ if(port == InputCategory::Port1 && port1) return port1->status(index, id);
+ if(port == InputCategory::Port2 && port2) return port2->status(index, id);
return 0;
}
-InputGroup::InputGroup(const char *n) : list(*this), name(n) {
+string InputMapper::modifierString() const {
+ string name;
+ if(modifier & InputModifier::Shift) name << "Shift+";
+ if(modifier & InputModifier::Control) name << "Control+";
+ if(modifier & InputModifier::Alt) name << "Alt+";
+ if(modifier & InputModifier::Super) name << "Super+";
+ return name;
+}
+
+int16_t InputMapper::state(uint16_t scancode) const { return stateTable[activeState][scancode]; }
+int16_t InputMapper::previousState(uint16_t scancode) const { return stateTable[!activeState][scancode]; }
+unsigned InputMapper::distance(uint16_t scancode) const { return abs(state(scancode) - previousState(scancode)); }
+
+InputMapper::InputMapper() : port1(0), port2(0) {
+ calibrated = false;
+ for(unsigned i = 0; i < Joypad::Count; i++) {
+ for(unsigned axis = 0; axis < Joypad::Axes; axis++) {
+ isTrigger[i][axis] = false;
+ }
+ }
+
+ activeState = 0;
+ for(unsigned i = 0; i < Scancode::Limit; i++) {
+ stateTable[0][i] = stateTable[1][i] = 0;
+ }
}
diff --git a/src/ui_qt/input/input.hpp b/src/ui_qt/input/input.hpp
index 55e784c2..0e1467b7 100644
--- a/src/ui_qt/input/input.hpp
+++ b/src/ui_qt/input/input.hpp
@@ -1,88 +1,89 @@
-struct InputCode {
- enum type_t {
- KeyboardButton,
- MouseAxis,
- MouseButton,
- JoypadHat,
- JoypadAxis,
- JoypadButton,
- Unknown,
- };
- enum axistype_t {
- Stick, //bi-directional, centered analog stick (min = -32768, inactive = 0, max = +32767)
- Trigger, //uni-directional, pressure-sensitive analog trigger button (min = -32768, inactive = max = +32767)
- InvalidAxis, //not a joypad axis code, or said joypad is not calibrated
- };
- static type_t type(uint16_t code);
- static axistype_t axisType(uint16_t code);
- static int mouseNumber(uint16_t code);
- static int joypadNumber(uint16_t code);
-};
-
-class InputManager {
-public:
- void bind();
- void poll();
- void clear();
- void flush();
-
- int16_t state(uint16_t code) const;
- int16_t lastState(uint16_t code) const;
- int16_t getStatus(unsigned deviceid, unsigned id) const;
-
- void refresh();
- void calibrate(unsigned joypad);
- bool calibrated(unsigned joypad) const;
- InputCode::axistype_t axisType(unsigned joypad, unsigned axis) const;
- function onInput;
-
- InputManager();
-
-private:
- bool activeState;
- int16_t stateTable[2][nall::input_limit];
-
- //joypad axis calibration data
- struct Pad {
- bool calibrated;
- InputCode::axistype_t axis[joypad<>::axes];
- } pad[joypad<>::count];
-} inputManager;
+struct InputSpecifier { enum { None, Up, Down, Left, Right, Lo, Hi, Trigger }; };
+struct InputModifier { enum { None = 0, Shift = 1, Control = 2, Alt = 4, Super = 8 }; };
+struct InputCategory { enum { Port1 = 0, Port2 = 1, UserInterface = 2, Hidden = 3 }; };
struct InputGroup;
-struct InputObject {
+struct MappedInput {
InputGroup *parent;
- enum type_t { Button, Axis };
- enum modifier_t { None, Up, Down, Left, Right, Lo, Hi, Trigger };
-
- type_t type; //type of input this object is mapped to
- const char *name; //plain-text name ("Up", "Down", ... "Start")
- string &id; //config-item reference ("joypad1.start") name ("joypad00.button00")
- uint16_t code; //nall::input code ID
- InputCode::type_t codetype; //hardware button / axis type
- modifier_t modifier; //hardware specialization (joypad-axis "::lo", "::hi", etc)
- int16_t state; //code state as of last inputManager.poll()
+ string name;
+ string label;
+ unsigned specifier;
+ unsigned modifier;
+ unsigned scancode;
+ int16_t state;
+ int16_t previousState;
+ int16_t cachedState;
void bind();
- void bind(uint16_t code);
- void poll(int16_t state);
- InputObject(type_t t, const char *n, string &s);
+ virtual void poll() = 0;
+ virtual void cache();
+
+ MappedInput(const char*, const char*);
};
-struct InputGroup : public array {
- const char *name;
+struct DigitalInput : MappedInput {
+ void poll();
- void attach(InputObject &object);
+ bool isPressed() const;
+ bool wasPressed() const;
+
+ DigitalInput(const char*, const char*);
+};
+
+struct AnalogInput : MappedInput {
+ void poll();
+
+ AnalogInput(const char*, const char*);
+};
+
+struct HotkeyInput : DigitalInput {
+ void poll();
+ virtual void pressed() {}
+
+ HotkeyInput(const char*, const char*);
+};
+
+struct InputGroup : public array {
+ unsigned category;
+ string label;
+
+ void attach(MappedInput*);
void bind();
- void clear();
- void poll(const int16_t *table);
- virtual int16_t state(unsigned index) const;
- InputGroup(const char *n);
+ void poll();
+ void cache();
+ void flushCache();
+ virtual int16_t status(unsigned, unsigned) const { return 0; }
-private:
- array &list;
+ InputGroup(unsigned, const char*);
};
-#include "device.hpp"
+struct InputMapper : public array {
+ InputGroup *port1;
+ InputGroup *port2;
+
+ bool calibrated;
+ bool isTrigger[Joypad::Count][Joypad::Axes];
+
+ bool activeState;
+ int16_t stateTable[2][Scancode::Limit];
+ unsigned modifier;
+
+ void calibrate();
+ void bind();
+ void poll();
+ void cache();
+ int16_t status(bool, unsigned, unsigned, unsigned);
+
+ string modifierString() const;
+ int16_t state(uint16_t) const;
+ int16_t previousState(uint16_t) const;
+ unsigned distance(uint16_t) const;
+
+ InputMapper();
+};
+
+InputMapper& mapper();
+
+#include "controller.hpp"
#include "userinterface.hpp"
diff --git a/src/ui_qt/input/userinterface-emulationspeed.cpp b/src/ui_qt/input/userinterface-emulationspeed.cpp
new file mode 100644
index 00000000..b4e50d91
--- /dev/null
+++ b/src/ui_qt/input/userinterface-emulationspeed.cpp
@@ -0,0 +1,118 @@
+InputGroup userInterfaceEmulationSpeed(InputCategory::UserInterface, "Emulation Speed");
+
+namespace UserInterfaceEmulationSpeed {
+
+struct Decrease : HotkeyInput {
+ void pressed() {
+ if(config().system.speed > 0) config().system.speed--;
+ utility.updateEmulationSpeed();
+ mainWindow->syncUi();
+ }
+
+ Decrease() : HotkeyInput("Decrease", "config.userInterface.emulationSpeed.decrease") {
+ name = "Control+KB0::Divide";
+ userInterfaceEmulationSpeed.attach(this);
+ }
+} decrease;
+
+struct Increase : HotkeyInput {
+ void pressed() {
+ if(config().system.speed < 4) config().system.speed++;
+ utility.updateEmulationSpeed();
+ mainWindow->syncUi();
+ }
+
+ Increase() : HotkeyInput("Increase", "config.userInterface.emulationSpeed.increase") {
+ name = "Control+KB0::Multiply";
+ userInterfaceEmulationSpeed.attach(this);
+ }
+} increase;
+
+struct SetSlowestSpeed : HotkeyInput {
+ void pressed() {
+ config().system.speed = 0;
+ utility.updateEmulationSpeed();
+ mainWindow->syncUi();
+ }
+
+ SetSlowestSpeed() : HotkeyInput("Set Slowest Speed", "config.userInterface.emulationSpeed.setSlowest") {
+ name = "Control+KB0::Num1";
+ userInterfaceEmulationSpeed.attach(this);
+ }
+} setSlowestSpeed;
+
+struct SetSlowSpeed : HotkeyInput {
+ void pressed() {
+ config().system.speed = 1;
+ utility.updateEmulationSpeed();
+ mainWindow->syncUi();
+ }
+
+ SetSlowSpeed() : HotkeyInput("Set Slow Speed", "config.userInterface.emulationSpeed.setSlow") {
+ name = "Control+KB0::Num2";
+ userInterfaceEmulationSpeed.attach(this);
+ }
+} setSlowSpeed;
+
+struct SetNormalSpeed : HotkeyInput {
+ void pressed() {
+ config().system.speed = 2;
+ utility.updateEmulationSpeed();
+ mainWindow->syncUi();
+ }
+
+ SetNormalSpeed() : HotkeyInput("Set Normal Speed", "config.userInterface.emulationSpeed.setNormal") {
+ name = "Control+KB0::Num3";
+ userInterfaceEmulationSpeed.attach(this);
+ }
+} setNormalSpeed;
+
+struct SetFastSpeed : HotkeyInput {
+ void pressed() {
+ config().system.speed = 3;
+ utility.updateEmulationSpeed();
+ mainWindow->syncUi();
+ }
+
+ SetFastSpeed() : HotkeyInput("Set Fast Speed", "config.userInterface.emulationSpeed.setFast") {
+ name = "Control+KB0::Num4";
+ userInterfaceEmulationSpeed.attach(this);
+ }
+} setFastSpeed;
+
+struct SetFastestSpeed : HotkeyInput {
+ void pressed() {
+ config().system.speed = 4;
+ utility.updateEmulationSpeed();
+ mainWindow->syncUi();
+ }
+
+ SetFastestSpeed() : HotkeyInput("Set Fastest Speed", "config.userInterface.emulationSpeed.setFastest") {
+ name = "Control+KB0::Num5";
+ userInterfaceEmulationSpeed.attach(this);
+ }
+} setFastestSpeed;
+
+struct SynchronizeVideo : HotkeyInput {
+ void pressed() {
+ utility.toggleSynchronizeVideo();
+ }
+
+ SynchronizeVideo() : HotkeyInput("Synchronize Video", "config.userInterface.emulationSpeed.synchronizeVideo") {
+ name = "Control+KB0::V";
+ userInterfaceEmulationSpeed.attach(this);
+ }
+} synchronizeVideo;
+
+struct SynchronizeAudio : HotkeyInput {
+ void pressed() {
+ utility.toggleSynchronizeAudio();
+ }
+
+ SynchronizeAudio() : HotkeyInput("Synchronize Audio", "config.userInterface.emulationSpeed.synchronizeAudio") {
+ name = "Control+KB0::A";
+ userInterfaceEmulationSpeed.attach(this);
+ }
+} synchronizeAudio;
+
+}
diff --git a/src/ui_qt/input/userinterface-general.cpp b/src/ui_qt/input/userinterface-general.cpp
new file mode 100644
index 00000000..791af36e
--- /dev/null
+++ b/src/ui_qt/input/userinterface-general.cpp
@@ -0,0 +1,68 @@
+InputGroup userInterfaceGeneral(InputCategory::UserInterface, "General");
+
+namespace UserInterfaceGeneral {
+
+struct ToggleMenubar : HotkeyInput {
+ void pressed() {
+ utility.toggleMenubar();
+ }
+
+ ToggleMenubar() : HotkeyInput("Toggle Menubar", "input.userInterface.general.toggleMenubar") {
+ name = "KB0::F12";
+ userInterfaceGeneral.attach(this);
+ }
+} toggleMenubar;
+
+struct ToggleStatusbar : HotkeyInput {
+ void pressed() {
+ utility.toggleStatusbar();
+ }
+
+ ToggleStatusbar() : HotkeyInput("Toggle Statusbar", "input.userInterface.general.toggleStatusbar") {
+ name = "KB0::F12";
+ userInterfaceGeneral.attach(this);
+ }
+} toggleStatusbar;
+
+struct ToggleCheatSystem : HotkeyInput {
+ void pressed() {
+ if(SNES::cheat.enabled() == false) {
+ SNES::cheat.enable();
+ utility.showMessage("Cheat system enabled.");
+ } else {
+ SNES::cheat.disable();
+ utility.showMessage("Cheat system disabled.");
+ }
+ }
+
+ ToggleCheatSystem() : HotkeyInput("Toggle Cheat System", "input.userInterface.general.toggleCheatSystem") {
+ userInterfaceGeneral.attach(this);
+ }
+} toggleCheatSystem;
+
+struct CaptureScreenshot : HotkeyInput {
+ void pressed() {
+ //tell SNES::Interface to save a screenshot at the next video_refresh() event
+ interface.saveScreenshot = true;
+ }
+
+ CaptureScreenshot() : HotkeyInput("Capture Screenshot", "input.userInterface.general.captureScreenshot") {
+ userInterfaceGeneral.attach(this);
+ }
+} captureScreenshot;
+
+//put here instead of in a separate "Audio Settings" group,
+//because there is only one audio option at present
+struct MuteAudioOutput : HotkeyInput {
+ void pressed() {
+ mainWindow->settings_muteAudio->toggleChecked();
+ config().audio.mute = mainWindow->settings_muteAudio->isChecked();
+ }
+
+ MuteAudioOutput() : HotkeyInput("Mute Audio Output", "input.userInterface.general.muteAudioOutput") {
+ name = "Shift+KB0::M";
+ userInterfaceGeneral.attach(this);
+ }
+} muteAudioOutput;
+
+}
diff --git a/src/ui_qt/input/userinterface-states.cpp b/src/ui_qt/input/userinterface-states.cpp
new file mode 100644
index 00000000..722f48c8
--- /dev/null
+++ b/src/ui_qt/input/userinterface-states.cpp
@@ -0,0 +1,115 @@
+InputGroup userInterfaceStates(InputCategory::UserInterface, "States");
+
+namespace UserInterfaceStates {
+
+//note: interally, there are ten quick save slots: 0-9
+//for the sake of users, this is displayed as 1-10 in the GUI
+unsigned activeState = 0;
+
+struct LoadActiveState : HotkeyInput {
+ void pressed() {
+ utility.quickLoad(activeState);
+ }
+
+ LoadActiveState() : HotkeyInput("Load Active Quick State", "input.userInterface.states.loadActiveQuickState") {
+ name = "KB0::F2";
+ userInterfaceStates.attach(this);
+ }
+} loadActiveState;
+
+struct SaveActiveState : HotkeyInput {
+ void pressed() {
+ utility.quickSave(activeState);
+ }
+
+ SaveActiveState() : HotkeyInput("Save Active Quick State", "input.userInterface.states.saveActiveQuickState") {
+ name = "Shift+KB0::F2";
+ userInterfaceStates.attach(this);
+ }
+} saveActiveState;
+
+struct DecrementActiveState : HotkeyInput {
+ void pressed() {
+ activeState = (activeState + 10 - 1) % 10;
+ utility.showMessage(string() << "Quick state " << (activeState + 1) << " selected.");
+ }
+
+ DecrementActiveState() : HotkeyInput("Decrement Active Quick State Slot", "input.userInterface.states.decrementActiveQuickState") {
+ name = "KB0::F3";
+ userInterfaceStates.attach(this);
+ }
+} decrementActiveState;
+
+struct IncrementActiveState : HotkeyInput {
+ void pressed() {
+ activeState = (activeState + 10 + 1) % 10;
+ utility.showMessage(string() << "Quick state " << (activeState + 1) << " selected.");
+ }
+
+ IncrementActiveState() : HotkeyInput("Increment Active Quick State Slot", "input.userInterface.states.incrementActiveQuickState") {
+ name = "KB0::F4";
+ userInterfaceStates.attach(this);
+ }
+} incrementActiveState;
+
+struct LoadState1 : HotkeyInput {
+ void pressed() {
+ utility.quickLoad(0);
+ }
+
+ LoadState1() : HotkeyInput("Load Quick State 1", "input.userInterface.states.loadQuickState1") {
+ userInterfaceStates.attach(this);
+ }
+} loadState1;
+
+struct LoadState2 : HotkeyInput {
+ void pressed() {
+ utility.quickLoad(1);
+ }
+
+ LoadState2() : HotkeyInput("Load Quick State 2", "input.userInterface.states.loadQuickState2") {
+ userInterfaceStates.attach(this);
+ }
+} loadState2;
+
+struct LoadState3 : HotkeyInput {
+ void pressed() {
+ utility.quickLoad(2);
+ }
+
+ LoadState3() : HotkeyInput("Load Quick State 3", "input.userInterface.states.loadQuickState3") {
+ userInterfaceStates.attach(this);
+ }
+} loadState3;
+
+struct SaveState1 : HotkeyInput {
+ void pressed() {
+ utility.quickSave(0);
+ }
+
+ SaveState1() : HotkeyInput("Save Quick State 1", "input.userInterface.states.saveQuickState1") {
+ userInterfaceStates.attach(this);
+ }
+} saveState1;
+
+struct SaveState2 : HotkeyInput {
+ void pressed() {
+ utility.quickSave(1);
+ }
+
+ SaveState2() : HotkeyInput("Save Quick State 2", "input.userInterface.states.saveQuickState2") {
+ userInterfaceStates.attach(this);
+ }
+} saveState2;
+
+struct SaveState3 : HotkeyInput {
+ void pressed() {
+ utility.quickSave(2);
+ }
+
+ SaveState3() : HotkeyInput("Save Quick State 3", "input.userInterface.states.saveQuickState3") {
+ userInterfaceStates.attach(this);
+ }
+} saveState3;
+
+}
diff --git a/src/ui_qt/input/userinterface-system.cpp b/src/ui_qt/input/userinterface-system.cpp
new file mode 100644
index 00000000..9809bbad
--- /dev/null
+++ b/src/ui_qt/input/userinterface-system.cpp
@@ -0,0 +1,88 @@
+InputGroup userInterfaceSystem(InputCategory::UserInterface, "System");
+
+namespace UserInterfaceSystem {
+
+struct LoadCartridge : HotkeyInput {
+ void pressed() {
+ diskBrowser->loadCartridge();
+ }
+
+ LoadCartridge() : HotkeyInput("Load Cartridge", "input.userInterface.system.loadCartridge") {
+ name = "Shift+KB0::L";
+ userInterfaceSystem.attach(this);
+ }
+} loadCartridge;
+
+struct LoadBsxSlottedCartridge : HotkeyInput {
+ void pressed() {
+ loaderWindow->loadBsxSlottedCartridge("", "");
+ }
+
+ LoadBsxSlottedCartridge() : HotkeyInput("Load BS-X Slotted Cartridge", "input.userInterface.system.loadBsxSlottedcartridge") {
+ userInterfaceSystem.attach(this);
+ }
+} loadBsxSlottedCartridge;
+
+struct LoadBsxCartridge : HotkeyInput {
+ void pressed() {
+ loaderWindow->loadBsxCartridge(config().path.bsx, "");
+ }
+
+ LoadBsxCartridge() : HotkeyInput("Load BS-X Cartridge", "input.userInterface.system.loadBsxCartridge") {
+ userInterfaceSystem.attach(this);
+ }
+} loadBsxCartridge;
+
+struct LoadSufamiTurboCartridge : HotkeyInput {
+ void pressed() {
+ loaderWindow->loadSufamiTurboCartridge(config().path.st, "", "");
+ }
+
+ LoadSufamiTurboCartridge() : HotkeyInput("Load Sufami Turbo Cartridge", "input.userInterface.system.loadSufamiTurboCartridge") {
+ userInterfaceSystem.attach(this);
+ }
+} loadSufamiTurboCartridge;
+
+struct LoadSuperGameBoyCartridge : HotkeyInput {
+ void pressed() {
+ loaderWindow->loadSuperGameBoyCartridge(config().path.sgb, "");
+ }
+
+ LoadSuperGameBoyCartridge() : HotkeyInput("Load Super Game Boy Cartridge", "input.userInterface.system.loadSuperGameBoyCartridge") {
+ userInterfaceSystem.attach(this);
+ }
+} loadSuperGameBoyCartridge;
+
+struct PowerCycle : HotkeyInput {
+ void pressed() {
+ utility.modifySystemState(Utility::PowerCycle);
+ }
+
+ PowerCycle() : HotkeyInput("Power Cycle", "input.userInterface.system.powerCycle") {
+ userInterfaceSystem.attach(this);
+ }
+} powerCycle;
+
+struct Reset : HotkeyInput {
+ void pressed() {
+ utility.modifySystemState(Utility::Reset);
+ }
+
+ Reset() : HotkeyInput("Reset", "input.userInterface.system.reset") {
+ userInterfaceSystem.attach(this);
+ }
+} reset;
+
+struct Pause : HotkeyInput {
+ void pressed() {
+ application.pause = !application.pause;
+ if(application.pause) audio.clear();
+ }
+
+ Pause() : HotkeyInput("Pause", "input.userInterface.system.pause") {
+ name = "KB0::Pause";
+ userInterfaceSystem.attach(this);
+ }
+} pause;
+
+}
diff --git a/src/ui_qt/input/userinterface-videosettings.cpp b/src/ui_qt/input/userinterface-videosettings.cpp
new file mode 100644
index 00000000..14951d22
--- /dev/null
+++ b/src/ui_qt/input/userinterface-videosettings.cpp
@@ -0,0 +1,115 @@
+InputGroup userInterfaceVideoSettings(InputCategory::UserInterface, "Video Settings");
+
+namespace UserInterfaceVideoSettings {
+
+struct ToggleFullscreen : HotkeyInput {
+ void pressed() {
+ utility.toggleFullscreen();
+ }
+
+ ToggleFullscreen() : HotkeyInput("Toggle Fullscreen Mode", "input.userInterface.videoSettings.toggleFullscreen") {
+ name = "KB0::F11";
+ userInterfaceVideoSettings.attach(this);
+ }
+} toggleFullscreen;
+
+struct SmoothVideoOutput : HotkeyInput {
+ void pressed() {
+ utility.toggleSmoothVideoOutput();
+ }
+
+ SmoothVideoOutput() : HotkeyInput("Smooth Video Output", "input.userInterface.videoSettings.smoothVideoOutput") {
+ name = "Shift+KB0::S";
+ userInterfaceVideoSettings.attach(this);
+ }
+} smoothVideoOutput;
+
+struct SetNtscMode : HotkeyInput {
+ void pressed() {
+ utility.setNtscMode();
+ }
+
+ SetNtscMode() : HotkeyInput("Set NTSC Mode", "input.userInterface.videoSettings.ntscMode") {
+ name = "Shift+KB0::N";
+ userInterfaceVideoSettings.attach(this);
+ }
+} setNtscMode;
+
+struct SetPalMode : HotkeyInput {
+ void pressed() {
+ utility.setPalMode();
+ }
+
+ SetPalMode() : HotkeyInput("Set PAL Mode", "input.userInterface.videoSettings.palMode") {
+ name = "Shift+KB0::P";
+ userInterfaceVideoSettings.attach(this);
+ }
+} setPalMode;
+
+struct AspectCorrection : HotkeyInput {
+ void pressed() {
+ utility.toggleAspectCorrection();
+ }
+
+ AspectCorrection() : HotkeyInput("Aspect Correction", "input.userInterface.videoSettings.aspectCorrection") {
+ name = "Shift+KB0::A";
+ userInterfaceVideoSettings.attach(this);
+ }
+} aspectCorrection;
+
+struct Scale1x : HotkeyInput {
+ void pressed() {
+ utility.setScale(1);
+ }
+
+ Scale1x() : HotkeyInput("Scale 1x", "input.userInterface.videoSettings.scale1x") {
+ name = "Shift+KB0::Num1";
+ userInterfaceVideoSettings.attach(this);
+ }
+} scale1x;
+
+struct Scale2x : HotkeyInput {
+ void pressed() {
+ utility.setScale(2);
+ }
+
+ Scale2x() : HotkeyInput("Scale 2x", "input.userInterface.videoSettings.scale2x") {
+ name = "Shift+KB0::Num2";
+ userInterfaceVideoSettings.attach(this);
+ }
+} scale2x;
+
+struct Scale3x : HotkeyInput {
+ void pressed() {
+ utility.setScale(3);
+ }
+
+ Scale3x() : HotkeyInput("Scale 3x", "input.userInterface.videoSettings.scale3x") {
+ name = "Shift+KB0::Num3";
+ userInterfaceVideoSettings.attach(this);
+ }
+} scale3x;
+
+struct Scale4x : HotkeyInput {
+ void pressed() {
+ utility.setScale(4);
+ }
+
+ Scale4x() : HotkeyInput("Scale 4x", "input.userInterface.videoSettings.scale4x") {
+ name = "Shift+KB0::Num4";
+ userInterfaceVideoSettings.attach(this);
+ }
+} scale4x;
+
+struct Scale5x : HotkeyInput {
+ void pressed() {
+ utility.setScale(5);
+ }
+
+ Scale5x() : HotkeyInput("Scale 5x", "input.userInterface.videoSettings.scale5x") {
+ name = "Shift+KB0::Num5";
+ userInterfaceVideoSettings.attach(this);
+ }
+} scale5x;
+
+}
diff --git a/src/ui_qt/input/userinterface.cpp b/src/ui_qt/input/userinterface.cpp
deleted file mode 100644
index c8e89205..00000000
--- a/src/ui_qt/input/userinterface.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-//==============
-//InputGroupPool
-//==============
-
-void InputGroupPool::attach(InputGroup &group) {
- list.add(&group);
-}
-
-void InputGroupPool::bind() {
- for(unsigned i = 0; i < list.size(); i++) list[i]->bind();
-}
-
-void InputGroupPool::clear() {
- for(unsigned i = 0; i < list.size(); i++) list[i]->clear();
-}
-
-void InputGroupPool::poll(const int16_t *table) {
- for(unsigned i = 0; i < list.size(); i++) list[i]->poll(table);
-}
-
-InputGroupPool::InputGroupPool() : list(*this) {
-}
-
-//
-
-InputUiGeneral inputUiGeneral;
-InputUiPool inputUiPool;
-
-InputUiGeneral::InputUiGeneral() : InputGroup("General"),
-loadCartridge(InputObject::Button, "Load cartridge", config.input.uiGeneral.loadCartridge),
-pauseEmulation(InputObject::Button, "Pause emulation", config.input.uiGeneral.pauseEmulation),
-resetSystem(InputObject::Button, "Reset system", config.input.uiGeneral.resetSystem),
-powerCycleSystem(InputObject::Button, "Power cycle system", config.input.uiGeneral.powerCycleSystem),
-
-captureScreenshot(InputObject::Button, "Capture screenshot", config.input.uiGeneral.captureScreenshot),
-showStateManager(InputObject::Button, "Show state manager window", config.input.uiGeneral.showStateManager),
-quickLoad1(InputObject::Button, "Load from temporary state 1", config.input.uiGeneral.quickLoad1),
-quickLoad2(InputObject::Button, "Load from temporary state 2", config.input.uiGeneral.quickLoad2),
-quickLoad3(InputObject::Button, "Load from temporary state 3", config.input.uiGeneral.quickLoad3),
-quickSave1(InputObject::Button, "Save to temporary state 1", config.input.uiGeneral.quickSave1),
-quickSave2(InputObject::Button, "Save to temporary state 2", config.input.uiGeneral.quickSave2),
-quickSave3(InputObject::Button, "Save to temporary state 3", config.input.uiGeneral.quickSave3),
-
-lowerSpeed(InputObject::Button, "Decrease emulation speed", config.input.uiGeneral.lowerSpeed),
-raiseSpeed(InputObject::Button, "Increase emulation speed", config.input.uiGeneral.raiseSpeed),
-toggleCheatSystem(InputObject::Button, "Toggle cheat system on or off", config.input.uiGeneral.toggleCheatSystem),
-toggleFullscreen(InputObject::Button, "Toggle fullscreen mode", config.input.uiGeneral.toggleFullscreen),
-toggleMenu(InputObject::Button, "Toggle menubar", config.input.uiGeneral.toggleMenu),
-toggleStatus(InputObject::Button, "Toggle statusbar", config.input.uiGeneral.toggleStatus),
-exitEmulator(InputObject::Button, "Exit emulator", config.input.uiGeneral.exitEmulator) {
- attach(loadCartridge);
- attach(pauseEmulation);
- attach(resetSystem);
- attach(powerCycleSystem);
-
- attach(captureScreenshot);
- attach(showStateManager);
- attach(quickLoad1);
- attach(quickLoad2);
- attach(quickLoad3);
- attach(quickSave1);
- attach(quickSave2);
- attach(quickSave3);
-
- attach(lowerSpeed);
- attach(raiseSpeed);
- attach(toggleCheatSystem);
- attach(toggleFullscreen);
- attach(toggleMenu);
- attach(toggleStatus);
- attach(exitEmulator);
-}
-
-InputUiPool::InputUiPool() {
- attach(inputUiGeneral);
-}
diff --git a/src/ui_qt/input/userinterface.hpp b/src/ui_qt/input/userinterface.hpp
index 6ab87ace..f291e10a 100644
--- a/src/ui_qt/input/userinterface.hpp
+++ b/src/ui_qt/input/userinterface.hpp
@@ -1,41 +1,5 @@
-struct InputUiGeneral : public InputGroup {
- InputObject loadCartridge;
- InputObject pauseEmulation;
- InputObject resetSystem;
- InputObject powerCycleSystem;
- InputObject captureScreenshot;
- InputObject showStateManager;
- InputObject quickLoad1;
- InputObject quickLoad2;
- InputObject quickLoad3;
- InputObject quickSave1;
- InputObject quickSave2;
- InputObject quickSave3;
- InputObject lowerSpeed;
- InputObject raiseSpeed;
- InputObject toggleCheatSystem;
- InputObject toggleFullscreen;
- InputObject toggleMenu;
- InputObject toggleStatus;
- InputObject exitEmulator;
-
- InputUiGeneral();
-};
-
-struct InputGroupPool : public array {
- void attach(InputGroup &group);
- void bind();
- void clear();
- void poll(const int16_t *table);
- InputGroupPool();
-
-private:
- array &list;
-};
-
-struct InputUiPool : public InputGroupPool {
- InputUiPool();
-};
-
-extern InputUiGeneral inputUiGeneral;
-extern InputUiPool inputUiPool;
+extern InputGroup userInterfaceGeneral;
+extern InputGroup userInterfaceSystem;
+extern InputGroup userInterfaceEmulationSpeed;
+extern InputGroup userInterfaceStates;
+extern InputGroup userInterfaceVideoSettings;
diff --git a/src/ui_qt/interface.cpp b/src/ui_qt/interface.cpp
index 4be999d6..396bb2b9 100644
--- a/src/ui_qt/interface.cpp
+++ b/src/ui_qt/interface.cpp
@@ -14,16 +14,16 @@ void Interface::video_refresh(uint16_t *data, unsigned pitch, unsigned *line, un
}
void Interface::audio_sample(uint16_t left, uint16_t right) {
- if(config.audio.mute) left = right = 0;
+ if(config().audio.mute) left = right = 0;
audio.sample(left, right);
}
void Interface::input_poll() {
- inputManager.poll();
+ mapper().cache();
}
-int16_t Interface::input_poll(unsigned deviceid, unsigned id) {
- return inputManager.getStatus(deviceid, id);
+int16_t Interface::input_poll(bool port, unsigned device, unsigned index, unsigned id) {
+ return mapper().status(port, device, index, id);
}
void Interface::captureScreenshot(uint32_t *data, unsigned pitch, unsigned width, unsigned height) {
@@ -40,9 +40,9 @@ void Interface::captureScreenshot(uint32_t *data, unsigned pitch, unsigned width
);
filename << t << ".png";
- string path = config.path.data;
+ string path = config().path.data;
if(path == "") path = dir(utility.cartridge.baseName);
- image.save(utf8() << path << filename);
+ image.save(string() << path << filename);
utility.showMessage("Screenshot saved.");
}
diff --git a/src/ui_qt/interface.hpp b/src/ui_qt/interface.hpp
index 30c9ea75..0be6fe81 100644
--- a/src/ui_qt/interface.hpp
+++ b/src/ui_qt/interface.hpp
@@ -3,7 +3,7 @@ public:
void video_refresh(uint16_t *data, unsigned pitch, unsigned *line, unsigned width, unsigned height);
void audio_sample(uint16_t left, uint16_t right);
void input_poll();
- int16_t input_poll(unsigned deviceid, unsigned id);
+ int16_t input_poll(bool port, unsigned device, unsigned index, unsigned id);
Interface();
void captureScreenshot(uint32_t*, unsigned, unsigned, unsigned);
diff --git a/src/ui_qt/link/filter.cpp b/src/ui_qt/link/filter.cpp
index c5943c5c..9f93f283 100644
--- a/src/ui_qt/link/filter.cpp
+++ b/src/ui_qt/link/filter.cpp
@@ -1,3 +1,81 @@
+//==============
+//ScanlineFilter
+//==============
+
+ScanlineFilter scanlineFilter;
+
+void ScanlineFilter::size(unsigned &width, unsigned &height) {
+ if(enabled && height <= 240) height *= 2;
+}
+
+void ScanlineFilter::render(
+ const uint16_t *&input, unsigned &pitch,
+ const unsigned *&line, unsigned width, unsigned &height
+) {
+ if(enabled && height <= 240) {
+ pitch >>= 1;
+
+ const uint16_t *sp = input;
+ uint16_t *dp = buffer;
+ unsigned *lp = linewidth;
+ for(unsigned y = 0; y < height; y++) {
+ for(unsigned x = 0; x < line[y]; x++) {
+ uint16_t color = *sp++;
+ *(dp + 0) = color;
+ *(dp + 512) = adjust[color];
+ dp++;
+ }
+
+ sp += pitch - line[y];
+ dp += 1024 - line[y];
+
+ *lp++ = line[y];
+ *lp++ = line[y];
+ }
+
+ input = buffer;
+ pitch = 1024;
+ line = linewidth;
+ height *= 2;
+ }
+}
+
+void ScanlineFilter::setIntensity(unsigned intensity) {
+ if(intensity >= 100) {
+ enabled = false;
+ } else {
+ enabled = true;
+
+ for(unsigned i = 0; i < 32768; i++) {
+ unsigned r = (i >> 0) & 31;
+ unsigned g = (i >> 5) & 31;
+ unsigned b = (i >> 10) & 31;
+
+ r = (double)r * (double)intensity / 100.0;
+ g = (double)g * (double)intensity / 100.0;
+ b = (double)b * (double)intensity / 100.0;
+
+ adjust[i] = (r << 0) + (g << 5) + (b << 10);
+ }
+ }
+}
+
+ScanlineFilter::ScanlineFilter() {
+ enabled = false;
+ adjust = new uint16_t[32768];
+ buffer = new uint16_t[512 * 480];
+ setIntensity(50);
+}
+
+ScanlineFilter::~ScanlineFilter() {
+ delete[] adjust;
+ delete[] buffer;
+}
+
+//======
+//Filter
+//======
+
Filter filter;
const uint8_t Filter::gamma_ramp_table[32] = {
@@ -90,8 +168,10 @@ void Filter::colortable_update() {
}
void Filter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
+ scanlineFilter.size(width, height);
+
if(opened() && renderer > 0) {
- return dl_size(renderer - 1, outwidth, outheight, width, height);
+ return dl_size(renderer, outwidth, outheight, width, height);
}
outwidth = width;
@@ -103,8 +183,10 @@ void Filter::render(
const uint16_t *input, unsigned pitch,
const unsigned *line, unsigned width, unsigned height
) {
+ scanlineFilter.render(input, pitch, line, width, height);
+
if(opened() && renderer > 0) {
- return dl_render(renderer - 1, output, outpitch, input, pitch, line, width, height);
+ return dl_render(renderer, output, outpitch, input, pitch, line, width, height);
}
pitch >>= 1;
@@ -131,7 +213,7 @@ void Filter::render(
QWidget* Filter::settings() {
if(opened() && renderer > 0) {
- return dl_settings(renderer - 1);
+ return dl_settings(renderer);
} else {
return 0;
}
@@ -161,10 +243,10 @@ Filter::Filter() {
dl_settings = sym("snesfilter_settings");
dl_colortable(colortable);
- dl_configuration(config);
+ dl_configuration(config());
} else {
- config.video.windowed.swFilter = 0;
- config.video.fullscreen.swFilter = 0;
+ config().video.windowed.swFilter = 0;
+ config().video.fullscreen.swFilter = 0;
}
}
diff --git a/src/ui_qt/link/filter.hpp b/src/ui_qt/link/filter.hpp
index f4205731..6db29989 100644
--- a/src/ui_qt/link/filter.hpp
+++ b/src/ui_qt/link/filter.hpp
@@ -1,3 +1,20 @@
+class ScanlineFilter {
+public:
+ bool enabled;
+
+ void size(unsigned&, unsigned&);
+ void render(const uint16_t*&, unsigned&, const unsigned*&, unsigned, unsigned&);
+ void setIntensity(unsigned);
+
+ ScanlineFilter();
+ ~ScanlineFilter();
+
+private:
+ uint16_t *adjust;
+ uint16_t *buffer;
+ unsigned linewidth[480];
+};
+
class Filter : public library {
public:
function dl_supported;
@@ -34,4 +51,5 @@ private:
uint8_t gamma_adjust(uint8_t input);
};
+extern ScanlineFilter scanlineFilter;
extern Filter filter;
diff --git a/src/ui_qt/link/reader.cpp b/src/ui_qt/link/reader.cpp
index 48dd390f..e5f9d43f 100644
--- a/src/ui_qt/link/reader.cpp
+++ b/src/ui_qt/link/reader.cpp
@@ -31,13 +31,14 @@ Reader::Reader() {
load = bind(&Reader::direct_load, this);
}
- filterList = supported();
- if(filterList.length() > 0) {
- filterList = string()
+ compressionList = supported();
+ if(compressionList.length() > 0) compressionList = string() << " " << compressionList;
+
+ if(opened()) {
+ extensionList = string()
<< " *.smc *.swc *.fig"
<< " *.ufo *.gd3 *.gd7 *.dx2 *.mgd *.mgh"
<< " *.048 *.058 *.068 *.078 *.bin"
- << " *.usa *.eur *.jap *.aus *.bsx"
- << " " << filterList;
+ << " *.usa *.eur *.jap *.aus *.bsx";
}
}
diff --git a/src/ui_qt/link/reader.hpp b/src/ui_qt/link/reader.hpp
index c8eec5b1..1cc93411 100644
--- a/src/ui_qt/link/reader.hpp
+++ b/src/ui_qt/link/reader.hpp
@@ -1,6 +1,7 @@
class Reader : public library {
public:
- string filterList;
+ string compressionList;
+ string extensionList;
function supported;
function load;
diff --git a/src/ui_qt/main.cpp b/src/ui_qt/main.cpp
index 5fe4a648..d768104a 100644
--- a/src/ui_qt/main.cpp
+++ b/src/ui_qt/main.cpp
@@ -1,13 +1,6 @@
#include "main.hpp"
#include "resource/resource.rcc"
-//nall::string <> QString interface: allows string streaming; automatically converts to UTF-16
-class utf8 : public nall::string {
-public:
- template utf8& operator<<(T t) { string::operator<<(t); return *this; }
- operator const QString() const { return QString::fromUtf8(*this); }
-};
-
#if defined(PLATFORM_X)
#include "platform/platform_x.cpp"
#elif defined(PLATFORM_OSX)
@@ -27,18 +20,11 @@ const char defaultStylesheet[] =
" margin-bottom: 5px;"
" margin-left: -5px;"
" margin-top: 5px;"
- "}"
- "\n"
+ "}\n"
+
"#backdrop {"
" background: #000000;"
- "}"
- "\n"
- "#mouse-capture-box {"
- " border: 1px solid #808080;"
- " color: #000000;"
- " font-weight: bold;"
- "}"
- "\n";
+ "}\n";
#include "application/application.cpp"
#include "debugger/debugger.cpp"
diff --git a/src/ui_qt/settings/advanced.cpp b/src/ui_qt/settings/advanced.cpp
index c0be4480..516fb289 100644
--- a/src/ui_qt/settings/advanced.cpp
+++ b/src/ui_qt/settings/advanced.cpp
@@ -127,20 +127,20 @@ void AdvancedSettingsWindow::initializeUi() {
part.split(";", video.driver_list());
for(unsigned i = 0; i < part.size(); i++) {
- videoDriver->addItem(utf8() << part[i]);
- if(part[i] == config.system.video) videoDriver->setCurrentIndex(i);
+ videoDriver->addItem(part[i]);
+ if(part[i] == config().system.video) videoDriver->setCurrentIndex(i);
}
part.split(";", audio.driver_list());
for(unsigned i = 0; i < part.size(); i++) {
- audioDriver->addItem(utf8() << part[i]);
- if(part[i] == config.system.audio) audioDriver->setCurrentIndex(i);
+ audioDriver->addItem(part[i]);
+ if(part[i] == config().system.audio) audioDriver->setCurrentIndex(i);
}
part.split(";", input.driver_list());
for(unsigned i = 0; i < part.size(); i++) {
- inputDriver->addItem(utf8() << part[i]);
- if(part[i] == config.system.input) inputDriver->setCurrentIndex(i);
+ inputDriver->addItem(part[i]);
+ if(part[i] == config().system.input) inputDriver->setCurrentIndex(i);
}
regionAuto->setChecked(SNES::config.region == SNES::System::Autodetect);
@@ -150,21 +150,21 @@ void AdvancedSettingsWindow::initializeUi() {
portSatellaview->setChecked(SNES::config.expansion_port == SNES::System::ExpansionBSX);
portNone->setChecked (SNES::config.expansion_port == SNES::System::ExpansionNone);
- focusPause->setChecked (config.input.focusPolicy == Configuration::Input::FocusPolicyPauseEmulation);
- focusIgnore->setChecked(config.input.focusPolicy == Configuration::Input::FocusPolicyIgnoreInput);
- focusAllow->setChecked (config.input.focusPolicy == Configuration::Input::FocusPolicyAllowInput);
+ focusPause->setChecked (config().input.focusPolicy == Configuration::Input::FocusPolicyPauseEmulation);
+ focusIgnore->setChecked(config().input.focusPolicy == Configuration::Input::FocusPolicyIgnoreInput);
+ focusAllow->setChecked (config().input.focusPolicy == Configuration::Input::FocusPolicyAllowInput);
}
void AdvancedSettingsWindow::videoDriverChange(int index) {
- if(index >= 0) config.system.video = videoDriver->itemText(index).toUtf8().data();
+ if(index >= 0) config().system.video = videoDriver->itemText(index).toUtf8().data();
}
void AdvancedSettingsWindow::audioDriverChange(int index) {
- if(index >= 0) config.system.audio = audioDriver->itemText(index).toUtf8().data();
+ if(index >= 0) config().system.audio = audioDriver->itemText(index).toUtf8().data();
}
void AdvancedSettingsWindow::inputDriverChange(int index) {
- if(index >= 0) config.system.input = inputDriver->itemText(index).toUtf8().data();
+ if(index >= 0) config().system.input = inputDriver->itemText(index).toUtf8().data();
}
void AdvancedSettingsWindow::setRegionAuto() { SNES::config.region = SNES::System::Autodetect; }
@@ -174,6 +174,6 @@ void AdvancedSettingsWindow::setRegionPAL() { SNES::config.region = SNES::Syste
void AdvancedSettingsWindow::setPortSatellaview() { SNES::config.expansion_port = SNES::System::ExpansionBSX; }
void AdvancedSettingsWindow::setPortNone() { SNES::config.expansion_port = SNES::System::ExpansionNone; }
-void AdvancedSettingsWindow::pauseWithoutFocus() { config.input.focusPolicy = Configuration::Input::FocusPolicyPauseEmulation; }
-void AdvancedSettingsWindow::ignoreInputWithoutFocus() { config.input.focusPolicy = Configuration::Input::FocusPolicyIgnoreInput; }
-void AdvancedSettingsWindow::allowInputWithoutFocus() { config.input.focusPolicy = Configuration::Input::FocusPolicyAllowInput; }
+void AdvancedSettingsWindow::pauseWithoutFocus() { config().input.focusPolicy = Configuration::Input::FocusPolicyPauseEmulation; }
+void AdvancedSettingsWindow::ignoreInputWithoutFocus() { config().input.focusPolicy = Configuration::Input::FocusPolicyIgnoreInput; }
+void AdvancedSettingsWindow::allowInputWithoutFocus() { config().input.focusPolicy = Configuration::Input::FocusPolicyAllowInput; }
diff --git a/src/ui_qt/settings/audio.cpp b/src/ui_qt/settings/audio.cpp
index 0b7713d2..e937f5bb 100644
--- a/src/ui_qt/settings/audio.cpp
+++ b/src/ui_qt/settings/audio.cpp
@@ -39,16 +39,21 @@ AudioSettingsWindow::AudioSettingsWindow() {
layout->addSpacing(Style::WidgetSpacing);
sliders = new QGridLayout; {
- volumeLabel = new QLabel("Volume: 100%");
+ volumeLabel = new QLabel("Volume:");
volumeLabel->setToolTip("Warning: any volume other than 100% will result in a slight audio quality loss");
sliders->addWidget(volumeLabel, 0, 0);
+ volumeValue = new QLabel;
+ volumeValue->setAlignment(Qt::AlignHCenter);
+ volumeValue->setMinimumWidth(volumeValue->fontMetrics().width("262144hz"));
+ sliders->addWidget(volumeValue, 0, 1);
+
volume = new QSlider(Qt::Horizontal);
volume->setMinimum(0);
volume->setMaximum(200);
- sliders->addWidget(volume, 0, 1);
+ sliders->addWidget(volume, 0, 2);
- frequencySkewLabel = new QLabel("Input frequency: 32000hz");
+ frequencySkewLabel = new QLabel("Input frequency:");
frequencySkewLabel->setToolTip(
"Adjusts audio resampling rate.\n"
"When both video sync and audio sync are enabled, use this setting to fine-tune the output.\n"
@@ -57,10 +62,14 @@ AudioSettingsWindow::AudioSettingsWindow() {
);
sliders->addWidget(frequencySkewLabel, 1, 0);
+ frequencySkewValue = new QLabel;
+ frequencySkewValue->setAlignment(Qt::AlignHCenter);
+ sliders->addWidget(frequencySkewValue, 1, 1);
+
frequencySkew = new QSlider(Qt::Horizontal);
- frequencySkew->setMinimum(31800);
- frequencySkew->setMaximum(32200);
- sliders->addWidget(frequencySkew);
+ frequencySkew->setMinimum(31500);
+ frequencySkew->setMaximum(32500);
+ sliders->addWidget(frequencySkew, 1, 2);
}
sliders->setSpacing(Style::WidgetSpacing);
layout->addLayout(sliders);
@@ -76,50 +85,50 @@ AudioSettingsWindow::AudioSettingsWindow() {
void AudioSettingsWindow::syncUi() {
int n;
- n = config.audio.outputFrequency;
+ n = config().audio.outputFrequency;
if(n <= 32000) frequency->setCurrentIndex(0);
else if(n <= 44100) frequency->setCurrentIndex(1);
else if(n <= 48000) frequency->setCurrentIndex(2);
else if(n <= 96000) frequency->setCurrentIndex(3);
else frequency->setCurrentIndex(0);
- n = config.audio.latency;
+ n = config().audio.latency;
latency->setCurrentIndex((n - 20) / 20);
- n = config.audio.volume;
- volumeLabel->setText(utf8() << "Volume: " << n << "%");
+ n = config().audio.volume;
+ volumeValue->setText(string() << n << "%");
volume->setSliderPosition(n);
- n = config.audio.inputFrequency;
- frequencySkewLabel->setText(utf8() << "Input frequency: " << n << "hz");
+ n = config().audio.inputFrequency;
+ frequencySkewValue->setText(string() << n << "hz");
frequencySkew->setSliderPosition(n);
}
void AudioSettingsWindow::frequencyChange(int value) {
switch(value) { default:
- case 0: config.audio.outputFrequency = 32000; break;
- case 1: config.audio.outputFrequency = 44100; break;
- case 2: config.audio.outputFrequency = 48000; break;
- case 3: config.audio.outputFrequency = 96000; break;
+ case 0: config().audio.outputFrequency = 32000; break;
+ case 1: config().audio.outputFrequency = 44100; break;
+ case 2: config().audio.outputFrequency = 48000; break;
+ case 3: config().audio.outputFrequency = 96000; break;
}
- audio.set(Audio::Frequency, config.audio.outputFrequency);
+ audio.set(Audio::Frequency, config().audio.outputFrequency);
utility.updateEmulationSpeed();
}
void AudioSettingsWindow::latencyChange(int value) {
value = max(0, min(5, value));
- config.audio.latency = 20 + value * 20;
- audio.set(Audio::Latency, config.audio.latency);
+ config().audio.latency = 20 + value * 20;
+ audio.set(Audio::Latency, config().audio.latency);
}
void AudioSettingsWindow::volumeAdjust(int value) {
- config.audio.volume = value;
- audio.set(Audio::Volume, config.audio.volume);
+ config().audio.volume = value;
+ audio.set(Audio::Volume, config().audio.volume);
syncUi();
}
void AudioSettingsWindow::frequencySkewAdjust(int value) {
- config.audio.inputFrequency = value;
+ config().audio.inputFrequency = value;
utility.updateEmulationSpeed();
syncUi();
}
diff --git a/src/ui_qt/settings/audio.moc.hpp b/src/ui_qt/settings/audio.moc.hpp
index 3cc83949..eb3780e5 100644
--- a/src/ui_qt/settings/audio.moc.hpp
+++ b/src/ui_qt/settings/audio.moc.hpp
@@ -11,8 +11,10 @@ public:
QComboBox *latency;
QGridLayout *sliders;
QLabel *volumeLabel;
+ QLabel *volumeValue;
QSlider *volume;
QLabel *frequencySkewLabel;
+ QLabel *frequencySkewValue;
QSlider *frequencySkew;
void syncUi();
diff --git a/src/ui_qt/settings/input.cpp b/src/ui_qt/settings/input.cpp
index 0de196c1..067503b8 100644
--- a/src/ui_qt/settings/input.cpp
+++ b/src/ui_qt/settings/input.cpp
@@ -1,26 +1,33 @@
-InputSettingsWindow::InputSettingsWindow() {
+InputSettingsWindow::InputSettingsWindow() : activeObject(0) {
layout = new QVBoxLayout;
layout->setMargin(0);
- layout->setSpacing(0);
+ layout->setSpacing(Style::WidgetSpacing);
setLayout(layout);
title = new QLabel("Input Configuration Editor");
title->setProperty("class", "title");
layout->addWidget(title);
- selection = new QHBoxLayout; {
- port = new QComboBox;
- port->addItem("Controller Port 1");
- port->addItem("Controller Port 2");
- port->addItem("User Interface");
- selection->addWidget(port);
+ comboLayout = new QHBoxLayout;
+ layout->addLayout(comboLayout);
- device = new QComboBox;
- selection->addWidget(device);
- }
- selection->setSpacing(Style::WidgetSpacing);
- layout->addLayout(selection);
- layout->addSpacing(Style::WidgetSpacing);
+ port = new QComboBox;
+ port->addItem("Controller Port 1");
+ port->addItem("Controller Port 2");
+ port->addItem("User Interface");
+ comboLayout->addWidget(port);
+
+ device = new QComboBox;
+ comboLayout->addWidget(device);
+
+ selectionWidget = new QWidget;
+ selectionWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ layout->addWidget(selectionWidget);
+
+ selectionLayout = new QVBoxLayout;
+ selectionLayout->setMargin(0);
+ selectionLayout->setSpacing(Style::WidgetSpacing);
+ selectionWidget->setLayout(selectionLayout);
list = new QTreeWidget;
list->setColumnCount(3);
@@ -28,63 +35,94 @@ InputSettingsWindow::InputSettingsWindow() {
list->setAllColumnsShowFocus(true);
list->setRootIsDecorated(false);
list->hideColumn(0); //used for default sorting
- layout->addWidget(list);
- layout->addSpacing(Style::WidgetSpacing);
+ selectionLayout->addWidget(list);
- controls = new QHBoxLayout; {
- assign = new QPushButton("Assign ...");
- controls->addWidget(assign);
+ selectionControlLayout = new QHBoxLayout;
+ selectionLayout->addLayout(selectionControlLayout);
- assignAll = new QPushButton("Assign All ...");
- controls->addWidget(assignAll);
+ assignButton = new QPushButton("Assign");
+ selectionControlLayout->addWidget(assignButton);
- unassign = new QPushButton("Unassign");
- controls->addWidget(unassign);
- }
- controls->setSpacing(Style::WidgetSpacing);
- layout->addLayout(controls);
+ assignAllButton = new QPushButton("Assign All");
+ selectionControlLayout->addWidget(assignAllButton);
+
+ unassignButton = new QPushButton("Unassign");
+ selectionControlLayout->addWidget(unassignButton);
+
+ unassignAllButton = new QPushButton("Unassign All");
+ selectionControlLayout->addWidget(unassignAllButton);
+
+ assignmentWidget = new QWidget;
+ assignmentWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ assignmentWidget->hide();
+ layout->addWidget(assignmentWidget);
+
+ assignmentLayout = new QVBoxLayout;
+ assignmentLayout->setMargin(0);
+ assignmentLayout->setSpacing(Style::WidgetSpacing);
+ assignmentWidget->setLayout(assignmentLayout);
+
+ assignmentLabel = new QLabel;
+ assignmentLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ assignmentLabel->setAlignment(Qt::AlignTop);
+ assignmentLabel->setFocusPolicy(Qt::StrongFocus);
+ assignmentLabel->setFrameShape(QFrame::Panel);
+ assignmentLabel->setFrameShadow(QFrame::Sunken);
+ assignmentLayout->addWidget(assignmentLabel);
+
+ assignmentControlLayout = new QHBoxLayout;
+ assignmentLayout->addLayout(assignmentControlLayout);
+
+ xaxisButton = new QPushButton("X-axis");
+ assignmentControlLayout->addWidget(xaxisButton);
+
+ yaxisButton = new QPushButton("Y-axis");
+ assignmentControlLayout->addWidget(yaxisButton);
+
+ spacer = new QWidget;
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ assignmentControlLayout->addWidget(spacer);
+
+ helpButton = new QPushButton("Help");
+ assignmentControlLayout->addWidget(helpButton);
+
+ cancelButton = new QPushButton("Cancel Assignment");
+ assignmentControlLayout->addWidget(cancelButton);
connect(port, SIGNAL(currentIndexChanged(int)), this, SLOT(portChanged()));
connect(device, SIGNAL(currentIndexChanged(int)), this, SLOT(reloadList()));
- connect(list, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(assignKey()));
+
+ connect(list, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(assign()));
connect(list, SIGNAL(itemSelectionChanged()), this, SLOT(listChanged()));
- connect(assign, SIGNAL(released()), this, SLOT(assignKey()));
- connect(assignAll, SIGNAL(released()), this, SLOT(assignAllKeys()));
- connect(unassign, SIGNAL(released()), this, SLOT(unassignKey()));
+ connect(assignButton, SIGNAL(released()), this, SLOT(assign()));
+ connect(assignAllButton, SIGNAL(released()), this, SLOT(assignAll()));
+ connect(unassignButton, SIGNAL(released()), this, SLOT(unassign()));
+ connect(unassignAllButton, SIGNAL(released()), this, SLOT(unassignAll()));
+
+ connect(xaxisButton, SIGNAL(released()), this, SLOT(assignXaxis()));
+ connect(yaxisButton, SIGNAL(released()), this, SLOT(assignYaxis()));
+ connect(helpButton, SIGNAL(released()), this, SLOT(showHelp()));
+ connect(cancelButton, SIGNAL(released()), this, SLOT(cancelAssignment()));
portChanged();
}
void InputSettingsWindow::syncUi() {
QList itemList = list->selectedItems();
- assign->setEnabled(itemList.count() == 1);
- //allow rapid assign for controllers from both ports, but not for UI shortcuts
- assignAll->setEnabled(port->currentIndex() < 2);
- unassign->setEnabled(itemList.count() == 1);
+ assignButton->setEnabled(itemList.count() == 1);
+ assignAllButton->setEnabled(port->currentIndex() < 2); //only allow for controllers, not GUI hotkeys
+ unassignButton->setEnabled(itemList.count() == 1);
}
//when port combobox item is changed, device list needs to be repopulated
void InputSettingsWindow::portChanged() {
disconnect(device, SIGNAL(currentIndexChanged(int)), this, SLOT(reloadList()));
-
device->clear();
- deviceItem.reset();
- int index = port->currentIndex();
- if(index < 2) {
- //this is a controller port
- for(unsigned i = 0; i < inputPool.size(); i++) {
- //only add devices for selected port
- if(inputPool[i]->port == index) {
- device->addItem(inputPool[i]->name);
- deviceItem.add(inputPool[i]);
- }
- }
- } else {
- //user interface controls
- for(unsigned i = 0; i < inputUiPool.size(); i++) {
- device->addItem(inputUiPool[i]->name);
- deviceItem.add(inputUiPool[i]);
+ unsigned index = port->currentIndex();
+ for(unsigned i = 0; i < mapper().size(); i++) {
+ if(mapper()[i]->category == index) {
+ device->addItem(mapper()[i]->label);
}
}
@@ -96,17 +134,28 @@ void InputSettingsWindow::portChanged() {
void InputSettingsWindow::reloadList() {
list->clear();
list->setSortingEnabled(false);
- listItem.reset();
- int index = device->currentIndex();
- if(index < deviceItem.size()) {
- InputGroup &group = *deviceItem[index];
- for(unsigned i = 0; i < group.size(); i++) {
- QTreeWidgetItem *item = new QTreeWidgetItem(list);
- item->setText(0, utf8() << (int)(1000000 + i));
- item->setText(1, group[i]->name);
- item->setText(2, (const char*)group[i]->id);
- listItem.add(item);
+ unsigned portIndex = port->currentIndex();
+ unsigned deviceIndex = device->currentIndex();
+ unsigned index = 0;
+ for(unsigned i = 0; i < mapper().size(); i++) {
+ if(mapper()[i]->category == portIndex) {
+ if(index != deviceIndex) {
+ index++;
+ continue;
+ }
+
+ InputGroup &group = *(mapper()[i]);
+ for(unsigned i = 0; i < group.size(); i++) {
+ QTreeWidgetItem *item = new QTreeWidgetItem(list);
+ item->setData(0, Qt::UserRole, QVariant(i));
+ item->setText(0, string() << (1000000 + i));
+ item->setText(1, group[i]->label);
+ item->setText(2, group[i]->name);
+ }
+
+ activeGroup = &group;
+ break;
}
}
@@ -120,54 +169,248 @@ void InputSettingsWindow::listChanged() {
syncUi();
}
-//InputCaptureWindow calls this after a successful key assignment change:
-//need to update list of values to show new key assignment value.
-void InputSettingsWindow::updateList() {
- int index = device->currentIndex();
- if(index < deviceItem.size()) {
- InputGroup &group = *deviceItem[index];
+//===================
+//assignment routines
+//===================
- for(unsigned i = 0; i < listItem.size(); i++) {
- listItem[i]->setText(2, (const char*)group[i]->id);
- }
+void InputSettingsWindow::beginAssignment() {
+ settingsWindow->list->setEnabled(false);
+ port->setEnabled(false);
+ device->setEnabled(false);
+ selectionWidget->hide();
+ assignmentWidget->show();
+}
+
+void InputSettingsWindow::showHelp() {
+ string message;
+
+ message << "Digital Button Assignment:
";
+ message << "To assign, do any one of the following:
";
+ message << "• press any keyboard key
";
+ message << "• click any mouse button inside the capture box
";
+ message << "• move any joypad hat in the desired direction
";
+ message << "• move any joypad axis in the desired direction
";
+ message << "• press any joypad button
";
+ message << "For multi-key assignment, hold any combination of these keys down first:
";
+ message << "• Shift, Control, Alt, Super";
+ message << "
";
+
+ message << "Analog Axis Assignment:
";
+ message << "To assign, do any one of the following:
";
+ message << "• click the desired mouse axis button
";
+ message << "• move any joypad axis in either direction";
+
+ audio.clear();
+ QMessageBox::information(settingsWindow, "Input Assignment Help", message);
+}
+
+void InputSettingsWindow::assignObject(MappedInput *object) {
+ //flush any pending events to prevent instantaneous assignment of eg mouse buttons
+ activeObject = 0;
+ activeMouse = 0;
+ mapper().poll();
+
+ activeObject = object;
+
+ string label;
+ label << "" << port->currentText().toUtf8().constData() << " :: ";
+ label << device->currentText().toUtf8().constData() << " :: ";
+ label << activeObject->label << "
";
+
+ if(dynamic_cast(activeObject)) {
+ xaxisButton->setVisible(false);
+ yaxisButton->setVisible(false);
+ label << "Digital Button Assignment";
+ } else if(dynamic_cast(activeObject)) {
+ xaxisButton->setVisible(true);
+ yaxisButton->setVisible(true);
+ label << "Analog Axis Assignment";
+ }
+
+ if(dynamic_cast(activeGroup)
+ || dynamic_cast(activeGroup)) {
+ assignmentLabel->setStyleSheet(
+ "background-image: url(:/joypad.png);"
+ "background-position: bottom center;"
+ "background-repeat: none;"
+ );
+ } else {
+ assignmentLabel->setStyleSheet("");
+ }
+
+ assignmentLabel->setText(label);
+ assignmentLabel->setFocus();
+}
+
+void InputSettingsWindow::endAssignment() {
+ activeObject = 0;
+
+ if(multiAssign == false || ++multiAssignIndex >= activeGroup->size()) {
+ mapper().bind();
+ reloadList();
+
+ assignmentWidget->hide();
+ selectionWidget->show();
+ settingsWindow->list->setEnabled(true);
+ port->setEnabled(true);
+ device->setEnabled(true);
+ } else {
+ assignObject((*activeGroup)[multiAssignIndex]);
}
}
-void InputSettingsWindow::assignKey() {
- int index = device->currentIndex();
- if(index < deviceItem.size()) {
- InputGroup &group = *deviceItem[index];
+void InputSettingsWindow::assign() {
+ if(activeObject) return;
+ multiAssign = false;
- QTreeWidgetItem *item = list->currentItem();
- if(item && item->isSelected()) {
- signed i = listItem.find(item);
- if(i >= 0) inputCaptureWindow->activate(group[i]);
+ QTreeWidgetItem *item = list->currentItem();
+ if(!item) return;
+ unsigned index = item->data(0, Qt::UserRole).toUInt();
+
+ beginAssignment();
+ assignObject((*activeGroup)[index]);
+}
+
+void InputSettingsWindow::assignAll() {
+ if(activeObject) return;
+ multiAssign = true;
+
+ beginAssignment();
+ assignObject((*activeGroup)[multiAssignIndex = 0]);
+}
+
+void InputSettingsWindow::unassign() {
+ QTreeWidgetItem *item = list->currentItem();
+ if(!item) return;
+ unsigned index = item->data(0, Qt::UserRole).toUInt();
+ MappedInput *object = (*activeGroup)[index];
+ object->name = "None";
+ mapper().bind();
+ reloadList();
+}
+
+void InputSettingsWindow::unassignAll() {
+ for(unsigned i = 0; i < activeGroup->size(); i++) {
+ MappedInput *object = (*activeGroup)[i];
+ object->name = "None";
+ }
+ mapper().bind();
+ reloadList();
+}
+
+void InputSettingsWindow::cancelAssignment() {
+ multiAssign = false;
+ endAssignment();
+}
+
+void InputSettingsWindow::setAssignment(string name) {
+ if(multiAssign == true) {
+ //make sure this mapping was not previously used
+ for(unsigned i = 0; i < multiAssignIndex; i++) {
+ if(name == (*activeGroup)[i]->name) return;
}
}
+
+ activeObject->name = name;
+ endAssignment();
+}
+
+void InputSettingsWindow::assignXaxis() {
+ setAssignment(Scancode::encode(mouse(activeMouse).axis(0)));
+}
+
+void InputSettingsWindow::assignYaxis() {
+ setAssignment(Scancode::encode(mouse(activeMouse).axis(1)));
+}
+
+void InputSettingsWindow::inputEvent(uint16_t scancode) {
+ if(dynamic_cast(activeObject)) {
+ digitalInputEvent(scancode);
+ } else if(dynamic_cast(activeObject)) {
+ analogInputEvent(scancode);
+ }
}
-void InputSettingsWindow::assignAllKeys() {
- int index = port->currentIndex();
- if(index < 2) {
- index = device->currentIndex();
- if(index < deviceItem.size()) {
- inputCaptureWindow->activate(deviceItem[index]);
+void InputSettingsWindow::digitalInputEvent(uint16_t scancode) {
+ if(!isActiveWindow() || isMinimized()) return;
+
+ if(Keyboard::isAnyKey(scancode) && mapper().state(scancode)) {
+ for(unsigned i = 0; i < Keyboard::Count; i++) {
+ //don't map escape key, as it is reserved by the user interface
+ if(scancode == keyboard(i)[Keyboard::Escape]) return;
}
+
+ setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode));
+ } else if(Mouse::isAnyButton(scancode) && mapper().state(scancode)) {
+ //ensure button was clicked inside assignment label box
+ QRect windowRect = settingsWindow->geometry();
+ QRect splitterRect = settingsWindow->splitter->geometry();
+ QRect panelRect = settingsWindow->panel->geometry();
+ QRect captureRect = assignmentWidget->geometry();
+ QRect widgetRect = assignmentLabel->geometry();
+ unsigned wx = windowRect.x() + splitterRect.x() + panelRect.x() + captureRect.x();
+ unsigned wy = windowRect.y() + splitterRect.y() + panelRect.y() + captureRect.y();
+ unsigned px = QCursor::pos().x();
+ unsigned py = QCursor::pos().y();
+
+ if(px < wx || px >= wx + widgetRect.size().width()) return;
+ if(py < wy || py >= wy + widgetRect.size().height()) return;
+
+ setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode));
+ } else if(Joypad::isAnyHat(scancode)) {
+ int16_t state = mapper().state(scancode);
+ string position;
+ if(state == Joypad::HatUp) position = ".Up";
+ if(state == Joypad::HatDown) position = ".Down";
+ if(state == Joypad::HatLeft) position = ".Left";
+ if(state == Joypad::HatRight) position = ".Right";
+ if(position == "") return;
+
+ setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode) << position);
+ } else if(Joypad::isAnyAxis(scancode) && mapper().distance(scancode) > 64) {
+ if(mapper().calibrated == false) {
+ MappedInput *temp = activeObject;
+ activeObject = 0;
+ mapper().calibrate();
+ activeObject = temp;
+ }
+
+ if(mapper().isTrigger[Joypad::numberDecode(scancode)][Joypad::axisDecode(scancode)] == false) {
+ int16_t state = mapper().state(scancode);
+ string position;
+ if(state < -24576) position = ".Lo";
+ if(state > +24576) position = ".Hi";
+ if(position == "") return;
+
+ setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode) << position);
+ } else {
+ int16_t state = mapper().state(scancode);
+ if(state >= 0) return;
+
+ setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode) << ".Trigger");
+ }
+ } else if(Joypad::isAnyButton(scancode) && mapper().state(scancode)) {
+ setAssignment(string() << mapper().modifierString() << Scancode::encode(scancode));
}
}
-void InputSettingsWindow::unassignKey() {
- int index = device->currentIndex();
- if(index < deviceItem.size()) {
- InputGroup &group = *deviceItem[index];
+void InputSettingsWindow::analogInputEvent(uint16_t scancode) {
+ if(!isActiveWindow() || isMinimized()) return;
- QTreeWidgetItem *item = list->currentItem();
- if(item && item->isSelected()) {
- signed i = listItem.find(item);
- if(i >= 0) {
- group[i]->id = "none";
- inputManager.bind(); //update key bindings to reflect object ID change above
- item->setText(2, (const char*)group[i]->id);
+ if(Mouse::isAnyButton(scancode)) {
+ activeMouse = Mouse::numberDecode(scancode);
+ } else if(Joypad::isAnyAxis(scancode) && mapper().distance(scancode) > 64) {
+ if(mapper().calibrated == false) {
+ MappedInput *temp = activeObject;
+ activeObject = 0;
+ mapper().calibrate();
+ activeObject = temp;
+ }
+
+ if(mapper().isTrigger[Joypad::numberDecode(scancode)][Joypad::axisDecode(scancode)] == false) {
+ int16_t state = mapper().state(scancode);
+ if(state < -24576 || state > +24576) {
+ setAssignment(string() << Scancode::encode(scancode));
}
}
}
diff --git a/src/ui_qt/settings/input.moc.hpp b/src/ui_qt/settings/input.moc.hpp
index bbf0e93a..0816ddd6 100644
--- a/src/ui_qt/settings/input.moc.hpp
+++ b/src/ui_qt/settings/input.moc.hpp
@@ -4,28 +4,58 @@ class InputSettingsWindow : public QWidget {
public:
QVBoxLayout *layout;
QLabel *title;
- QHBoxLayout *selection;
+ QHBoxLayout *comboLayout;
QComboBox *port;
QComboBox *device;
- QTreeWidget *list;
- QHBoxLayout *controls;
- QPushButton *assign;
- QPushButton *assignAll;
- QPushButton *unassign;
+ QWidget *selectionWidget;
+ QVBoxLayout *selectionLayout;
+ QTreeWidget *list;
+ QHBoxLayout *selectionControlLayout;
+ QPushButton *assignButton;
+ QPushButton *assignAllButton;
+ QPushButton *unassignButton;
+ QPushButton *unassignAllButton;
+
+ QWidget *assignmentWidget;
+ QVBoxLayout *assignmentLayout;
+ QLabel *assignmentLabel;
+ QHBoxLayout *assignmentControlLayout;
+ QPushButton *xaxisButton;
+ QPushButton *yaxisButton;
+ QWidget *spacer;
+ QPushButton *helpButton;
+ QPushButton *cancelButton;
+
+ void inputEvent(uint16_t scancode);
void syncUi();
InputSettingsWindow();
-public slots:
+private slots:
void portChanged();
void reloadList();
void listChanged();
- void updateList();
- void assignKey();
- void assignAllKeys();
- void unassignKey();
+ void assign();
+ void assignAll();
+ void unassign();
+ void unassignAll();
+ void assignXaxis();
+ void assignYaxis();
+ void showHelp();
+ void cancelAssignment();
private:
- array deviceItem;
- array listItem;
+ InputGroup *activeGroup;
+ MappedInput *activeObject;
+ unsigned activeMouse;
+ bool multiAssign;
+ unsigned multiAssignIndex;
+
+ void setAssignment(string name);
+ void digitalInputEvent(uint16_t scancode);
+ void analogInputEvent(uint16_t scancode);
+
+ void beginAssignment();
+ void assignObject(MappedInput *object);
+ void endAssignment();
} *inputSettingsWindow;
diff --git a/src/ui_qt/settings/paths.cpp b/src/ui_qt/settings/paths.cpp
index 56e99b7d..9aa71a80 100644
--- a/src/ui_qt/settings/paths.cpp
+++ b/src/ui_qt/settings/paths.cpp
@@ -31,7 +31,7 @@ PathSettingWidget::PathSettingWidget(string &pathValue_, const char *labelText,
updatePath();
}
-void PathSettingWidget::selectPath(const string &newPath) {
+void PathSettingWidget::assignPath(string newPath) {
pathValue = string() << newPath << "/";
updatePath();
}
@@ -39,15 +39,19 @@ void PathSettingWidget::selectPath(const string &newPath) {
void PathSettingWidget::updatePath() {
if(pathValue == "") {
path->setStyleSheet("color: #808080");
- path->setText(utf8() << pathDefaultLabel);
+ path->setText(pathDefaultLabel);
} else {
path->setStyleSheet("color: #000000");
- path->setText(utf8() << pathValue);
+ path->setText(pathValue);
}
}
void PathSettingWidget::selectPath() {
- diskBrowser->chooseFolder(this, pathBrowseLabel);
+ diskBrowser->chooseFolder(
+ bind(&PathSettingWidget::assignPath, this),
+ config().path.current.folder,
+ pathBrowseLabel
+ );
}
void PathSettingWidget::defaultPath() {
@@ -66,12 +70,12 @@ PathSettingsWindow::PathSettingsWindow() {
title->setProperty("class", "title");
layout->addWidget(title);
- gamePath = new PathSettingWidget(config.path.rom, "Games:", "Startup path", "Default Game Path");
- savePath = new PathSettingWidget(config.path.save, "Save RAM:", "Same as loaded game", "Default Save RAM Path");
- statePath = new PathSettingWidget(config.path.state, "Save states:", "Same as loaded game", "Default Save State Path");
- patchPath = new PathSettingWidget(config.path.patch, "UPS patches:", "Same as loaded game", "Default UPS Patch Path");
- cheatPath = new PathSettingWidget(config.path.cheat, "Cheat codes:", "Same as loaded game", "Default Cheat Code Path");
- dataPath = new PathSettingWidget(config.path.data, "Exported data:", "Same as loaded game", "Default Exported Data Path");
+ gamePath = new PathSettingWidget(config().path.rom, "Games:", "Remember last path", "Default Game Path");
+ savePath = new PathSettingWidget(config().path.save, "Save RAM:", "Same as loaded game", "Default Save RAM Path");
+ statePath = new PathSettingWidget(config().path.state, "Save states:", "Same as loaded game", "Default Save State Path");
+ patchPath = new PathSettingWidget(config().path.patch, "UPS patches:", "Same as loaded game", "Default UPS Patch Path");
+ cheatPath = new PathSettingWidget(config().path.cheat, "Cheat codes:", "Same as loaded game", "Default Cheat Code Path");
+ dataPath = new PathSettingWidget(config().path.data, "Exported data:", "Same as loaded game", "Default Exported Data Path");
layout->addWidget(gamePath);
layout->addWidget(savePath);
diff --git a/src/ui_qt/settings/paths.moc.hpp b/src/ui_qt/settings/paths.moc.hpp
index 86e63a81..1c68c124 100644
--- a/src/ui_qt/settings/paths.moc.hpp
+++ b/src/ui_qt/settings/paths.moc.hpp
@@ -12,8 +12,9 @@ public:
string &pathValue;
string pathDefaultLabel;
string pathBrowseLabel;
- void selectPath(const string&);
+ void assignPath(string);
void updatePath();
+
PathSettingWidget(string&, const char*, const char*, const char*);
public slots:
diff --git a/src/ui_qt/settings/pixelshader.cpp b/src/ui_qt/settings/pixelshader.cpp
new file mode 100644
index 00000000..40c50c5c
--- /dev/null
+++ b/src/ui_qt/settings/pixelshader.cpp
@@ -0,0 +1,82 @@
+PixelShaderWindow::PixelShaderWindow() {
+ layout = new QVBoxLayout;
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->setAlignment(Qt::AlignTop);
+ setLayout(layout);
+
+ title = new QLabel("Pixel Shader Selection");
+ title->setProperty("class", "title");
+ layout->addWidget(title);
+
+ gridLayout = new QGridLayout;
+ gridLayout->setHorizontalSpacing(Style::WidgetSpacing);
+ layout->addLayout(gridLayout);
+
+ fragmentLabel = new QLabel("Fragment shader:");
+ gridLayout->addWidget(fragmentLabel, 0, 0, 1, 3);
+
+ fragmentPath = new QLineEdit;
+ gridLayout->addWidget(fragmentPath, 1, 0);
+
+ fragmentSelect = new QPushButton("Select ...");
+ gridLayout->addWidget(fragmentSelect, 1, 1);
+
+ fragmentDefault = new QPushButton("Default");
+ gridLayout->addWidget(fragmentDefault, 1, 2);
+
+ vertexLabel = new QLabel("Vertex shader:");
+ gridLayout->addWidget(vertexLabel, 2, 0, 1, 3);
+
+ vertexPath = new QLineEdit;
+ gridLayout->addWidget(vertexPath, 3, 0);
+
+ vertexSelect = new QPushButton("Select ...");
+ gridLayout->addWidget(vertexSelect, 3, 1);
+
+ vertexDefault = new QPushButton("Default");
+ gridLayout->addWidget(vertexDefault, 3, 2);
+
+ synchronize();
+
+ connect(fragmentSelect, SIGNAL(released()), this, SLOT(selectFragmentShader()));
+ connect(vertexSelect, SIGNAL(released()), this, SLOT(selectVertexShader()));
+ connect(fragmentDefault, SIGNAL(released()), this, SLOT(defaultFragmentShader()));
+ connect(vertexDefault, SIGNAL(released()), this, SLOT(defaultVertexShader()));
+}
+
+void PixelShaderWindow::synchronize() {
+ fragmentPath->setText(config().path.fragmentShader);
+ vertexPath->setText(config().path.vertexShader);
+}
+
+void PixelShaderWindow::selectFragmentShader() {
+ diskBrowser->chooseFile(
+ bind(&PixelShaderWindow::assignFragmentShader, this),
+ config().path.current.shader,
+ "Select Fragment Shader"
+ );
+}
+
+void PixelShaderWindow::selectVertexShader() {
+ diskBrowser->chooseFile(
+ bind(&PixelShaderWindow::assignVertexShader, this),
+ config().path.current.shader,
+ "Select Vertex Shader"
+ );
+}
+
+void PixelShaderWindow::defaultFragmentShader() { assignFragmentShader(""); }
+void PixelShaderWindow::defaultVertexShader() { assignVertexShader(""); }
+
+void PixelShaderWindow::assignFragmentShader(string filename) {
+ config().path.fragmentShader = filename;
+ synchronize();
+ utility.updatePixelShader();
+}
+
+void PixelShaderWindow::assignVertexShader(string filename) {
+ config().path.vertexShader = filename;
+ synchronize();
+ utility.updatePixelShader();
+}
diff --git a/src/ui_qt/settings/pixelshader.moc.hpp b/src/ui_qt/settings/pixelshader.moc.hpp
new file mode 100644
index 00000000..4e6f8329
--- /dev/null
+++ b/src/ui_qt/settings/pixelshader.moc.hpp
@@ -0,0 +1,28 @@
+class PixelShaderWindow : public QWidget {
+ Q_OBJECT
+
+public:
+ QVBoxLayout *layout;
+ QLabel *title;
+ QGridLayout *gridLayout;
+ QLabel *fragmentLabel;
+ QLineEdit *fragmentPath;
+ QPushButton *fragmentSelect;
+ QPushButton *fragmentDefault;
+ QLabel *vertexLabel;
+ QLineEdit *vertexPath;
+ QPushButton *vertexSelect;
+ QPushButton *vertexDefault;
+
+ void synchronize();
+ PixelShaderWindow();
+
+public slots:
+ void selectFragmentShader();
+ void selectVertexShader();
+ void defaultFragmentShader();
+ void defaultVertexShader();
+
+ void assignFragmentShader(string);
+ void assignVertexShader(string);
+} *pixelShaderWindow;
diff --git a/src/ui_qt/settings/settings.cpp b/src/ui_qt/settings/settings.cpp
index 06d865f5..1b8e6bdc 100644
--- a/src/ui_qt/settings/settings.cpp
+++ b/src/ui_qt/settings/settings.cpp
@@ -1,11 +1,11 @@
#include "video.cpp"
+#include "pixelshader.cpp"
#include "audio.cpp"
#include "input.cpp"
#include "paths.cpp"
#include "advanced.cpp"
-#include "utility/inputcapture.cpp"
-SettingsWindow::SettingsWindow() : QbWindow(config.geometry.settingsWindow) {
+SettingsWindow::SettingsWindow() : QbWindow(config().geometry.settingsWindow) {
setObjectName("settings-window");
setWindowTitle("Configuration Settings");
resize(625, 360);
@@ -18,14 +18,20 @@ SettingsWindow::SettingsWindow() : QbWindow(config.geometry.settingsWindow) {
splitter = new QSplitter;
layout->addWidget(splitter);
+ video = new QTreeWidgetItem(QStringList() << "Video");
+ audio = new QTreeWidgetItem(QStringList() << "Audio");
+ input = new QTreeWidgetItem(QStringList() << "Input");
+ paths = new QTreeWidgetItem(QStringList() << "Paths");
+ advanced = new QTreeWidgetItem(QStringList() << "Advanced");
+
//use QTreeWidget instead of QListWidget, as only the former has setAllColumnsShowFocus()
//this is needed to have the dotted-selection rectangle encompass the icons
list = new QTreeWidget;
- list->addTopLevelItem(video = new QTreeWidgetItem(QStringList() << "Video"));
- list->addTopLevelItem(audio = new QTreeWidgetItem(QStringList() << "Audio"));
- list->addTopLevelItem(input = new QTreeWidgetItem(QStringList() << "Input"));
- list->addTopLevelItem(paths = new QTreeWidgetItem(QStringList() << "Paths"));
- list->addTopLevelItem(advanced = new QTreeWidgetItem(QStringList() << "Advanced"));
+ list->addTopLevelItem(video);
+ list->addTopLevelItem(audio);
+ list->addTopLevelItem(input);
+ list->addTopLevelItem(paths);
+ list->addTopLevelItem(advanced);
list->setCurrentItem(input); //select most frequently used panel by default
list->setHeaderHidden(true);
list->setRootIsDecorated(false);
@@ -52,8 +58,6 @@ SettingsWindow::SettingsWindow() : QbWindow(config.geometry.settingsWindow) {
pathSettingsWindow = new PathSettingsWindow;
advancedSettingsWindow = new AdvancedSettingsWindow;
- inputCaptureWindow = new InputCaptureWindow;
-
panelLayout = new QStackedLayout(panel);
panelLayout->addWidget(videoSettingsWindow);
panelLayout->addWidget(audioSettingsWindow);
@@ -70,9 +74,9 @@ SettingsWindow::SettingsWindow() : QbWindow(config.geometry.settingsWindow) {
void SettingsWindow::itemChanged() {
QTreeWidgetItem *item = list->currentItem();
- if(item == video) panelLayout->setCurrentWidget(videoSettingsWindow);
- if(item == audio) panelLayout->setCurrentWidget(audioSettingsWindow);
- if(item == input) panelLayout->setCurrentWidget(inputSettingsWindow);
- if(item == paths) panelLayout->setCurrentWidget(pathSettingsWindow);
+ if(item == video) panelLayout->setCurrentWidget(videoSettingsWindow);
+ if(item == audio) panelLayout->setCurrentWidget(audioSettingsWindow);
+ if(item == input) panelLayout->setCurrentWidget(inputSettingsWindow);
+ if(item == paths) panelLayout->setCurrentWidget(pathSettingsWindow);
if(item == advanced) panelLayout->setCurrentWidget(advancedSettingsWindow);
}
diff --git a/src/ui_qt/settings/settings.moc.hpp b/src/ui_qt/settings/settings.moc.hpp
index 7c751ded..bfc9a8e3 100644
--- a/src/ui_qt/settings/settings.moc.hpp
+++ b/src/ui_qt/settings/settings.moc.hpp
@@ -1,9 +1,9 @@
#include "video.moc"
+#include "pixelshader.moc"
#include "audio.moc"
#include "input.moc"
#include "paths.moc"
#include "advanced.moc"
-#include "utility/inputcapture.moc"
class SettingsWindow : public QbWindow {
Q_OBJECT
diff --git a/src/ui_qt/settings/utility/inputcapture.cpp b/src/ui_qt/settings/utility/inputcapture.cpp
deleted file mode 100644
index 81ec2226..00000000
--- a/src/ui_qt/settings/utility/inputcapture.cpp
+++ /dev/null
@@ -1,451 +0,0 @@
-InputCaptureWindow::InputCaptureWindow() : QbWindow(config.geometry.inputCaptureWindow) {
- activeObject = 0;
- activeGroup = 0;
- groupIndex = 0;
- inputLock = false;
-
- setObjectName("input-capture-window");
- setWindowTitle("Input Capture");
-
- layout = new QVBoxLayout;
- layout->setMargin(Style::WindowMargin);
- layout->setSpacing(0);
- layout->setAlignment(Qt::AlignTop);
- setLayout(layout);
-
- hlayout = new QHBoxLayout;
- hlayout->setSpacing(Style::WidgetSpacing); {
- title = new QLabel;
- hlayout->addWidget(title, 0, Qt::AlignTop);
-
- mouseAxes = new QPushButton(" Assign Mouse Axis ");
- mouseAxes->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
- hlayout->addWidget(mouseAxes, 0, Qt::AlignTop);
-
- mouseButtons = new QPushButton(" Assign Mouse Button ");
- mouseButtons->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
- hlayout->addWidget(mouseButtons, 0, Qt::AlignTop);
- }
- layout->addLayout(hlayout);
-
- imageSpacer = new QWidget;
- imageSpacer->setFixedSize(Style::WidgetSpacing, Style::WidgetSpacing);
- layout->addWidget(imageSpacer);
-
- imageWidget = new ImageWidget;
- layout->addWidget(imageWidget, 0, Qt::AlignHCenter);
-
- connect(mouseAxes, SIGNAL(released()), this, SLOT(assignMouseAxis()));
- connect(mouseButtons, SIGNAL(released()), this, SLOT(assignMouseButton()));
-
- inputMouseCaptureWindow = new InputMouseCaptureWindow;
- inputCalibrationWindow = new InputCalibrationWindow;
-}
-
-void InputCaptureWindow::activate(InputObject *object) {
- if(!activeGroup) hide();
-
- utf8 info;
- info << "ID: ";
- if(object->parent) {
- InputDevice *device = dynamic_cast(object->parent);
- if(device) info << "Controller port " << (int)(device->port + 1) << " :: ";
- else info << "User interface :: ";
- info << object->parent->name << " :: ";
- }
- info << object->name << "
";
-
- activeObject = object;
- if(activeObject->type == InputObject::Button) {
- mouseAxes->hide();
- mouseButtons->show();
-
- info << "Press any key or button to assign to this ID.";
- } else /*(activeObject->type == InputObject::Axis)*/ {
- mouseAxes->show();
- mouseButtons->hide();
-
- info << "Move any axis to assign to this ID.";
- }
-
- if(dynamic_cast(activeObject->parent)) {
- imageSpacer->show();
- imageWidget->setFixedSize(480, 210);
- imageWidget->show();
- } else {
- imageSpacer->hide();
- imageWidget->hide();
- }
-
- title->setText(info);
- show();
- shrink();
-}
-
-void InputCaptureWindow::activate(InputGroup *group) {
- activeGroup = group;
- groupIndex = 0;
- hide();
- activate((*activeGroup)[groupIndex]);
-}
-
-void InputCaptureWindow::inputEvent(uint16_t code, bool forceAssign /* = false */) {
- if(!activeObject || inputLock == true) return;
-
- //input polling is global, need to block mouse actions that may be UI interactions.
- //custom controls on window allow mouse assignment instead.
- if(forceAssign == false) {
- if(inputMouseCaptureWindow->isActiveWindow()) {
- inputMouseCaptureWindow->inputEvent(code);
- return;
- }
- if(!isActiveWindow()) return;
-
- //get as much info as possible about this code
- InputCode::type_t type = InputCode::type(code);
- InputCode::axistype_t axisType = InputCode::axisType(code);
- int joypadNumber = InputCode::joypadNumber(code);
- int16_t state = inputManager.state(code);
- unsigned distance = abs(state - inputManager.lastState(code));
-
- if(type == InputCode::JoypadHat) {
- //hats can be in any of nine clock-wise states (4x direct, 4x angled and centered.)
- //only map when hat is moved to an explicit direction.
- if(state != joypad<>::hat_up && state != joypad<>::hat_down
- && state != joypad<>::hat_left && state != joypad<>::hat_right) return;
- }
-
- if(type == InputCode::JoypadAxis) {
- //require a degree of resistance to prevent accidental mapping
- if(axisType == InputCode::Stick) {
- //require axis to be pressed almost completely toward a specific direction
- if(state > -28672 && state < +28672) return;
- } else if(axisType == InputCode::Trigger) {
- //require trigger to be at least 75% pressed down
- if(state > -16384) return;
- } else {
- //invalid axis type: most likely the controller has yet to be calibrated
- if(joypadNumber < 0) return; //should never occur
-
- //some analog triggers report phantom motion even when user does not touch gamepad
- if(distance < 64) return; //require some degree of force to trigger calibration
- if(state > -8192 && state < +8192) return; //ignore center motion
-
- if(inputManager.calibrated(joypadNumber) == false) {
- inputCalibrationWindow->activate(joypadNumber);
- }
-
- //block assignment until controller is fully calibrated
- return;
- }
- }
-
- if(activeObject->type == InputObject::Axis) {
- if(type == InputCode::KeyboardButton
- || type == InputCode::MouseAxis
- || type == InputCode::MouseButton
- || type == InputCode::JoypadHat
- || type == InputCode::JoypadButton
- ) return;
-
- //uni-directional trigger cannot map to bi-directional axis
- if(type == InputCode::JoypadAxis && axisType == InputCode::Trigger) return;
- }
-
- if(activeObject->type == InputObject::Button) {
- if(type == InputCode::MouseAxis
- || type == InputCode::MouseButton
- ) return;
-
- //only capture on button press, not release
- if(type != InputCode::JoypadAxis && state == false) return;
- }
-
- //if assigning a complete controller set, ensure requested key has not been assigned
- //to a previous entry in the group already. this prevents slow motion of joypad axes
- //from assigning the same value to multiple entries in rapid succession.
- if(activeGroup && groupIndex > 0) {
- for(unsigned i = 0; i < groupIndex; i++) {
- if(code == (*activeGroup)[i]->code) {
- //joypad hats and axes have multiple states, and are differentiated by modifier.
- //allow mapping only if requested modifier is unique.
- if(type == InputCode::JoypadHat) {
- if(state == joypad<>::hat_up && (*activeGroup)[i]->modifier == InputObject::Up ) return;
- if(state == joypad<>::hat_down && (*activeGroup)[i]->modifier == InputObject::Down ) return;
- if(state == joypad<>::hat_left && (*activeGroup)[i]->modifier == InputObject::Left ) return;
- if(state == joypad<>::hat_right && (*activeGroup)[i]->modifier == InputObject::Right) return;
- } else if(type == InputCode::JoypadAxis) {
- if(axisType == InputCode::Stick) {
- if(state < 0 && (*activeGroup)[i]->modifier == InputObject::Lo) return;
- if(state >= 0 && (*activeGroup)[i]->modifier == InputObject::Hi) return;
- } else if(axisType == InputCode::Trigger) {
- if((*activeGroup)[i]->modifier == InputObject::Trigger) return;
- }
- } else {
- //this code has already been used, do not map it
- return;
- }
- }
- }
- }
- }
-
- //bind code and update GUI input assignment list
- activeObject->bind(code);
- inputSettingsWindow->updateList();
- activeObject = 0;
-
- //ignore multiple simultaneous state changes.
- //this helps with joypads that only activate
- //analog inputs after the first button press.
- inputLock = true;
- for(unsigned i = 0; i < 2; i++) inputManager.refresh();
- inputLock = false;
-
- if(!activeGroup) {
- hide();
- inputMouseCaptureWindow->hide();
- } else {
- //try and map the next code in this input group
- groupIndex++;
- if(groupIndex < activeGroup->size()) {
- activate((*activeGroup)[groupIndex]);
- } else {
- //all group codes mapped
- hide();
- inputMouseCaptureWindow->hide();
- activeGroup = 0;
- }
- }
-}
-
-void InputCaptureWindow::closeEvent(QCloseEvent *event) {
- QbWindow::closeEvent(event);
-
- //window closed by user, cancel key assignment
- activeObject = 0;
- activeGroup = 0;
-
- inputMouseCaptureWindow->hide();
- inputCalibrationWindow->dismiss();
-}
-
-void InputCaptureWindow::assignMouseAxis() {
- //refresh input state so that mouse release event (from SIGNAL(released())
- //is not sent immediately after window is visible.
- inputManager.refresh();
- inputMouseCaptureWindow->activate(InputMouseCaptureWindow::AxisMode);
-}
-
-void InputCaptureWindow::assignMouseButton() {
- inputManager.refresh();
- inputMouseCaptureWindow->activate(InputMouseCaptureWindow::ButtonMode);
-}
-
-void InputCaptureWindow::ImageWidget::paintEvent(QPaintEvent*) {
- //currently, there is only an image available for the joypad.
- //in the future, this routine should determine which type of
- //image to draw via activeObject->parent's derived class type.
- QPainter painter(this);
- QPixmap pixmap(":/joypad.png");
- painter.drawPixmap(0, 0, pixmap);
-}
-
-//=======================
-//InputMouseCaptureWindow
-//=======================
-
-InputMouseCaptureWindow::InputMouseCaptureWindow() : QbWindow(config.geometry.inputMouseCaptureWindow) {
- setObjectName("input-mouse-capture-window");
- setWindowTitle("Mouse Input Capture");
-
- layout = new QVBoxLayout;
- layout->setMargin(Style::WindowMargin);
- layout->setSpacing(0);
- layout->setAlignment(Qt::AlignTop);
- setLayout(layout);
-
- info = new QLabel;
- layout->addWidget(info);
- layout->addSpacing(Style::WidgetSpacing);
-
- captureBox = new QLabel("[ capture box ]");
- captureBox->setObjectName("mouse-capture-box");
- captureBox->setAlignment(Qt::AlignCenter);
- captureBox->setFixedHeight(120);
- layout->addWidget(captureBox);
-
- buttonLayout = new QHBoxLayout;
- buttonLayout->setSpacing(Style::WidgetSpacing);
- buttonLayout->setAlignment(Qt::AlignRight);
- layout->addLayout(buttonLayout);
-
- xAxis = new QPushButton("X-axis");
- buttonLayout->addWidget(xAxis);
-
- yAxis = new QPushButton("Y-axis");
- buttonLayout->addWidget(yAxis);
-
- connect(xAxis, SIGNAL(released()), this, SLOT(assignAxisX()));
- connect(yAxis, SIGNAL(released()), this, SLOT(assignAxisY()));
-}
-
-void InputMouseCaptureWindow::activate(InputMouseCaptureWindow::Mode mode_) {
- hide();
- activeMode = mode_;
-
- if(activeMode == AxisMode) {
- captureBox->hide();
- xAxis->show();
- yAxis->show();
-
- info->setText(utf8()
- << "To assign a mouse axis to this ID, please click the desired axis button
"
- << "below, using the mouse that you want the axis to be assigned to."
- );
-
- activeMouse = -1;
- } else /*(activeMode == ButtonMode) */ {
- captureBox->show();
- xAxis->hide();
- yAxis->hide();
-
- info->setText(utf8()
- << "To assign a mouse button to this ID, please place the mouse you wish to map
"
- << "over the capture box below, and then click any mouse button to set assignment."
- );
- }
-
- show();
-}
-
-//this is only called when isActiveWindow() == true
-void InputMouseCaptureWindow::inputEvent(uint16_t code) {
- InputCode::type_t type = InputCode::type(code);
- int16_t state = inputManager.state(code);
-
- if(activeMode == AxisMode) {
- //when pressing down mouse button (eg to select "X-axis" or "Y-axis"),
- //record mouse index for later assignment
- if(type == InputCode::MouseButton && state == true) {
- activeMouse = InputCode::mouseNumber(code);
- return;
- }
- } else if(activeMode == ButtonMode) {
- //if this is a mouse button that is being released ...
- if(type == InputCode::MouseButton && state == false) {
- //ensure button was clicked inside active capture box
- QRect windowRect = geometry();
- QRect widgetRect = captureBox->geometry();
- unsigned wx = windowRect.left() + widgetRect.left();
- unsigned wy = windowRect.top() + widgetRect.top();
- unsigned px = QCursor::pos().x();
- unsigned py = QCursor::pos().y();
-
- if(px < wx || px >= wx + widgetRect.size().width() ) return;
- if(py < wy || py >= wy + widgetRect.size().height()) return;
-
- inputCaptureWindow->inputEvent(code, true);
- return;
- }
- }
-}
-
-void InputMouseCaptureWindow::assignAxisX() {
- if(activeMouse >= 0) {
- inputCaptureWindow->inputEvent(mouse<>::index(activeMouse, mouse<>::x), true);
- }
-}
-
-void InputMouseCaptureWindow::assignAxisY() {
- if(activeMouse >= 0) {
- inputCaptureWindow->inputEvent(mouse<>::index(activeMouse, mouse<>::y), true);
- }
-}
-
-//====================
-//InputCalibrateWindow
-//====================
-
-//background:
-//===========
-//HID devices work by sending device state *changes* only. what this means is that when an application is started,
-//it does not know the current state of said device. the keyboard and mouse are exceptions, as the OS globally
-//tracks their states. but this does apply to joypads. once a button is pressed, or an axis is moved, the entire
-//joypad state will be sent in a message, that APIs such as DirectInput and SDL will buffer.
-//
-//to complicate matters, recent joypads have added pressure-sensitive buttons (triggers), in addition to the
-//existing analog sticks. but this functionality was not extended to the USB HID state or to various platform
-//input APIs. instead, they are treated exactly like axes.
-//
-//however, an application needs to treat these two input types distinctly:
-//a stick is a bi-directional input. the stick starts off centered, and can be moved left or right, or up or down.
-//a trigger is a uni-directional input. it can only be pushed down.
-//
-//a stick's default, unpressed state is centered (0), whereas a trigger's default state is fully depressed (+32767.)
-//but because the default state is not available until the user presses a button on a joypad, it is not possible to
-//calibrate a joypad on startup. all axes will report a value of 0, even if buttons are depressed.
-//
-//thusly, this class is needed. it will spawn a window upon the first attempt to map a joypad axis after startup.
-//by the point this window appears, an axis must have been moved, so the joypad state is now valid. but since it's
-//not possible to tell which button was pressed or which axis was moved, it's possible the axis that we're trying to
-//map was moved. so querying its state now might result in improper mapping. so instead, this window is shown, and
-//the user is asked not to press any buttons or move any axes. after hitting okay to confirm the joypad is idle,
-//the joypad can finally be calibrated properly.
-//
-//upon assignment, the calibration data is appended to the input assignment value (eg "joypad00.axis00::trigger"),
-//so that calibration is not necessary every time the emulator is run -- only when modifying input mapping on an axis.
-
-void InputCalibrationWindow::activate(unsigned joy) {
- //do not override an already active calibration window
- if(isVisible()) return;
-
- activeJoypad = joy;
- info->setText(utf8()
- << "Joypad #" << joy << " needs to be calibrated before it can be mapped. "
- << "Please ensure
that no buttons are pressed, "
- << "and all axes are centered before pressing ok."
- );
-
- show();
- ok->setFocus();
-}
-
-InputCalibrationWindow::InputCalibrationWindow() : QbWindow(config.geometry.inputCalibrationWindow) {
- activeJoypad = -1;
-
- setObjectName("input-calibrate-window");
- setWindowTitle("Joypad Calibration");
-
- layout = new QVBoxLayout;
- layout->setMargin(Style::WindowMargin);
- layout->setSpacing(0);
- layout->setAlignment(Qt::AlignTop);
- setLayout(layout);
-
- info = new QLabel;
- layout->addWidget(info);
- layout->addSpacing(Style::WidgetSpacing);
-
- controlLayout = new QHBoxLayout;
- controlLayout->setAlignment(Qt::AlignRight);
- layout->addLayout(controlLayout);
-
- ok = new QPushButton("Ok");
- controlLayout->addWidget(ok);
-
- connect(ok, SIGNAL(released()), this, SLOT(dismiss()));
-}
-
-void InputCalibrationWindow::dismiss() {
- hide();
- if(activeJoypad != -1) {
- inputManager.calibrate(activeJoypad);
- activeJoypad = -1;
- }
-}
-
-void InputCalibrationWindow::closeEvent(QCloseEvent *event) {
- QbWindow::closeEvent(event);
- dismiss();
-}
diff --git a/src/ui_qt/settings/utility/inputcapture.moc.hpp b/src/ui_qt/settings/utility/inputcapture.moc.hpp
deleted file mode 100644
index 9f4d6468..00000000
--- a/src/ui_qt/settings/utility/inputcapture.moc.hpp
+++ /dev/null
@@ -1,76 +0,0 @@
-class InputCaptureWindow : public QbWindow {
- Q_OBJECT
-
-public:
- QVBoxLayout *layout;
- QHBoxLayout *hlayout;
- QLabel *title;
- QPushButton *mouseAxes;
- QPushButton *mouseButtons;
- QWidget *imageSpacer;
- struct ImageWidget : public QWidget {
- void paintEvent(QPaintEvent*);
- } *imageWidget;
-
- void activate(InputObject *object);
- void activate(InputGroup *group);
- void inputEvent(uint16_t code, bool forceAssign = false);
- void closeEvent(QCloseEvent*);
- InputCaptureWindow();
-
-public slots:
- void assignMouseAxis();
- void assignMouseButton();
-
-private:
- InputObject *activeObject;
- InputGroup *activeGroup;
- unsigned groupIndex;
- bool inputLock;
-} *inputCaptureWindow;
-
-class InputMouseCaptureWindow : public QbWindow {
- Q_OBJECT
-
-public:
- enum Mode { AxisMode, ButtonMode };
-
- QVBoxLayout *layout;
- QLabel *info;
- QLabel *captureBox;
- QHBoxLayout *buttonLayout;
- QPushButton *xAxis;
- QPushButton *yAxis;
-
- void activate(Mode);
- void inputEvent(uint16_t code);
- InputMouseCaptureWindow();
-
-public slots:
- void assignAxisX();
- void assignAxisY();
-
-private:
- Mode activeMode;
- signed activeMouse;
-} *inputMouseCaptureWindow;
-
-class InputCalibrationWindow : public QbWindow {
- Q_OBJECT
-
-public:
- QVBoxLayout *layout;
- QLabel *info;
- QHBoxLayout *controlLayout;
- QPushButton *ok;
-
- void activate(unsigned joy);
- void closeEvent(QCloseEvent*);
- InputCalibrationWindow();
-
-public slots:
- void dismiss();
-
-private:
- int activeJoypad;
-} *inputCalibrationWindow;
diff --git a/src/ui_qt/settings/video.cpp b/src/ui_qt/settings/video.cpp
index b1d8dee9..1e7acad6 100644
--- a/src/ui_qt/settings/video.cpp
+++ b/src/ui_qt/settings/video.cpp
@@ -10,29 +10,55 @@ VideoSettingsWindow::VideoSettingsWindow() {
layout->addWidget(title);
sliders = new QGridLayout; {
- lcontrast = new QLabel("Contrast adjust: +100%");
- sliders->addWidget(lcontrast, 0, 0);
+ contrastLabel = new QLabel("Contrast adjust:");
+ sliders->addWidget(contrastLabel, 0, 0);
+
+ contrastValue = new QLabel;
+ contrastValue->setAlignment(Qt::AlignHCenter);
+ contrastValue->setMinimumWidth(contrastValue->fontMetrics().width("+100%"));
+ sliders->addWidget(contrastValue, 0, 1);
contrast = new QSlider(Qt::Horizontal);
contrast->setMinimum(-95);
contrast->setMaximum(+95);
- sliders->addWidget(contrast, 0, 1);
+ sliders->addWidget(contrast, 0, 2);
- lbrightness = new QLabel("Brightness adjust: +100%");
- sliders->addWidget(lbrightness, 1, 0);
+ brightnessLabel = new QLabel("Brightness adjust:");
+ sliders->addWidget(brightnessLabel, 1, 0);
+
+ brightnessValue = new QLabel;
+ brightnessValue->setAlignment(Qt::AlignHCenter);
+ sliders->addWidget(brightnessValue, 1, 1);
brightness = new QSlider(Qt::Horizontal);
brightness->setMinimum(-95);
brightness->setMaximum(+95);
- sliders->addWidget(brightness, 1, 1);
+ sliders->addWidget(brightness, 1, 2);
- lgamma = new QLabel("Gamma adjust: +100%");
- sliders->addWidget(lgamma, 2, 0);
+ gammaLabel = new QLabel("Gamma adjust:");
+ sliders->addWidget(gammaLabel, 2, 0);
+
+ gammaValue = new QLabel;
+ gammaValue->setAlignment(Qt::AlignHCenter);
+ sliders->addWidget(gammaValue, 2, 1);
gamma = new QSlider(Qt::Horizontal);
gamma->setMinimum(-95);
gamma->setMaximum(+95);
- sliders->addWidget(gamma, 2, 1);
+ sliders->addWidget(gamma, 2, 2);
+
+ scanlineLabel = new QLabel("Scanline adjust:");
+ sliders->addWidget(scanlineLabel, 3, 0);
+
+ scanlineValue = new QLabel;
+ scanlineValue->setAlignment(Qt::AlignHCenter);
+ sliders->addWidget(scanlineValue, 3, 1);
+
+ scanline = new QSlider(Qt::Horizontal);
+ scanline->setMinimum(0);
+ scanline->setMaximum(20);
+ scanline->setPageStep(4);
+ sliders->addWidget(scanline, 3, 2);
}
sliders->setSpacing(Style::WidgetSpacing);
layout->addLayout(sliders);
@@ -48,9 +74,13 @@ VideoSettingsWindow::VideoSettingsWindow() {
options->setSpacing(Style::WidgetSpacing);
layout->addLayout(options);
+ pixelShaderWindow = new PixelShaderWindow;
+ layout->addWidget(pixelShaderWindow);
+
connect(contrast, SIGNAL(valueChanged(int)), this, SLOT(contrastAdjust(int)));
connect(brightness, SIGNAL(valueChanged(int)), this, SLOT(brightnessAdjust(int)));
connect(gamma, SIGNAL(valueChanged(int)), this, SLOT(gammaAdjust(int)));
+ connect(scanline, SIGNAL(valueChanged(int)), this, SLOT(scanlineAdjust(int)));
connect(enableGammaRamp, SIGNAL(stateChanged(int)), this, SLOT(gammaRampToggle(int)));
syncUi();
@@ -59,41 +89,51 @@ VideoSettingsWindow::VideoSettingsWindow() {
void VideoSettingsWindow::syncUi() {
int n;
- n = config.video.contrastAdjust;
- lcontrast->setText(utf8() << "Contrast adjust: " << (n > 0 ? "+" : "") << n << "%");
+ n = config().video.contrastAdjust;
+ contrastValue->setText(string() << (n > 0 ? "+" : "") << n << "%");
contrast->setSliderPosition(n);
- n = config.video.brightnessAdjust;
- lbrightness->setText(utf8() << "Brightness adjust: " << (n > 0 ? "+" : "") << n << "%");
+ n = config().video.brightnessAdjust;
+ brightnessValue->setText(string() << (n > 0 ? "+" : "") << n << "%");
brightness->setSliderPosition(n);
- n = config.video.gammaAdjust;
- lgamma->setText(utf8() << "Gamma adjust: " << (n > 0 ? "+" : "") << n << "%");
+ n = config().video.gammaAdjust;
+ gammaValue->setText(string() << (n > 0 ? "+" : "") << n << "%");
gamma->setSliderPosition(n);
- enableGammaRamp->setChecked(config.video.enableGammaRamp);
-}
+ n = config().video.scanlineAdjust;
+ scanlineValue->setText(string() << n << "%");
+ scanline->setSliderPosition(n / 5);
-void VideoSettingsWindow::gammaRampToggle(int state) {
- config.video.enableGammaRamp = (state == Qt::Checked);
- syncUi();
- utility.updateColorFilter();
+ enableGammaRamp->setChecked(config().video.enableGammaRamp);
}
void VideoSettingsWindow::contrastAdjust(int value) {
- config.video.contrastAdjust = value;
+ config().video.contrastAdjust = value;
syncUi();
utility.updateColorFilter();
}
void VideoSettingsWindow::brightnessAdjust(int value) {
- config.video.brightnessAdjust = value;
+ config().video.brightnessAdjust = value;
syncUi();
utility.updateColorFilter();
}
void VideoSettingsWindow::gammaAdjust(int value) {
- config.video.gammaAdjust = value;
+ config().video.gammaAdjust = value;
+ syncUi();
+ utility.updateColorFilter();
+}
+
+void VideoSettingsWindow::scanlineAdjust(int value) {
+ config().video.scanlineAdjust = value * 5;
+ syncUi();
+ scanlineFilter.setIntensity(value * 5);
+}
+
+void VideoSettingsWindow::gammaRampToggle(int state) {
+ config().video.enableGammaRamp = (state == Qt::Checked);
syncUi();
utility.updateColorFilter();
}
diff --git a/src/ui_qt/settings/video.moc.hpp b/src/ui_qt/settings/video.moc.hpp
index fdc90a81..b6e67aa5 100644
--- a/src/ui_qt/settings/video.moc.hpp
+++ b/src/ui_qt/settings/video.moc.hpp
@@ -5,12 +5,18 @@ public:
QVBoxLayout *layout;
QLabel *title;
QGridLayout *sliders;
- QLabel *lcontrast;
+ QLabel *contrastLabel;
+ QLabel *contrastValue;
QSlider *contrast;
- QLabel *lbrightness;
+ QLabel *brightnessLabel;
+ QLabel *brightnessValue;
QSlider *brightness;
- QLabel *lgamma;
+ QLabel *gammaLabel;
+ QLabel *gammaValue;
QSlider *gamma;
+ QLabel *scanlineLabel;
+ QLabel *scanlineValue;
+ QSlider *scanline;
QHBoxLayout *options;
QCheckBox *enableGammaRamp;
@@ -18,8 +24,9 @@ public:
VideoSettingsWindow();
public slots:
- void gammaRampToggle(int);
void contrastAdjust(int);
void brightnessAdjust(int);
void gammaAdjust(int);
+ void scanlineAdjust(int);
+ void gammaRampToggle(int);
} *videoSettingsWindow;
diff --git a/src/ui_qt/tools/cheateditor.cpp b/src/ui_qt/tools/cheateditor.cpp
index f9d48f8c..551961af 100644
--- a/src/ui_qt/tools/cheateditor.cpp
+++ b/src/ui_qt/tools/cheateditor.cpp
@@ -115,8 +115,8 @@ void CheatEditorWindow::updateItem(QTreeWidgetItem *item) {
if(lcode.size() > 1) lcode[0] << "+" << lcode.size() - 1;
item->setCheckState(1, code.enabled ? Qt::Checked : Qt::Unchecked);
- item->setText(1, utf8() << lcode[0]);
- item->setText(2, utf8() << code.desc);
+ item->setText(1, lcode[0]);
+ item->setText(2, code.desc);
}
void CheatEditorWindow::popupMenu(const QPoint &point) {
@@ -138,7 +138,7 @@ void CheatEditorWindow::reloadList() {
item->setData(0, Qt::UserRole, QVariant(n));
char slot[16];
sprintf(slot, "%3u", n + 1);
- item->setText(0, utf8() << slot);
+ item->setText(0, slot);
updateItem(item);
}
}
@@ -157,8 +157,8 @@ void CheatEditorWindow::listChanged() {
SNES::Cheat::cheat_t code;
SNES::cheat.get(n, code);
- descEdit->setText(utf8() << code.desc);
- codeEdit->setText(utf8() << code.code);
+ descEdit->setText(code.desc);
+ codeEdit->setText(code.code);
}
syncUi();
diff --git a/src/ui_qt/tools/cheatfinder.cpp b/src/ui_qt/tools/cheatfinder.cpp
index 363bd19c..368f5511 100644
--- a/src/ui_qt/tools/cheatfinder.cpp
+++ b/src/ui_qt/tools/cheatfinder.cpp
@@ -144,7 +144,7 @@ void CheatFinderWindow::searchMemory() {
string text = valueEdit->text().toUtf8().constData();
//auto-detect input data type
- if(strbegin(text, "0x")) data = strhex(text + 2);
+ if(strbegin(text, "0x")) data = strhex((const char*)text + 2);
else if(strbegin(text, "-")) data = strsigned(text);
else data = strunsigned(text);
diff --git a/src/ui_qt/tools/statemanager.cpp b/src/ui_qt/tools/statemanager.cpp
index d5bb5f0b..7c9d8f87 100644
--- a/src/ui_qt/tools/statemanager.cpp
+++ b/src/ui_qt/tools/statemanager.cpp
@@ -116,9 +116,9 @@ void StateManagerWindow::reloadList() {
lstring part;
part.split("\t", state[n]);
item->setData(0, Qt::UserRole, QVariant(n));
- item->setText(0, utf8() << part[0]);
- item->setText(1, utf8() << part[1]);
- item->setText(2, utf8() << part[2]);
+ item->setText(0, part[0]);
+ item->setText(1, part[1]);
+ item->setText(2, part[2]);
}
list->setSortingEnabled(true);
@@ -131,9 +131,9 @@ void StateManagerWindow::updateItem(QTreeWidgetItem *item) {
lstring state, part;
utility.loadStateInfo(state);
part.split("\t", state[n]);
- item->setText(0, utf8() << part[0]);
- item->setText(1, utf8() << part[1]);
- item->setText(2, utf8() << part[2]);
+ item->setText(0, part[0]);
+ item->setText(1, part[1]);
+ item->setText(2, part[2]);
}
void StateManagerWindow::listChanged() {
diff --git a/src/ui_qt/tools/tools.cpp b/src/ui_qt/tools/tools.cpp
index aa295b1a..e1fd43c4 100644
--- a/src/ui_qt/tools/tools.cpp
+++ b/src/ui_qt/tools/tools.cpp
@@ -2,7 +2,7 @@
#include "cheatfinder.cpp"
#include "statemanager.cpp"
-ToolsWindow::ToolsWindow() : QbWindow(config.geometry.toolsWindow) {
+ToolsWindow::ToolsWindow() : QbWindow(config().geometry.toolsWindow) {
setObjectName("tools-window");
setWindowTitle("Tools");
resize(625, 360);
diff --git a/src/ui_qt/utility/cartridge.cpp b/src/ui_qt/utility/cartridge.cpp
index 8d0cf6fb..b41a1408 100644
--- a/src/ui_qt/utility/cartridge.cpp
+++ b/src/ui_qt/utility/cartridge.cpp
@@ -6,6 +6,7 @@ bool Utility::loadCartridgeNormal(const char *base) {
loadMemory(cartridge.baseName, ".srm", SNES::memory::cartram);
loadMemory(cartridge.baseName, ".rtc", SNES::memory::cartrtc);
+ cartridge.fileName = cartridge.baseName;
cartridge.name = notdir(nall::basename(cartridge.baseName));
modifySystemState(LoadCartridge);
@@ -21,6 +22,7 @@ bool Utility::loadCartridgeBsxSlotted(const char *base, const char *slot) {
loadMemory(cartridge.baseName, ".srm", SNES::memory::cartram);
loadMemory(cartridge.baseName, ".rtc", SNES::memory::cartrtc);
+ cartridge.fileName = cartridge.baseName;
cartridge.name = notdir(nall::basename(cartridge.baseName));
if(*slot) cartridge.name << " + " << notdir(nall::basename(cartridge.slotAName));
@@ -37,6 +39,7 @@ bool Utility::loadCartridgeBsx(const char *base, const char *slot) {
loadMemory(cartridge.baseName, ".srm", SNES::memory::bsxram );
loadMemory(cartridge.baseName, ".psr", SNES::memory::bsxpram);
+ cartridge.fileName = cartridge.slotAName;
cartridge.name = *slot
? notdir(nall::basename(cartridge.slotAName))
: notdir(nall::basename(cartridge.baseName));
@@ -55,6 +58,7 @@ bool Utility::loadCartridgeSufamiTurbo(const char *base, const char *slotA, cons
loadMemory(cartridge.slotAName, ".srm", SNES::memory::stAram);
loadMemory(cartridge.slotBName, ".srm", SNES::memory::stBram);
+ cartridge.fileName = cartridge.slotAName;
if(!*slotA && !*slotB) cartridge.name = notdir(nall::basename(cartridge.baseName));
else if(!*slotB) cartridge.name = notdir(nall::basename(cartridge.slotAName));
else if(!*slotA) cartridge.name = notdir(nall::basename(cartridge.slotBName));
@@ -73,6 +77,7 @@ bool Utility::loadCartridgeSuperGameBoy(const char *base, const char *slot) {
loadMemory(cartridge.slotAName, ".sav", SNES::memory::gbram);
loadMemory(cartridge.slotBName, ".rtc", SNES::memory::gbrtc);
+ cartridge.fileName = cartridge.slotAName;
cartridge.name = *slot
? notdir(nall::basename(cartridge.slotAName))
: notdir(nall::basename(cartridge.baseName));
@@ -134,16 +139,16 @@ void Utility::modifySystemState(system_state_t state) {
else if(SNES::cartridge.has_st011()) chip = "ST011";
else if(SNES::cartridge.has_st018()) chip = "ST018";
if(chip != "") {
- QMessageBox::warning(mainWindow, "Warning", utf8()
+ QMessageBox::warning(mainWindow, "Warning", string()
<< "Warning:
The " << chip << " chip was detected, which is not fully emulated yet.
"
<< "It is unlikely that this title will work properly.
");
}
- showMessage(utf8()
+ showMessage(string()
<< "Loaded " << cartridge.name
<< (cartridge.patchApplied ? ", and applied UPS patch." : "."));
- mainWindow->setWindowTitle(utf8() << bsnesTitle << " v" << bsnesVersion << " - " << cartridge.name);
- debugger->echo(utf8() << "Loaded " << cartridge.name << ".
");
+ mainWindow->setWindowTitle(string() << bsnesTitle << " v" << bsnesVersion << " - " << cartridge.name);
+ debugger->echo(string() << "Loaded " << cartridge.name << ".
");
} break;
case UnloadCartridge: {
@@ -157,8 +162,8 @@ void Utility::modifySystemState(system_state_t state) {
application.power = false;
application.pause = true;
- showMessage(utf8() << "Unloaded " << cartridge.name << ".");
- mainWindow->setWindowTitle(utf8() << bsnesTitle << " v" << bsnesVersion);
+ showMessage(string() << "Unloaded " << cartridge.name << ".");
+ mainWindow->setWindowTitle(string() << bsnesTitle << " v" << bsnesVersion);
} break;
case PowerOn: {
@@ -217,7 +222,7 @@ bool Utility::loadCartridge(string &filename, SNES::MappedRAM &memory) {
cartridge.patchApplied = false;
string name;
- name << filepath(nall::basename(filename), config.path.patch);
+ name << filepath(nall::basename(filename), config().path.patch);
name << ".ups";
file fp;
@@ -235,7 +240,7 @@ bool Utility::loadCartridge(string &filename, SNES::MappedRAM &memory) {
bool apply = false;
if(result == ups::ok) apply = true;
- if(config.file.bypass_patch_crc32) {
+ if(config().file.bypass_patch_crc32) {
if(result == ups::input_crc32_invalid ) apply = true;
if(result == ups::output_crc32_invalid) apply = true;
}
@@ -259,7 +264,7 @@ bool Utility::loadMemory(const char *filename, const char *extension, SNES::Mapp
if(memory.size() == 0 || memory.size() == -1U) return false;
string name;
- name << filepath(nall::basename(filename), config.path.save);
+ name << filepath(nall::basename(filename), config().path.save);
name << extension;
file fp;
@@ -279,7 +284,7 @@ bool Utility::saveMemory(const char *filename, const char *extension, SNES::Mapp
if(memory.size() == 0 || memory.size() == -1U) return false;
string name;
- name << filepath(nall::basename(filename), config.path.save);
+ name << filepath(nall::basename(filename), config().path.save);
name << extension;
file fp;
@@ -292,7 +297,7 @@ bool Utility::saveMemory(const char *filename, const char *extension, SNES::Mapp
void Utility::loadCheats() {
string name, data;
- name << filepath(nall::basename(cartridge.baseName), config.path.cheat);
+ name << filepath(nall::basename(cartridge.baseName), config().path.cheat);
name << ".cht";
SNES::cheat.clear();
@@ -301,7 +306,7 @@ void Utility::loadCheats() {
void Utility::saveCheats() {
string name;
- name << filepath(nall::basename(cartridge.baseName), config.path.cheat);
+ name << filepath(nall::basename(cartridge.baseName), config().path.cheat);
name << ".cht";
file fp;
@@ -327,7 +332,7 @@ string Utility::filepath(const char *filename, const char *pathname) {
//replace relative path with absolute path
if(strbegin(path, "./")) {
ltrim(path, "./");
- path = string() << config.path.base << path;
+ path = string() << config().path.base << path;
}
//remove folder part of filename
diff --git a/src/ui_qt/utility/state.cpp b/src/ui_qt/utility/state.cpp
index 04b59b2f..c3b1fb7f 100644
--- a/src/ui_qt/utility/state.cpp
+++ b/src/ui_qt/utility/state.cpp
@@ -3,7 +3,6 @@
//this function is used to disable save state support globally for these titles.
bool Utility::saveStatesSupported() {
if(SNES::cartridge.mode() == SNES::Cartridge::ModeBsx) return false;
- if(SNES::cartridge.mode() == SNES::Cartridge::ModeSuperGameBoy) return false;
if(SNES::cartridge.has_superfx()) return false;
if(SNES::cartridge.has_sa1()) return false;
@@ -18,17 +17,17 @@ bool Utility::saveStatesSupported() {
void Utility::quickLoad(uint8 slot) {
if(SNES::cartridge.loaded() == false || application.power == false) return;
if(saveStatesSupported() == false) {
- showMessage(utf8() << "Error: cannot save state due to unserializable special chip.");
+ showMessage(string() << "Error: cannot save state due to unserializable special chip.");
return;
}
string name;
- name << filepath(nall::basename(cartridge.baseName), config.path.state);
+ name << filepath(nall::basename(cartridge.fileName), config().path.state);
name << "-" << (unsigned)(slot + 1) << ".bst";
file fp;
if(fp.open(name, file::mode_read) == false) {
- showMessage(utf8() << "Error: unable to load quick state " << (unsigned)(slot + 1) << ".");
+ showMessage(string() << "Error: unable to load quick state " << (unsigned)(slot + 1) << ".");
return;
}
@@ -39,64 +38,64 @@ void Utility::quickLoad(uint8 slot) {
serializer state(data, size);
if(SNES::system.unserialize(state) == true) {
- showMessage(utf8() << "Quick state " << (unsigned)(slot + 1) << " loaded.");
+ showMessage(string() << "Quick state " << (unsigned)(slot + 1) << " loaded.");
} else {
- showMessage(utf8() << "Error: unable to load quick state " << (unsigned)(slot + 1) << ".");
+ showMessage(string() << "Error: unable to load quick state " << (unsigned)(slot + 1) << ".");
}
}
void Utility::quickSave(uint8 slot) {
if(SNES::cartridge.loaded() == false || application.power == false) return;
if(saveStatesSupported() == false) {
- showMessage(utf8() << "Error: cannot save state due to unserializable special chip.");
+ showMessage(string() << "Error: cannot save state due to unserializable special chip.");
return;
}
SNES::system.runtosave();
string name;
- name << filepath(nall::basename(cartridge.baseName), config.path.state);
+ name << filepath(nall::basename(cartridge.fileName), config().path.state);
name << "-" << (unsigned)(slot + 1) << ".bst";
serializer state = SNES::system.serialize();
file fp;
if(fp.open(name, file::mode_write) == false) {
- showMessage(utf8() << "Error: unable to save quick state " << (unsigned)(slot + 1) << ".");
+ showMessage(string() << "Error: unable to save quick state " << (unsigned)(slot + 1) << ".");
return;
}
fp.write(state.data(), state.size());
fp.close();
- showMessage(utf8() << "Quick state " << (unsigned)(slot + 1) << " saved.");
+ showMessage(string() << "Quick state " << (unsigned)(slot + 1) << " saved.");
}
void Utility::loadStateInfo(lstring &info) {
info.reset();
- string name = string() << filepath(nall::basename(cartridge.baseName), config.path.state) << ".bsa";
+ string name = string() << filepath(nall::basename(cartridge.fileName), config().path.state) << ".bsa";
if(SNES::statemanager.load(name) == false) return;
SNES::statemanager.list(info);
}
void Utility::setStateDescription(uint8 slot, const char *description) {
if(SNES::cartridge.loaded() == false) return;
- string name = string() << filepath(nall::basename(cartridge.baseName), config.path.state) << ".bsa";
+ string name = string() << filepath(nall::basename(cartridge.fileName), config().path.state) << ".bsa";
SNES::statemanager.set_description(name, slot, description);
}
void Utility::loadState(uint8 slot) {
if(SNES::cartridge.loaded() == false || application.power == false) return;
- string name = string() << filepath(nall::basename(cartridge.baseName), config.path.state) << ".bsa";
+ string name = string() << filepath(nall::basename(cartridge.fileName), config().path.state) << ".bsa";
try {
serializer state = SNES::statemanager.load(name, slot);
if(SNES::system.unserialize(state) == true) {
- showMessage(utf8() << "State loaded.");
+ showMessage(string() << "State loaded.");
} else {
- showMessage(utf8() << "Error: unable to load state.");
+ showMessage(string() << "Error: unable to load state.");
}
} catch(...) {
- showMessage(utf8() << "Error: unable to load state.");
+ showMessage(string() << "Error: unable to load state.");
return;
}
}
@@ -106,20 +105,20 @@ void Utility::saveState(uint8 slot, const char *description) {
SNES::system.runtosave();
serializer state = SNES::system.serialize();
- string name = string() << filepath(nall::basename(cartridge.baseName), config.path.state) << ".bsa";
+ string name = string() << filepath(nall::basename(cartridge.fileName), config().path.state) << ".bsa";
if(SNES::statemanager.save(name, slot, state, description) == true) {
- showMessage(utf8() << "State saved.");
+ showMessage(string() << "State saved.");
} else {
- showMessage(utf8() << "Error: unable to save state.");
+ showMessage(string() << "Error: unable to save state.");
}
}
void Utility::deleteState(uint8 slot) {
if(SNES::cartridge.loaded() == false) return;
- string name = string() << filepath(nall::basename(cartridge.baseName), config.path.state) << ".bsa";
+ string name = string() << filepath(nall::basename(cartridge.fileName), config().path.state) << ".bsa";
if(SNES::statemanager.erase(name, slot) == true) {
- showMessage(utf8() << "State deleted.");
+ showMessage(string() << "State deleted.");
} else {
- showMessage(utf8() << "Error: unable to delete state.");
+ showMessage(string() << "Error: unable to delete state.");
}
}
diff --git a/src/ui_qt/utility/utility.cpp b/src/ui_qt/utility/utility.cpp
index 7bb03413..c2ea3b88 100644
--- a/src/ui_qt/utility/utility.cpp
+++ b/src/ui_qt/utility/utility.cpp
@@ -2,46 +2,9 @@
#include "state.cpp"
#include "window.cpp"
-//returns true if requested code is a button, and it has just been pressed down
-bool Utility::isButtonDown(uint16_t inputCode, InputObject &object) {
- if(inputCode != object.code) return false;
-
- if(object.codetype != InputCode::KeyboardButton
- && object.codetype != InputCode::MouseButton
- && object.codetype != InputCode::JoypadHat
- && object.codetype != InputCode::JoypadAxis
- && object.codetype != InputCode::JoypadButton) return false;
-
- int16_t state = inputManager.state(object.code);
- int16_t lastState = inputManager.lastState(object.code);
-
- if(object.codetype == InputCode::JoypadHat) {
- switch(object.modifier) {
- case InputObject::Up: return (state & joypad<>::hat_up ) && !(lastState & joypad<>::hat_up );
- case InputObject::Down: return (state & joypad<>::hat_down ) && !(lastState & joypad<>::hat_down );
- case InputObject::Left: return (state & joypad<>::hat_left ) && !(lastState & joypad<>::hat_left );
- case InputObject::Right: return (state & joypad<>::hat_right) && !(lastState & joypad<>::hat_right);
- }
- } else if(object.codetype == InputCode::JoypadAxis) {
- switch(object.modifier) {
- case InputObject::Lo: return (state < -16384) && !(lastState < -16384);
- case InputObject::Hi: return (state > +16384) && !(lastState > +16384);
- case InputObject::Trigger: return (state < 0) && !(lastState < 0);
- }
- } else {
- return (state == 1) && !(lastState == 1);
- }
-
- return false; //fall-through for modifier-less hats / axes
-}
-
-void Utility::inputEvent(uint16_t code) {
- //forward key-press event
- //(in case window is currently active and capturing a new button / axis assignment)
- inputCaptureWindow->inputEvent(code);
-
- for(unsigned i = 0; i < keyboard<>::count; i++) {
- if(code == keyboard<>::index(i, keyboard<>::escape) && inputManager.state(code)) {
+void Utility::inputEvent(uint16_t scancode) {
+ for(unsigned i = 0; i < Keyboard::Count; i++) {
+ if(scancode == keyboard(i)[Keyboard::Escape] && mapper().state(scancode)) {
if(mainWindow->isActive() && input.acquired()) {
//release mouse capture
input.unacquire();
@@ -49,96 +12,11 @@ void Utility::inputEvent(uint16_t code) {
}
}
}
-
- if(mainWindow->isActive()) {
- bool resizeWindow = false;
-
- if(isButtonDown(code, inputUiGeneral.loadCartridge)) {
- diskBrowser->loadCartridge();
- }
-
- if(isButtonDown(code, inputUiGeneral.pauseEmulation)) {
- application.pause = !application.pause;
- if(application.pause) audio.clear();
- }
-
- if(isButtonDown(code, inputUiGeneral.resetSystem)) {
- modifySystemState(Reset);
- }
-
- if(isButtonDown(code, inputUiGeneral.powerCycleSystem)) {
- modifySystemState(PowerCycle);
- }
-
- if(isButtonDown(code, inputUiGeneral.captureScreenshot)) {
- //tell SNES::Interface to save a screenshot at the next video_refresh() event
- interface.saveScreenshot = true;
- }
-
- if(isButtonDown(code, inputUiGeneral.showStateManager)) {
- toolsWindow->showStateManager();
- }
-
- if(isButtonDown(code, inputUiGeneral.quickLoad1)) utility.quickLoad(0);
- if(isButtonDown(code, inputUiGeneral.quickLoad2)) utility.quickLoad(1);
- if(isButtonDown(code, inputUiGeneral.quickLoad3)) utility.quickLoad(2);
- if(isButtonDown(code, inputUiGeneral.quickSave1)) utility.quickSave(0);
- if(isButtonDown(code, inputUiGeneral.quickSave2)) utility.quickSave(1);
- if(isButtonDown(code, inputUiGeneral.quickSave3)) utility.quickSave(2);
-
- if(isButtonDown(code, inputUiGeneral.lowerSpeed)) {
- config.system.speed--;
- updateEmulationSpeed();
- mainWindow->syncUi();
- }
-
- if(isButtonDown(code, inputUiGeneral.raiseSpeed)) {
- config.system.speed++;
- updateEmulationSpeed();
- mainWindow->syncUi();
- }
-
- if(isButtonDown(code, inputUiGeneral.toggleCheatSystem)) {
- if(SNES::cheat.enabled() == false) {
- SNES::cheat.enable();
- showMessage("Cheat system enabled.");
- } else {
- SNES::cheat.disable();
- showMessage("Cheat system disabled.");
- }
- }
-
- if(isButtonDown(code, inputUiGeneral.toggleFullscreen)) {
- config.video.isFullscreen = !config.video.isFullscreen;
- updateFullscreenState();
- resizeMainWindow();
- mainWindow->syncUi();
- }
-
- if(isButtonDown(code, inputUiGeneral.toggleMenu)) {
- mainWindow->menuBar->setVisible(!mainWindow->menuBar->isVisibleTo(mainWindow));
- resizeWindow = true;
- }
-
- if(isButtonDown(code, inputUiGeneral.toggleStatus)) {
- mainWindow->statusBar->setVisible(!mainWindow->statusBar->isVisibleTo(mainWindow));
- resizeWindow = true;
- }
-
- //prevent calling twice when toggleMenu == toggleStatus
- if(resizeWindow == true) {
- resizeMainWindow();
- }
-
- if(isButtonDown(code, inputUiGeneral.exitEmulator)) {
- application.terminate = true;
- }
- }
}
//display message in main window statusbar area for three seconds
void Utility::showMessage(const char *message) {
- mainWindow->statusBar->showMessage(utf8() << message, 3000);
+ mainWindow->statusBar->showMessage(string() << message, 3000);
}
//updates system state text at bottom-right of main window statusbar
@@ -160,7 +38,7 @@ void Utility::updateSystemState() {
return;
}
- mainWindow->systemState->setText(utf8() << text);
+ mainWindow->systemState->setText(text);
}
void Utility::acquireMouse() {
@@ -179,12 +57,12 @@ void Utility::unacquireMouse() {
}
void Utility::updateAvSync() {
- video.set(Video::Synchronize, config.video.synchronize);
- audio.set(Audio::Synchronize, config.audio.synchronize);
+ video.set(Video::Synchronize, config().video.synchronize);
+ audio.set(Audio::Synchronize, config().audio.synchronize);
}
void Utility::updateVideoMode() {
- if(config.video.context->region == 0) {
+ if(config().video.context->region == 0) {
SNES::video.set_mode(SNES::Video::ModeNTSC);
} else {
SNES::video.set_mode(SNES::Video::ModePAL);
@@ -192,42 +70,43 @@ void Utility::updateVideoMode() {
}
void Utility::updateColorFilter() {
- filter.contrast = config.video.contrastAdjust;
- filter.brightness = config.video.brightnessAdjust;
- filter.gamma = 100 + config.video.gammaAdjust;
- filter.gamma_ramp = config.video.enableGammaRamp;
+ filter.contrast = config().video.contrastAdjust;
+ filter.brightness = config().video.brightnessAdjust;
+ filter.gamma = 100 + config().video.gammaAdjust;
+ filter.gamma_ramp = config().video.enableGammaRamp;
filter.colortable_update();
}
+void Utility::updatePixelShader() {
+ string filedata;
+
+ if(filedata.readfile(config().path.fragmentShader)) {
+ video.set(Video::FragmentShader, (const char*)filedata);
+ } else {
+ video.set(Video::FragmentShader, (const char*)0);
+ }
+
+ if(filedata.readfile(config().path.vertexShader)) {
+ video.set(Video::VertexShader, (const char*)filedata);
+ } else {
+ video.set(Video::VertexShader, (const char*)0);
+ }
+}
+
void Utility::updateHardwareFilter() {
- video.set(Video::Filter, config.video.context->hwFilter);
+ video.set(Video::Filter, config().video.context->hwFilter);
}
void Utility::updateSoftwareFilter() {
- filter.renderer = config.video.context->swFilter;
-
-/*libfilter::FilterInterface::FilterType type;
- switch(config.video.context->swFilter) { default:
- case 0: type = libfilter::FilterInterface::Direct; break;
- case 1: type = libfilter::FilterInterface::Scanline; break;
- case 2: type = libfilter::FilterInterface::Scale2x; break;
- case 3: type = libfilter::FilterInterface::LQ2x; break;
- case 4: type = libfilter::FilterInterface::HQ2x; break;
- case 5: type = libfilter::FilterInterface::NTSC; break;
- }
- libfilter::filter.set(type);
-
- if(type == libfilter::FilterInterface::NTSC) {
- libfilter::filter_ntsc.adjust(0, 0, 0, 0, 0, config.video.enableNtscMergeFields);
- }*/
+ filter.renderer = config().video.context->swFilter;
}
void Utility::updateEmulationSpeed() {
- config.system.speed = max(0, min(4, (signed)config.system.speed));
+ config().system.speed = max(0, min(4, (signed)config().system.speed));
double scale[] = { 0.50, 0.75, 1.00, 1.50, 2.00 };
- unsigned outfreq = config.audio.outputFrequency;
- unsigned infreq = config.audio.inputFrequency * scale[config.system.speed] + 0.5;
+ unsigned outfreq = config().audio.outputFrequency;
+ unsigned infreq = config().audio.inputFrequency * scale[config().system.speed] + 0.5;
audio.set(Audio::Resample, true); //always resample (required for volume adjust + frequency scaler)
audio.set(Audio::ResampleRatio, (double)infreq / (double)outfreq);
@@ -236,4 +115,25 @@ void Utility::updateEmulationSpeed() {
void Utility::updateControllers() {
SNES::input.port_set_device(0, SNES::config.controller_port1);
SNES::input.port_set_device(1, SNES::config.controller_port2);
+
+ switch(config().input.port1) { default:
+ case ControllerPort1::None: mapper().port1 = 0; break;
+ case ControllerPort1::Gamepad: mapper().port1 = &Controllers::gamepad1; break;
+ case ControllerPort1::Asciipad: mapper().port1 = &Controllers::asciipad1; break;
+ case ControllerPort1::Multitap: mapper().port1 = &Controllers::multitap1; break;
+ case ControllerPort1::Mouse: mapper().port1 = &Controllers::mouse1; break;
+ }
+
+ switch(config().input.port2) { default:
+ case ControllerPort2::None: mapper().port2 = 0; break;
+ case ControllerPort2::Gamepad: mapper().port2 = &Controllers::gamepad2; break;
+ case ControllerPort2::Asciipad: mapper().port2 = &Controllers::asciipad2; break;
+ case ControllerPort2::Multitap: mapper().port2 = &Controllers::multitap2; break;
+ case ControllerPort2::Mouse: mapper().port2 = &Controllers::mouse2; break;
+ case ControllerPort2::SuperScope: mapper().port2 = &Controllers::superscope; break;
+ case ControllerPort2::Justifier: mapper().port2 = &Controllers::justifier1; break;
+ case ControllerPort2::Justifiers: mapper().port2 = &Controllers::justifiers; break;
+ }
+
+ mainWindow->syncUi();
}
diff --git a/src/ui_qt/utility/utility.hpp b/src/ui_qt/utility/utility.hpp
index 66d44801..ae28c624 100644
--- a/src/ui_qt/utility/utility.hpp
+++ b/src/ui_qt/utility/utility.hpp
@@ -1,8 +1,7 @@
class Utility {
public:
//utility.cpp
- bool isButtonDown(uint16_t inputCode, InputObject &object);
- void inputEvent(uint16_t code);
+ void inputEvent(uint16_t scancode);
void showMessage(const char *message);
void updateSystemState();
void acquireMouse();
@@ -11,6 +10,7 @@ public:
void updateAvSync();
void updateVideoMode();
void updateColorFilter();
+ void updatePixelShader();
void updateHardwareFilter();
void updateSoftwareFilter();
void updateEmulationSpeed();
@@ -18,7 +18,8 @@ public:
//cartridge.cpp
struct Cartridge {
- string name; //printable cartridge name
+ string name; //printable cartridge name
+ string fileName; //ideal file name for saving eg states to disk
string baseName, slotAName, slotBName;
bool patchApplied;
} cartridge;
@@ -56,4 +57,14 @@ public:
void updateFullscreenState();
void constrainSize(unsigned &x, unsigned &y, unsigned max);
void resizeMainWindow();
+ void toggleSynchronizeVideo();
+ void toggleSynchronizeAudio();
+ void setNtscMode();
+ void setPalMode();
+ void toggleSmoothVideoOutput();
+ void toggleAspectCorrection();
+ void setScale(unsigned);
+ void toggleFullscreen();
+ void toggleMenubar();
+ void toggleStatusbar();
} utility;
diff --git a/src/ui_qt/utility/window.cpp b/src/ui_qt/utility/window.cpp
index 4b57a5fd..6e138e04 100644
--- a/src/ui_qt/utility/window.cpp
+++ b/src/ui_qt/utility/window.cpp
@@ -1,16 +1,16 @@
void Utility::updateFullscreenState() {
video.clear();
- if(config.video.isFullscreen == false) {
- config.video.context = &config.video.windowed;
+ if(config().video.isFullscreen == false) {
+ config().video.context = &config().video.windowed;
mainWindow->showNormal();
mainWindow->menuBar->setVisible(true);
mainWindow->statusBar->setVisible(true);
} else {
- config.video.context = &config.video.fullscreen;
+ config().video.context = &config().video.fullscreen;
mainWindow->showFullScreen();
- mainWindow->menuBar->setVisible(!config.system.autoHideMenus);
- mainWindow->statusBar->setVisible(!config.system.autoHideMenus);
+ mainWindow->menuBar->setVisible(!config().system.autoHideMenus);
+ mainWindow->statusBar->setVisible(!config().system.autoHideMenus);
}
QApplication::processEvents();
@@ -37,20 +37,20 @@ void Utility::constrainSize(unsigned &x, unsigned &y, unsigned max) {
}
void Utility::resizeMainWindow() {
- unsigned region = config.video.context->region;
- unsigned multiplier = config.video.context->multiplier;
+ unsigned region = config().video.context->region;
+ unsigned multiplier = config().video.context->multiplier;
unsigned width = 256 * multiplier;
unsigned height = (region == 0 ? 224 : 239) * multiplier;
- if(config.video.context->correctAspectRatio) {
+ if(config().video.context->correctAspectRatio) {
if(region == 0) {
- width = (double)width * config.video.ntscAspectRatio + 0.5; //NTSC adjust
+ width = (double)width * config().video.ntscAspectRatio + 0.5; //NTSC adjust
} else {
- width = (double)width * config.video.palAspectRatio + 0.5; //PAL adjust
+ width = (double)width * config().video.palAspectRatio + 0.5; //PAL adjust
}
}
- if(config.video.isFullscreen == false) {
+ if(config().video.isFullscreen == false) {
//get effective desktop work area region (ignore Windows taskbar, OS X dock, etc.)
QRect deskRect = QApplication::desktop()->availableGeometry(mainWindow);
@@ -88,3 +88,72 @@ void Utility::resizeMainWindow() {
//window resizing sometimes breaks audio sync, this call re-initializes it
updateAvSync();
}
+
+void Utility::toggleSynchronizeVideo() {
+ mainWindow->settings_emulationSpeed_syncVideo->toggleChecked();
+ config().video.synchronize = mainWindow->settings_emulationSpeed_syncVideo->isChecked();
+ updateAvSync();
+}
+
+void Utility::toggleSynchronizeAudio() {
+ mainWindow->settings_emulationSpeed_syncAudio->toggleChecked();
+ config().audio.synchronize = mainWindow->settings_emulationSpeed_syncAudio->isChecked();
+ updateAvSync();
+}
+
+void Utility::setNtscMode() {
+ config().video.context->region = 0;
+ updateVideoMode();
+ resizeMainWindow();
+ mainWindow->shrink();
+ mainWindow->syncUi();
+}
+
+void Utility::setPalMode() {
+ config().video.context->region = 1;
+ updateVideoMode();
+ resizeMainWindow();
+ mainWindow->shrink();
+ mainWindow->syncUi();
+}
+
+void Utility::toggleSmoothVideoOutput() {
+ mainWindow->settings_smoothVideo->toggleChecked();
+ config().video.context->hwFilter = mainWindow->settings_smoothVideo->isChecked();
+ updateHardwareFilter();
+ mainWindow->syncUi();
+}
+
+void Utility::toggleAspectCorrection() {
+ mainWindow->settings_videoMode_correctAspectRatio->toggleChecked();
+ config().video.context->correctAspectRatio = mainWindow->settings_videoMode_correctAspectRatio->isChecked();
+ resizeMainWindow();
+ mainWindow->shrink();
+}
+
+void Utility::setScale(unsigned scale) {
+ config().video.context->multiplier = scale;
+ resizeMainWindow();
+ mainWindow->shrink();
+ mainWindow->syncUi();
+}
+
+void Utility::toggleFullscreen() {
+ mainWindow->settings_videoMode_fullscreen->toggleChecked();
+ config().video.isFullscreen = mainWindow->settings_videoMode_fullscreen->isChecked();
+ updateFullscreenState();
+ resizeMainWindow();
+ mainWindow->syncUi();
+}
+
+void Utility::toggleMenubar() {
+ mainWindow->menuBar->setVisible(!mainWindow->menuBar->isVisibleTo(mainWindow));
+ resizeMainWindow();
+ mainWindow->shrink();
+}
+
+void Utility::toggleStatusbar() {
+ mainWindow->statusBar->setVisible(!mainWindow->statusBar->isVisibleTo(mainWindow));
+ resizeMainWindow();
+ mainWindow->shrink();
+}