Home

Awesome

InputCandy by Lost Astronaut

GitHub Logo

InputCandy focuses on providing input testing and customization for users of PC and gamepad-friendly platforms (consoles).

It's that classic "control setup" panel system you are accustomed to seeing in video games small and large, but for GameMaker.

It also is an object-oriented input API, with action matching, and a bunch of device detection features for keyboard, mouse and any SDL controller.

For GMS 2.3.1+

Always get the latest version from https://github.com/LAGameStudio/InputCandy See a bug? Submit an issue here, or better yet, a Pull Request.

Games Using InputCandy

Using InputCandy but not yet on this list? Submit your game via the Issues tab.

Games that have used or benefitted from or contributed to InputCandy:

Asking Questions

If you need to ask the primary author a question, do so on the Lost Astronaut discord in the #inputcandy channel: https://discord.gg/PN6gS3CAEe

I have posted some additional code there to help people integrate InputCandy with their game. There are many ways to do it, so I've left it over there because you can come up with your own implementation or tie it into your own game in whatever way you choose.

If you have found an issue, simply create one here

Supporting InputCandy

If you download, use, or just simply like this library, please star the above Repo, it helps. :) If you use this library in your game, please add the provided Lost Astronaut and Image Candy logos to your startup screen if you wish to give back a little credit to the creators of InputCandy.

Likewise, we'd love to showcase any game you make with InputCandy here on this page, or in a file included with future versions of InputCandy, so please open an "Issue" and announce your game when it's available for others to play, and we'll include it.

Understanding the Situation

InputCandy is good for the following things:

  1. Provides a quick way of supporting most controllers (mouse, keyboard, and broadly implemented gamepad support) for your game menus. Use InputCandySimple, or the MenuControls example for cross-platform VCS, PC and Linux support (below)
  2. Provides a way for PC games to permit full Keyboard and Mouse customization. Use ICUI.
  3. Provides a diagnostic feature useful on multiple platforms to troubleshoot what values are actually coming from a controller when you physically move it. Use rm_InputCandy_diagnostics
  4. For local multiplayer ("couch" coop etc), InputCandy provides a way for users to select which player uses which controller.
  5. Adapting to changing configurations
  6. Remembering previous configurations
  7. Provide a controller and mouse-friendly UI for customizing controls (ICUI)
  8. Provide a way for users to see what their controllers are doing, and to test control schemes (ICUI's Test on Simulator)

However, in first writing and later using InputCandy, SDL and GameMaker, I can tell you the following nuggets of wisdom:

  1. There is no reliable way to detect most controllers, including the most common ones like XBOX and PS4. This is because no one uses the GUID properly and third-party companies fake their GUID information or the GUID information returned to GameMaker is unreliable and differs per platform. The "Gamepad Description" is also not reliable.
  2. Because there is no reliable way to detect most controllers, use of the SDLDB should be done so only in specific situations and is generally not recommended. It certainly cannot be automagically applied to detected gamepads without user confirmation and one of those "Reverting in 15 seconds..." screens like you see in the Windows desktop when you change resolutions.
  3. Because there is no reliable way to detect most controllers, you may have to resort to checking "number of buttons, hats and axis" in specific cases which can result in false positives.
  4. See Issue #2

Example Implementation

In my game, Apolune: Through the Wormhole, InputCandy user-customization of controls is used as a fallback, and before I implemented anything to do with InputCandy, I identified requirements:

  1. The game targets PCs running Windows OR Linux, OR the VCS Console.
  2. It would support a maximum of 8 players in local multiplayer.
  3. The year of development is 2023, so it should support sane, contemporary controller default profiles without players having to use InputCandy at all. Those default profiles were determined by the target platforms. For Steam, the default would be supporting an XBOX controller, since this works well with the SteamDeck, is the most commonly used contemporary PC gamepad, and is most readily supported by GameMaker's default gamepad values. For Linux, I am aware that the axis values are centered on 0.5,0.5 not 0.0,0.0 as it is on Windows. The values range (on Linux) from 0 to 1, while on Windows they go from -1 to 1. Finally, I was targeting the Atari VCS Console, which has two possible native controllers, the VCS Classic and the VCS Modern.
  4. I still wanted the option for players to be able to fully customize other USB controllers if they so choose.
  5. It would allow connect and disconnect (hot swapping) of controllers. Allow meaning it will not crash.

Where InputCandy shines is not in the ability to detect controller manufacturers, but rather to detect if they are connected, and to assign them to players and remember that setting. It also works well when adjusting if a player has disconnected a controller during gameplay.

In point 2 above, I'm talking about profiles. What I mean is, specific implementations selectable by the player. While Issue #4 suggests InputCandy provide a formal way of handling this, as it stands in <1.0.0 versions, it is left up to you, the game developer, to handle this because it is really specific to what you are trying to accomplish, ie. what platforms and expectations you have of your user audience.

For example, I chose to support the XBOX Series X/S controller. It is wise to also support the PS4 Dual Shock controller. In 2023, these are the most likely controllers for the PC, not because the game is going to come out on those consoles. Additionally, I targeted 1 other platform, the Atari VCS Console, so I have support built in for the VCS Modern and the VCS Classic.

In my game controller menus, before it even reaches InputCandy, each of the 8 players has a default profile appropriate to the build platform. For Steam builds, it chooses XBOX, and for the VCS it chooses the VCS. Users then have the option of changing the profile to VCS (if they are using it on the VCS or on the PC with VCS hardware), XBOX (if they are using XBOX controllers on the VCS or on the PC), and PS4 (if they are using the PS4 controller), or CUSTOM, which is the InputCandy actions. Note that on the PC, CUSTOM is the default setting for Player 1 when no gamepads are selected, because they must not have a gamepad and need to use InputCandy to handle the keyboard actions.

InputCandy's "assign device to player" ICUI panel is used to allow for specific assignments. Each player has his/her own profile choice (VCS, XBOX, PS4 or CUSTOM). I then wrote a series of functions wrapped around various actions. When these functions are called, for example, CheckFireButtonForPlayer(player_number), it checks my game's settings to see which of the profiles has been chosen for the player. These settings are stored and handled separately from InputCandy's settings.

If CUSTOM is chosen, IC_Match is called, if XBOX, VCS or PS4 is chosen, it calls specific GML functions that will handle those activities. For Apolune: Through the Wormhole, the game is a top-down shooter, so it has the following:

For each of these functions, I check against the player's game settings. Here's an example for the CheckMenu function:

function CheckMenuButtonForPlayer(pn) {
	var hand=GetPlayerControllerProfile(pn);
	if ( hand == false ) return false; // This means no device is selected.  In the future, this may check keyboard only if it is the keyboard-using-player.
	var dv=hand.slot_id;
	if ( hand.slot_id != none ) {
		if ( isPlayerUsingVCSControls(pn) ) { // "VCS"
			if ( isPlayerUsingVCSClassic(pn) ) {
				return gamepad_button_check_released(dv,gp_face4);
			} else { // VCS Modern
				return gamepad_button_check_released(dv,gp_shoulderrb);
			}
		} else if ( isPlayerUsingXBOXControls(pn) ) { // "XBOX"
			return gamepad_button_check_released(dv,gp_start);
		} else if ( isPlayerUsingPS4Controls(pn) ) { // "PS4"
			return gamepad_button_check_released(dv,gp_start);
		} else if ( isPlayerUsingInputCandy(pn) ) { // "CUSTOM"
			return IC_Match(pn,global.game_actions.menu.index); // Calls InputCandy to test for action
		}
	} else if ( pn-1 == __INPUTCANDY.player_using_keyboard_mouse ) { 
		return IC_Match(pn,global.game_actions.menu.index);
 // This calls InputCandy to test for action.  In the future, this may check keyboard only if it is the keyboard-using-player.
	}
}

The way I went about figuring out how to program the above is by testing each controller on each platform using InputCandy's rm_InputCandy_diagnostics, and then writing a special case for each scenario that needed one.

Finally, I want to mention special considerations for the "Move" action. The "Move" action is complicated because I let the user use the d-pad OR the stick. It returns the following values in a struct:

	var result={
		combined: { x:0, y:0 },
		move2: { x:0, y:0 },
		move: { x:0, y:0 },
		angle: AXIS_NO_VALUE,
		angle2: AXIS_NO_VALUE,
		left: false,
		up: false,
		right: false,
		down: false,
		leftUp: false,
		leftDown: false,
		rightUp: false,
		rightDown: false,
		left2: false,
		up2: false,
		right2: false,
		down2: false,
		leftUp2: false,
		leftDown2: false,
		rightUp2: false,
		rightDown2: false,
		raw: false,
		raw2: false
	};

In the above struct, the player ship object has to interpret these controls to update ship parameters (speed, direction, etc). The combined value takes the "greater magnitude" of move2 and move vectors. Usually, the player will only be pressing one or the other, but they may be pressing both. It also returns the explicit values for both the move and move2 (d-pad and stick). For the VCS Classic, Move2 is never set so those all appear as false always and shouldn't affect anything else. The raw and raw2 values are the structs returned by global.IC.MatchDirectional(), aka the struct seen in global.ICI.New_ICMoving

MenuControls

You need a generic, broadly usable, keyboard-friendly, and game-controller-friendly way of navigating menus before the player is asked a single configuration question. This is the code I use in Apolune: Through the Wormhole to do this. It is used on all cutscenes, help panels, game menus, and the main menu. It has the ability to guess which player is doing the "accept" action. It also tries to indicate if a VCS controller is present. The MenuControls struct will return "release" signals for "left", "right", "up", "down", "back", "accept", and "cancel" - and you can also access globally the previous state via global.Menucontrols_old_results if you absolutely need to.

This code is built on top of InputCandySimple. It supports VCS, PC games and can be adapted to other consoles. This code is an example of the code used in Apolune: Through the Wormhole, and allows users to navigate game menus when the game first starts up. Using this they can navigate to a menu option that leads to the customization panels available in ICUI.

  1. Create an object o_MenuControls.
  2. In o_MenuControls:Create, call Init_MenuControls()
  3. In o_MenuControls:BeginStep, call MenuControls_top_of_frame()
  4. In o_MenuControls:PostDraw, call MenuControls_end_of_frame()
  5. Include o_MenuControls in any room that will serve as your game menu, and optionally during any cut-scene movie or help screen.
  6. In any object that controls your menus, cut-scenes or help panel, access in a Step by calling var controls=MenuControls();
  7. Create a script called "MenuControls" and paste in the following:

#macro MenuControls_defaultresults  { left: false, right: false, up: false, down: false, accept: false, cancel: false, back: false, initiator: none, key_or_mouse: false, VCS: { moderns: [], classics: [], modern: false, classic: false } }
function MenuControls() {
	return global.MenuControls_final_results;
}

function Init_MenuControls() {
	global.ic_simple_controls=InputCandySimple();
	global.MenuControls_old_results=MenuControls_defaultresults;
	global.MenuControls_results=MenuControls_defaultresults;
	global.MenuControls_final_results=MenuControls_defaultresults;
	global.MenuControls_selection_changed=false;
	global.MenuControls_last_selected_by_controls=true;
	global.MenuControls_frame_delay=0;
	global.MenuControls_initiator=none;
	global.MenuControls_mousepos = { mx: mouse_x, my: mouse_y };
}

function MenuControls_top_of_frame() {
	global.MenuControls_initiator=none;
	if ( global.MenuControls_frame_delay > 0 ) {
		global.MenuControls_frame_delay -= 1;
	}
	var controls=global.ic_simple_controls;
	var devices=controls.devices();
	var results=MenuControls_defaultresults;
	var newmousepos= { mx: mouse_x, my: mouse_y };
	if ( global.MenuControls_mousepos.mx != newmousepos.mx
	  or global.MenuControls_mousepos.my != newmousepos.my ) {
		  global.MenuControls_last_selected_by_controls = false;
	}
	global.MenuControls_mousepos=newmousepos;
	for ( var i=0; i<devices.count; i++ ) {
		var dv=i;
		var pn=i+1;
		var VCS_modern=( devices.gamepad_names[dv] == "Atari Game Controller" 
			|| devices.gamepad_names[dv] == "Atari Controller"
			|| devices.gamepad_names[dv] == "Atari VCS Modern Controller"
			|| devices.gamepad_guids[dv] == "03000000503200000210000000000000"
			|| devices.gamepad_guids[dv] == "03000000503200000210000011010000"
			|| devices.gamepad_guids[dv] == "05000000503200000210000000000000"
			|| devices.gamepad_guids[dv] == "05000000503200000210000045010000"
			|| devices.gamepad_guids[dv] == "05000000503200000210000046010000"
			|| devices.gamepad_guids[dv] == "05000000503200000210000047010000"
			||  ( os_type == os_linux && ( gamepad_button_count(dv) == 11 && gamepad_hat_count(dv) == 1 && gamepad_axis_count(dv) == 6 ) )
			);		
		var VCS_classic=( devices.gamepad_names[dv] == "Classic Controller"
			|| devices.gamepad_names[dv] == "Atari Classic Controller"
			|| devices.gamepad_guids[dv] == "03000000503200000110000000000000"
			|| devices.gamepad_guids[dv] == "03000000503200000110000011010000"
			|| devices.gamepad_guids[dv] == "05000000503200000110000000000000"
			|| devices.gamepad_guids[dv] == "05000000503200000110000044010000"
			|| devices.gamepad_guids[dv] == "05000000503200000110000046010000"
			|| ( gamepad_button_count(dv) == 5 && gamepad_hat_count(dv) == 1 && gamepad_axis_count(dv) == 1 ) );
		if ( VCS_classic ) {
			results.accept |= gamepad_button_check(dv,gp_face1); if ( results.accept and results.initiator == none ) results.initiator=pn;
			results.cancel |= gamepad_button_check(dv,gp_face2);
			results.back |= gamepad_button_check(dv,gp_face3);
			if ( gamepad_hat_value(dv,0)&1 ) {
				results.up |= true;
			}
			if ( gamepad_hat_value(dv,0)&2 ) {
				results.right |= true;
			}
			if ( gamepad_hat_value(dv,0)&4 ) {
				results.down |= true;
			}
			if ( gamepad_hat_value(dv,0)&8 ) {
				results.left |= true;
			}
		} else if ( VCS_modern ) {
			results.accept |= controls.A(pn);  if ( results.accept and results.initiator == none ) results.initiator=pn;
			results.cancel |= controls.B(pn);
			results.back   |= gamepad_button_check(dv,gp_select) or gamepad_button_check(dv,gp_start);
			if ( gamepad_hat_value(dv,0)&1 || (os_type == os_linux && (gamepad_axis_value(dv,1) < 0.4 || gamepad_axis_value(dv,4) < 0.4)) || (os_type == os_windows && (gamepad_axis_value(dv,1) < -0.5 || gamepad_axis_value(dv,4) > 0.5)) ) {
				results.up |= true;
			}
			if ( gamepad_hat_value(dv,0)&2 || (os_type == os_linux && (gamepad_axis_value(dv,0) > 0.6 || gamepad_axis_value(dv,3) > 0.6)) || (os_type == os_windows && (gamepad_axis_value(dv,0) > 0.5 || gamepad_axis_value(dv,3) > 0.5)) ) {
				results.right |= true;
			}
			if ( gamepad_hat_value(dv,0)&8 || (os_type == os_linux && (gamepad_axis_value(dv,0) < 0.4 || gamepad_axis_value(dv,3) < 0.4)) || (os_type == os_windows && (gamepad_axis_value(dv,0) < -0.5 || gamepad_axis_value(dv,3) < -0.5)) ) {
				results.left |= true;
			}
			if ( gamepad_hat_value(dv,0)&4 || (os_type == os_linux && (gamepad_axis_value(dv,1) > 0.6 || gamepad_axis_value(dv,4) > 0.6)) || (os_type == os_windows && (gamepad_axis_value(dv,1) > 0.5 || gamepad_axis_value(dv,4) < -0.5)) ) {
				results.down |= true;
			}
		} else {
			results.left   |= controls.left(pn);
			results.right  |= controls.right(pn);
			results.up     |= controls.up(pn);
			results.down   |= controls.down(pn);
			results.accept |= controls.A(pn); if ( results.accept and results.initiator == none ) results.initiator=pn;
			results.cancel |= controls.B(pn);
			results.back   |= gamepad_button_check(dv,gp_select) or keyboard_check(vk_escape);
		}
		results.VCS.moderns[i]=VCS_modern;
		results.VCS.classics[i]=VCS_classic;
		results.VCS.modern |= VCS_modern;
		results.VCS.classic |= VCS_classic;
	}
	var key_or_mouse_accept = keyboard_check(vk_enter) or keyboard_check(vk_control) or mouse_check_button(mb_left);
	results.accept |= key_or_mouse_accept; if ( key_or_mouse_accept ) results.initiator=1;
	results.cancel |= mouse_check_button(mb_right);
	results.back |= mouse_check_button(mb_middle);
	global.MenuControls_results=results;
	var old_results=global.MenuControls_old_results;
	var final_results=MenuControls_defaultresults;
	final_results.left   = !results.left   and old_results.left;
	final_results.right  = !results.right  and old_results.right;
	final_results.up     = !results.up     and old_results.up;
	final_results.down   = !results.down   and old_results.down;
	final_results.accept = !results.accept and old_results.accept;
	final_results.cancel = !results.cancel and old_results.cancel;
	final_results.back   = !results.back   and old_results.back;
	final_results.VCS    = results.VCS;
	final_results.key_or_mouse = key_or_mouse_accept;
	if ( final_results.accept ) global.MenuControls_initiator = old_results.initiator;
	global.MenuControls_final_results=final_results;	
}

function MenuControls_end_of_frame() {
	global.MenuControls_old_results=global.MenuControls_results;
	global.MenuControls_selection_changed=false;
	global.ANIMTIME += global.dt;
}

Using InputCandy

You can use InputCandy in pieces or as a whole.

It currently does not handle multitouch, screen reorientation, platform-specific scenarios beyond gamepads.

InputCandy makes it easier to use input in GameMaker and does all of the "settings" and "selection" for you, so you can easily import these features into other projects. It was first written by LostAstronaut.com for use with their games.

It's important to note that this is for detecting momentary actions, not for detecting textual input ("typing"). It treats mice, keyboard and gamepad input as "button states"

InputCandy has two modes:

To access Simple mode, see the script InputCandySimple included in the package. It's one function, so you don't have to import all the other stuff.

A Notes file contains Advanced mode information. You want to use this if you want wider support for the gamepad, and the ability to allow players to set their own control schemes.

What is InputCandy Advanced Good For?

InputCandy "Advanced" is split into several components:

InputCandy comes with:

InputCandy is good for:

If you are going to use SDLDB, and you are testing with devices that don't map or have no DB entry, developers on the GameMaker Discord emphatically encourages you to submit a Pull Request to the SDL Gamecontroller Database at https://github.com/gabomdq/SDL_GameControllerDB

Note that the use of the SDLDB is turned off by default as it may have undesired consequences and is not really necessary if the player is going to be permitted to remap input by use of device testing/capture or input selection.

Input Device Control Concept Diagram

The following diagram illustrates the basic relationships of major concepts found in GameMaker, SDL, and InputCandy. It is not a complete architecture diagram but is simple enough, yet complex enough, to illustrate how everything is connected in InputCandy.

The bottom of this chart (above), the nodes labeled Actions, Settings, Players, are the exposed surface of InputCandy that you, as a game developer, can choose to limit yourself to when implementing InputCandy as your control layer. You create Actions, in turn, you attempt to match them, and you choose when to go about the activation and deactivation of Players. If you use the packaged ICUI helpers, then players create Settings (and bindings) as needed and can access the SDLDB if you load that component.

By matching "actions", players can influence the behavior of the game, which is "fun" for the player. A very dry way to explain user experience, but this is the gist of it.

Feature List

Support Table

The following table illustrates the support level for each device type by the InputCandy framework.

PlatformInputCandy's coverage
Windows PCKeyboard, Mouse, Gamepads supported in InputCandy for 1-X players, no touch support: use GameMaker to support
Linux PCKeyboard, Mouse, Gamepads supported in InputCandy for 1-X players, no touch support: use GameMaker to support
MacSupport similar to Linux and Windows, needs further testing and corner cases
Apple TVSome coverage, use GameMaker to handle touch and other special platform options, Gamepads supported
iOSSome coverage, use GameMaker to handle touch and other special platform options, Gamepads supported
AndroidSome coverage, use GameMaker to handle touch and other special platform options, Gamepads supported
Atari VCSSee https://forum.yoyogames.com/index.php?threads/building-for-atari-vcs-ubuntu-18-04.96036/#post-591776
XboxUntested, Gamepads supported
Sony PS4/5Untested, Gamepads supported
HTML5 (Web)Untested, Gamepads supported

In the above table, I'm trying to illustrate that, if you are making a single-player game for a touch device, this probably isn't the library for you. If you want to support multiple controllers and user-defined control bindings, and you want to also support the keyboard and mouse, this library is probably for you. It's tailored to support physical controllers, mouse+keyboard, on the PC and consoles. It's not really for mobile, but it might help with physical controllers supported by mobile devices and tablets.

As an alternative, there are many on GitHub. You may like https://github.com/JujuAdams/input/ which purports to be "Comprehensive cross-platform input for GameMaker Studio 2.3.0" and seems to support mobile and web more extensively.

InputCandy's default settings panels for your games can be accessed directly or by calling the base panel. This allows you to divide up the UI as you desire. The UI also smartly turns off features when they have no value. You'll never see a menu with one option, for example.

The default panels that are all interconnected are as follows:

Hardware Testing Notes

Advanced features of the library have been tested on a windows PC with the following devices attached:

- Retrolink N64 Style Classic Controller for PC ($3.99)
- X-Box 360 Wired USB Red Controller ($12.95) 
	- Stick-press did not register on right stick
	- Stick-press on left stick only worked when stick was slightly up-left
	- Supported vibration
	- Cannot detect X button  
- Modern XBOX Controller (X or S series) ($49.95)
	- Generally maps correctly to most GameMaker defaults
 		- Left trigger registers as "Buttons[10]" and has a range of 0.0 - 0.30 (fully pulled)
   		- Underneath micro buttons do not register (cannot read value)
 	- Left/right switch control on LED illuminated did not register (cannot read value)
	- Cannot detect X button
    - PS4 Dual Shock (in progress)
- Tomee USB Controller for PC/PS3 (PS3-style controller) ($19.99)
	- Both stick-presses registered properly
	- Triggers registered as shoulders and shoulders registered as triggers
- LUXMO SNES Wired USB Controller for PC ($7.99)
- ATARI VCS Classic Controller (not in a special mode)
- ATARI VCS Modern Controller (not in a special mode)
- Mouse, Keyboard

Note that initial testing did not use any SDL remapping.

I personally recommend the Tomee USB Controller (PS3-style) for anyone looking to get a nice controller, though other brands of the same style (PS3) may be just as good and you can get them in 2.4Ghz and other forms of wireless (Bluetooth and others). This stick offered the most options and was easy to use, had good tactile feedback and some versions of the PS3 for PC support rumble vibration. The one I had didn't.

Buttons labeled by InputCandy (and GameMaker) don't always match, for example: "A" (gp_face1) may not be labeled as such on any controller. The Retrolink N64-style controller makes A one of the yellow arrow buttons. SNES-style controller may label its button "X" to "A"

At some point we'll test on Xbox. Right now it is mainly tested on PCs. Volunteer to test for us! File an Issue after you do so.

Project Roadmap

Remaining Progress Toward 1.0.0

This table lists the remaining action items to be included in the 1.0.0 release.

FeatureProgress
Advanced vibration optionsA system for time-based vibration events is planned
SDL Mapping Confirmation TestA feature is needed to assure that input control is not lost when a user activates an SDL mapping that ruins their device settings. This panel should appear after a new mapping is selected.
Capture Input FeatureSelection of input by capturing device input is a stretch goal that is not required for use now, but would be a value-added feature assisting players in setting up their input controls aside from the current list selection method. This feature is also designed around allowing them to choose control axis in a two stage capture so they can program their thumbsticks (or other axis) as input.
Live Device SimulatorA special screen that allows users to test their devices and get visual feedback. Originally it was intended to include features created for the Atari by computercoder on the Atari developer discord. This set of features was to use light-up indicators on actual photographs of devices in an ever-expanding list of device-associated photographs, but the feature should probably be backscoped to just show buttons for 1.0.0
DocumentationTutorials on Github wiki, intro video, promo video, dev debrief/diary video planned for 1.0.0
Tech DebtClean up ICUI such that users can reuse certain parts independently of the default workflow

Beyond 1.0.0

FeatureVersion PriorityProgress
Testing on other platformsAny next versionWe need volunteers publishing to XBox, PS4/5 and other platforms
Adding additional prefab UI components1.1.x and aboveAdding additional more polished diagnostic tools that have their own Panel objects to be included in ICUI and as objects that can be included in your game ; adding a default "game menu" that can be styled ; a virtual keyboard for high score name entry, or any text entry, usable by controllers
Thumbstick virtualization?Provide a way to define virtualized thumbsticks (combinations of axis) ... requires additional research and thinking about usefulness. This feature has a first step in the planned capture input feature; Virtual thumbstick "axis couplers" for axis support other than just gp_axis_l and gp_axis_h
Expanding Live Device Silmulator1.5.x and aboveExpanding the Live Device simulator to support common console input controls (XInput, PS3, SNES/iBuffalo), STEAM Controller? As these are the most common controllers or are platform-specific devices ; the goal is to use a visualization of the controller and "light up" or "arrow indicators" to show movements of the joystick, d-pads, buttons, etc, initially targeting: XBox, PS3/4/5, Atari VCS
Allowing Keyboard to be exchanged for players other than player 1?Not sure if this is needed
Virtual on-screen joysticks1.8.x and aboveTouch-sensor joysticks as a selectable device type for platforms that have touch screens ; there are other libraries that can handle this so this may be beyond scope
Network Mirroring of Input2.xThis may end up being a different library or "extension" to InputCandy (Networking support to transmit controller signals across the network)

See the Notes > Note1.txt that is included in the project for more information on how to use this library.