Introducing UserInput Module

UserInput Module — Overview

Module: UserInput

This module provides an advanced way to handle user input in Roblox, similar to an InputContext, but directly built on top of UserInputService.
It supports both keyboard and gamepad inputs, allowing dynamic switching between them at runtime.

It is inspired by Sleitnick’s Input Framework and is designed for developers who want fine-grained control over which keys are tracked and how input events are handled.


Key Features

  1. Multiple Input Types
  • Supports "Keyboard" or "Gamepad".
  • Can switch input type at runtime with ChangeInputType() (keys are cleared during the switch).
  1. Key Management
  • KeysRegistered stores all active key bindings.
  • Methods for:
    • .ChangeKey() — replace all keys.
    • .AddKey() — add keys without duplicates.
    • .RemoveKey() — remove keys selectively.
  1. Signal-Based Input Events
  • .Pressed(callback) — triggered when a registered key is pressed.
  • .Released(callback) — triggered when a registered key is released.
  • Signals ensure clean, reusable connections.
  1. Lifecycle Control
  • .DisconnectPressed() and .DisconnectReleased() — stop listening to events.
  • .Destroy() — cleans up signals, registered keys, and the input structure.

API Summary

Public

  • KeysRegistered: {Enum.KeyCode} — array of registered keys.
  • ChangeInputType(type: "Gamepad" | "Keyboard") — switches between input devices.
  • ChangeKey(keys) — replaces all registered keys.
  • AddKey(keys) — adds keys to the list.
  • RemoveKey(keys) — removes keys from the list.
  • Pressed(callback) — connects a function to key-press events.
  • Released(callback) — connects a function to key-release events.
  • DisconnectPressed() — disconnects .Pressed signals.
  • DisconnectReleased() — disconnects .Released signals.
  • Destroy() — fully destroys the input component.

Private

  • __setUpInputStructKeyPressed() — internal setup for key press detection.
  • __setUpInputStructKeyReleased() — internal setup for key release detection.

Example Usage

lua

local Input = UserInput.new({
    Keys = {Enum.KeyCode.A, Enum.KeyCode.B},
    InputType = "Keyboard"
})

Input:Pressed(function(key)
    print("Pressed:", key)
end)

Input:Released(function(key)
    print("Released:", key)
end)

-- Switch to gamepad at runtime
Input:ChangeInputType("Gamepad")

Design Notes

  • Abstraction Layer: Separates keyboard/gamepad logic through inputStruct, allowing easy future expansion.
  • Signal-Based Architecture: Clean event handling, easy subscription/unsubscription.
  • Runtime Flexibility: Input type and keys can be updated without restarting the game session.

Full documentation

8 Likes

would use this but it’s PascalCase :crying_cat:

1 Like

Version : 1.1

  • added .Observe(), track the current input type of the user.
  • fixed type annotation bug

File : UserInput

1 Like

Version : 1.2

  • fixed some issues with .KeyReleased
  • updated comments
  • updated api

Updated file : UserInput

Version 1.2.1

  • added alias for the constructor and the component
--Constructor alias
UserInput.New = UserInput.new

--Component alias
Component.pressed = Component.Pressed
Component.released = Component.Released
Component.changeInputType = Component.ChangeInputType
Component.changeInputtype = Component.ChangeInputType
Component.addKey = Component.AddKey
Component.addkey = Component.AddKey
Component.removeKey = Component.RemoveKey
Component.removekey = Component.RemoveKey
Component.disconnectPressed = Component.DisconnectPressed
Component.disconnectpressed = Component.DisconnectPressed
Component.disconnectReleased = Component.DisconnectReleased
Component.disconnectreleased = Component.DisconnectReleased
Component.observe = Component.Observe
Component.destroy = Component.Destroy

File UserInput

Hello,
How can i get the mouse?
image

Only keyboard and Gamepad use the Mouse framework from Sleitnick

i will implement mouse when i get the time

File UserInput

Version : 1.3

Changes

  • Overhaul of all alias
    -- Constructor alias for convenience and consistency
    UserInput.New = UserInput.new
    
    -- Comprehensive method aliases for various naming conventions and case sensitivity
    Component.pressed = Component.Pressed
    Component.released = Component.Released
    Component.changeInputType = Component.ChangeInputType
    Component.changeInputtype = Component.ChangeInputType
    Component.addKey = Component.AddKey
    Component.addkey = Component.AddKey
    Component.removeKey = Component.RemoveKey
    Component.removekey = Component.RemoveKey
    Component.middleUp = Component.MiddleUp
    Component.middleup = Component.MiddleUp
    Component.middleDown = Component.MiddleDown
    Component.middledown = Component.MiddleDown
    Component.scrolled = Component.Scrolled
    Component.moved = Component.Moved
    Component.disconnectPressed = Component.DisconnectPressed
    Component.disconnectpressed = Component.DisconnectPressed
    Component.disconnectReleased = Component.DisconnectReleased
    Component.disconnectreleased = Component.DisconnectReleased
    Component.disconnectScrolledSignal = Component.DisconnectScrolledSignal
    Component.disconnectscrolledSignal = Component.DisconnectScrolledSignal
    Component.disconnectMovedSignal = Component.DisconnectMovedSignal
    Component.disconnectmovedSignal = Component.DisconnectMovedSignal
    Component.disconnectMiddleUpSignal = Component.DisconnectMiddleUpSignal
    Component.disconnectmiddleUpSignal = Component.DisconnectMiddleUpSignal
    Component.discconectmiddleupSignal = Component.DisconnectMiddleUpSignal
    Component.disconnectMiddleDownSignal = Component.DisconnectMiddleDownSignal
    Component.disconnectmiddleDownSignal = Component.DisconnectMiddleDownSignal
    Component.disconectmiddledownSignal = Component.DisconnectMiddleDownSignal
    Component.observe = Component.Observe
    Component.destroy = Component.Destroy
    
    -- Additional aliases for complete coverage
    Component.Changekey = Component.ChangeKey
    Component.ChangeKeys = Component.ChangeKey
    Component.changeKeys = Component.ChangeKey
    Component.Addkeys = Component.AddKey
    Component.addkeys = Component.AddKey
    Component.Removekeys = Component.RemoveKey
    Component.removekeys = Component.RemoveKey
    Component.Middleup = Component.MiddleUp
    Component.Middledown = Component.MiddleDown
    Component.Scroll = Component.Scrolled
    Component.DisconnectScroll = Component.DisconnectScrolledSignal
    Component.DisconnectMove = Component.DisconnectMovedSignal
    Component.DisconnectMiddleDown = Component.DisconnectMiddleDownSignal
    Component.ObserveInput = Component.Observe
    Component.cleanup = Component.Destroy
    

News

  • Now the module can support the Mouse.
    local MouseTest = UserInput.new({InputType = "Mouse", Keys = {
    	Enum.UserInputType.MouseButton3, -- Middle Mouse Button
    	Enum.UserInputType.MouseButton1 -- Left Mouse Button
    }})
    
    MouseTest:Pressed(function(key)
    	print(key)
    end)
    
    MouseTest:Released(function(key)
    	print(key)
    end)
    
    --@MouseOnly
    MouseTest:Scrolled(function(scrollAmount)
    	print(scrollAmount)
    end)
    
    --@MouseOnly
    MouseTest:MiddleUp(function(key)
    	print(key)
    end)
    
    --@MouseOnly
    MouseTest:MiddleDown(function(key)
    	print(key)
    end)
    
    --@MouseOnly
    MouseTest:Moved(function(pos)
    	print(pos)
    end)
    
    MouseTest:DisconnectPressed()
    MouseTest:DisconnectReleased()
    --@MouseOnly
    MouseTest:DisconnectScrolledSignal()
    --@MouseOnly
    MouseTest:DisconnectMiddleUpSignal()
    --@MouseOnly
    MouseTest:DisconnectMiddleDown()
    --@MouseOnly
    MouseTest:DisconnectMovedSignal()
    
1 Like

File UserInput

Version : 1.3.2

  • string is now supported when adding,removing and changing keys

    local Input = UserInput.new({InputType = "Keyboard",Keys = {"E"}})
    
    Input:AddKey({"C"})
    Input:RemoveKey({"E","C"})
    Input:ChangeKey({"E","A"})
    Input:ChangeInputType("Mouse",{"MouseButton1"})
    
  • Fixed almost all warnings making the code more readable

  • Added DisconnectAll

    --[[
    	Disconnect all signals
    	Useful for clean up events
    ]]
    function Component.DisconnectAll(self : UserInputComponent)
    	self:DisconnectPressed()
    	self:DisconnectReleased()
    	self:DisconnectMiddleUpSignal()
    	self:DisconnectMiddleDownSignal()
    	self:DisconnectScrolledSignal()
    	self:DisconnectMovedSignal()
    end
    
  • Alias for DisconnectAll

    Component.disconnectAll = Component.DisconnectAll
    Component.disconnectall = Component.DisconnectAll
    
  • ChangeInputType can now set keys (Optional)

    ChangeInputType(InputType: "Gamepad" | "Keyboard" | "Mouse",Keys : {Enum.KeyCode | Enum.UserInputType}?) -- Empty by default
    
  • UserInput.new the InputConfiguration is now optional

    local Input = UserInput.new() -> {Keys = {},InputType = "Keyboard"}
    
1 Like