From a043dd852fbdce6c9ffa0581769d70ecda1d6071 Mon Sep 17 00:00:00 2001 From: fgenesis Date: Wed, 13 Jul 2016 05:00:19 +0200 Subject: [PATCH] Major input handling improvements (#28): - Support joystick hotplugging - Support axes as buttons (means xbox360 shoulder triggers can be used as buttons) - Show pretty joystick axis & button names if possible - Tabify input actions UI - Add 'mouse' column to input actions UI - Allow to configure form hotkeys - Allow ALL keys, get rid of internal key remapping - SDL2: Use scancodes instead of keycodes since they are layout independent - Allow extra mouse buttons (if present) - Remove "lmbd" & "lmbu" actions in favor of "PrimaryAction" & "SecondaryAction" Makes the configuration less redundant and doesn't send each action twice, which happened if both were set to the same key. - Fix Regressions from prev commits (menu not opening on Esc) Still has a few minor bugs/issues that need to be fixed, but pushing this now before the commit gets too large again. --- Aquaria/AquariaMenuItem.cpp | 109 ++++++++++--- Aquaria/AquariaMenuItem.h | 2 + Aquaria/Avatar.cpp | 42 +----- Aquaria/DSQ.cpp | 16 +- Aquaria/Game.cpp | 8 + Aquaria/InGameMenu.cpp | 294 ++++++++++++++++++++++++------------ Aquaria/InGameMenu.h | 15 +- Aquaria/UserSettings.cpp | 20 +-- BBGE/ActionInput.cpp | 91 ++++++++++- BBGE/ActionInput.h | 1 + BBGE/ActionMapper.cpp | 32 ++++ BBGE/ActionMapper.h | 13 +- BBGE/Core.cpp | 18 ++- BBGE/Core.h | 10 +- BBGE/DebugFont.cpp | 10 +- BBGE/DebugFont.h | 4 + BBGE/Joystick.cpp | 103 +++++++++---- BBGE/Joystick.h | 12 +- files/data/stringbank.txt | 8 +- 19 files changed, 585 insertions(+), 223 deletions(-) diff --git a/Aquaria/AquariaMenuItem.cpp b/Aquaria/AquariaMenuItem.cpp index 047eb6c..33f0029 100644 --- a/Aquaria/AquariaMenuItem.cpp +++ b/Aquaria/AquariaMenuItem.cpp @@ -464,7 +464,7 @@ AquariaKeyConfig::AquariaKeyConfig(const std::string &actionInputName, InputSetT if (inputSetType == INPUTSET_OTHER) bg->setWidthHeight(40, 20); else - bg->setWidthHeight(100, 20); + bg->setWidthHeight(90, 20); bg->color = Vector(0.5, 0.5, 0.5); bg->alphaMod = 0; @@ -481,6 +481,7 @@ AquariaKeyConfig::AquariaKeyConfig(const std::string &actionInputName, InputSetT keyDown = false; acceptEsc = false; + joystickID = 0; toggleEnterKey(false); } @@ -598,7 +599,7 @@ void AquariaKeyConfig::onUpdate(float dt) { if (k) { - keyConfigFont->setText(getInputCodeToString(*k)); + keyConfigFont->setText(getInputCodeToUserString(*k, joystickID)); } else if (value) { @@ -660,7 +661,7 @@ void AquariaKeyConfig::onUpdate(float dt) while (dsq->game->getKeyState(i)) { - dsq->run(0.1); + dsq->run(0.1f); } toggleEnterKey(0); @@ -672,35 +673,107 @@ void AquariaKeyConfig::onUpdate(float dt) } break; case INPUTSET_MOUSE: - break; - case INPUTSET_JOY: { + bool clear = false; + int ac = 0; if (core->getKeyState(KEY_DELETE) || core->getKeyState(KEY_BACKSPACE)) { - *k = 0; + clear = true; + } + else if(core->getKeyState(KEY_ESCAPE)) + { + // do nothing + } + else if(dsq->mouse.rawButtonMask) + { + MouseButtons btns = dsq->mouse.buttons; + + while(dsq->mouse.rawButtonMask) + dsq->run(0.1f); + + if(btns.left) + ac = MOUSE_BUTTON_LEFT; + else if(btns.right) + ac = MOUSE_BUTTON_RIGHT; + else if(btns.middle) + ac = MOUSE_BUTTON_MIDDLE; + else + { + for(unsigned i = 0; i < mouseExtraButtons; ++i) + if(btns.extra[i]) + { + ac = MOUSE_BUTTON_EXTRA_START+i; + break; + } + } + } + + if(ac || clear) + { toggleEnterKey(0); waitingForInput = 0; AquariaGuiElement::canDirMoveGlobal = true; + + if(clear || *k == ac) // clear key if pressed again + *k = 0; + else + *k = ac; + } + } + break; + case INPUTSET_JOY: + { + int ac = 0; + bool clear = false; + if (core->getKeyState(KEY_DELETE) || core->getKeyState(KEY_BACKSPACE)) + { + clear = true; + } + else if(core->getKeyState(KEY_ESCAPE)) + { + // do nothing } else { - for (int i = JOY_BUTTON_0; i <= MAX_JOYSTICK_BTN; i++) + Joystick *j = core->joysticks[joystickID]; + if(j) { - if (dsq->game->getKeyState(i)) - { - *k = i; - - while (dsq->game->getKeyState(i)) + for (int i = 0; i < MAX_JOYSTICK_BTN; i++) + if (j->getButton(i)) { - dsq->run(0.1); + ac = JOY_BUTTON_0 + i; + while (j->getButton(i)) + dsq->run(0.1f); + break; } - toggleEnterKey(0); - waitingForInput = 0; - AquariaGuiElement::canDirMoveGlobal = true; - break; - } + if(!ac) + for(int i = 0; i < MAX_JOYSTICK_AXIS; ++i) + { + float ax = j->getAxisUncalibrated(i); + if(fabsf(ax) > JOY_AXIS_THRESHOLD) + { + ac = (ax < 0.0f ? JOY_AXIS_0_NEG : JOY_AXIS_0_POS) + i; + while (fabsf(j->getAxisUncalibrated(i)) > JOY_AXIS_THRESHOLD) + dsq->run(0.1f); + break; + } + } } + else + clear = true; + } + + if(ac || clear) + { + toggleEnterKey(0); + waitingForInput = 0; + AquariaGuiElement::canDirMoveGlobal = true; + + if(clear || *k == ac) // clear key if pressed again + *k = 0; + else + *k = ac; } } break; diff --git a/Aquaria/AquariaMenuItem.h b/Aquaria/AquariaMenuItem.h index a544528..942a92b 100644 --- a/Aquaria/AquariaMenuItem.h +++ b/Aquaria/AquariaMenuItem.h @@ -171,6 +171,7 @@ public: static AquariaKeyConfig *waitingForInput; void setAcceptEsc(bool a); + void setJoystickID(int id); protected: void toggleEnterKey(int on); @@ -185,6 +186,7 @@ protected: int inputIdx; TTFText *keyConfigFont; Quad *bg; + int joystickID; bool acceptEsc; }; diff --git a/Aquaria/Avatar.cpp b/Aquaria/Avatar.cpp index 7d139f7..d0d89f0 100644 --- a/Aquaria/Avatar.cpp +++ b/Aquaria/Avatar.cpp @@ -128,24 +128,14 @@ void Avatar::bindInput() ActionMapper::clearActions(); ActionMapper::clearCreatedEvents(); - dsq->user.control.actionSet.importAction(this, "PrimaryAction", ACTION_PRIMARY); dsq->user.control.actionSet.importAction(this, "SecondaryAction", ACTION_SECONDARY); - dsq->user.control.actionSet.importAction(this, "Revert", ACTION_REVERT); - dsq->user.control.actionSet.importAction(this, "SwimUp", ACTION_SWIMUP); dsq->user.control.actionSet.importAction(this, "SwimDown", ACTION_SWIMDOWN); dsq->user.control.actionSet.importAction(this, "SwimLeft", ACTION_SWIMLEFT); dsq->user.control.actionSet.importAction(this, "SwimRight", ACTION_SWIMRIGHT); - /* - dsq->user.control.actionSet.importAction(this, "SingUp", ACTION_SINGUP); - dsq->user.control.actionSet.importAction(this, "SingDown", ACTION_SINGDOWN); - dsq->user.control.actionSet.importAction(this, "SingLeft", ACTION_SINGLEFT); - dsq->user.control.actionSet.importAction(this, "SingRight", ACTION_SINGRIGHT); - */ - dsq->user.control.actionSet.importAction(this, "SongSlot1", ACTION_SONGSLOT1); dsq->user.control.actionSet.importAction(this, "SongSlot2", ACTION_SONGSLOT2); dsq->user.control.actionSet.importAction(this, "SongSlot3", ACTION_SONGSLOT3); @@ -157,29 +147,9 @@ void Avatar::bindInput() dsq->user.control.actionSet.importAction(this, "SongSlot9", ACTION_SONGSLOT9); dsq->user.control.actionSet.importAction(this, "SongSlot10", ACTION_SONGSLOT10); + dsq->user.control.actionSet.importAction(this, "Revert", ACTION_REVERT); dsq->user.control.actionSet.importAction(this, "Look", ACTION_LOOK); - - /* - dsq->user.control.actionSet.importAction(this, "SongSlot5", "f5"); - dsq->user.control.actionSet.importAction(this, "SongSlot6", "f6"); - dsq->user.control.actionSet.importAction(this, "SongSlot7", "f7"); - dsq->user.control.actionSet.importAction(this, "SongSlot8", "f8"); - */ - dsq->user.control.actionSet.importAction(this, "Roll", ACTION_ROLL); - - /* - // song note keys - addAction("s1", KEY_1); - addAction("s2", KEY_2); - addAction("s3", KEY_3); - addAction("s4", KEY_4); - addAction("s5", KEY_5); - addAction("s6", KEY_6); - addAction("s7", KEY_7); - addAction("s8", KEY_8); - */ - } // note: z is set to 1.0 when we want the aim to be used as the shot direction @@ -4226,12 +4196,12 @@ Vector Avatar::getFakeCursorPosition() { axisInput = j->position.getLength2D(); if(axisInput >= JOYSTICK_LOW_THRESHOLD) - break; + { + const float axisMult = (maxMouse - minMouse) / (JOYSTICK_HIGH_THRESHOLD - JOYSTICK_LOW_THRESHOLD); + const float distance = minMouse + ((axisInput - JOYSTICK_LOW_THRESHOLD) * axisMult); + return (j->position * (distance / axisInput)); + } } - - const float axisMult = (maxMouse - minMouse) / (JOYSTICK_HIGH_THRESHOLD - JOYSTICK_LOW_THRESHOLD); - const float distance = minMouse + ((axisInput - JOYSTICK_LOW_THRESHOLD) * axisMult); - return (j->position * (distance / axisInput)); } return Vector(0,0,0); } diff --git a/Aquaria/DSQ.cpp b/Aquaria/DSQ.cpp index e7fa8c8..91c5f5c 100644 --- a/Aquaria/DSQ.cpp +++ b/Aquaria/DSQ.cpp @@ -3744,8 +3744,8 @@ void DSQ::bindInput() { clearActions(); - almb = user.control.actionSet.getActionInputByName("lmb"); - armb = user.control.actionSet.getActionInputByName("rmb"); + almb = user.control.actionSet.getActionInputByName("PrimaryAction"); + armb = user.control.actionSet.getActionInputByName("SecondaryAction"); user.control.actionSet.importAction(this, "Escape", ACTION_ESC); @@ -3988,7 +3988,17 @@ void DSQ::onUpdate(float dt) os << std::endl; os << "globalScale: " << core->globalScale.x << std::endl; os << "mousePos:(" << core->mouse.position.x << ", " << core->mouse.position.y << ") mouseChange:(" << core->mouse.change.x << ", " << core->mouse.change.y << ")\n"; - //os << "joyStick:(" << core->joystick.position.x << ", " << core->joystick.position.y << ")\n"; + for(size_t i = 0; i < joysticks.size(); ++i) + if(Joystick *j = joysticks[i]) + { + os << "J[" << i << "]:["; + for(unsigned ii = 0; ii < MAX_JOYSTICK_BTN; ++ii) + if(j->getButton(ii)) + os << (ii % 10); + else + os << '-'; + os << "], (" << j->position.x << ", " << j->position.y << "), ("<< j->rightStick.x << ", " << j->rightStick.y << ")\n"; + } os << "altState: " << core->getKeyState(KEY_LALT) << " | " << core->getKeyState(KEY_RALT) << std::endl; os << "PMFree: " << particleManager->getFree() << " Active: " << particleManager->getNumActive() << std::endl; os << "cameraPos: (" << dsq->cameraPos.x << ", " << dsq->cameraPos.y << ")" << std::endl; diff --git a/Aquaria/Game.cpp b/Aquaria/Game.cpp index 9ce64a7..6614d18 100644 --- a/Aquaria/Game.cpp +++ b/Aquaria/Game.cpp @@ -2540,6 +2540,12 @@ void Game::action(int id, int state, int source) if(isIgnoreAction((AquariaActions)id)) return; + // forward + if(id == ACTION_TOGGLEMENU) + { + themenu->action(id, state, source); + } + if (id == ACTION_TOGGLEHELPSCREEN && !state) { onToggleHelpScreen(); @@ -3787,7 +3793,9 @@ void Game::onPressEscape() if (!paused) { if (core->getNestedMains() == 1 && !core->isStateJumpPending()) + { action(ACTION_TOGGLEMENU, 1, -1); // show menu + } } if ((dsq->saveSlotMode != SSM_NONE || dsq->inModSelector) && core->isNested()) diff --git a/Aquaria/InGameMenu.cpp b/Aquaria/InGameMenu.cpp index d49b6df..2c4d960 100644 --- a/Aquaria/InGameMenu.cpp +++ b/Aquaria/InGameMenu.cpp @@ -8,6 +8,7 @@ #include "DSQ.h" #include "Avatar.h" #include "GridRender.h" +#include "DebugFont.h" static InGameMenu *themenu = 0; @@ -26,6 +27,21 @@ const int numTreasures = 16*2; const Vector worldLeftCenter(217,250), worldRightCenter(575, 250); const Vector opt_save_original = Vector(350, 350), opt_cancel_original = Vector(450, 350); +const int KEYCONFIG_FIRST_COL_DISTANCE = 170; +const int KEYCONFIG_COL_DISTANCE = 105; + +class KeyConfigMenuReceiver : public DebugButtonReceiver +{ +public: + void buttonPress(DebugButton *db) + { + themenu->switchToKeyConfigPage(db->buttonID); + } +}; + +static KeyConfigMenuReceiver keyConfigRecv; + + // --------- Private class defs, not used outside --------------- @@ -1240,6 +1256,7 @@ void InGameMenu::show(bool ignoreInput, bool optionsOnly, MenuPage menuPage) opt_cancel->setHidden(false); options->setHidden(false); keyConfigButton->setHidden(false); + keyConfigBg->setHidden(false); cook->setHidden(false); foodSort->setHidden(false); recipes->setHidden(false); @@ -1458,6 +1475,7 @@ void InGameMenu::hide(bool effects, bool cancel) opt_cancel->setHidden(true); options->setHidden(true); keyConfigButton->setHidden(true); + keyConfigBg->setHidden(true); cook->setHidden(true); foodSort->setHidden(true); recipes->setHidden(true); @@ -1490,26 +1508,35 @@ void InGameMenu::hide(bool effects, bool cancel) } -void InGameMenu::addKeyConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int y, bool acceptEsc) +void InGameMenu::addKeyConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int x, int y, bool acceptEsc) { TTFText *lb = new TTFText(&dsq->fontArialSmallest); lb->setText(label); - lb->position = Vector(140,y); + lb->position = Vector(x,y); group->addChild(lb, PM_POINTER); + x += KEYCONFIG_FIRST_COL_DISTANCE; + + AquariaKeyConfig *m = new AquariaKeyConfig(actionInputName, INPUTSET_MOUSE, 0); + m->position = Vector(x,y); + group->addChild(m, PM_POINTER); + x += KEYCONFIG_COL_DISTANCE; AquariaKeyConfig *k1 = new AquariaKeyConfig(actionInputName, INPUTSET_KEY, 0); - k1->position = Vector(350,y); + k1->position = Vector(x,y); group->addChild(k1, PM_POINTER); k1->setAcceptEsc(acceptEsc); + x += KEYCONFIG_COL_DISTANCE; AquariaKeyConfig *k2 = new AquariaKeyConfig(actionInputName, INPUTSET_KEY, 1); - k2->position = Vector(475,y); + k2->position = Vector(x,y); group->addChild(k2, PM_POINTER); k2->setAcceptEsc(acceptEsc); + x += KEYCONFIG_COL_DISTANCE; AquariaKeyConfig *j1 = new AquariaKeyConfig(actionInputName, INPUTSET_JOY, 0); - j1->position = Vector(600,y); + j1->position = Vector(x,y); group->addChild(j1, PM_POINTER); + x += KEYCONFIG_COL_DISTANCE; k1->setDirMove(DIR_RIGHT, k2); k2->setDirMove(DIR_RIGHT, j1); @@ -1518,15 +1545,15 @@ void InGameMenu::addKeyConfigLine(RenderObject *group, const std::string &label, k2->setDirMove(DIR_LEFT, k1); } -AquariaKeyConfig *InGameMenu::addAxesConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int y, int offx) +AquariaKeyConfig *InGameMenu::addAxesConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int offx, int y) { TTFText *lb = new TTFText(&dsq->fontArialSmallest); lb->setText(label); - lb->position = Vector(140+offx, y); + lb->position = Vector(offx, y); group->addChild(lb, PM_POINTER); AquariaKeyConfig *i1 = new AquariaKeyConfig(actionInputName, INPUTSET_OTHER, 0); - i1->position = Vector(140+80+offx,y); + i1->position = Vector(80+offx,y); //i1->setLock(l1); group->addChild(i1, PM_POINTER); @@ -1624,6 +1651,19 @@ void InGameMenu::sortFood() } } +RenderObject *InGameMenu::createBasicKeyConfig() +{ + RenderObject *keyConfig = new RenderObject; + + keyConfigBg->addChild(keyConfig, PM_POINTER); + + keyConfig->shareAlphaWithChildren = 1; + keyConfig->followCamera = 1; + keyConfig->position = Vector(0, -40); + + return keyConfig; +} + void InGameMenu::create() { float menuz = 4; @@ -1910,105 +1950,144 @@ void InGameMenu::create() game->addRenderObject(keyConfigButton, LR_MENU); - - group_keyConfig = new RenderObject; - - /* - Quad *kbg = new Quad("gui/keyconfig-menu", Vector(400,300)); - kbg->setWidthHeight(800, 800); - group_keyConfig->addChild(kbg); - */ - - //Quad *kcb = new Quad; - RoundedRect *kcb = new RoundedRect(); - //kcb->color = 0; - //kcb->alphaMod = 0.75; - kcb->position = Vector(400,276 - 10); - kcb->setWidthHeight(580, 455, 10); - group_keyConfig->addChild(kcb, PM_POINTER); - - int offy = -20; - #define SB(x) dsq->continuity.stringBank.get(x) + keyConfigBg = new RoundedRect(); + keyConfigBg->position = Vector(400,276 - 10 - 40); + keyConfigBg->setWidthHeight(580, 455, 10); + keyConfigBg->followCamera = 1; + keyConfigBg->shareAlphaWithChildren = 1; + keyConfigBg->setHidden(true); + game->addRenderObject(keyConfigBg, LR_OVERLAY); + + int offy = 20 - keyConfigBg->position.y; + const int offx = 140 - keyConfigBg->position.x; + const int yi = 20; + + TTFText *header_tabs = new TTFText(&dsq->fontArialSmall); + header_tabs->setText(SB(2130)); + header_tabs->position = Vector(offx, offy); + keyConfigBg->addChild(header_tabs, PM_POINTER); + + keyCategoryButtons.clear(); + for(int i = 0; i < NUM_KEY_CONFIG_PAGES; ++i) + { + const float w = 100; + const std::string& label = SB(2150+i); + DebugButton *b = new DebugButton(i, &keyConfigRecv, w); + b->position = Vector(150 + offx + i * (w+10), offy); + b->label->setText(label); + keyConfigBg->addChild(b, PM_POINTER); + keyCategoryButtons.push_back(b); + } + offy += 2*yi; + TTFText *header_action = new TTFText(&dsq->fontArialSmall); header_action->setText(SB(2101)); - header_action->position = Vector(140, 80+offy); - group_keyConfig->addChild(header_action, PM_POINTER); + header_action->position = Vector(offx, offy); + keyConfigBg->addChild(header_action, PM_POINTER); + + TTFText *header_mouse = new TTFText(&dsq->fontArialSmall); + header_mouse->setText(SB(2131)); + header_mouse->position = Vector(offx+KEYCONFIG_FIRST_COL_DISTANCE, offy); + header_mouse->setAlign(ALIGN_CENTER); + keyConfigBg->addChild(header_mouse, PM_POINTER); TTFText *header_key1 = new TTFText(&dsq->fontArialSmall); header_key1->setText(SB(2102)); - header_key1->position = Vector(350, 80+offy); + header_key1->position = Vector(offx+KEYCONFIG_FIRST_COL_DISTANCE+KEYCONFIG_COL_DISTANCE, offy); header_key1->setAlign(ALIGN_CENTER); - group_keyConfig->addChild(header_key1, PM_POINTER); + keyConfigBg->addChild(header_key1, PM_POINTER); TTFText *header_key2 = new TTFText(&dsq->fontArialSmall); header_key2->setText(SB(2103)); - header_key2->position = Vector(475, 80+offy); + header_key2->position = Vector(offx+KEYCONFIG_FIRST_COL_DISTANCE+2*KEYCONFIG_COL_DISTANCE, offy); header_key2->setAlign(ALIGN_CENTER); - group_keyConfig->addChild(header_key2, PM_POINTER); + keyConfigBg->addChild(header_key2, PM_POINTER); TTFText *header_joy = new TTFText(&dsq->fontArialSmall); header_joy->setText(SB(2104)); - header_joy->position = Vector(600, 80+offy); + header_joy->position = Vector(offx+KEYCONFIG_FIRST_COL_DISTANCE+3*KEYCONFIG_COL_DISTANCE, offy); header_joy->setAlign(ALIGN_CENTER); - group_keyConfig->addChild(header_joy, PM_POINTER); + keyConfigBg->addChild(header_joy, PM_POINTER); - addKeyConfigLine(group_keyConfig, SB(2105), "lmb", 100+offy); - addKeyConfigLine(group_keyConfig, SB(2106), "rmb", 120+offy); - addKeyConfigLine(group_keyConfig, SB(2107), "PrimaryAction", 140+offy); - addKeyConfigLine(group_keyConfig, SB(2108), "SecondaryAction", 160+offy); - addKeyConfigLine(group_keyConfig, SB(2109), "SwimUp", 180+offy); - addKeyConfigLine(group_keyConfig, SB(2110), "SwimDown", 200+offy); - addKeyConfigLine(group_keyConfig, SB(2111), "SwimLeft", 220+offy); - addKeyConfigLine(group_keyConfig, SB(2112), "SwimRight", 240+offy); - addKeyConfigLine(group_keyConfig, SB(2113), "Roll", 260+offy); - addKeyConfigLine(group_keyConfig, SB(2114), "Revert", 280+offy); - addKeyConfigLine(group_keyConfig, SB(2115), "WorldMap", 300+offy); - addKeyConfigLine(group_keyConfig, SB(2116), "Escape", 320+offy, true); + offy += 2*yi; - AquariaKeyConfig* s1x = addAxesConfigLine(group_keyConfig, SB(2117), "s1ax", 340+offy, 0); - AquariaKeyConfig* s1y = addAxesConfigLine(group_keyConfig, SB(2118), "s1ay", 340+offy, 130); - AquariaKeyConfig* s2x = addAxesConfigLine(group_keyConfig, SB(2119), "s2ax", 340+offy, 260); - AquariaKeyConfig* s2y = addAxesConfigLine(group_keyConfig, SB(2120), "s2ay", 340+offy, 380); + // PART 1 + { + RenderObject *kk = createBasicKeyConfig(); + group_keyConfig[0] = kk; - s1x->setDirMove(DIR_LEFT, s1x); - s1x->setDirMove(DIR_RIGHT, s1y); + int y = 0; - s1y->setDirMove(DIR_LEFT, s1x); - s1y->setDirMove(DIR_RIGHT, s2x); + addKeyConfigLine(kk, SB(2107), "PrimaryAction", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2108), "SecondaryAction", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2109), "SwimUp", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2110), "SwimDown", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2111), "SwimLeft", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2112), "SwimRight", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2113), "Roll", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2114), "Revert", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2115), "WorldMap", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2127), "Look", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2116), "Escape", offx, offy+(y+=yi), true); - s2x->setDirMove(DIR_LEFT, s1y); - s2x->setDirMove(DIR_RIGHT, s2y); + y+=yi; + AquariaKeyConfig* s1x = addAxesConfigLine(kk, SB(2117), "s1ax", offx, y+offy); + AquariaKeyConfig* s1y = addAxesConfigLine(kk, SB(2118), "s1ay", offx+130, y+offy); + AquariaKeyConfig* s2x = addAxesConfigLine(kk, SB(2119), "s2ax", offx+260, y+offy); + AquariaKeyConfig* s2y = addAxesConfigLine(kk, SB(2120), "s2ay", offx+380, y+offy); + y+=yi; - s2y->setDirMove(DIR_LEFT, s2x); - s2y->setDirMove(DIR_RIGHT, s2y); + s1x->setDirMove(DIR_LEFT, s1x); + s1x->setDirMove(DIR_RIGHT, s1y); - offy += 20; + s1y->setDirMove(DIR_LEFT, s1x); + s1y->setDirMove(DIR_RIGHT, s2x); - addKeyConfigLine(group_keyConfig, SB(2121), "PrevPage", 340+offy); - addKeyConfigLine(group_keyConfig, SB(2122), "NextPage", 360+offy); - addKeyConfigLine(group_keyConfig, SB(2123), "CookFood", 380+offy); - addKeyConfigLine(group_keyConfig, SB(2124), "FoodLeft", 400+offy); - addKeyConfigLine(group_keyConfig, SB(2125), "FoodRight", 420+offy); - addKeyConfigLine(group_keyConfig, SB(2126), "FoodDrop", 440+offy); + s2x->setDirMove(DIR_LEFT, s1y); + s2x->setDirMove(DIR_RIGHT, s2y); - addKeyConfigLine(group_keyConfig, SB(2127), "Look", 460+offy); + s2y->setDirMove(DIR_LEFT, s2x); + s2y->setDirMove(DIR_RIGHT, s2y); + } + + // PART 2 + { + RenderObject *kk = createBasicKeyConfig(); + group_keyConfig[1] = kk; + + int y = 0; + + addKeyConfigLine(kk, SB(2121), "PrevPage", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2122), "NextPage", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2123), "CookFood", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2124), "FoodLeft", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2125), "FoodRight", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2126), "FoodDrop", offx, offy+(y+=yi)); + addKeyConfigLine(kk, SB(2128), "ToggleHelp", offx, offy+(y+=yi)); + } + + // PART 2 + { + RenderObject *kk = createBasicKeyConfig(); + group_keyConfig[2] = kk; + + int y = 0; + std::string slotstr = SB(2129); + for(unsigned i = 1; i <= 10; ++i) // SongSlot starts at 1 + { + std::ostringstream osname; + osname << slotstr << ' ' << i; + std::ostringstream osac; + osac << "SongSlot" << i; + addKeyConfigLine(kk, osname.str(), osac.str(), offx, offy+(y+=yi)); + } + } - addKeyConfigLine(group_keyConfig, SB(2128), "ToggleHelp", 480+offy); #undef SB - group_keyConfig->shareAlphaWithChildren = 1; - group_keyConfig->followCamera = 1; - group_keyConfig->alpha = 0; - group_keyConfig->setHidden(true); - - group_keyConfig->position = Vector(0, -40); - - game->addRenderObject(group_keyConfig, LR_OVERLAY); - - cook = new AquariaMenuItem; cook->useQuad("Gui/cook-button"); cook->useGlow("particles/glow", 128, 40); @@ -3604,28 +3683,29 @@ void InGameMenu::toggleKeyConfigMenu(bool f) keyConfigMenu = true; - group_keyConfig->setHidden(false); - group_keyConfig->alpha = 1; + keyConfigBg->setHidden(false); + keyConfigBg->alpha = 1; + + for(unsigned i = 0; i < NUM_KEY_CONFIG_PAGES; ++i) + { + // FG: FIXME: changed layout: m, k1, k2, j + RenderObject::Children::reverse_iterator it = group_keyConfig[i]->children.rbegin(); + AquariaKeyConfig *upright0 = (AquariaKeyConfig*)(*it++); + AquariaKeyConfig *upright = (AquariaKeyConfig*)(*it++); + AquariaKeyConfig *upleft = (AquariaKeyConfig*)(*it++); + + //opt_cancel->setDirMove(DIR_UP, upright); + upright->setDirMove(DIR_DOWN, opt_cancel); + upright0->setDirMove(DIR_DOWN, opt_cancel); + + //opt_save->setDirMove(DIR_UP, upleft); + upleft->setDirMove(DIR_DOWN, opt_save); + } + + switchToKeyConfigPage(0); dsq->user_bcontrol = dsq->user; - //group_keyConfig->children[group_keyConfig->children.size()-3] - - RenderObject::Children::reverse_iterator i = group_keyConfig->children.rbegin(); - AquariaKeyConfig *upright0 = (AquariaKeyConfig*)(*i); - i++; - AquariaKeyConfig *upright = (AquariaKeyConfig*)(*i); - i++; - AquariaKeyConfig *upleft = (AquariaKeyConfig*)(*i); - - opt_cancel->setDirMove(DIR_UP, upright); - upright->setDirMove(DIR_DOWN, opt_cancel); - upright0->setDirMove(DIR_DOWN, opt_cancel); - - opt_save->setDirMove(DIR_UP, upleft); - upleft->setDirMove(DIR_DOWN, opt_save); - - opt_cancel->alpha = 1; opt_save->alpha = 1; @@ -3641,8 +3721,8 @@ void InGameMenu::toggleKeyConfigMenu(bool f) { keyConfigMenu = false; - group_keyConfig->alpha = 0; - group_keyConfig->setHidden(true); + keyConfigBg->setHidden(true); + keyConfigBg->alpha = 0; opt_cancel->alpha = 0; opt_save->alpha = 0; @@ -3654,6 +3734,22 @@ void InGameMenu::toggleKeyConfigMenu(bool f) } } +void InGameMenu::switchToKeyConfigPage(int page) +{ + assert(page < NUM_KEY_CONFIG_PAGES); + for(unsigned i = 0; i < NUM_KEY_CONFIG_PAGES; ++i) + { + group_keyConfig[i]->setHidden(true); + group_keyConfig[i]->alpha = 0; + keyCategoryButtons[i]->inactiveColor = Vector(0, 0, 0.5f); + keyCategoryButtons[i]->inactiveAlpha = 0.5f; + } + keyCategoryButtons[page]->inactiveColor = Vector(0.3f, 0.3f, 0.7f); + keyCategoryButtons[page]->inactiveAlpha = 0.7f; + group_keyConfig[page]->setHidden(false); + group_keyConfig[page]->alpha = 1; +} + void InGameMenu::toggleOptionsMenu(bool f, bool skipBackup, bool isKeyConfig) { const float t = 0; diff --git a/Aquaria/InGameMenu.h b/Aquaria/InGameMenu.h index 7083a98..b8c35c5 100644 --- a/Aquaria/InGameMenu.h +++ b/Aquaria/InGameMenu.h @@ -21,6 +21,8 @@ class AquariaSlider; class AquariaComboBox; class RecipeMenuEntry; class Recipe; +class RoundedRect; +class DebugButton; enum MenuPage @@ -66,6 +68,8 @@ class InGameMenu : public ActionMapper friend class TreasureSlot; friend class SongSlot; friend class FoodHolder; + friend class KeyConfigMenuReceiver; + enum { NUM_KEY_CONFIG_PAGES = 3 }; public: InGameMenu(); @@ -188,9 +192,9 @@ private: void onKeyConfig(); - void addKeyConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int y, bool acceptEsc = false); + void addKeyConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int x, int y, bool acceptEsc = false); - AquariaKeyConfig *addAxesConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int y, int offx); + AquariaKeyConfig *addAxesConfigLine(RenderObject *group, const std::string &label, const std::string &actionInputName, int offx, int y); void onOptionsSave(); void onOptionsCancel(); @@ -200,8 +204,11 @@ private: AquariaComboBox *resBox; Quad *songBubbles, *energyIdol, *liCrystal; - RenderObject *group_keyConfig; - + RenderObject *group_keyConfig[NUM_KEY_CONFIG_PAGES]; + RoundedRect *keyConfigBg; + std::vector keyCategoryButtons; + RenderObject *createBasicKeyConfig(); + void switchToKeyConfigPage(int page); Quad *options; void onExitCheckNo(); diff --git a/Aquaria/UserSettings.cpp b/Aquaria/UserSettings.cpp index 0bcf1ff..2357595 100644 --- a/Aquaria/UserSettings.cpp +++ b/Aquaria/UserSettings.cpp @@ -312,9 +312,6 @@ void UserSettings::load(bool doApply, const std::string &overrideFile) control.actionSet.clearActions(); - - control.actionSet.addActionInput("lmb"); - control.actionSet.addActionInput("rmb"); control.actionSet.addActionInput("PrimaryAction"); control.actionSet.addActionInput("SecondaryAction"); control.actionSet.addActionInput("SwimUp"); @@ -535,13 +532,16 @@ void UserSettings::apply() dsq->loops.updateVolume(); // FIXME: This should be per-joystick - /*core->joystick.s1ax = control.s1ax; - core->joystick.s1ay = control.s1ay; - core->joystick.s2ax = control.s2ax; - core->joystick.s2ay = control.s2ay; - - core->joystick.deadZone1 = control.s1dead; - core->joystick.deadZone2 = control.s2dead;*/ + for(size_t i = 0; i < core->joysticks.size(); ++i) + { + Joystick *j = core->joysticks[i]; + j->s1ax = control.s1ax; + j->s1ay = control.s1ay; + j->s2ax = control.s2ax; + j->s2ay = control.s2ay; + j->deadZone1 = control.s1dead; + j->deadZone2 = control.s2dead; + } core->debugLogActive = system.debugLogOn; diff --git a/BBGE/ActionInput.cpp b/BBGE/ActionInput.cpp index 3bebdde..300a09b 100644 --- a/BBGE/ActionInput.cpp +++ b/BBGE/ActionInput.cpp @@ -21,14 +21,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "ActionInput.h" #include "ActionMapper.h" +#include "Core.h" #include "SDL.h" #ifndef BBGE_BUILD_SDL2 #error Needs fixes for SDL 1.2, doesnt support scancodes #endif - -std::string getInputCodeToString(int k) +static std::string inputcode2string(int k) { if(k <= 0) return std::string(); @@ -42,7 +42,7 @@ std::string getInputCodeToString(int k) os << "K:" << k; return os.str(); } - + if(k >= JOY_BUTTON_0 && k < JOY_BUTTON_END) { std::stringstream os; @@ -50,6 +50,20 @@ std::string getInputCodeToString(int k) return os.str(); } + if(k >= JOY_AXIS_0_POS && k < JOY_AXIS_END_POS) + { + std::stringstream os; + os << "AX:+" << (k - JOY_AXIS_0_POS); + return os.str(); + } + + if(k >= JOY_AXIS_0_NEG && k < JOY_AXIS_END_NEG) + { + std::stringstream os; + os << "AX:-" << (k - JOY_AXIS_0_NEG); + return os.str(); + } + switch(k) { case MOUSE_BUTTON_LEFT: @@ -58,11 +72,66 @@ std::string getInputCodeToString(int k) return "RMB"; case MOUSE_BUTTON_MIDDLE: return "MMB"; + default: + if(k >= MOUSE_BUTTON_EXTRA_START && k < MOUSE_BUTTON_EXTRA_START+mouseExtraButtons) + { + std::ostringstream os; + os << "MB:" << (k - MOUSE_BUTTON_LEFT); + return os.str(); + } } return std::string(); } +static const char *jaxisname(int joysickID, int axis) +{ + Joystick *j = joysickID < core->joysticks.size() ? core->joysticks[joysickID] : NULL; + return j ? j->getAxisName(axis) : NULL; +} + +static const char *jbtnname(int joysickID, int btn) +{ + Joystick *j = joysickID < core->joysticks.size() ? core->joysticks[joysickID] : NULL; + return j ? j->getButtonName(btn) : NULL; +} + + + +std::string getInputCodeToString(int k) +{ + std::string s = inputcode2string(k); + if(s.empty()) + return "NONE"; + return spacesToUnderscores(s); +} + +std::string getInputCodeToUserString(int k, int joystickID) +{ + const char *pretty = NULL; + + // Special case keyboard input: + // Return key name for current keyboard layout! + // It's just confusing to see Y instead of Z with a german keyboard layout... + if(k < SDL_NUM_SCANCODES) + { + const SDL_Keycode kcode = SDL_GetKeyFromScancode((SDL_Scancode)k); + if(kcode != SDLK_UNKNOWN) + pretty = SDL_GetKeyName(kcode); + } + if(k >= JOY_AXIS_0_POS && k < JOY_AXIS_END_POS) + pretty = jaxisname(joystickID, k - JOY_AXIS_0_POS); + else if(k >= JOY_AXIS_0_NEG && k < JOY_AXIS_END_NEG) + pretty = jaxisname(joystickID, k - JOY_AXIS_0_NEG); + else if(k >= JOY_BUTTON_0 && k < JOY_BUTTON_END) + pretty = jbtnname(joystickID, k - JOY_BUTTON_0); + + if(pretty && *pretty) + return pretty; + + return inputcode2string(k); +} + int getStringToInputCode(const std::string& s) { if(s == "LMB") @@ -75,8 +144,22 @@ int getStringToInputCode(const std::string& s) return atoi(s.c_str() + 2); if(!strncmp(s.c_str(), "JB:", 3)) return JOY_BUTTON_0 + atoi(s.c_str() + 3); + if(!strncmp(s.c_str(), "MB:", 3)) + return MOUSE_BUTTON_LEFT + atoi(s.c_str() + 3); + if(s.length() > 4 && !strncmp(s.c_str(), "AX:", 3)) + { + int n = atoi(s.c_str() + 4); + switch(s[3]) + { + case '+': return JOY_AXIS_0_POS + n; + case '-': return JOY_AXIS_0_NEG + n; + default: return 0; + } + } + if(s == "NONE") + return 0; - return SDL_GetScancodeFromName(s.c_str()); + return SDL_GetScancodeFromName(underscoresToSpaces(s).c_str()); } diff --git a/BBGE/ActionInput.h b/BBGE/ActionInput.h index 034d57d..4383da4 100644 --- a/BBGE/ActionInput.h +++ b/BBGE/ActionInput.h @@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define INP_JOYSIZE 1 std::string getInputCodeToString(int k); +std::string getInputCodeToUserString(int k, int joystickID); int getStringToInputCode(const std::string& s); class ActionInput diff --git a/BBGE/ActionMapper.cpp b/BBGE/ActionMapper.cpp index 57e9be8..704bab4 100644 --- a/BBGE/ActionMapper.cpp +++ b/BBGE/ActionMapper.cpp @@ -195,6 +195,10 @@ bool ActionMapper::getKeyState(int k) { keyState = (core->mouse.buttons.middle == DOWN); } + else if (k >= MOUSE_BUTTON_EXTRA_START && k < MOUSE_BUTTON_EXTRA_START+mouseExtraButtons) + { + keyState = core->mouse.buttons.extra[k - MOUSE_BUTTON_EXTRA_START]; + } else if (k >= JOY_BUTTON_0 && k < JOY_BUTTON_END) { int v = k - JOY_BUTTON_0; @@ -205,6 +209,34 @@ bool ActionMapper::getKeyState(int k) if( ((keyState = j->getButton(v))) ) break; } + else if (k >= JOY_AXIS_0_POS && k < JOY_AXIS_END_POS) + { + int v = k - JOY_AXIS_0_POS; + + for(size_t i = 0; i < core->joysticks.size(); ++i) + if(Joystick *j = core->joysticks[i]) + if(j->isEnabled()) + { + float ax = j->getAxisUncalibrated(v); + keyState = ax > JOY_AXIS_THRESHOLD; + if(keyState) + break; + } + } + else if (k >= JOY_AXIS_0_NEG && k < JOY_AXIS_END_NEG) + { + int v = k - JOY_AXIS_END_NEG; + + for(size_t i = 0; i < core->joysticks.size(); ++i) + if(Joystick *j = core->joysticks[i]) + if(j->isEnabled()) + { + float ax = j->getAxisUncalibrated(v); + keyState = ax < -JOY_AXIS_THRESHOLD; + if(keyState) + break; + } + } return keyState; } diff --git a/BBGE/ActionMapper.h b/BBGE/ActionMapper.h index 77e7c54..b4702a7 100644 --- a/BBGE/ActionMapper.h +++ b/BBGE/ActionMapper.h @@ -45,15 +45,18 @@ struct ActionData enum ActionButtonType { // must start at > 512 (SDL scancodes end there) - MOUSE_BUTTON_LEFT = 999, - MOUSE_BUTTON_RIGHT = 1000, - MOUSE_BUTTON_MIDDLE = 1001, + MOUSE_BUTTON_LEFT = 1000, + MOUSE_BUTTON_RIGHT = 1001, + MOUSE_BUTTON_MIDDLE = 1002, + MOUSE_BUTTON_EXTRA_START = 1003, JOY_BUTTON_0 = 2000, JOY_BUTTON_END = JOY_BUTTON_0 + MAX_JOYSTICK_BTN, // one past end - JOY_AXIS_0 = 3000, - JOY_AXIS_END = JOY_AXIS_0 + MAX_JOYSTICK_AXIS, + JOY_AXIS_0_POS = 3000, + JOY_AXIS_0_NEG = 3100, + JOY_AXIS_END_POS = JOY_AXIS_0_POS + MAX_JOYSTICK_AXIS, + JOY_AXIS_END_NEG = JOY_AXIS_0_NEG + MAX_JOYSTICK_AXIS, }; class ActionMapper diff --git a/BBGE/Core.cpp b/BBGE/Core.cpp index ed6c517..f12a515 100644 --- a/BBGE/Core.cpp +++ b/BBGE/Core.cpp @@ -627,9 +627,10 @@ void Core::initJoystickLibrary() SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER); #else SDL_InitSubSystem(SDL_INIT_JOYSTICK); + detectJoysticks(); #endif - detectJoysticks(); + joystickEnabled = true; } void Core::clearJoysticks() @@ -639,6 +640,9 @@ void Core::clearJoysticks() joysticks.clear(); } + +// Only used for SDL 1.2 code path. +// SDL2 automatically fires joystick added events upon startup void Core::detectJoysticks() { clearJoysticks(); @@ -648,6 +652,7 @@ void Core::detectJoysticks() os << "Found [" << n << "] joysticks"; debugLog(os.str()); + joysticks.reserve(n); for(unsigned i = 0; i < n; ++i) { Joystick *j = new Joystick; @@ -656,8 +661,6 @@ void Core::detectJoysticks() else delete j; } - - joystickEnabled = !joysticks.empty(); } bool Core::initInputLibrary() @@ -685,7 +688,8 @@ void Core::onUpdate(float dt) pollEvents(); for(size_t i = 0; i < joysticks.size(); ++i) - joysticks[i]->update(dt); + if(joysticks[i]) + joysticks[i]->update(dt); onMouseInput(); @@ -1587,7 +1591,7 @@ void Core::pollEvents() if (updateMouse) { int x, y; - Uint8 mousestate = SDL_GetMouseState(&x,&y); + unsigned mousestate = SDL_GetMouseState(&x,&y); if (mouse.buttonsEnabled) { @@ -1595,7 +1599,11 @@ void Core::pollEvents() mouse.buttons.right = mousestate & SDL_BUTTON(3)?DOWN:UP; mouse.buttons.middle = mousestate & SDL_BUTTON(2)?DOWN:UP; + for(unsigned i = 0; i < mouseExtraButtons; ++i) + mouse.buttons.extra[i] = mousestate & SDL_BUTTON(3+i)?DOWN:UP; + mouse.pure_buttons = mouse.buttons; + mouse.rawButtonMask = mousestate; if (flipMouseButtons) { diff --git a/BBGE/Core.h b/BBGE/Core.h index 1992d33..1e2890f 100644 --- a/BBGE/Core.h +++ b/BBGE/Core.h @@ -76,6 +76,8 @@ const int baseVirtualHeight = 600; enum ButtonState { UP = 0, DOWN }; +const unsigned mouseExtraButtons = 8; + struct MouseButtons { MouseButtons () @@ -86,6 +88,7 @@ struct MouseButtons } ButtonState left, right, middle; + ButtonState extra[mouseExtraButtons]; }; struct Mouse @@ -94,16 +97,13 @@ struct Mouse { scrollWheel = scrollWheelChange = lastScrollWheel = 0; buttonsEnabled = true; - movementEnabled = true; } Vector position, lastPosition; MouseButtons buttons; MouseButtons pure_buttons; + unsigned rawButtonMask; Vector change; - - - // movementEnabled is not implemented yet - bool buttonsEnabled, movementEnabled; + bool buttonsEnabled; int scrollWheel, scrollWheelChange, lastScrollWheel; }; diff --git a/BBGE/DebugFont.cpp b/BBGE/DebugFont.cpp index a92a676..a65f7b6 100644 --- a/BBGE/DebugFont.cpp +++ b/BBGE/DebugFont.cpp @@ -165,6 +165,7 @@ void DebugFont::setAlign(Align align) DebugButton::DebugButton(int buttonID, DebugButtonReceiver *receiver, int bgWidth, int fsize, bool quitMain) : RenderObject(), label(0), highlight(0), quitMain(quitMain), receiver(receiver), buttonID(buttonID) + , activeAlpha(0.5f), activeColor(1,1,1), inactiveAlpha(0.5f), inactiveColor(0,0,0) { if (bgWidth == 0) bgWidth = 150; @@ -175,7 +176,8 @@ DebugButton::DebugButton(int buttonID, DebugButtonReceiver *receiver, int bgWidt highlight = new Quad(); highlight->setWidthHeight(szw, fsize); highlight->position = Vector(szw*0.5f, 0); - highlight->alpha = 0.5; + highlight->alpha = inactiveAlpha; + highlight->color = inactiveColor; addChild(highlight, PM_POINTER); label = new DebugFont(float(fsize)/3.0f, "DebugButton"); @@ -199,7 +201,8 @@ void DebugButton::onUpdate(float dt) if (highlight->isCoordinateInsideWorld(core->mouse.position) && ((!md) || (md && !core->mouse.buttons.left))) { - highlight->color.interpolateTo(Vector(1, 1, 1), 0.1); + highlight->color.interpolateTo(activeColor, 0.1); + highlight->alpha.interpolateTo(activeAlpha, 0.1); if (core->mouse.buttons.left && !md) md = true; @@ -224,7 +227,8 @@ void DebugButton::onUpdate(float dt) { md = false; } - highlight->color.interpolateTo(Vector(0,0,0), 0.1); + highlight->color.interpolateTo(inactiveColor, 0.1); + highlight->alpha.interpolateTo(inactiveAlpha, 0.1); } diff --git a/BBGE/DebugFont.h b/BBGE/DebugFont.h index 21f982a..7c46149 100644 --- a/BBGE/DebugFont.h +++ b/BBGE/DebugFont.h @@ -58,6 +58,10 @@ public: EventPtr event; bool quitMain; int buttonID; + float activeAlpha; + Vector activeColor; + float inactiveAlpha; + Vector inactiveColor; protected: void onUpdate(float dt); diff --git a/BBGE/Joystick.cpp b/BBGE/Joystick.cpp index b64ac61..cc4c44d 100644 --- a/BBGE/Joystick.cpp +++ b/BBGE/Joystick.cpp @@ -44,6 +44,8 @@ Joystick::Joystick() deadZone2 = 0.3; clearRumbleTime= 0; + numJoyAxes = 0; + clearAxes(); s1ax = 0; s1ay = 1; @@ -56,6 +58,7 @@ Joystick::Joystick() bool Joystick::init(int stick) { stickIndex = stick; + numJoyAxes = 0; #ifdef BBGE_BUILD_SDL2 if (SDL_IsGameController(stick)) @@ -88,7 +91,10 @@ bool Joystick::init(int stick) #ifdef BBGE_BUILD_SDL2 debugLog(std::string("Initialized Joystick [") + SDL_JoystickName(sdl_joy) + "]"); if (sdl_controller) + { debugLog("Joystick is a Game Controller"); + numJoyAxes = SDL_CONTROLLER_AXIS_MAX; + } if (sdl_haptic) debugLog("Joystick has force feedback support"); instanceID = SDL_JoystickInstanceID(sdl_joy); @@ -97,6 +103,11 @@ bool Joystick::init(int stick) instanceID = SDL_JoystickIndex(sdl_joy); #endif + if(!numJoyAxes) + numJoyAxes = SDL_JoystickNumAxes(sdl_joy); + if(numJoyAxes > MAX_JOYSTICK_AXIS) + numJoyAxes = MAX_JOYSTICK_AXIS; + return true; } @@ -126,6 +137,14 @@ void Joystick::shutdown() SDL_JoystickClose(sdl_joy); sdl_joy = 0; } + + numJoyAxes = 0; + clearAxes(); +} + +void Joystick::clearAxes() +{ + memset(axisRaw, 0, sizeof(axisRaw)); } void Joystick::rumble(float leftMotor, float rightMotor, float time) @@ -195,28 +214,18 @@ void Joystick::update(float dt) if (sdl_controller) { - Sint16 xaxis = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_LEFTX); - Sint16 yaxis = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_LEFTY); - position.x = float(xaxis)/32768.0f; - position.y = float(yaxis)/32768.0f; + for(int i = 0; i < numJoyAxes; ++i) + { + Sint16 ax = SDL_GameControllerGetAxis(sdl_controller, (SDL_GameControllerAxis)i); + axisRaw[i] = float(ax)/32768.0f; + } - Sint16 xaxis2 = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_RIGHTX); - Sint16 yaxis2 = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_RIGHTY); - rightStick.x = float(xaxis2)/32768.0f; - rightStick.y = float(yaxis2)/32768.0f; + position.x = axisRaw[SDL_CONTROLLER_AXIS_LEFTX]; + position.y = axisRaw[SDL_CONTROLLER_AXIS_LEFTY]; + rightStick.x = axisRaw[SDL_CONTROLLER_AXIS_RIGHTX]; + rightStick.y = axisRaw[SDL_CONTROLLER_AXIS_RIGHTY]; } else - { - Sint16 xaxis = SDL_JoystickGetAxis(sdl_joy, s1ax); - Sint16 yaxis = SDL_JoystickGetAxis(sdl_joy, s1ay); - position.x = float(xaxis)/32768.0f; - position.y = float(yaxis)/32768.0f; - - Sint16 xaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ax); - Sint16 yaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ay); - rightStick.x = float(xaxis2)/32768.0f; - rightStick.y = float(yaxis2)/32768.0f; - } #else if (!SDL_JoystickOpened(stickIndex)) { @@ -224,17 +233,19 @@ void Joystick::update(float dt) sdl_joy = NULL; return; } - - Sint16 xaxis = SDL_JoystickGetAxis(sdl_joy, s1ax); - Sint16 yaxis = SDL_JoystickGetAxis(sdl_joy, s1ay); - position.x = xaxis/32768.0f; - position.y = yaxis/32768.0f; - - Sint16 xaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ax); - Sint16 yaxis2 = SDL_JoystickGetAxis(sdl_joy, s2ay); - rightStick.x = xaxis2/32768.0f; - rightStick.y = yaxis2/32768.0f; #endif + // Note: this connects with the else above when the SDL2 path is compiled! + { + for(int i = 0; i < numJoyAxes; ++i) + { + Sint16 ax = SDL_JoystickGetAxis(sdl_joy, i); + axisRaw[i] = float(ax)/32768.0f; + } + position.x = axisRaw[s1ax]; + position.y = axisRaw[s1ay]; + rightStick.x = axisRaw[s2ax]; + rightStick.y = axisRaw[s2ay]; + } calibrate(position, deadZone1); calibrate(rightStick, deadZone2); @@ -269,3 +280,37 @@ bool Joystick::anyButton() const { return !!buttonBitmask;; } + +int Joystick::getNumAxes() const +{ +#ifdef BBGE_BUILD_SDL2 + return sdl_controller ? SDL_CONTROLLER_AXIS_MAX : numJoyAxes; +#else + return numJoyAxes; +#endif +} + +float Joystick::getAxisUncalibrated(int id) const +{ + return id < MAX_JOYSTICK_AXIS ? axisRaw[id] : 0.0f; +} + +const char *Joystick::getAxisName(int axis) const +{ + if(axis >= numJoyAxes) + return NULL; +#ifdef BBGE_BUILD_SDL2 + if(sdl_controller) + return SDL_GameControllerGetStringForAxis((SDL_GameControllerAxis)axis); +#endif + return NULL; +} + +const char *Joystick::getButtonName(int btn) const +{ +#ifdef BBGE_BUILD_SDL2 + if(sdl_controller) + return SDL_GameControllerGetStringForButton((SDL_GameControllerButton)btn); +#endif + return NULL; +} diff --git a/BBGE/Joystick.h b/BBGE/Joystick.h index 59e4f87..3a8407a 100644 --- a/BBGE/Joystick.h +++ b/BBGE/Joystick.h @@ -13,6 +13,8 @@ #define MAX_JOYSTICK_BTN 32 #define MAX_JOYSTICK_AXIS 32 +const static float JOY_AXIS_THRESHOLD = 0.6f; + class Joystick { public: @@ -32,20 +34,28 @@ public: void calibrate(Vector &vec, float dead); bool anyButton() const; bool getButton(unsigned id) const { return !!(buttonBitmask & (1u << id)); } + float getAxisUncalibrated(int id) const; + int getNumAxes() const; int getIndex() const { return stickIndex; } int getInstanceID() const { return instanceID; } inline bool isEnabled() const { return enabled; } + const char *getAxisName(int axis) const; + const char *getButtonName(int btn) const; + Vector rightStick; int s1ax, s1ay, s2ax, s2ay; private: + void clearAxes(); bool enabled; int stickIndex; int instanceID; - unsigned buttonBitmask; // FIXME: this should go + unsigned buttonBitmask; + int numJoyAxes; SDL_Joystick *sdl_joy; + float axisRaw[MAX_JOYSTICK_AXIS]; # ifdef BBGE_BUILD_SDL2 SDL_GameController *sdl_controller; diff --git a/files/data/stringbank.txt b/files/data/stringbank.txt index dc2e690..e108031 100644 --- a/files/data/stringbank.txt +++ b/files/data/stringbank.txt @@ -237,4 +237,10 @@ 2125 Food Right 2126 Food Drop 2127 Look -2128 Help \ No newline at end of file +2128 Help +2129 Song Slot # +2130 Category +2131 Mouse +2150 Movement +2151 Menu +2152 Quick Keys \ No newline at end of file