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() << "" "" "" 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(); +}
Version: " << bsnesVersion << "
Author: byuu