1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-02-24 15:04:00 +00:00

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.
This commit is contained in:
fgenesis 2016-07-13 05:00:19 +02:00
parent 082dcacad8
commit a043dd852f
19 changed files with 585 additions and 223 deletions

View file

@ -464,7 +464,7 @@ AquariaKeyConfig::AquariaKeyConfig(const std::string &actionInputName, InputSetT
if (inputSetType == INPUTSET_OTHER) if (inputSetType == INPUTSET_OTHER)
bg->setWidthHeight(40, 20); bg->setWidthHeight(40, 20);
else else
bg->setWidthHeight(100, 20); bg->setWidthHeight(90, 20);
bg->color = Vector(0.5, 0.5, 0.5); bg->color = Vector(0.5, 0.5, 0.5);
bg->alphaMod = 0; bg->alphaMod = 0;
@ -481,6 +481,7 @@ AquariaKeyConfig::AquariaKeyConfig(const std::string &actionInputName, InputSetT
keyDown = false; keyDown = false;
acceptEsc = false; acceptEsc = false;
joystickID = 0;
toggleEnterKey(false); toggleEnterKey(false);
} }
@ -598,7 +599,7 @@ void AquariaKeyConfig::onUpdate(float dt)
{ {
if (k) if (k)
{ {
keyConfigFont->setText(getInputCodeToString(*k)); keyConfigFont->setText(getInputCodeToUserString(*k, joystickID));
} }
else if (value) else if (value)
{ {
@ -660,7 +661,7 @@ void AquariaKeyConfig::onUpdate(float dt)
while (dsq->game->getKeyState(i)) while (dsq->game->getKeyState(i))
{ {
dsq->run(0.1); dsq->run(0.1f);
} }
toggleEnterKey(0); toggleEnterKey(0);
@ -672,36 +673,108 @@ void AquariaKeyConfig::onUpdate(float dt)
} }
break; break;
case INPUTSET_MOUSE: case INPUTSET_MOUSE:
{
bool clear = false;
int ac = 0;
if (core->getKeyState(KEY_DELETE) || core->getKeyState(KEY_BACKSPACE))
{
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; break;
case INPUTSET_JOY: case INPUTSET_JOY:
{ {
int ac = 0;
bool clear = false;
if (core->getKeyState(KEY_DELETE) || core->getKeyState(KEY_BACKSPACE)) if (core->getKeyState(KEY_DELETE) || core->getKeyState(KEY_BACKSPACE))
{ {
*k = 0; clear = true;
toggleEnterKey(0); }
waitingForInput = 0; else if(core->getKeyState(KEY_ESCAPE))
AquariaGuiElement::canDirMoveGlobal = true; {
// do nothing
} }
else else
{ {
for (int i = JOY_BUTTON_0; i <= MAX_JOYSTICK_BTN; i++) Joystick *j = core->joysticks[joystickID];
if(j)
{ {
if (dsq->game->getKeyState(i)) for (int i = 0; i < MAX_JOYSTICK_BTN; i++)
if (j->getButton(i))
{ {
*k = i; ac = JOY_BUTTON_0 + i;
while (j->getButton(i))
while (dsq->game->getKeyState(i)) dsq->run(0.1f);
{ break;
dsq->run(0.1);
} }
toggleEnterKey(0); if(!ac)
waitingForInput = 0; for(int i = 0; i < MAX_JOYSTICK_AXIS; ++i)
AquariaGuiElement::canDirMoveGlobal = true; {
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; 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; break;
} }

View file

@ -171,6 +171,7 @@ public:
static AquariaKeyConfig *waitingForInput; static AquariaKeyConfig *waitingForInput;
void setAcceptEsc(bool a); void setAcceptEsc(bool a);
void setJoystickID(int id);
protected: protected:
void toggleEnterKey(int on); void toggleEnterKey(int on);
@ -185,6 +186,7 @@ protected:
int inputIdx; int inputIdx;
TTFText *keyConfigFont; TTFText *keyConfigFont;
Quad *bg; Quad *bg;
int joystickID;
bool acceptEsc; bool acceptEsc;
}; };

View file

@ -128,24 +128,14 @@ void Avatar::bindInput()
ActionMapper::clearActions(); ActionMapper::clearActions();
ActionMapper::clearCreatedEvents(); ActionMapper::clearCreatedEvents();
dsq->user.control.actionSet.importAction(this, "PrimaryAction", ACTION_PRIMARY); dsq->user.control.actionSet.importAction(this, "PrimaryAction", ACTION_PRIMARY);
dsq->user.control.actionSet.importAction(this, "SecondaryAction", ACTION_SECONDARY); 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, "SwimUp", ACTION_SWIMUP);
dsq->user.control.actionSet.importAction(this, "SwimDown", ACTION_SWIMDOWN); dsq->user.control.actionSet.importAction(this, "SwimDown", ACTION_SWIMDOWN);
dsq->user.control.actionSet.importAction(this, "SwimLeft", ACTION_SWIMLEFT); dsq->user.control.actionSet.importAction(this, "SwimLeft", ACTION_SWIMLEFT);
dsq->user.control.actionSet.importAction(this, "SwimRight", ACTION_SWIMRIGHT); 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, "SongSlot1", ACTION_SONGSLOT1);
dsq->user.control.actionSet.importAction(this, "SongSlot2", ACTION_SONGSLOT2); dsq->user.control.actionSet.importAction(this, "SongSlot2", ACTION_SONGSLOT2);
dsq->user.control.actionSet.importAction(this, "SongSlot3", ACTION_SONGSLOT3); 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, "SongSlot9", ACTION_SONGSLOT9);
dsq->user.control.actionSet.importAction(this, "SongSlot10", ACTION_SONGSLOT10); 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, "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); 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 // note: z is set to 1.0 when we want the aim to be used as the shot direction
@ -4226,13 +4196,13 @@ Vector Avatar::getFakeCursorPosition()
{ {
axisInput = j->position.getLength2D(); axisInput = j->position.getLength2D();
if(axisInput >= JOYSTICK_LOW_THRESHOLD) if(axisInput >= JOYSTICK_LOW_THRESHOLD)
break; {
}
const float axisMult = (maxMouse - minMouse) / (JOYSTICK_HIGH_THRESHOLD - JOYSTICK_LOW_THRESHOLD); const float axisMult = (maxMouse - minMouse) / (JOYSTICK_HIGH_THRESHOLD - JOYSTICK_LOW_THRESHOLD);
const float distance = minMouse + ((axisInput - JOYSTICK_LOW_THRESHOLD) * axisMult); const float distance = minMouse + ((axisInput - JOYSTICK_LOW_THRESHOLD) * axisMult);
return (j->position * (distance / axisInput)); return (j->position * (distance / axisInput));
} }
}
}
return Vector(0,0,0); return Vector(0,0,0);
} }

View file

@ -3744,8 +3744,8 @@ void DSQ::bindInput()
{ {
clearActions(); clearActions();
almb = user.control.actionSet.getActionInputByName("lmb"); almb = user.control.actionSet.getActionInputByName("PrimaryAction");
armb = user.control.actionSet.getActionInputByName("rmb"); armb = user.control.actionSet.getActionInputByName("SecondaryAction");
user.control.actionSet.importAction(this, "Escape", ACTION_ESC); user.control.actionSet.importAction(this, "Escape", ACTION_ESC);
@ -3988,7 +3988,17 @@ void DSQ::onUpdate(float dt)
os << std::endl; os << std::endl;
os << "globalScale: " << core->globalScale.x << 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 << "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 << "altState: " << core->getKeyState(KEY_LALT) << " | " << core->getKeyState(KEY_RALT) << std::endl;
os << "PMFree: " << particleManager->getFree() << " Active: " << particleManager->getNumActive() << std::endl; os << "PMFree: " << particleManager->getFree() << " Active: " << particleManager->getNumActive() << std::endl;
os << "cameraPos: (" << dsq->cameraPos.x << ", " << dsq->cameraPos.y << ")" << std::endl; os << "cameraPos: (" << dsq->cameraPos.x << ", " << dsq->cameraPos.y << ")" << std::endl;

View file

@ -2540,6 +2540,12 @@ void Game::action(int id, int state, int source)
if(isIgnoreAction((AquariaActions)id)) if(isIgnoreAction((AquariaActions)id))
return; return;
// forward
if(id == ACTION_TOGGLEMENU)
{
themenu->action(id, state, source);
}
if (id == ACTION_TOGGLEHELPSCREEN && !state) if (id == ACTION_TOGGLEHELPSCREEN && !state)
{ {
onToggleHelpScreen(); onToggleHelpScreen();
@ -3787,8 +3793,10 @@ void Game::onPressEscape()
if (!paused) if (!paused)
{ {
if (core->getNestedMains() == 1 && !core->isStateJumpPending()) if (core->getNestedMains() == 1 && !core->isStateJumpPending())
{
action(ACTION_TOGGLEMENU, 1, -1); // show menu action(ACTION_TOGGLEMENU, 1, -1); // show menu
} }
}
if ((dsq->saveSlotMode != SSM_NONE || dsq->inModSelector) && core->isNested()) if ((dsq->saveSlotMode != SSM_NONE || dsq->inModSelector) && core->isNested())
{ {

View file

@ -8,6 +8,7 @@
#include "DSQ.h" #include "DSQ.h"
#include "Avatar.h" #include "Avatar.h"
#include "GridRender.h" #include "GridRender.h"
#include "DebugFont.h"
static InGameMenu *themenu = 0; static InGameMenu *themenu = 0;
@ -26,6 +27,21 @@ const int numTreasures = 16*2;
const Vector worldLeftCenter(217,250), worldRightCenter(575, 250); const Vector worldLeftCenter(217,250), worldRightCenter(575, 250);
const Vector opt_save_original = Vector(350, 350), opt_cancel_original = Vector(450, 350); 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 --------------- // --------- Private class defs, not used outside ---------------
@ -1240,6 +1256,7 @@ void InGameMenu::show(bool ignoreInput, bool optionsOnly, MenuPage menuPage)
opt_cancel->setHidden(false); opt_cancel->setHidden(false);
options->setHidden(false); options->setHidden(false);
keyConfigButton->setHidden(false); keyConfigButton->setHidden(false);
keyConfigBg->setHidden(false);
cook->setHidden(false); cook->setHidden(false);
foodSort->setHidden(false); foodSort->setHidden(false);
recipes->setHidden(false); recipes->setHidden(false);
@ -1458,6 +1475,7 @@ void InGameMenu::hide(bool effects, bool cancel)
opt_cancel->setHidden(true); opt_cancel->setHidden(true);
options->setHidden(true); options->setHidden(true);
keyConfigButton->setHidden(true); keyConfigButton->setHidden(true);
keyConfigBg->setHidden(true);
cook->setHidden(true); cook->setHidden(true);
foodSort->setHidden(true); foodSort->setHidden(true);
recipes->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); TTFText *lb = new TTFText(&dsq->fontArialSmallest);
lb->setText(label); lb->setText(label);
lb->position = Vector(140,y); lb->position = Vector(x,y);
group->addChild(lb, PM_POINTER); 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); AquariaKeyConfig *k1 = new AquariaKeyConfig(actionInputName, INPUTSET_KEY, 0);
k1->position = Vector(350,y); k1->position = Vector(x,y);
group->addChild(k1, PM_POINTER); group->addChild(k1, PM_POINTER);
k1->setAcceptEsc(acceptEsc); k1->setAcceptEsc(acceptEsc);
x += KEYCONFIG_COL_DISTANCE;
AquariaKeyConfig *k2 = new AquariaKeyConfig(actionInputName, INPUTSET_KEY, 1); AquariaKeyConfig *k2 = new AquariaKeyConfig(actionInputName, INPUTSET_KEY, 1);
k2->position = Vector(475,y); k2->position = Vector(x,y);
group->addChild(k2, PM_POINTER); group->addChild(k2, PM_POINTER);
k2->setAcceptEsc(acceptEsc); k2->setAcceptEsc(acceptEsc);
x += KEYCONFIG_COL_DISTANCE;
AquariaKeyConfig *j1 = new AquariaKeyConfig(actionInputName, INPUTSET_JOY, 0); AquariaKeyConfig *j1 = new AquariaKeyConfig(actionInputName, INPUTSET_JOY, 0);
j1->position = Vector(600,y); j1->position = Vector(x,y);
group->addChild(j1, PM_POINTER); group->addChild(j1, PM_POINTER);
x += KEYCONFIG_COL_DISTANCE;
k1->setDirMove(DIR_RIGHT, k2); k1->setDirMove(DIR_RIGHT, k2);
k2->setDirMove(DIR_RIGHT, j1); k2->setDirMove(DIR_RIGHT, j1);
@ -1518,15 +1545,15 @@ void InGameMenu::addKeyConfigLine(RenderObject *group, const std::string &label,
k2->setDirMove(DIR_LEFT, k1); 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); TTFText *lb = new TTFText(&dsq->fontArialSmallest);
lb->setText(label); lb->setText(label);
lb->position = Vector(140+offx, y); lb->position = Vector(offx, y);
group->addChild(lb, PM_POINTER); group->addChild(lb, PM_POINTER);
AquariaKeyConfig *i1 = new AquariaKeyConfig(actionInputName, INPUTSET_OTHER, 0); AquariaKeyConfig *i1 = new AquariaKeyConfig(actionInputName, INPUTSET_OTHER, 0);
i1->position = Vector(140+80+offx,y); i1->position = Vector(80+offx,y);
//i1->setLock(l1); //i1->setLock(l1);
group->addChild(i1, PM_POINTER); 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() void InGameMenu::create()
{ {
float menuz = 4; float menuz = 4;
@ -1910,67 +1950,94 @@ void InGameMenu::create()
game->addRenderObject(keyConfigButton, LR_MENU); 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) #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); TTFText *header_action = new TTFText(&dsq->fontArialSmall);
header_action->setText(SB(2101)); header_action->setText(SB(2101));
header_action->position = Vector(140, 80+offy); header_action->position = Vector(offx, offy);
group_keyConfig->addChild(header_action, PM_POINTER); 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); TTFText *header_key1 = new TTFText(&dsq->fontArialSmall);
header_key1->setText(SB(2102)); 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); 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); TTFText *header_key2 = new TTFText(&dsq->fontArialSmall);
header_key2->setText(SB(2103)); 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); 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); TTFText *header_joy = new TTFText(&dsq->fontArialSmall);
header_joy->setText(SB(2104)); 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); 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); offy += 2*yi;
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);
AquariaKeyConfig* s1x = addAxesConfigLine(group_keyConfig, SB(2117), "s1ax", 340+offy, 0); // PART 1
AquariaKeyConfig* s1y = addAxesConfigLine(group_keyConfig, SB(2118), "s1ay", 340+offy, 130); {
AquariaKeyConfig* s2x = addAxesConfigLine(group_keyConfig, SB(2119), "s2ax", 340+offy, 260); RenderObject *kk = createBasicKeyConfig();
AquariaKeyConfig* s2y = addAxesConfigLine(group_keyConfig, SB(2120), "s2ay", 340+offy, 380); group_keyConfig[0] = kk;
int y = 0;
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);
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;
s1x->setDirMove(DIR_LEFT, s1x); s1x->setDirMove(DIR_LEFT, s1x);
s1x->setDirMove(DIR_RIGHT, s1y); s1x->setDirMove(DIR_RIGHT, s1y);
@ -1983,32 +2050,44 @@ void InGameMenu::create()
s2y->setDirMove(DIR_LEFT, s2x); s2y->setDirMove(DIR_LEFT, s2x);
s2y->setDirMove(DIR_RIGHT, s2y); s2y->setDirMove(DIR_RIGHT, s2y);
}
offy += 20; // PART 2
{
RenderObject *kk = createBasicKeyConfig();
group_keyConfig[1] = kk;
addKeyConfigLine(group_keyConfig, SB(2121), "PrevPage", 340+offy); int y = 0;
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);
addKeyConfigLine(group_keyConfig, SB(2127), "Look", 460+offy); 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 #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 = new AquariaMenuItem;
cook->useQuad("Gui/cook-button"); cook->useQuad("Gui/cook-button");
cook->useGlow("particles/glow", 128, 40); cook->useGlow("particles/glow", 128, 40);
@ -3604,27 +3683,28 @@ void InGameMenu::toggleKeyConfigMenu(bool f)
keyConfigMenu = true; keyConfigMenu = true;
group_keyConfig->setHidden(false); keyConfigBg->setHidden(false);
group_keyConfig->alpha = 1; keyConfigBg->alpha = 1;
dsq->user_bcontrol = dsq->user; 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++);
//group_keyConfig->children[group_keyConfig->children.size()-3] //opt_cancel->setDirMove(DIR_UP, upright);
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); upright->setDirMove(DIR_DOWN, opt_cancel);
upright0->setDirMove(DIR_DOWN, opt_cancel); upright0->setDirMove(DIR_DOWN, opt_cancel);
opt_save->setDirMove(DIR_UP, upleft); //opt_save->setDirMove(DIR_UP, upleft);
upleft->setDirMove(DIR_DOWN, opt_save); upleft->setDirMove(DIR_DOWN, opt_save);
}
switchToKeyConfigPage(0);
dsq->user_bcontrol = dsq->user;
opt_cancel->alpha = 1; opt_cancel->alpha = 1;
opt_save->alpha = 1; opt_save->alpha = 1;
@ -3641,8 +3721,8 @@ void InGameMenu::toggleKeyConfigMenu(bool f)
{ {
keyConfigMenu = false; keyConfigMenu = false;
group_keyConfig->alpha = 0; keyConfigBg->setHidden(true);
group_keyConfig->setHidden(true); keyConfigBg->alpha = 0;
opt_cancel->alpha = 0; opt_cancel->alpha = 0;
opt_save->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) void InGameMenu::toggleOptionsMenu(bool f, bool skipBackup, bool isKeyConfig)
{ {
const float t = 0; const float t = 0;

View file

@ -21,6 +21,8 @@ class AquariaSlider;
class AquariaComboBox; class AquariaComboBox;
class RecipeMenuEntry; class RecipeMenuEntry;
class Recipe; class Recipe;
class RoundedRect;
class DebugButton;
enum MenuPage enum MenuPage
@ -66,6 +68,8 @@ class InGameMenu : public ActionMapper
friend class TreasureSlot; friend class TreasureSlot;
friend class SongSlot; friend class SongSlot;
friend class FoodHolder; friend class FoodHolder;
friend class KeyConfigMenuReceiver;
enum { NUM_KEY_CONFIG_PAGES = 3 };
public: public:
InGameMenu(); InGameMenu();
@ -188,9 +192,9 @@ private:
void onKeyConfig(); 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 onOptionsSave();
void onOptionsCancel(); void onOptionsCancel();
@ -200,8 +204,11 @@ private:
AquariaComboBox *resBox; AquariaComboBox *resBox;
Quad *songBubbles, *energyIdol, *liCrystal; Quad *songBubbles, *energyIdol, *liCrystal;
RenderObject *group_keyConfig; RenderObject *group_keyConfig[NUM_KEY_CONFIG_PAGES];
RoundedRect *keyConfigBg;
std::vector<DebugButton*> keyCategoryButtons;
RenderObject *createBasicKeyConfig();
void switchToKeyConfigPage(int page);
Quad *options; Quad *options;
void onExitCheckNo(); void onExitCheckNo();

View file

@ -312,9 +312,6 @@ void UserSettings::load(bool doApply, const std::string &overrideFile)
control.actionSet.clearActions(); control.actionSet.clearActions();
control.actionSet.addActionInput("lmb");
control.actionSet.addActionInput("rmb");
control.actionSet.addActionInput("PrimaryAction"); control.actionSet.addActionInput("PrimaryAction");
control.actionSet.addActionInput("SecondaryAction"); control.actionSet.addActionInput("SecondaryAction");
control.actionSet.addActionInput("SwimUp"); control.actionSet.addActionInput("SwimUp");
@ -535,13 +532,16 @@ void UserSettings::apply()
dsq->loops.updateVolume(); dsq->loops.updateVolume();
// FIXME: This should be per-joystick // FIXME: This should be per-joystick
/*core->joystick.s1ax = control.s1ax; for(size_t i = 0; i < core->joysticks.size(); ++i)
core->joystick.s1ay = control.s1ay; {
core->joystick.s2ax = control.s2ax; Joystick *j = core->joysticks[i];
core->joystick.s2ay = control.s2ay; j->s1ax = control.s1ax;
j->s1ay = control.s1ay;
core->joystick.deadZone1 = control.s1dead; j->s2ax = control.s2ax;
core->joystick.deadZone2 = control.s2dead;*/ j->s2ay = control.s2ay;
j->deadZone1 = control.s1dead;
j->deadZone2 = control.s2dead;
}
core->debugLogActive = system.debugLogOn; core->debugLogActive = system.debugLogOn;

View file

@ -21,14 +21,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "ActionInput.h" #include "ActionInput.h"
#include "ActionMapper.h" #include "ActionMapper.h"
#include "Core.h"
#include "SDL.h" #include "SDL.h"
#ifndef BBGE_BUILD_SDL2 #ifndef BBGE_BUILD_SDL2
#error Needs fixes for SDL 1.2, doesnt support scancodes #error Needs fixes for SDL 1.2, doesnt support scancodes
#endif #endif
static std::string inputcode2string(int k)
std::string getInputCodeToString(int k)
{ {
if(k <= 0) if(k <= 0)
return std::string(); return std::string();
@ -50,6 +50,20 @@ std::string getInputCodeToString(int k)
return os.str(); 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) switch(k)
{ {
case MOUSE_BUTTON_LEFT: case MOUSE_BUTTON_LEFT:
@ -58,11 +72,66 @@ std::string getInputCodeToString(int k)
return "RMB"; return "RMB";
case MOUSE_BUTTON_MIDDLE: case MOUSE_BUTTON_MIDDLE:
return "MMB"; 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(); 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) int getStringToInputCode(const std::string& s)
{ {
if(s == "LMB") if(s == "LMB")
@ -75,8 +144,22 @@ int getStringToInputCode(const std::string& s)
return atoi(s.c_str() + 2); return atoi(s.c_str() + 2);
if(!strncmp(s.c_str(), "JB:", 3)) if(!strncmp(s.c_str(), "JB:", 3))
return JOY_BUTTON_0 + atoi(s.c_str() + 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());
} }

View file

@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define INP_JOYSIZE 1 #define INP_JOYSIZE 1
std::string getInputCodeToString(int k); std::string getInputCodeToString(int k);
std::string getInputCodeToUserString(int k, int joystickID);
int getStringToInputCode(const std::string& s); int getStringToInputCode(const std::string& s);
class ActionInput class ActionInput

View file

@ -195,6 +195,10 @@ bool ActionMapper::getKeyState(int k)
{ {
keyState = (core->mouse.buttons.middle == DOWN); 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) else if (k >= JOY_BUTTON_0 && k < JOY_BUTTON_END)
{ {
int v = k - JOY_BUTTON_0; int v = k - JOY_BUTTON_0;
@ -205,6 +209,34 @@ bool ActionMapper::getKeyState(int k)
if( ((keyState = j->getButton(v))) ) if( ((keyState = j->getButton(v))) )
break; 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; return keyState;
} }

View file

@ -45,15 +45,18 @@ struct ActionData
enum ActionButtonType enum ActionButtonType
{ {
// must start at > 512 (SDL scancodes end there) // must start at > 512 (SDL scancodes end there)
MOUSE_BUTTON_LEFT = 999, MOUSE_BUTTON_LEFT = 1000,
MOUSE_BUTTON_RIGHT = 1000, MOUSE_BUTTON_RIGHT = 1001,
MOUSE_BUTTON_MIDDLE = 1001, MOUSE_BUTTON_MIDDLE = 1002,
MOUSE_BUTTON_EXTRA_START = 1003,
JOY_BUTTON_0 = 2000, JOY_BUTTON_0 = 2000,
JOY_BUTTON_END = JOY_BUTTON_0 + MAX_JOYSTICK_BTN, // one past end JOY_BUTTON_END = JOY_BUTTON_0 + MAX_JOYSTICK_BTN, // one past end
JOY_AXIS_0 = 3000, JOY_AXIS_0_POS = 3000,
JOY_AXIS_END = JOY_AXIS_0 + MAX_JOYSTICK_AXIS, 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 class ActionMapper

View file

@ -627,9 +627,10 @@ void Core::initJoystickLibrary()
SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER); SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER);
#else #else
SDL_InitSubSystem(SDL_INIT_JOYSTICK); SDL_InitSubSystem(SDL_INIT_JOYSTICK);
detectJoysticks();
#endif #endif
detectJoysticks(); joystickEnabled = true;
} }
void Core::clearJoysticks() void Core::clearJoysticks()
@ -639,6 +640,9 @@ void Core::clearJoysticks()
joysticks.clear(); joysticks.clear();
} }
// Only used for SDL 1.2 code path.
// SDL2 automatically fires joystick added events upon startup
void Core::detectJoysticks() void Core::detectJoysticks()
{ {
clearJoysticks(); clearJoysticks();
@ -648,6 +652,7 @@ void Core::detectJoysticks()
os << "Found [" << n << "] joysticks"; os << "Found [" << n << "] joysticks";
debugLog(os.str()); debugLog(os.str());
joysticks.reserve(n);
for(unsigned i = 0; i < n; ++i) for(unsigned i = 0; i < n; ++i)
{ {
Joystick *j = new Joystick; Joystick *j = new Joystick;
@ -656,8 +661,6 @@ void Core::detectJoysticks()
else else
delete j; delete j;
} }
joystickEnabled = !joysticks.empty();
} }
bool Core::initInputLibrary() bool Core::initInputLibrary()
@ -685,6 +688,7 @@ void Core::onUpdate(float dt)
pollEvents(); pollEvents();
for(size_t i = 0; i < joysticks.size(); ++i) for(size_t i = 0; i < joysticks.size(); ++i)
if(joysticks[i])
joysticks[i]->update(dt); joysticks[i]->update(dt);
onMouseInput(); onMouseInput();
@ -1587,7 +1591,7 @@ void Core::pollEvents()
if (updateMouse) if (updateMouse)
{ {
int x, y; int x, y;
Uint8 mousestate = SDL_GetMouseState(&x,&y); unsigned mousestate = SDL_GetMouseState(&x,&y);
if (mouse.buttonsEnabled) if (mouse.buttonsEnabled)
{ {
@ -1595,7 +1599,11 @@ void Core::pollEvents()
mouse.buttons.right = mousestate & SDL_BUTTON(3)?DOWN:UP; mouse.buttons.right = mousestate & SDL_BUTTON(3)?DOWN:UP;
mouse.buttons.middle = mousestate & SDL_BUTTON(2)?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.pure_buttons = mouse.buttons;
mouse.rawButtonMask = mousestate;
if (flipMouseButtons) if (flipMouseButtons)
{ {

View file

@ -76,6 +76,8 @@ const int baseVirtualHeight = 600;
enum ButtonState { UP = 0, DOWN }; enum ButtonState { UP = 0, DOWN };
const unsigned mouseExtraButtons = 8;
struct MouseButtons struct MouseButtons
{ {
MouseButtons () MouseButtons ()
@ -86,6 +88,7 @@ struct MouseButtons
} }
ButtonState left, right, middle; ButtonState left, right, middle;
ButtonState extra[mouseExtraButtons];
}; };
struct Mouse struct Mouse
@ -94,16 +97,13 @@ struct Mouse
{ {
scrollWheel = scrollWheelChange = lastScrollWheel = 0; scrollWheel = scrollWheelChange = lastScrollWheel = 0;
buttonsEnabled = true; buttonsEnabled = true;
movementEnabled = true;
} }
Vector position, lastPosition; Vector position, lastPosition;
MouseButtons buttons; MouseButtons buttons;
MouseButtons pure_buttons; MouseButtons pure_buttons;
unsigned rawButtonMask;
Vector change; Vector change;
bool buttonsEnabled;
// movementEnabled is not implemented yet
bool buttonsEnabled, movementEnabled;
int scrollWheel, scrollWheelChange, lastScrollWheel; int scrollWheel, scrollWheelChange, lastScrollWheel;
}; };

View file

@ -165,6 +165,7 @@ void DebugFont::setAlign(Align align)
DebugButton::DebugButton(int buttonID, DebugButtonReceiver *receiver, int bgWidth, int fsize, bool quitMain) DebugButton::DebugButton(int buttonID, DebugButtonReceiver *receiver, int bgWidth, int fsize, bool quitMain)
: RenderObject(), label(0), highlight(0), quitMain(quitMain), receiver(receiver), buttonID(buttonID) : 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) if (bgWidth == 0)
bgWidth = 150; bgWidth = 150;
@ -175,7 +176,8 @@ DebugButton::DebugButton(int buttonID, DebugButtonReceiver *receiver, int bgWidt
highlight = new Quad(); highlight = new Quad();
highlight->setWidthHeight(szw, fsize); highlight->setWidthHeight(szw, fsize);
highlight->position = Vector(szw*0.5f, 0); highlight->position = Vector(szw*0.5f, 0);
highlight->alpha = 0.5; highlight->alpha = inactiveAlpha;
highlight->color = inactiveColor;
addChild(highlight, PM_POINTER); addChild(highlight, PM_POINTER);
label = new DebugFont(float(fsize)/3.0f, "DebugButton"); 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))) 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) if (core->mouse.buttons.left && !md)
md = true; md = true;
@ -224,7 +227,8 @@ void DebugButton::onUpdate(float dt)
{ {
md = false; md = false;
} }
highlight->color.interpolateTo(Vector(0,0,0), 0.1); highlight->color.interpolateTo(inactiveColor, 0.1);
highlight->alpha.interpolateTo(inactiveAlpha, 0.1);
} }

View file

@ -58,6 +58,10 @@ public:
EventPtr event; EventPtr event;
bool quitMain; bool quitMain;
int buttonID; int buttonID;
float activeAlpha;
Vector activeColor;
float inactiveAlpha;
Vector inactiveColor;
protected: protected:
void onUpdate(float dt); void onUpdate(float dt);

View file

@ -44,6 +44,8 @@ Joystick::Joystick()
deadZone2 = 0.3; deadZone2 = 0.3;
clearRumbleTime= 0; clearRumbleTime= 0;
numJoyAxes = 0;
clearAxes();
s1ax = 0; s1ax = 0;
s1ay = 1; s1ay = 1;
@ -56,6 +58,7 @@ Joystick::Joystick()
bool Joystick::init(int stick) bool Joystick::init(int stick)
{ {
stickIndex = stick; stickIndex = stick;
numJoyAxes = 0;
#ifdef BBGE_BUILD_SDL2 #ifdef BBGE_BUILD_SDL2
if (SDL_IsGameController(stick)) if (SDL_IsGameController(stick))
@ -88,7 +91,10 @@ bool Joystick::init(int stick)
#ifdef BBGE_BUILD_SDL2 #ifdef BBGE_BUILD_SDL2
debugLog(std::string("Initialized Joystick [") + SDL_JoystickName(sdl_joy) + "]"); debugLog(std::string("Initialized Joystick [") + SDL_JoystickName(sdl_joy) + "]");
if (sdl_controller) if (sdl_controller)
{
debugLog("Joystick is a Game Controller"); debugLog("Joystick is a Game Controller");
numJoyAxes = SDL_CONTROLLER_AXIS_MAX;
}
if (sdl_haptic) if (sdl_haptic)
debugLog("Joystick has force feedback support"); debugLog("Joystick has force feedback support");
instanceID = SDL_JoystickInstanceID(sdl_joy); instanceID = SDL_JoystickInstanceID(sdl_joy);
@ -97,6 +103,11 @@ bool Joystick::init(int stick)
instanceID = SDL_JoystickIndex(sdl_joy); instanceID = SDL_JoystickIndex(sdl_joy);
#endif #endif
if(!numJoyAxes)
numJoyAxes = SDL_JoystickNumAxes(sdl_joy);
if(numJoyAxes > MAX_JOYSTICK_AXIS)
numJoyAxes = MAX_JOYSTICK_AXIS;
return true; return true;
} }
@ -126,6 +137,14 @@ void Joystick::shutdown()
SDL_JoystickClose(sdl_joy); SDL_JoystickClose(sdl_joy);
sdl_joy = 0; sdl_joy = 0;
} }
numJoyAxes = 0;
clearAxes();
}
void Joystick::clearAxes()
{
memset(axisRaw, 0, sizeof(axisRaw));
} }
void Joystick::rumble(float leftMotor, float rightMotor, float time) void Joystick::rumble(float leftMotor, float rightMotor, float time)
@ -195,28 +214,18 @@ void Joystick::update(float dt)
if (sdl_controller) if (sdl_controller)
{ {
Sint16 xaxis = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_LEFTX); for(int i = 0; i < numJoyAxes; ++i)
Sint16 yaxis = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_LEFTY); {
position.x = float(xaxis)/32768.0f; Sint16 ax = SDL_GameControllerGetAxis(sdl_controller, (SDL_GameControllerAxis)i);
position.y = float(yaxis)/32768.0f; axisRaw[i] = float(ax)/32768.0f;
}
Sint16 xaxis2 = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_RIGHTX); position.x = axisRaw[SDL_CONTROLLER_AXIS_LEFTX];
Sint16 yaxis2 = SDL_GameControllerGetAxis(sdl_controller, SDL_CONTROLLER_AXIS_RIGHTY); position.y = axisRaw[SDL_CONTROLLER_AXIS_LEFTY];
rightStick.x = float(xaxis2)/32768.0f; rightStick.x = axisRaw[SDL_CONTROLLER_AXIS_RIGHTX];
rightStick.y = float(yaxis2)/32768.0f; rightStick.y = axisRaw[SDL_CONTROLLER_AXIS_RIGHTY];
} }
else 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 #else
if (!SDL_JoystickOpened(stickIndex)) if (!SDL_JoystickOpened(stickIndex))
{ {
@ -224,17 +233,19 @@ void Joystick::update(float dt)
sdl_joy = NULL; sdl_joy = NULL;
return; 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 #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(position, deadZone1);
calibrate(rightStick, deadZone2); calibrate(rightStick, deadZone2);
@ -269,3 +280,37 @@ bool Joystick::anyButton() const
{ {
return !!buttonBitmask;; 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;
}

View file

@ -13,6 +13,8 @@
#define MAX_JOYSTICK_BTN 32 #define MAX_JOYSTICK_BTN 32
#define MAX_JOYSTICK_AXIS 32 #define MAX_JOYSTICK_AXIS 32
const static float JOY_AXIS_THRESHOLD = 0.6f;
class Joystick class Joystick
{ {
public: public:
@ -32,20 +34,28 @@ public:
void calibrate(Vector &vec, float dead); void calibrate(Vector &vec, float dead);
bool anyButton() const; bool anyButton() const;
bool getButton(unsigned id) const { return !!(buttonBitmask & (1u << id)); } bool getButton(unsigned id) const { return !!(buttonBitmask & (1u << id)); }
float getAxisUncalibrated(int id) const;
int getNumAxes() const;
int getIndex() const { return stickIndex; } int getIndex() const { return stickIndex; }
int getInstanceID() const { return instanceID; } int getInstanceID() const { return instanceID; }
inline bool isEnabled() const { return enabled; } inline bool isEnabled() const { return enabled; }
const char *getAxisName(int axis) const;
const char *getButtonName(int btn) const;
Vector rightStick; Vector rightStick;
int s1ax, s1ay, s2ax, s2ay; int s1ax, s1ay, s2ax, s2ay;
private: private:
void clearAxes();
bool enabled; bool enabled;
int stickIndex; int stickIndex;
int instanceID; int instanceID;
unsigned buttonBitmask; // FIXME: this should go unsigned buttonBitmask;
int numJoyAxes;
SDL_Joystick *sdl_joy; SDL_Joystick *sdl_joy;
float axisRaw[MAX_JOYSTICK_AXIS];
# ifdef BBGE_BUILD_SDL2 # ifdef BBGE_BUILD_SDL2
SDL_GameController *sdl_controller; SDL_GameController *sdl_controller;

View file

@ -238,3 +238,9 @@
2126 Food Drop 2126 Food Drop
2127 Look 2127 Look
2128 Help 2128 Help
2129 Song Slot #
2130 Category
2131 Mouse
2150 Movement
2151 Menu
2152 Quick Keys