440 lines
10 KiB
Haxe
440 lines
10 KiB
Haxe
package funkin.util;
|
|
|
|
import funkin.input.Controls.Device;
|
|
import flixel.input.gamepad.FlxGamepad;
|
|
import flixel.input.gamepad.FlxGamepadInputID;
|
|
import flixel.input.keyboard.FlxKey;
|
|
|
|
using flixel.util.FlxStringUtil;
|
|
|
|
/**
|
|
* Utilities for working with inputs.
|
|
*/
|
|
@:nullSafety
|
|
class InputUtil
|
|
{
|
|
/**
|
|
* Format a key or button for the given device.
|
|
*
|
|
* @param id The key or button to format.
|
|
* @param device The input device the key or button belongs to.
|
|
* @return A human readable string representing the button.
|
|
*/
|
|
public static function format(id:Int, device:Device):String
|
|
{
|
|
return switch (device)
|
|
{
|
|
case Keys:
|
|
getKeyName(id);
|
|
case Gamepad(gamepadID):
|
|
FlxG.gamepads.getByID(gamepadID) != null ? getButtonName(id, FlxG.gamepads.getByID(gamepadID)) : 'N/A';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if all of the keys in keyArray are being pressed,
|
|
* but also only fires once on the last key in the array being justPressed
|
|
* @param keyArray An array of FlxKeys
|
|
* @return Bool True if all of the keys in keyArray are being pressed, with at least one of them being in a JUST_PRESSED state
|
|
*/
|
|
public static function allPressedWithDebounce(keyArray:Array<FlxKey>):Bool
|
|
{
|
|
return allPressed(keyArray) && FlxG.keys.anyJustPressed(keyArray);
|
|
}
|
|
|
|
/**
|
|
* Returns true if all of the keys in keyArray are being pressed
|
|
* @param keyArray An array of FlxKeys
|
|
* @return Bool True if all keys in keyArray are being pressed
|
|
*/
|
|
public static function allPressed(keyArray:Array<FlxKey>):Bool
|
|
{
|
|
return !anyNotPressed(keyArray);
|
|
}
|
|
|
|
/**
|
|
* Returns if any key is not being pressed (or just pressed)
|
|
* @param keyArray An array of FlxKeys
|
|
* @return Bool True if there's any key in keyArray that isn't being pressed
|
|
*/
|
|
public static function anyNotPressed(keyArray:Array<FlxKey>):Bool
|
|
{
|
|
var isKeyNotPressed:FlxKey->Bool = key -> return FlxG.keys.checkStatus(key, RELEASED) || FlxG.keys.checkStatus(key, JUST_RELEASED);
|
|
return keyArray.exists(isKeyNotPressed);
|
|
}
|
|
|
|
/**
|
|
* Get the key name for a given key code.
|
|
* @param id The key code to get the name of
|
|
* @return The name of the key
|
|
*/
|
|
public static function getKeyName(id:Int):String
|
|
{
|
|
return switch (id)
|
|
{
|
|
case ZERO:
|
|
'0';
|
|
case ONE:
|
|
'1';
|
|
case TWO:
|
|
'2';
|
|
case THREE:
|
|
'3';
|
|
case FOUR:
|
|
'4';
|
|
case FIVE:
|
|
'5';
|
|
case SIX:
|
|
'6';
|
|
case SEVEN:
|
|
'7';
|
|
case EIGHT:
|
|
'8';
|
|
case NINE:
|
|
'9';
|
|
case PAGEUP:
|
|
'PgUp';
|
|
case PAGEDOWN:
|
|
'PgDown';
|
|
// case HOME : "Hm";
|
|
// case END : "End";
|
|
// case INSERT : "Ins";
|
|
// case ESCAPE : "Esc";
|
|
// case MINUS : "-";
|
|
// case PLUS : "+";
|
|
// case DELETE : "Del";
|
|
case BACKSPACE:
|
|
'BckSpc';
|
|
case LBRACKET:
|
|
'[';
|
|
case RBRACKET:
|
|
']';
|
|
case BACKSLASH:
|
|
'\\';
|
|
case CAPSLOCK:
|
|
'Caps';
|
|
case SEMICOLON:
|
|
';';
|
|
case QUOTE:
|
|
"'";
|
|
// case ENTER : "Ent";
|
|
// case SHIFT : "Shf";
|
|
case COMMA:
|
|
',';
|
|
case PERIOD:
|
|
'.';
|
|
case SLASH:
|
|
'/';
|
|
case GRAVEACCENT:
|
|
'`';
|
|
case CONTROL:
|
|
'Ctrl';
|
|
case ALT:
|
|
'Alt';
|
|
// case SPACE : "Spc";
|
|
// case UP : "Up";
|
|
// case DOWN : "Dn";
|
|
// case LEFT : "Lf";
|
|
// case RIGHT : "Rt";
|
|
// case TAB : "Tab";
|
|
case PRINTSCREEN:
|
|
'PrtScrn';
|
|
case NUMPADZERO:
|
|
'#0';
|
|
case NUMPADONE:
|
|
'#1';
|
|
case NUMPADTWO:
|
|
'#2';
|
|
case NUMPADTHREE:
|
|
'#3';
|
|
case NUMPADFOUR:
|
|
'#4';
|
|
case NUMPADFIVE:
|
|
'#5';
|
|
case NUMPADSIX:
|
|
'#6';
|
|
case NUMPADSEVEN:
|
|
'#7';
|
|
case NUMPADEIGHT:
|
|
'#8';
|
|
case NUMPADNINE:
|
|
'#9';
|
|
case NUMPADMINUS:
|
|
'#-';
|
|
case NUMPADPLUS:
|
|
'#+';
|
|
case NUMPADPERIOD:
|
|
'#.';
|
|
case NUMPADMULTIPLY:
|
|
'#*';
|
|
default:
|
|
titleCase(FlxKey.toStringMap[id] ?? '?');
|
|
}
|
|
}
|
|
|
|
static var dirReg:EReg = ~/^(l|r).?-(left|right|down|up)$/;
|
|
|
|
/**
|
|
* Get the shortened name of a button for a gamepad.
|
|
*
|
|
* @param id The button code to get the name of
|
|
* @param gamepad The gamepad to get the name from
|
|
* @return The name of the button
|
|
*/
|
|
public static inline function getButtonName(id:Int, gamepad:FlxGamepad):String
|
|
{
|
|
return switch (gamepad.getInputLabel(id))
|
|
{
|
|
case null, '':
|
|
shortenButtonName(FlxGamepadInputID.toStringMap[id]);
|
|
case label:
|
|
shortenButtonName(label);
|
|
}
|
|
}
|
|
|
|
static function shortenButtonName(name:Null<String>):String
|
|
{
|
|
return switch (name == null ? '' : name.toLowerCase())
|
|
{
|
|
case '':
|
|
'[?]';
|
|
// case "square" : "[]";
|
|
// case "circle" : "()";
|
|
// case "triangle": "/\\";
|
|
// case "plus" : "+";
|
|
// case "minus" : "-";
|
|
// case "home" : "Hm";
|
|
// case "guide" : "Gd";
|
|
// case "back" : "Bk";
|
|
// case "select" : "Bk";
|
|
// case "start" : "St";
|
|
// case "left" : "Lf";
|
|
// case "right" : "Rt";
|
|
// case "down" : "Dn";
|
|
// case "up" : "Up";
|
|
case dir if (dirReg.match(dir)):
|
|
dirReg.matched(1).toUpperCase() + ' ' + titleCase(dirReg.matched(2));
|
|
case label:
|
|
titleCase(label);
|
|
}
|
|
}
|
|
|
|
static inline function titleCase(str:String):String
|
|
{
|
|
return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase();
|
|
}
|
|
|
|
/**
|
|
* Get the name of a gamepad's controller type by parsing a name string.
|
|
* @param name The controller name string to parse
|
|
* @return The controller name
|
|
*/
|
|
public static inline function parsePadName(name:String):ControllerName
|
|
{
|
|
return ControllerName.parseName(name);
|
|
}
|
|
|
|
/**
|
|
* Get the name of a gamepad's controller type.
|
|
* @param gamepad The gamepad to get the name from
|
|
* @return The controller name.
|
|
*/
|
|
public static inline function getPadName(gamepad:FlxGamepad):ControllerName
|
|
{
|
|
return ControllerName.getName(gamepad);
|
|
}
|
|
|
|
/**
|
|
* Get the name of a gamepad's controller type.
|
|
* @param id The integer ID of the gamepad device to access.
|
|
* @return The controller name.
|
|
*/
|
|
public static inline function getPadNameById(id:Int):ControllerName
|
|
{
|
|
return ControllerName.getNameById(id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Represents a list of controller names, determined based on driver data.
|
|
* Used for displaying names and button prompts in the UI.
|
|
*/
|
|
@:nullSafety @:forward
|
|
enum abstract ControllerName(String) from String to String
|
|
{
|
|
/**
|
|
* Ouya controller
|
|
*/
|
|
public var OUYA = 'Ouya';
|
|
|
|
/**
|
|
* PlayStation 4 controller
|
|
*/
|
|
public var PS4 = 'PS4';
|
|
|
|
/**
|
|
* Logitech controller
|
|
*/
|
|
public var LOGI = 'Logi';
|
|
|
|
/**
|
|
* XBox controller
|
|
*/
|
|
public var XBOX = 'XBox';
|
|
|
|
/**
|
|
* XInput controller
|
|
*/
|
|
public var XINPUT = 'XInput';
|
|
|
|
/**
|
|
* Wii controller
|
|
*/
|
|
public var WII = 'Wii';
|
|
|
|
/**
|
|
* Nintendo Switch Pro Controller
|
|
*/
|
|
public var PRO_CON = 'Pro_Con';
|
|
|
|
/**
|
|
* Nintendo Switch JoyCons
|
|
*/
|
|
public var JOYCONS = 'Joycons';
|
|
|
|
/**
|
|
* Nintendo Switch JoyCon (Left Only)
|
|
*/
|
|
public var JOYCON_L = 'Joycon_L';
|
|
|
|
/**
|
|
* Nintendo Switch JoyCon (Right Only)
|
|
*/
|
|
public var JOYCON_R = 'Joycon_R';
|
|
|
|
/**
|
|
* MFi controller
|
|
*/
|
|
public var MFI = 'MFI';
|
|
|
|
/**
|
|
* A generic gamepad.
|
|
*/
|
|
public var PAD = 'Pad';
|
|
|
|
/**
|
|
* Get the asset path for a device.
|
|
* @param device The input device
|
|
* @return The path to the device asset image
|
|
*/
|
|
public static function getAssetByDevice(device:Device):String
|
|
{
|
|
return switch (device)
|
|
{
|
|
case Keys:
|
|
getAsset(null);
|
|
case Gamepad(id):
|
|
getAsset(FlxG.gamepads.getByID(id));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the asset path for a gamepad.
|
|
* @param gamepad The gamepad to get the asset for, or null for keyboard
|
|
* @return The path to the device asset image
|
|
*/
|
|
public static function getAsset(gamepad:Null<FlxGamepad>):String
|
|
{
|
|
if (gamepad == null) return 'assets/images/ui/devices/Keys.png';
|
|
|
|
var name = parseName(gamepad.name);
|
|
var path = 'assets/images/ui/devices/$name.png';
|
|
if (openfl.utils.Assets.exists(path)) return path;
|
|
|
|
return 'assets/images/ui/devices/Pad.png';
|
|
}
|
|
|
|
/**
|
|
* Get the controller name for a gamepad by its ID.
|
|
* @param id The gamepad ID
|
|
* @return The controller name
|
|
*/
|
|
public static inline function getNameById(id:Int):ControllerName
|
|
{
|
|
return getName(FlxG.gamepads.getByID(id));
|
|
}
|
|
|
|
/**
|
|
* Get the controller name for a gamepad.
|
|
* @param gamepad The gamepad to get the name from
|
|
* @return The controller name
|
|
*/
|
|
public static inline function getName(gamepad:FlxGamepad):ControllerName
|
|
{
|
|
return parseName(gamepad.name);
|
|
}
|
|
|
|
/**
|
|
* Parse a controller name string and return the corresponding ControllerName.
|
|
* @param name The controller name string to parse
|
|
* @return The corresponding ControllerName enum value
|
|
*/
|
|
public static function parseName(name:String):ControllerName
|
|
{
|
|
name = name.toLowerCase().remove('-').remove('_');
|
|
|
|
if (name.contains('ouya'))
|
|
{
|
|
return OUYA;
|
|
}
|
|
else if (name.contains('wireless controller') || name.contains('ps4'))
|
|
{
|
|
return PS4;
|
|
}
|
|
else if (name.contains('logitech'))
|
|
{
|
|
return LOGI;
|
|
}
|
|
else if (name.contains('xbox'))
|
|
{
|
|
return XBOX;
|
|
}
|
|
else if (name.contains('xinput'))
|
|
{
|
|
return XINPUT;
|
|
}
|
|
else if (name.contains('nintendo rvlcnt01tr') || name.contains('nintendo rvlcnt01'))
|
|
{
|
|
return WII;
|
|
}
|
|
else if (name.contains('mayflash wiimote pc adapter'))
|
|
{
|
|
return WII;
|
|
}
|
|
else if (name.contains('pro controller'))
|
|
{
|
|
return PRO_CON;
|
|
}
|
|
else if (name.contains('joycon l+r'))
|
|
{
|
|
return JOYCONS;
|
|
}
|
|
else if (name.contains('joycon (l)'))
|
|
{
|
|
return JOYCON_L;
|
|
}
|
|
else if (name.contains('joycon (r)'))
|
|
{
|
|
return JOYCON_R;
|
|
}
|
|
else if (name.contains('mfi'))
|
|
{
|
|
return MFI;
|
|
}
|
|
else
|
|
{
|
|
return PAD;
|
|
}
|
|
}
|
|
}
|