160 lines
5.2 KiB
Haxe
160 lines
5.2 KiB
Haxe
package funkin.mobile.input;
|
|
|
|
import flixel.input.actions.FlxAction.FlxActionDigital;
|
|
import flixel.input.actions.FlxActionInput;
|
|
import flixel.input.FlxInput.FlxInputState;
|
|
import flixel.input.actions.FlxActionInputDigital.FlxActionInputDigitalIFlxInput;
|
|
import funkin.input.Controls;
|
|
import funkin.mobile.ui.FunkinButton;
|
|
import funkin.mobile.ui.FunkinHitbox;
|
|
import funkin.play.notes.NoteDirection;
|
|
#if android
|
|
import funkin.external.android.KeyboardUtil;
|
|
#elseif ios
|
|
import funkin.external.apple.KeyboardUtil;
|
|
#end
|
|
import lime.ui.Gamepad as LimeGamepad;
|
|
import openfl.events.KeyboardEvent;
|
|
import openfl.events.TouchEvent;
|
|
|
|
/**
|
|
* Handles setting up and managing input controls for the game.
|
|
*/
|
|
class ControlsHandler
|
|
{
|
|
/**
|
|
* Returns whether the last input was sent through touch.
|
|
*/
|
|
public static var lastInputTouch(default, null):Bool = true;
|
|
|
|
/**
|
|
* Returns whether there's a gamepad or keyboard devices connected and active.
|
|
*/
|
|
public static var hasExternalInputDevice(get, never):Bool;
|
|
|
|
/**
|
|
* Returns whether an external input device is currently used as the main input.
|
|
*/
|
|
public static var usingExternalInputDevice(get, never):Bool;
|
|
|
|
/**
|
|
* Initialize input trackers used to get the current status of the `lastInputTouch` field.
|
|
*/
|
|
public static function initInputTrackers():Void
|
|
{
|
|
FlxG.stage.addEventListener(KeyboardEvent.KEY_DOWN, (_) -> lastInputTouch = false);
|
|
FlxG.stage.addEventListener(TouchEvent.TOUCH_BEGIN, (_) -> lastInputTouch = true);
|
|
|
|
function doGamepad(gamepad:LimeGamepad)
|
|
{
|
|
gamepad.onButtonDown.add((_) -> lastInputTouch = false);
|
|
}
|
|
|
|
for (gamepad in LimeGamepad.devices.values()) doGamepad(gamepad);
|
|
|
|
LimeGamepad.onConnect.add((gamepad) -> doGamepad(gamepad));
|
|
}
|
|
|
|
/**
|
|
* Adds a button input to a given FlxActionDigital and caches it.
|
|
*
|
|
* @param action The FlxActionDigital to add the button input to.
|
|
* @param button The FunkinButton associated with the action.
|
|
* @param state The input state to associate with the action.
|
|
* @param cachedInput The array of FlxActionInput objects to cache the input.
|
|
*/
|
|
public static function addButton(action:FlxActionDigital, button:FunkinButton, state:FlxInputState, cachedInput:Array<FlxActionInput>):Void
|
|
{
|
|
if (action == null || button == null || cachedInput == null) return;
|
|
|
|
final input:FlxActionInputDigitalIFlxInput = new FlxActionInputDigitalIFlxInput(button, state);
|
|
cachedInput.push(input);
|
|
action.add(input);
|
|
}
|
|
|
|
/**
|
|
* Sets up hitbox controls based on game controls and hitbox hints.
|
|
*
|
|
* @param controls The controls instance defining game controls.
|
|
* @param hitbox The hitbox to associate with the controls.
|
|
* @param cachedInput The array of action input objects to cache the input.
|
|
*/
|
|
@:access(funkin.input.Controls)
|
|
public static function setupHitbox(controls:Controls, hitbox:FunkinHitbox, cachedInput:Array<FlxActionInput>):Void
|
|
{
|
|
if (controls == null || hitbox == null) return;
|
|
|
|
for (hint in hitbox.members)
|
|
{
|
|
@:privateAccess
|
|
switch (hint.noteDirection)
|
|
{
|
|
case NoteDirection.LEFT:
|
|
controls.forEachBound(Control.NOTE_LEFT, function(action:FlxActionDigital, state:FlxInputState):Void
|
|
{
|
|
addButton(action, hint, state, cachedInput);
|
|
});
|
|
case NoteDirection.DOWN:
|
|
controls.forEachBound(Control.NOTE_DOWN, function(action:FlxActionDigital, state:FlxInputState):Void
|
|
{
|
|
addButton(action, hint, state, cachedInput);
|
|
});
|
|
case NoteDirection.UP:
|
|
controls.forEachBound(Control.NOTE_UP, function(action:FlxActionDigital, state:FlxInputState):Void
|
|
{
|
|
addButton(action, hint, state, cachedInput);
|
|
});
|
|
case NoteDirection.RIGHT:
|
|
controls.forEachBound(Control.NOTE_RIGHT, function(action:FlxActionDigital, state:FlxInputState):Void
|
|
{
|
|
addButton(action, hint, state, cachedInput);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes cached input associated with game controls.
|
|
*
|
|
* @param controls The Controls instance defining game controls.
|
|
* @param cachedInput The array of action input objects to clear cached input from.
|
|
*/
|
|
public static function removeCachedInput(controls:Controls, cachedInput:Array<FlxActionInput>):Void
|
|
{
|
|
for (action in controls.digitalActions)
|
|
{
|
|
var i:Int = action.inputs.length;
|
|
|
|
while (i-- > 0)
|
|
{
|
|
var j:Int = cachedInput.length;
|
|
|
|
while (j-- > 0)
|
|
{
|
|
if (cachedInput[j] == action.inputs[i])
|
|
{
|
|
action.remove(action.inputs[i]);
|
|
cachedInput.remove(cachedInput[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@:noCompletion
|
|
static function get_hasExternalInputDevice():Bool
|
|
{
|
|
var gamepads:Bool = FlxG.gamepads.numActiveGamepads > 0;
|
|
var keyboards:Bool = #if android KeyboardUtil.keyboardConnected #elseif ios KeyboardUtil.isKeyboardConnected() #else false #end;
|
|
var chromebook:Bool = #if android extension.androidtools.Tools.isChromebook() #else false #end;
|
|
|
|
return gamepads || keyboards || chromebook;
|
|
}
|
|
|
|
@:noCompletion
|
|
static function get_usingExternalInputDevice():Bool
|
|
{
|
|
return ControlsHandler.hasExternalInputDevice && !ControlsHandler.lastInputTouch;
|
|
}
|
|
}
|