diff --git a/Makefile b/Makefile index 5e77950..6e394a0 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ widget.oo: widget.cpp widget.hh gui.oo: gui.cpp gui.hh Makefile font.hh menu.hh sdl_ttf_font.hh \ dialogue_box.hh help_box.hh main_menu.cpp disc_menu.cpp \ file_browser.hh timer.hh game_info.hh widget.hh options_menu.cpp \ - network_menu.cpp theme_menu.cpp mocks/Prefs.h mocks/C64.h + network_menu.cpp theme_menu.cpp bind_keys_menu.cpp mocks/Prefs.h mocks/C64.h virtual_keyboard.oo: virtual_keyboard.hh virtual_keyboard.cpp widget.hh listener.hh @@ -27,7 +27,7 @@ dialogue_box.oo: dialogue_box.cpp dialogue_box.hh menu.hh listener.hh listener.oo: listener.cpp listener.hh -main.oo: menu.hh utils.hh sdl_ttf_font.hh Makefile +main.oo: menu.hh gui.hh utils.hh sdl_ttf_font.hh Makefile menu: $(OBJS) g++ `sdl-config --libs` -lSDL -lSDL_image -lSDL_ttf -o $@ $+ diff --git a/bind_keys_menu.cpp b/bind_keys_menu.cpp new file mode 100644 index 0000000..0129551 --- /dev/null +++ b/bind_keys_menu.cpp @@ -0,0 +1,413 @@ +#include "gui.hh" +#include "menu.hh" +#include "help_box.hh" +#include "virtual_keyboard.hh" + +class BindKeysView; +class BindKeysMenu : public Menu, public KeyboardListener +{ + friend class BindKeysView; + +public: + BindKeysMenu(Font *font, HelpBox *help) : Menu(font) + { + this->help = help; + memset(this->hm, 0, sizeof(this->hm)); + this->setText(bind_key_menu_messages); + } + + ~BindKeysMenu() + { + this->freeHelpMessages(); + } + + virtual void selectCallback(int which) + { + int *ck = NULL; + + switch(which) + { + case 0: /* Classic */ + switch (this->p_submenus[0].sel) + { + case 0: ck = &Gui::gui->np->JoystickHats[0][0]; break; + case 1: ck = &Gui::gui->np->JoystickHats[0][1]; break; + case 2: ck = &Gui::gui->np->JoystickHats[0][2]; break; + case 3: ck = &Gui::gui->np->JoystickHats[0][3]; break; + case 4: ck = &Gui::gui->np->JoystickButtons[0][0]; break; + case 5: ck = &Gui::gui->np->JoystickButtons[0][1]; break; + case 6: ck = &Gui::gui->np->JoystickButtons[0][2]; break; + case 7: ck = &Gui::gui->np->JoystickButtons[0][3]; break; + case 8: ck = &Gui::gui->np->JoystickButtons[0][4]; break; + default: + panic("Classic: impossible selection %d", this->p_submenus[0].sel); break; + } + break; + case 2: /* Nunchuk */ + switch (this->p_submenus[1].sel) + { + case 0: ck = &Gui::gui->np->JoystickAxes[0][0]; break; + case 1: ck = &Gui::gui->np->JoystickAxes[0][1]; break; + case 2: ck = &Gui::gui->np->JoystickButtons[0][7]; break; + case 3: ck = &Gui::gui->np->JoystickButtons[0][8]; break; + default: + panic("Nunchuk: impossible selection %d", this->p_submenus[1].sel); break; + } + break; + case 4: /* Classic */ + switch (this->p_submenus[2].sel) + { + case 0: ck = &Gui::gui->np->JoystickHats[0][0]; break; + case 1: ck = &Gui::gui->np->JoystickHats[0][1]; break; + case 2: ck = &Gui::gui->np->JoystickHats[0][2]; break; + case 3: ck = &Gui::gui->np->JoystickHats[0][3]; break; + case 4: ck = &Gui::gui->np->JoystickButtons[0][9]; break; + case 5: ck = &Gui::gui->np->JoystickButtons[0][10]; break; + case 6: ck = &Gui::gui->np->JoystickButtons[0][11]; break; + case 7: ck = &Gui::gui->np->JoystickButtons[0][12]; break; + case 8: ck = &Gui::gui->np->JoystickButtons[0][13]; break; + case 9: ck = &Gui::gui->np->JoystickButtons[0][14]; break; + case 10: ck = &Gui::gui->np->JoystickButtons[0][15]; break; + case 11: ck = &Gui::gui->np->JoystickButtons[0][16]; break; + case 12: ck = &Gui::gui->np->JoystickButtons[0][17]; break; + case 13: ck = &Gui::gui->np->JoystickButtons[0][18]; break; + default: + panic("Classic: impossible selection %d", this->p_submenus[2].sel); break; + } + break; + case 6: + switch (this->p_submenus[3].sel) + { + case 0: ck = &Gui::gui->np->JoystickAxes[0][0]; break; + case 1: ck = &Gui::gui->np->JoystickAxes[0][1]; break; + default: + panic("Classic: impossible selection %d", this->p_submenus[3].sel); break; + } + case 8: + switch (this->p_submenus[4].sel) + { + case 0: ck = &Gui::gui->np->JoystickAxes[0][2]; break; + case 1: ck = &Gui::gui->np->JoystickAxes[0][3]; break; + default: + panic("Classic: impossible selection %d", this->p_submenus[4].sel); break; + } + default: + panic("Impossible menu option\n"); + break; + } + this->cur_key = ck; + + VirtualKeyboard::kbd->activate(); + VirtualKeyboard::kbd->registerListener(this); + } + + virtual void hoverCallback(int which) + { + this->help->updateHelpMessage(which); + } + + virtual void escapeCallback(int which) + { + Gui::gui->popView(); + } + + virtual void keyCallback(bool shift, const char *str) + { + panic_if(!this->cur_key, "No key selected but keyboard active???\n"); + + *this->cur_key = this->stringToKeycode(str); + this->updateHelpMessages(); + this->help->updateHelpMessage(this->cur_sel); + VirtualKeyboard::kbd->deactivate(); + this->cur_key = NULL; + } + + void updateHelpMessages() + { + this->freeHelpMessages(); + + this->hm[0] = this->addOne(this->hm[0], this->allocOne("Up: %s", stringToPtr_Wiimote("Up"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("Down: %s", stringToPtr_Wiimote("Down"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("Left: %s", stringToPtr_Wiimote("Left"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("Right: %s", stringToPtr_Wiimote("Right"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("A: %s", stringToPtr_Wiimote("A"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("B: %s", stringToPtr_Wiimote("B"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("+: %s", stringToPtr_Wiimote("+"))); + this->hm[0] = this->addOne(this->hm[0], this->allocOne("-: %s", stringToPtr_Wiimote("-"))); + + /* Nunchuk */ + this->hm[2] = this->addOne(this->hm[2], this->allocOne("Horiz: %s", stringToPtr_Nunchuk("Horiz"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("Vert: %s", stringToPtr_Nunchuk("Vert"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("Z: %s", stringToPtr_Nunchuk("Z"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("C: %s", stringToPtr_Nunchuk("C"))); + + /* Classic */ + this->hm[4] = this->addOne(this->hm[4], this->allocOne("Up: %s", stringToPtr_Classic("Up"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("Down: %s", stringToPtr_Classic("Down"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("Left: %s", stringToPtr_Classic("Left"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("Right: %s", stringToPtr_Classic("Right"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("a: %s", stringToPtr_Classic("a"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("b: %s", stringToPtr_Classic("b"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("x: %s", stringToPtr_Classic("x"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("y: %s", stringToPtr_Classic("y"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("Zl: %s", stringToPtr_Classic("Zl"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("Zr: %s", stringToPtr_Classic("Zr"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("+: %s", stringToPtr_Classic("+"))); + this->hm[4] = this->addOne(this->hm[4], this->allocOne("-: %s", stringToPtr_Classic("-"))); + + /* + this->hm[2] = this->addOne(this->hm[2], this->allocOne("l: %s", stringToPtr_Classic("l"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("r: %s", stringToPtr_Classic("r"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("R-toggle: %s", stringToPtr_Classic("RA"))); + this->hm[2] = this->addOne(this->hm[2], this->allocOne("L-toggle: %s", stringToPtr_Classic("LA"))); + */ + + this->hm[6] = this->addOne(this->hm[6], this->allocOne("Horiz: %s", stringToPtr_Classic("LAH"))); + this->hm[6] = this->addOne(this->hm[6], this->allocOne("Vert: %s", stringToPtr_Classic("LAV"))); + + this->hm[8] = this->addOne(this->hm[8], this->allocOne("Horiz: %s", stringToPtr_Classic("RAH"))); + this->hm[8] = this->addOne(this->hm[8], this->allocOne("Vert: %s", stringToPtr_Classic("RAV"))); + + this->help->setHelpMessages(this->hm); + } + +private: + void freeHelpMessages() + { + for (unsigned i = 0; i < ARRAY_SIZE(this->hm); i++) + { + if (this->hm[i]) + { + for (int j = 0; this->hm[i][j]; j++) + free((void*)this->hm[i][j]); + free(this->hm[i]); + } + this->hm[i] = NULL; + } + } + +#define EQ(b) (strcmp(str, b) == 0) + int *stringToPtr_Classic(const char *str) + { + if (EQ("Up")) + return &Gui::gui->np->JoystickHats[0][0]; + if (EQ("Down")) + return &Gui::gui->np->JoystickHats[0][1]; + if (EQ("Left")) + return &Gui::gui->np->JoystickHats[0][2]; + if (EQ("Right")) + return &Gui::gui->np->JoystickHats[0][3]; + if (EQ("LAH")) + return &Gui::gui->np->JoystickAxes[0][0]; + if (EQ("LAV")) + return &Gui::gui->np->JoystickAxes[0][1]; + if (EQ("RAH")) + return &Gui::gui->np->JoystickAxes[0][2]; + if (EQ("RAV")) + return &Gui::gui->np->JoystickAxes[0][3]; + if (EQ("RA")) + return &Gui::gui->np->JoystickAxes[0][4]; + if (EQ("LA")) + return &Gui::gui->np->JoystickAxes[0][5]; + if (EQ("a")) + return &Gui::gui->np->JoystickButtons[0][9]; + if (EQ("b")) + return &Gui::gui->np->JoystickButtons[0][10]; + if (EQ("x")) + return &Gui::gui->np->JoystickButtons[0][11]; + if (EQ("y")) + return &Gui::gui->np->JoystickButtons[0][12]; + if (EQ("L")) + return &Gui::gui->np->JoystickButtons[0][13]; + if (EQ("R")) + return &Gui::gui->np->JoystickButtons[0][14]; + if (EQ("Zl")) + return &Gui::gui->np->JoystickButtons[0][15]; + if (EQ("Zr")) + return &Gui::gui->np->JoystickButtons[0][16]; + if (EQ("-")) + return &Gui::gui->np->JoystickButtons[0][17]; + if (EQ("+")) + return &Gui::gui->np->JoystickButtons[0][18]; + if (EQ("Home")) + return &Gui::gui->np->JoystickButtons[0][19]; + + /* Shound never happen! */ + panic("Illegal string %s\n", str); + + return NULL; + } + + int *stringToPtr_Nunchuk(const char *str) + { + if (EQ("Horiz")) + return &Gui::gui->np->JoystickAxes[0][0]; + if (EQ("Vert")) + return &Gui::gui->np->JoystickAxes[0][1]; + if (EQ("Z")) + return &Gui::gui->np->JoystickButtons[0][7]; + if (EQ("C")) + return &Gui::gui->np->JoystickButtons[0][8]; + + /* Shound never happen! */ + panic("Illegal string %s\n", str); + + return NULL; + } + + int *stringToPtr_Wiimote(const char *str) + { + if (EQ("Up")) + return &Gui::gui->np->JoystickHats[0][0]; + if (EQ("Down")) + return &Gui::gui->np->JoystickHats[0][1]; + if (EQ("Left")) + return &Gui::gui->np->JoystickHats[0][2]; + if (EQ("Right")) + return &Gui::gui->np->JoystickHats[0][3]; + if (EQ("A")) + return &Gui::gui->np->JoystickButtons[0][0]; + if (EQ("B")) + return &Gui::gui->np->JoystickButtons[0][1]; + if (EQ("1")) + return &Gui::gui->np->JoystickButtons[0][2]; + if (EQ("2")) + return &Gui::gui->np->JoystickButtons[0][3]; + if (EQ("+")) + return &Gui::gui->np->JoystickButtons[0][4]; + if (EQ("-")) + return &Gui::gui->np->JoystickButtons[0][5]; + if (EQ("Home")) + return &Gui::gui->np->JoystickButtons[0][6]; + + /* Shound never happen! */ + panic("Illegal string %s\n", str); + + return NULL; + } +#undef EQ + + const char **addOne(const char **dst, const char *what) + { + int cur; + int n = 0; + + if (dst != NULL) + { + for (n = 0; dst[n]; n++) + ; + } + cur = n; + n++; + dst = (const char **)xrealloc(dst, (n+1) * sizeof(const char*)); + dst[cur] = what; + dst[n] = NULL; + + return dst; + } + + const char *allocOne(const char *fmt, int *what) + { + const char *str = this->bindingToString(*what); + size_t len = strlen(str) + strlen(fmt) + 2; + char *out = (char *)xmalloc(len); + + sprintf(out, fmt, str); + + return out; + } + + int stringToKeycode(const char *str) + { + if (strcmp(str, "None") == 0) + return 0; + + /* default: */ + return VirtualKeyboard::kbd->stringToKeycode(str); + } + + const char *bindingToString(int val) + { + switch(val) + { + case JOY_NONE: + return "None"; + case JOY_HORIZ: + return "Horizontal"; + case JOY_VERT: + return "Vertical"; + case JOY_FIRE: + return "Fire"; + default: + break; + } + + /* default: */ + return VirtualKeyboard::kbd->keycodeToString(val); + } + + HelpBox *help; + int *cur_key; + const char **hm[10]; +}; + + +class BindKeysView : public GuiView +{ +public: + BindKeysView() : GuiView() + { + this->help = new HelpBox(NULL, NULL); + this->menu = new BindKeysMenu(NULL, this->help); + } + + ~BindKeysView() + { + delete this->help; + delete this->menu; + } + + void updateTheme() + { + this->menu->setFont(Gui::gui->small_font); + this->help->setFont(Gui::gui->small_font); + this->menu->setSelectedBackground(Gui::gui->bg_left, Gui::gui->bg_middle, + Gui::gui->bg_right, Gui::gui->bg_submenu_left, + Gui::gui->bg_submenu_middle, Gui::gui->bg_submenu_right); + } + + void viewPushCallback() + { + this->menu->updateHelpMessages(); + this->help->updateHelpMessage(0); + } + + void runLogic() + { + this->menu->runLogic(); + } + + void pushEvent(SDL_Event *ev) + { + this->menu->pushEvent(ev); + } + + void draw(SDL_Surface *where) + { + SDL_Rect dst; + + /* Blit the backgrounds */ + dst = (SDL_Rect){20,45,300,400}; + SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst); + + dst = (SDL_Rect){350,13,0,0}; + SDL_BlitSurface(Gui::gui->disc_info, NULL, where, &dst); + + this->menu->draw(where, 50, 70, 300, 400); + this->help->draw(where, 354, 24, 264, 210); + } + +protected: + BindKeysMenu *menu; + HelpBox *help; +}; diff --git a/gui.cpp b/gui.cpp index 9be32f2..adad101 100644 --- a/gui.cpp +++ b/gui.cpp @@ -30,6 +30,7 @@ static const char *get_theme_path(const char *dir, const char *what) /* These are a bit of special cases... */ #include "disc_menu.cpp" +#include "bind_keys_menu.cpp" #include "theme_menu.cpp" #include "options_menu.cpp" #include "network_menu.cpp" @@ -90,6 +91,7 @@ Gui::Gui() this->ov = new OptionsView(); this->nv = new NetworkView(); this->tv = new ThemeView(); + this->bkv = new BindKeysView(); this->pushView(mv); } @@ -153,6 +155,7 @@ bool Gui::setTheme(const char *path) this->ov->updateTheme(); this->nv->updateTheme(); this->tv->updateTheme(); + this->bkv->updateTheme(); VirtualKeyboard::kbd->updateTheme(); diff --git a/gui.hh b/gui.hh index 09fb0a9..933dd01 100644 --- a/gui.hh +++ b/gui.hh @@ -14,6 +14,7 @@ class DialogueBox; class MainView; +class BindKeysView; class DiscView; class OptionsView; class NetworkView; @@ -94,6 +95,7 @@ public: OptionsView *ov; NetworkView *nv; ThemeView *tv; + BindKeysView *bkv; GuiView **views; int n_views; diff --git a/help_box.hh b/help_box.hh index 3a8effc..56ca3ad 100644 --- a/help_box.hh +++ b/help_box.hh @@ -7,12 +7,19 @@ class HelpBox : public Menu { public: HelpBox(Font *font, const char ***all_messages) : Menu(font) + { + this->setHelpMessages(all_messages); + } + + void setHelpMessages(const char ***all_messages) { this->all_messages = all_messages; } void updateHelpMessage(int which) { + if (!this->all_messages) + return; this->setText(this->all_messages[which]); } diff --git a/main_menu.cpp b/main_menu.cpp index 7ff6a3d..c7e7ca2 100644 --- a/main_menu.cpp +++ b/main_menu.cpp @@ -55,8 +55,20 @@ public: case 2: /* Load/save states */ break; case 4: /* Keyboard */ - VirtualKeyboard::kbd->activate(); - VirtualKeyboard::kbd->registerListener(new KeyboardTypingListener()); + switch(this->p_submenus[2].sel) + { + case 0: + VirtualKeyboard::kbd->activate(); + VirtualKeyboard::kbd->registerListener(new KeyboardTypingListener()); + break; + case 1: + break; + case 2: + Gui::gui->pushView(Gui::gui->bkv); + break; + default: + panic("Illegal selection\n"); + } break; case 7: /* Reset the C64 */ printf("Resetting the C64\n"); diff --git a/menu_messages.cpp b/menu_messages.cpp index 92eec18..198f4aa 100644 --- a/menu_messages.cpp +++ b/menu_messages.cpp @@ -118,15 +118,15 @@ const char **options_menu_messages = (const char*[]){ }; const char **bind_key_menu_messages = (const char*[]){ - /*00*/ "Bind Wiimote", - /*01*/ "^|Up|Down|Left|Right|A|B|+|-", - /*02*/ "Bind Nunchuk", + /*00*/ "Wiimote", + /*01*/ "^|Up|Down|Left|Right|A|B|1|2|+|-", + /*02*/ "Nunchuk", /*03*/ "^|Horiz|Vert|Z|C", - /*04*/ "Bind Classic controller", + /*04*/ "Classic", /*05*/ "^|Up|Down|Left|a|b|x|y|Zl|Zr|+|-", - /*06*/ "Bind Classic controller (left analogue)", + /*06*/ "Classic (left analogue)", /*07*/ "^|Horiz|Vert", - /*08*/ "Bind Classic controller (right analogue)", + /*08*/ "Classic(right analogue)", /*09*/ "^|Horiz|Vert", NULL }; diff --git a/menu_messages.hh b/menu_messages.hh index 9ec6a30..81ed343 100644 --- a/menu_messages.hh +++ b/menu_messages.hh @@ -5,6 +5,8 @@ extern const char **main_menu_messages; extern const char **exit_dialogue_messages; extern const char **main_menu_help[]; +extern const char **bind_key_menu_messages; + extern const char **options_menu_messages; extern const char **options_menu_help[]; diff --git a/utils.hh b/utils.hh index cf93778..09a5998 100644 --- a/utils.hh +++ b/utils.hh @@ -17,7 +17,7 @@ class Font; #define panic(x...) do \ { \ fprintf(stderr, "=============PANIC PANIC PANIC===========\n"); \ - fprintf(stderr, x); \ + fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); fprintf(stderr, x); \ fprintf(stderr, "=========================================\n"); \ exit(1); \ } while(0) @@ -25,7 +25,7 @@ class Font; #define warning(x...) do \ { \ fprintf(stderr, "==============WARNING WARNING============\n"); \ - fprintf(stderr, x); \ + fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); fprintf(stderr, x); \ fprintf(stderr, "=========================================\n"); \ } while(0) diff --git a/virtual_keyboard.cpp b/virtual_keyboard.cpp index ee68556..870c094 100644 --- a/virtual_keyboard.cpp +++ b/virtual_keyboard.cpp @@ -241,6 +241,21 @@ virtkey_t VirtualKeyboard::eventToVirtkey(event_t ev) return INVALID_VIRTKEY; } +int VirtualKeyboard::stringToKeycode(const char *str) +{ + for (int i = 0; i < KEY_COLS * KEY_ROWS; i++) + { + virtkey_t key = keys[i]; + + if (key.name != NULL) + { + if (strcmp(key.name, str) == 0) + return key.kc; + } + } + + return 0; +} const char VirtualKeyboard::keycodeToChar(int kc) {