diff --git a/source/funkin/backend/system/Controls.hx b/source/funkin/backend/system/Controls.hx index 651b510f..72cd2c46 100644 --- a/source/funkin/backend/system/Controls.hx +++ b/source/funkin/backend/system/Controls.hx @@ -8,53 +8,6 @@ import flixel.input.actions.FlxActionSet; import flixel.input.gamepad.FlxGamepadInputID; import flixel.input.keyboard.FlxKey; -enum abstract Action(String) to String from String { - var UP = "up"; - var LEFT = "left"; - var RIGHT = "right"; - var DOWN = "down"; - var UP_P = "up-press"; - var LEFT_P = "left-press"; - var RIGHT_P = "right-press"; - var DOWN_P = "down-press"; - var UP_R = "up-release"; - var LEFT_R = "left-release"; - var RIGHT_R = "right-release"; - var DOWN_R = "down-release"; - - - var NOTE_UP = "note-up"; - var NOTE_LEFT = "note-left"; - var NOTE_RIGHT = "note-right"; - var NOTE_DOWN = "note-down"; - var NOTE_UP_P = "note-up-press"; - var NOTE_LEFT_P = "note-left-press"; - var NOTE_RIGHT_P = "note-right-press"; - var NOTE_DOWN_P = "note-down-press"; - var NOTE_UP_R = "note-up-release"; - var NOTE_LEFT_R = "note-left-release"; - var NOTE_RIGHT_R = "note-right-release"; - var NOTE_DOWN_R = "note-down-release"; - - var ACCEPT = "accept"; - var BACK = "back"; - var PAUSE = "pause"; - var RESET = "reset"; - var CHEAT = "cheat"; - var SWITCHMOD = "switchmod"; -} - -enum Device -{ - Keys; - Gamepad(id:Int); -} - -/** - * Since, in many cases multiple actions should use similar keys, we don't want the - * rebinding UI to list every action. ActionBinders are what the user perceives as - * an input so, for instance, they can't set jump-press and jump-release to different keys. - */ enum Control { UP; @@ -69,7 +22,7 @@ enum Control ACCEPT; BACK; PAUSE; - CHEAT; + //CHEAT; SWITCHMOD; } @@ -85,327 +38,128 @@ enum KeyboardScheme * A list of actions that a player would invoke via some input device. * Uses FlxActions to funnel various inputs to a single action. */ +// Macro generated +// A and B are swapped for switch @:noCustomClass +@:nullSafety +@:build(funkin.backend.system.macros.ControlsMacro.build()) class Controls extends FlxActionSet { - var _up = new FlxActionDigital(Action.UP); - var _left = new FlxActionDigital(Action.LEFT); - var _right = new FlxActionDigital(Action.RIGHT); - var _down = new FlxActionDigital(Action.DOWN); - var _upP = new FlxActionDigital(Action.UP_P); - var _leftP = new FlxActionDigital(Action.LEFT_P); - var _rightP = new FlxActionDigital(Action.RIGHT_P); - var _downP = new FlxActionDigital(Action.DOWN_P); - var _upR = new FlxActionDigital(Action.UP_R); - var _leftR = new FlxActionDigital(Action.LEFT_R); - var _rightR = new FlxActionDigital(Action.RIGHT_R); - var _downR = new FlxActionDigital(Action.DOWN_R); - - var _noteUp = new FlxActionDigital(Action.NOTE_UP); - var _noteLeft = new FlxActionDigital(Action.NOTE_LEFT); - var _noteRight = new FlxActionDigital(Action.NOTE_RIGHT); - var _noteDown = new FlxActionDigital(Action.NOTE_DOWN); - var _noteUpP = new FlxActionDigital(Action.NOTE_UP_P); - var _noteLeftP = new FlxActionDigital(Action.NOTE_LEFT_P); - var _noteRightP = new FlxActionDigital(Action.NOTE_RIGHT_P); - var _noteDownP = new FlxActionDigital(Action.NOTE_DOWN_P); - var _noteUpR = new FlxActionDigital(Action.NOTE_UP_R); - var _noteLeftR = new FlxActionDigital(Action.NOTE_LEFT_R); - var _noteRightR = new FlxActionDigital(Action.NOTE_RIGHT_R); - var _noteDownR = new FlxActionDigital(Action.NOTE_DOWN_R); - - var _accept = new FlxActionDigital(Action.ACCEPT); - var _back = new FlxActionDigital(Action.BACK); - var _pause = new FlxActionDigital(Action.PAUSE); - var _reset = new FlxActionDigital(Action.RESET); - var _cheat = new FlxActionDigital(Action.CHEAT); - var _switchMod = new FlxActionDigital(Action.SWITCHMOD); - - #if (haxe >= "4.0.0") - var byName:Map = []; + // Menus + #if !switch + @:rawGamepad([DPAD_UP, LEFT_STICK_DIGITAL_UP]) #else - var byName:Map = new Map(); + @:rawGamepad([DPAD_UP, LEFT_STICK_DIGITAL_UP, RIGHT_STICK_DIGITAL_UP]) #end + @:pressed("up") public var UP(get, set): Bool; + @:justPressed("up") public var UP_P(get, set): Bool; + @:justReleased("up") public var UP_R(get, set): Bool; + + #if !switch + @:rawGamepad([DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT]) + #else + @:rawGamepad([DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT]) + #end + @:pressed("left") public var LEFT(get, set): Bool; + @:justPressed("left") public var LEFT_P(get, set): Bool; + @:justReleased("left") public var LEFT_R(get, set): Bool; + + #if !switch + @:rawGamepad([DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT]) + #else + @:rawGamepad([DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT]) + #end + @:pressed("right") public var RIGHT(get, set): Bool; + @:justPressed("right") public var RIGHT_P(get, set): Bool; + @:justReleased("right") public var RIGHT_R(get, set): Bool; + + #if !switch + @:rawGamepad([DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN]) + #else + @:rawGamepad([DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN, RIGHT_STICK_DIGITAL_DOWN]) + #end + @:pressed("down") public var DOWN(get, set): Bool; + @:justPressed("down") public var DOWN_P(get, set): Bool; + @:justReleased("down") public var DOWN_R(get, set): Bool; + + // Note Controls + + #if !switch + @:rawGamepad([DPAD_UP, LEFT_STICK_DIGITAL_UP]) + #else + @:rawGamepad([DPAD_UP, LEFT_STICK_DIGITAL_UP, RIGHT_STICK_DIGITAL_UP]) + #end + @:pressed("note-up") public var NOTE_UP(get, set): Bool; + @:justPressed("note-up") public var NOTE_UP_P(get, set): Bool; + @:justReleased("note-up") public var NOTE_UP_R(get, set): Bool; + + #if !switch + @:rawGamepad([DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT]) + #else + @:rawGamepad([DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT]) + #end + @:pressed("note-left") public var NOTE_LEFT(get, set): Bool; + @:justPressed("note-left") public var NOTE_LEFT_P(get, set): Bool; + @:justReleased("note-left") public var NOTE_LEFT_R(get, set): Bool; + + #if !switch + @:rawGamepad([DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT]) + #else + @:rawGamepad([DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT]) + #end + @:pressed("note-right") public var NOTE_RIGHT(get, set): Bool; + @:justPressed("note-right") public var NOTE_RIGHT_P(get, set): Bool; + @:justReleased("note-right") public var NOTE_RIGHT_R(get, set): Bool; + + #if !switch + @:rawGamepad([DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN]) + #else + @:rawGamepad([DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN, RIGHT_STICK_DIGITAL_DOWN]) + #end + @:pressed("note-down") public var NOTE_DOWN(get, set): Bool; + @:justPressed("note-down") public var NOTE_DOWN_P(get, set): Bool; + @:justReleased("note-down") public var NOTE_DOWN_R(get, set): Bool; + + @:gamepad([A]) + @:justPressed("accept") public var ACCEPT(get, set): Bool; + @:pressed("accept") public var ACCEPT_HOLD(get, set): Bool; + @:justReleased("accept") public var ACCEPT_R(get, set): Bool; + + @:gamepad([B]) + @:justPressed("back") public var BACK(get, set): Bool; + @:pressed("back") public var BACK_HOLD(get, set): Bool; + @:justReleased("back") public var BACK_R(get, set): Bool; + + @:gamepad([START]) + @:justPressed("pause") public var PAUSE(get, set): Bool; + @:pressed("pause") public var PAUSE_HOLD(get, set): Bool; + @:justReleased("pause") public var PAUSE_R(get, set): Bool; + + @:gamepad([Y]) + @:justPressed("reset") public var RESET(get, set): Bool; + @:pressed("reset") public var RESET_HOLD(get, set): Bool; + @:justReleased("reset") public var RESET_R(get, set): Bool; + + //@:gamepad([]) + //@:justPressed("cheat") public var CHEAT(get, set): Bool; + //@:pressed("cheat") public var CHEAT_HOLD(get, set): Bool; + //@:justReleased("cheat") public var CHEAT_R(get, set): Bool; + + @:gamepad([FlxGamepadInputID.BACK]) // select button + @:justPressed("switchmod") public var SWITCHMOD(get, set): Bool; + @:pressed("switchmod") public var SWITCHMOD_HOLD(get, set): Bool; + @:justReleased("switchmod") public var SWITCHMOD_R(get, set): Bool; + + var byName:Map = []; public var gamepadsAdded:Array = []; - public var keyboardScheme = KeyboardScheme.None; - - public var UP(get, set):Bool; - - inline function get_UP() - return _up.check(); - - inline function set_UP(val) - return @:privateAccess _up._checked = val; - - public var LEFT(get, set):Bool; - - inline function get_LEFT() - return _left.check(); - - inline function set_LEFT(val) - return @:privateAccess _left._checked = val; - - public var RIGHT(get, set):Bool; - - inline function get_RIGHT() - return _right.check(); - - inline function set_RIGHT(val) - return @:privateAccess _right._checked = val; - - public var DOWN(get, set):Bool; - - inline function get_DOWN() - return _down.check(); - - inline function set_DOWN(val) - return @:privateAccess _down._checked = val; - - public var UP_P(get, set):Bool; - - inline function get_UP_P() - return _upP.check(); - - inline function set_UP_P(val) - return @:privateAccess _upP._checked = val; - - public var LEFT_P(get, set):Bool; - - inline function get_LEFT_P() - return _leftP.check(); - - inline function set_LEFT_P(val) - return @:privateAccess _leftP._checked = val; - - public var RIGHT_P(get, set):Bool; - - inline function get_RIGHT_P() - return _rightP.check(); - - inline function set_RIGHT_P(val) - return @:privateAccess _rightP._checked = val; - - public var DOWN_P(get, set):Bool; - - inline function get_DOWN_P() - return _downP.check(); - - inline function set_DOWN_P(val) - return @:privateAccess _downP._checked = val; - - public var UP_R(get, set):Bool; - - inline function get_UP_R() - return _upR.check(); - - inline function set_UP_R(val) - return @:privateAccess _upR._checked = val; - - public var LEFT_R(get, set):Bool; - - inline function get_LEFT_R() - return _leftR.check(); - - inline function set_LEFT_R(val) - return @:privateAccess _leftR._checked = val; - - public var RIGHT_R(get, set):Bool; - - inline function get_RIGHT_R() - return _rightR.check(); - - inline function set_RIGHT_R(val) - return @:privateAccess _rightR._checked = val; - - public var DOWN_R(get, set):Bool; - - inline function get_DOWN_R() - return _downR.check(); - - inline function set_DOWN_R(val) - return @:privateAccess _downR._checked = val; - - public var NOTE_UP(get, set):Bool; - - inline function get_NOTE_UP() - return _noteUp.check(); - - inline function set_NOTE_UP(val) - return @:privateAccess _noteUp._checked = val; - - public var NOTE_LEFT(get, set):Bool; - - inline function get_NOTE_LEFT() - return _noteLeft.check(); - - inline function set_NOTE_LEFT(val) - return @:privateAccess _noteLeft._checked = val; - - public var NOTE_RIGHT(get, set):Bool; - - inline function get_NOTE_RIGHT() - return _noteRight.check(); - - inline function set_NOTE_RIGHT(val) - return @:privateAccess _noteRight._checked = val; - - public var NOTE_DOWN(get, set):Bool; - - inline function get_NOTE_DOWN() - return _noteDown.check(); - - inline function set_NOTE_DOWN(val) - return @:privateAccess _noteDown._checked = val; - - public var NOTE_UP_P(get, set):Bool; - - inline function get_NOTE_UP_P() - return _noteUpP.check(); - - inline function set_NOTE_UP_P(val) - return @:privateAccess _noteUpP._checked = val; - - public var NOTE_LEFT_P(get, set):Bool; - - inline function get_NOTE_LEFT_P() - return _noteLeftP.check(); - - inline function set_NOTE_LEFT_P(val) - return @:privateAccess _noteLeftP._checked = val; - - public var NOTE_RIGHT_P(get, set):Bool; - - inline function get_NOTE_RIGHT_P() - return _noteRightP.check(); - - inline function set_NOTE_RIGHT_P(val) - return @:privateAccess _noteRightP._checked = val; - - public var NOTE_DOWN_P(get, set):Bool; - - inline function get_NOTE_DOWN_P() - return _noteDownP.check(); - - inline function set_NOTE_DOWN_P(val) - return @:privateAccess _noteDownP._checked = val; - - public var NOTE_UP_R(get, set):Bool; - - inline function get_NOTE_UP_R() - return _noteUpR.check(); - - inline function set_NOTE_UP_R(val) - return @:privateAccess _noteUpR._checked = val; - - public var NOTE_LEFT_R(get, set):Bool; - - inline function get_NOTE_LEFT_R() - return _noteLeftR.check(); - - inline function set_NOTE_LEFT_R(val) - return @:privateAccess _noteLeftR._checked = val; - - public var NOTE_RIGHT_R(get, set):Bool; - - inline function get_NOTE_RIGHT_R() - return _noteRightR.check(); - - inline function set_NOTE_RIGHT_R(val) - return @:privateAccess _noteRightR._checked = val; - - public var NOTE_DOWN_R(get, set):Bool; - - inline function get_NOTE_DOWN_R() - return _noteDownR.check(); - - inline function set_NOTE_DOWN_R(val) - return @:privateAccess _noteDownR._checked = val; - - public var ACCEPT(get, set):Bool; - - inline function get_ACCEPT() - return _accept.check(); - - inline function set_ACCEPT(val) - return @:privateAccess _accept._checked = val; - - public var BACK(get, set):Bool; - - inline function get_BACK() - return _back.check(); - - inline function set_BACK(val) - return @:privateAccess _back._checked = val; - - public var PAUSE(get, set):Bool; - - inline function get_PAUSE() - return _pause.check(); - - inline function set_PAUSE(val) - return @:privateAccess _pause._checked = val; - - public var RESET(get, set):Bool; - - inline function get_RESET() - return _reset.check(); - - inline function set_RESET(val) - return @:privateAccess _reset._checked = val; - - public var CHEAT(get, set):Bool; - - inline function get_CHEAT() - return _cheat.check(); - - inline function set_CHEAT(val) - return @:privateAccess _cheat._checked = val; - - public var SWITCHMOD(get, set):Bool; - - inline function get_SWITCHMOD() - return _switchMod.check(); - - inline function set_SWITCHMOD(val) - return @:privateAccess _switchMod._checked = val; + public var keyboardScheme:KeyboardScheme = None; public function new(name, scheme = None) { super(name); - add(_up); - add(_left); - add(_right); - add(_down); - add(_upP); - add(_leftP); - add(_rightP); - add(_downP); - add(_upR); - add(_leftR); - add(_rightR); - add(_downR); - - add(_noteUp); - add(_noteLeft); - add(_noteRight); - add(_noteDown); - add(_noteUpP); - add(_noteLeftP); - add(_noteRightP); - add(_noteDownP); - add(_noteUpR); - add(_noteLeftR); - add(_noteRightR); - add(_noteDownR); - - add(_accept); - add(_back); - add(_pause); - add(_reset); - add(_cheat); - add(_switchMod); + macro_addKeysToActions(); for (action in digitalActions) byName[action.name] = action; @@ -413,29 +167,10 @@ class Controls extends FlxActionSet setKeyboardScheme(scheme, false); } - override function update() + public function getKeyName(control:Control, idx:Int = 0):String { - super.update(); - } - - // inline - public function checkByName(name:Action):Bool - { - #if debug - if (!byName.exists(name)) - throw 'Invalid name: $name'; - #end - return byName[name].check(); - } - - public function getKeyName(control:Control):String - { - return getDialogueName(getActionFromControl(control)); - } - - public function getDialogueName(action:FlxActionDigital):String - { - var input = action.inputs[0]; + var action = macro_getActionFromControl(control); + var input = action.inputs[idx]; return switch input.device { case KEYBOARD: return '${(input.inputID : FlxKey)}'; @@ -444,198 +179,44 @@ class Controls extends FlxActionSet } } - public function getDialogueNameFromToken(token:String):String - { - return getDialogueName(getActionFromControl(Control.createByName(token.toUpperCase()))); - } - - function getActionFromControl(control:Control):FlxActionDigital - { - return switch (control) - { - case UP: _up; - case DOWN: _down; - case LEFT: _left; - case RIGHT: _right; - case NOTE_UP: _noteUp; - case NOTE_DOWN: _noteDown; - case NOTE_LEFT: _noteLeft; - case NOTE_RIGHT: _noteRight; - case ACCEPT: _accept; - case BACK: _back; - case PAUSE: _pause; - case RESET: _reset; - case CHEAT: _cheat; - case SWITCHMOD: _switchMod; - } - } - - static function init():Void - { - var actions = new FlxActionManager(); - FlxG.inputs.add(actions); - } - - /** - * Calls a function passing each action bound by the specified control - * @param control - * @param func - * @return ->Void) - */ - function forEachBound(control:Control, func:FlxActionDigital->FlxInputState->Void) - { - switch (control) - { - case NOTE_UP: - func(_noteUp, PRESSED); - func(_noteUpP, JUST_PRESSED); - func(_noteUpR, JUST_RELEASED); - case NOTE_LEFT: - func(_noteLeft, PRESSED); - func(_noteLeftP, JUST_PRESSED); - func(_noteLeftR, JUST_RELEASED); - case NOTE_RIGHT: - func(_noteRight, PRESSED); - func(_noteRightP, JUST_PRESSED); - func(_noteRightR, JUST_RELEASED); - case NOTE_DOWN: - func(_noteDown, PRESSED); - func(_noteDownP, JUST_PRESSED); - func(_noteDownR, JUST_RELEASED); - case UP: - func(_up, PRESSED); - func(_upP, JUST_PRESSED); - func(_upR, JUST_RELEASED); - case LEFT: - func(_left, PRESSED); - func(_leftP, JUST_PRESSED); - func(_leftR, JUST_RELEASED); - case RIGHT: - func(_right, PRESSED); - func(_rightP, JUST_PRESSED); - func(_rightR, JUST_RELEASED); - case DOWN: - func(_down, PRESSED); - func(_downP, JUST_PRESSED); - func(_downR, JUST_RELEASED); - case ACCEPT: - func(_accept, JUST_PRESSED); - case BACK: - func(_back, JUST_PRESSED); - case PAUSE: - func(_pause, JUST_PRESSED); - case RESET: - func(_reset, JUST_PRESSED); - case CHEAT: - func(_cheat, JUST_PRESSED); - case SWITCHMOD: - func(_switchMod, JUST_PRESSED); - } - } - - public function replaceBinding(control:Control, device:Device, ?toAdd:Int, ?toRemove:Int) + public function replaceBindingKeyboard(control:Control, ?toAdd:Int, ?toRemove:Int) { if (toAdd == toRemove) return; - switch (device) - { - case Keys: - if (toRemove != null) - unbindKeys(control, [toRemove]); - if (toAdd != null) - bindKeys(control, [toAdd]); - - case Gamepad(id): - if (toRemove != null) - unbindButtons(control, id, [toRemove]); - if (toAdd != null) - bindButtons(control, id, [toAdd]); - } + if (toRemove != null) + unbindKeys(control, [toRemove]); + if (toAdd != null) + bindKeys(control, [toAdd]); } - public function copyFrom(controls:Controls, ?device:Device) + public function replaceBindingGamepad(control:Control, deviceID:Int, ?toAdd:Int, ?toRemove:Int) { - #if (haxe >= "4.0.0") - for (name => action in controls.byName) - { - for (input in action.inputs) - { - if (device == null || isDevice(input, device)) - byName[name].add(cast input); - } - } - #else - for (name in controls.byName.keys()) - { - var action = controls.byName[name]; - for (input in action.inputs) - { - if (device == null || isDevice(input, device)) - byName[name].add(cast input); - } - } - #end + if (toAdd == toRemove) + return; - switch (device) - { - case null: - // add all - for (gamepad in controls.gamepadsAdded) - gamepadsAdded.pushOnce(gamepad); - - mergeKeyboardScheme(controls.keyboardScheme); - - case Gamepad(id): - gamepadsAdded.push(id); - case Keys: - mergeKeyboardScheme(controls.keyboardScheme); - } - } - - inline public function copyTo(controls:Controls, ?device:Device) - { - controls.copyFrom(this, device); - } - - function mergeKeyboardScheme(scheme:KeyboardScheme):Void - { - if (scheme != None) - { - switch (keyboardScheme) - { - case None: - keyboardScheme = scheme; - default: - keyboardScheme = Custom; - } - } + if (toRemove != null) + unbindButtons(control, deviceID, [toRemove]); + if (toAdd != null) + bindButtons(control, deviceID, [toAdd]); } /** * Sets all actions that pertain to the binder to trigger when the supplied keys are used. * If binder is a literal you can inline this */ - public function bindKeys(control:Control, keys:Array) + public inline function bindKeys(control:Control, keys:Array) { - #if (haxe >= "4.0.0") - inline forEachBound(control, (action, state) -> addKeys(action, keys, state)); - #else - forEachBound(control, function(action, state) addKeys(action, keys, state)); - #end + macro_forEachBound(control, (action, state) -> addKeys(action, keys, state)); } /** * Sets all actions that pertain to the binder to trigger when the supplied keys are used. * If binder is a literal you can inline this */ - public function unbindKeys(control:Control, keys:Array) + public inline function unbindKeys(control:Control, keys:Array) { - #if (haxe >= "4.0.0") - inline forEachBound(control, (action, _) -> removeKeys(action, keys)); - #else - forEachBound(control, function(action, _) removeKeys(action, keys)); - #end + macro_forEachBound(control, (action, _) -> removeKeys(action, keys)); } inline static function addKeys(action:FlxActionDigital, keys:Array, state:FlxInputState) @@ -662,53 +243,7 @@ class Controls extends FlxActionSet keyboardScheme = scheme; - switch (scheme) - { - case Solo: - inline bindKeys(Control.UP, Options.SOLO_UP); - inline bindKeys(Control.DOWN, Options.SOLO_DOWN); - inline bindKeys(Control.LEFT, Options.SOLO_LEFT); - inline bindKeys(Control.RIGHT, Options.SOLO_RIGHT); - inline bindKeys(Control.NOTE_UP, Options.SOLO_NOTE_UP); - inline bindKeys(Control.NOTE_DOWN, Options.SOLO_NOTE_DOWN); - inline bindKeys(Control.NOTE_LEFT, Options.SOLO_NOTE_LEFT); - inline bindKeys(Control.NOTE_RIGHT, Options.SOLO_NOTE_RIGHT); - inline bindKeys(Control.ACCEPT, Options.SOLO_ACCEPT); - inline bindKeys(Control.BACK, Options.SOLO_BACK); - inline bindKeys(Control.PAUSE, Options.SOLO_PAUSE); - inline bindKeys(Control.RESET, Options.SOLO_RESET); - inline bindKeys(Control.SWITCHMOD, Options.SOLO_SWITCHMOD); - case Duo(true): - inline bindKeys(Control.UP, Options.P1_UP); - inline bindKeys(Control.DOWN, Options.P1_DOWN); - inline bindKeys(Control.LEFT, Options.P1_LEFT); - inline bindKeys(Control.RIGHT, Options.P1_RIGHT); - inline bindKeys(Control.NOTE_UP, Options.P1_NOTE_UP); - inline bindKeys(Control.NOTE_DOWN, Options.P1_NOTE_DOWN); - inline bindKeys(Control.NOTE_LEFT, Options.P1_NOTE_LEFT); - inline bindKeys(Control.NOTE_RIGHT, Options.P1_NOTE_RIGHT); - inline bindKeys(Control.ACCEPT, Options.P1_ACCEPT); - inline bindKeys(Control.BACK, Options.P1_BACK); - inline bindKeys(Control.PAUSE, Options.P1_PAUSE); - inline bindKeys(Control.RESET, Options.P1_RESET); - inline bindKeys(Control.SWITCHMOD, Options.P1_SWITCHMOD); - case Duo(false): - inline bindKeys(Control.UP, Options.P2_UP); - inline bindKeys(Control.DOWN, Options.P2_DOWN); - inline bindKeys(Control.LEFT, Options.P2_LEFT); - inline bindKeys(Control.RIGHT, Options.P2_RIGHT); - inline bindKeys(Control.NOTE_UP, Options.P2_NOTE_UP); - inline bindKeys(Control.NOTE_DOWN, Options.P2_NOTE_DOWN); - inline bindKeys(Control.NOTE_LEFT, Options.P2_NOTE_LEFT); - inline bindKeys(Control.NOTE_RIGHT, Options.P2_NOTE_RIGHT); - inline bindKeys(Control.ACCEPT, Options.P2_ACCEPT); - inline bindKeys(Control.BACK, Options.P2_BACK); - inline bindKeys(Control.PAUSE, Options.P2_PAUSE); - inline bindKeys(Control.RESET, Options.P2_RESET); - inline bindKeys(Control.SWITCHMOD, Options.P2_SWITCHMOD); - case None: // nothing - case Custom: // nothing - } + macro_bindControls(scheme); } function removeKeyboard() @@ -725,30 +260,12 @@ class Controls extends FlxActionSet } } - public function addGamepad(id:Int, ?buttonMap:Map>):Void + public function addGamepad(id:Int, buttonMap:Map>):Void { gamepadsAdded.push(id); - #if (haxe >= "4.0.0") for (control => buttons in buttonMap) - inline bindButtons(control, id, buttons); - #else - for (control in buttonMap.keys()) - bindButtons(control, id, buttonMap[control]); - #end - } - - inline function addGamepadLiteral(id:Int, ?buttonMap:Map>):Void - { - gamepadsAdded.push(id); - - #if (haxe >= "4.0.0") - for (control => buttons in buttonMap) - inline bindButtons(control, id, buttons); - #else - for (control in buttonMap.keys()) - bindButtons(control, id, buttonMap[control]); - #end + bindButtons(control, id, buttons); } public function removeGamepad(deviceID:Int = FlxInputDeviceID.ALL):Void @@ -759,7 +276,7 @@ class Controls extends FlxActionSet while (i-- > 0) { var input = action.inputs[i]; - if (input.device == GAMEPAD && (deviceID == FlxInputDeviceID.ALL || input.deviceID == deviceID)) + if (isGamepad(input, deviceID)) action.remove(input); } } @@ -767,60 +284,22 @@ class Controls extends FlxActionSet gamepadsAdded.remove(deviceID); } - public function addDefaultGamepad(id):Void + /** + * Sets all actions that pertain to the binder to trigger when the supplied keys are used. + * If binder is a literal you can inline this + */ + public inline function bindButtons(control:Control, id, buttons) { - #if !switch - addGamepadLiteral(id, [ - Control.ACCEPT => [A], - Control.BACK => [B], - Control.UP => [DPAD_UP, LEFT_STICK_DIGITAL_UP], - Control.DOWN => [DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN], - Control.LEFT => [DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT], - Control.RIGHT => [DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT], - Control.PAUSE => [START], - Control.RESET => [Y] - ]); - #else - addGamepadLiteral(id, [ - //Swap A and B for switch - Control.ACCEPT => [B], - Control.BACK => [A], - Control.UP => [DPAD_UP, LEFT_STICK_DIGITAL_UP, RIGHT_STICK_DIGITAL_UP], - Control.DOWN => [DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN, RIGHT_STICK_DIGITAL_DOWN], - Control.LEFT => [DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT], - Control.RIGHT => [DPAD_RIGHT, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT], - Control.PAUSE => [START], - //Swap Y and X for switch - Control.RESET => [Y], - Control.CHEAT => [X] - ]); - #end + macro_forEachBound(control, (action, state) -> addButtons(action, buttons, state, id)); } /** * Sets all actions that pertain to the binder to trigger when the supplied keys are used. * If binder is a literal you can inline this */ - public function bindButtons(control:Control, id, buttons) + public inline function unbindButtons(control:Control, gamepadID:Int, buttons) { - #if (haxe >= "4.0.0") - inline forEachBound(control, (action, state) -> addButtons(action, buttons, state, id)); - #else - forEachBound(control, function(action, state) addButtons(action, buttons, state, id)); - #end - } - - /** - * Sets all actions that pertain to the binder to trigger when the supplied keys are used. - * If binder is a literal you can inline this - */ - public function unbindButtons(control:Control, gamepadID:Int, buttons) - { - #if (haxe >= "4.0.0") - inline forEachBound(control, (action, _) -> removeButtons(action, gamepadID, buttons)); - #else - forEachBound(control, function(action, _) removeButtons(action, gamepadID, buttons)); - #end + macro_forEachBound(control, (action, _) -> removeButtons(action, gamepadID, buttons)); } inline static function addButtons(action:FlxActionDigital, buttons:Array, state, id) @@ -840,49 +319,6 @@ class Controls extends FlxActionSet } } - public function getInputsFor(control:Control, device:Device, ?list:Array):Array - { - if (list == null) - list = []; - - switch (device) - { - case Keys: - for (input in getActionFromControl(control).inputs) - { - if (input.device == KEYBOARD) - list.push(input.inputID); - } - case Gamepad(id): - for (input in getActionFromControl(control).inputs) - { - if (input.deviceID == id) - list.push(input.inputID); - } - } - return list; - } - - public function removeDevice(device:Device) - { - switch (device) - { - case Keys: - setKeyboardScheme(None); - case Gamepad(id): - removeGamepad(id); - } - } - - static function isDevice(input:FlxActionInput, device:Device) - { - return switch device - { - case Keys: input.device == KEYBOARD; - case Gamepad(id): isGamepad(input, id); - } - } - inline static function isGamepad(input:FlxActionInput, deviceID:Int) { return input.device == GAMEPAD && (deviceID == FlxInputDeviceID.ALL || input.deviceID == deviceID); diff --git a/source/funkin/backend/system/macros/ControlsMacro.macro.hx b/source/funkin/backend/system/macros/ControlsMacro.macro.hx index 7c363f6f..49cb0a65 100644 --- a/source/funkin/backend/system/macros/ControlsMacro.macro.hx +++ b/source/funkin/backend/system/macros/ControlsMacro.macro.hx @@ -17,6 +17,7 @@ class ControlsMacro static var _currentControls: Map> = null; static var _currentGamepadControls: Map = null; static var _keySet: Map = null; + static var _internalMap: Map = null; public static macro function build(): Array { @@ -31,6 +32,7 @@ class ControlsMacro _currentControls = []; _currentGamepadControls = []; _keySet = []; + _internalMap = []; var fields = Context.getBuildFields(); for (field in fields.copy()) { @@ -75,14 +77,32 @@ class ControlsMacro meta: [] }); + function buildBindControl(s:String, prefix:String) { + var prefixxed = prefix + s; + + return macro bindKeys(Control.$s, Options.$prefixxed); + } + fields.push({ name: "macro_bindControls", access: [], kind: FFun({ ret: macro : Void, params: [], - expr: macro $b{_allControls.map((s) -> macro addKeys(Control.$s, $v{_keySet.get(s)}))}, - args: [] + expr: macro switch(keyScheme) { + case Solo: + $a{_allControls.map(buildBindControl.bind(_, "SOLO_"))}; + case Duo(true): + $a{_allControls.map(buildBindControl.bind(_, "P1_"))}; + case Duo(false): + $a{_allControls.map(buildBindControl.bind(_, "P2_"))}; + case None: // nothing + case Custom: // nothing + }, + args: [{ + name: "keyScheme", + type: macro : funkin.backend.system.Controls.KeyboardScheme + }] }), pos: Context.currentPos(), doc: null, @@ -95,7 +115,7 @@ class ControlsMacro kind: FFun({ ret: macro : Void, params: [], - expr: generateForEachBoundCode(), + expr: generateForEachBoundCode(macro control), args: [ { name: "control", @@ -112,42 +132,73 @@ class ControlsMacro meta: [] }); + fields.push({ + name: "macro_getActionFromControl", + access: [APrivate], + kind: FFun({ + ret: macro : FlxActionDigital, + params: [], + expr: generateGetActionFromControlCode(macro control), + args: [{ + name: "control", + type: macro : Control + }] + }), + pos: Context.currentPos(), + doc: null, + meta: [] + }); + // for (field in fields) - // trace(new haxe.macro.Printer().printField(field)); + // trace(new haxe.macro.Printer().printField(field)); _allControls = null; _allInternalControls = null; _currentControls = null; _currentGamepadControls = null; _keySet = null; + _internalMap = null; return fields; } - static function generateForEachBoundCode(): Expr + static function generateSwitchCase(expr:Expr, cases:Array, defaultCase:Expr): Expr { - var cases: Array = []; - - for (field => code in _currentControls) - { - cases.push({ - values: [macro Control.$field], - expr: macro $b{code} - }); - } - return { - expr: ESwitch(macro control, cases, macro {}), + expr: ESwitch(expr, cases, defaultCase), pos: Context.currentPos() } } + static function generateGetActionFromControlCode(value:Expr): Expr + { + return macro return ${generateSwitchCase(value, [ + for (short => internal in _internalMap) + { + values: [macro Control.$short], + expr: macro $i{internal} + } + ], macro null)}; + } + + static function generateForEachBoundCode(value:Expr): Expr + { + return generateSwitchCase(value, [ + for (field => code in _currentControls) + { + values: [macro Control.$field], + expr: macro $b{code} + } + ], macro {}); + } + static function generateGamepadCode(): Expr { var map: Array = []; for (name in _allControls) { var expr = _currentGamepadControls.get(name); + if(expr == null) continue; map.push(macro @:pos(expr.pos) Control.$name => ${expr}); } @@ -197,10 +248,13 @@ class ControlsMacro shortName = shortName.substr(0, shortName.length - 2); else if (shortName.endsWith(type = "_H")) shortName = shortName.substr(0, shortName.length - 2); + else if (shortName.endsWith(type = "_HOLD")) + shortName = shortName.substr(0, shortName.length - 5); else type = ""; var internalName = "_" + camelCase(shortName); + var internalNameNoType = internalName; if (type != "") internalName += type.substr(1); @@ -212,11 +266,12 @@ class ControlsMacro var shouldRemove = true; switch (meta.name) { - case ":gamepad": + case ":gamepad" | ":rawGamepad": if (!_currentGamepadControls.exists(shortName)) { var expr = meta.params[0]; - if (Context.defined("switch")) + var shouldRemap = meta.name != ":rawGamepad"; + if (shouldRemap && Context.defined("switch")) { expr = swapAB(expr); } @@ -256,6 +311,8 @@ class ControlsMacro _allControls.push(shortName); _keySet.set(shortName, keyset); + if (!_internalMap.exists(internalNameNoType)) + _internalMap.set(shortName, internalNameNoType); // Generated Code: var _uiUp = new FlxActionDigital("_uiUp"); var internalField: Field = {