Say Goodbye to Ugly Input Code =( → Meet CoolerInput :-D

Say Goodbye to Ugly Input Code :triumph: - Meet CoolerInput :sunglasses::sparkles:

:bangbang:This is a pretty bad resource, I am recoding it after I can do meta tables better

Tired of Roblox’s default UserInputService being hard to read and work with?
Yeah… same. So I made something better, cleaner, and way more powerful:
Introducing CoolerInput :brain::fire:

:jigsaw: Features:

:white_check_mark: Easy-to-use InputBegan and InputEnded handlers
:video_game: Supports KeyCodes and MouseButtons
:brain: Detects Combinations like Shift + C
:dart: Handles Input Sequences like A → B → C
:stopwatch: Supports time-limited and unlimited input chains
:eagle: Multiple functions per input supported

:scroll: Example Code (How to Use It):

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CoolerInput = require(ReplicatedStorage.Services.CoolorInput)

-- Simple key input
CoolerInput.Began[Enum.KeyCode.E] = function()
	print("E Began")
end

CoolerInput.Ended[Enum.KeyCode.E] = function()
	print("E Ended")
end

-- Mouse button input
CoolerInput.Began[Enum.UserInputType.MouseButton1] = function()
	print("M1 Began")
end

CoolerInput.Ended[Enum.UserInputType.MouseButton1] = function()
	print("M1 Ended")
end

-- Combo input: Shift + C
CoolerInput.CombinationBegan[{Enum.KeyCode.LeftShift, Enum.KeyCode.C}] = function()
	print("Left Shift + C Began")
end

CoolerInput.CombinationEnded[{Enum.KeyCode.LeftShift, Enum.KeyCode.C}] = function()
	print("Left Shift + C Ended")
end

-- Input sequence: A → B → C (within 2 seconds)
CoolerInput.RegisterSequence({Enum.KeyCode.A, Enum.KeyCode.B, Enum.KeyCode.C}, 2, function(sequence, duration)
	print("Secret Combo (A → B → C) completed")
	print(string.format("Time taken: %.2f seconds", duration))
end)

-- Input sequence: U → B → C (no time limit)
CoolerInput.RegisterSequence({Enum.KeyCode.U, Enum.KeyCode.B, Enum.KeyCode.C}, nil, function(sequence, duration)
	print("Secret Combo (U → B → C) completed")
	print(string.format("Time taken: %.2f seconds", duration))
end)

:brain: Get IT NOW

:link: Get CoolerInput Here V1
:link: Get CoolerInput Here V1.1

:warning: Issues to be fixed soon

–For the people complaining, keep in mind that this solves non-existent functionality such as input sequences or combinations, and keeps scripts more easier to read rather than using input service.

–I am not a great programmer, I never knew about static functions, so if your going to say something about them unless you are actually referring to Code and are willing to show me improvements

actual issue - Recode with static functions since it boosts preformance by 10-20% or whatever.

actual issue - No way to send single events, it just sends multiple over and over

:speech_balloon: Feedback & Suggestions

Got ideas or found bugs? Let me know below!
Let’s make input on Roblox not suck together :heart:

21 Likes

What if I want to assign multiple functions to my W key? I haven’t checked the code, it may use newindex to connect the function behind the scenes. However, it isn’t implicit from the design and isn’t explained within this thread, so can I do so?

Don’t work with inputs too much, but I remember how painful and unintuitive they were to use. The approach you are taking now, for the most part, seems to be right up my alley if I ever get to work on UI again.

2 Likes

No, you cannot.
Thank you for pointing this out, I will implent this, 15 ish minutes prolly.

This is what AI has said about this,

-- Assign the first function to the 'W' key press event
CoolerInput.Began[Enum.KeyCode.W] = function1

-- At this point, when 'W' is pressed, 'function1' will be called.

-- Now, assign a second function to the *same* 'W' key press event
CoolerInput.Began[Enum.KeyCode.W] = function2

-- Because of how the 'CoolerInput.Began' table and its __newindex work,
-- this assignment (CoolerInput.Began[Enum.KeyCode.W] = function2)
-- *overwrites* the previous value stored for Enum.KeyCode.W in the
-- internal 'beganCallbacks' table.

-- So, 'function1' is replaced by 'function2'.

-- When the 'W' key is actually pressed by the user, the InputBegan
-- event handler in the CoolerInput module looks up the callback
-- for Enum.KeyCode.W. It finds and calls only the *single* function
-- currently stored there, which is 'function2'.

-- Therefore, 'function1' will NOT be called, only 'function2'.
1 Like

Updated! Tbh I just used ai to make it based off of how I told it to do, you can now run multiple functions at once with,

CoolerInput.Began[Enum.KeyCode.W] = function1
CoolerInput.Began[Enum.KeyCode.W] = function2

Your comment also gave me the idea to do something like this though | which I am now working on

function print1()
	print("1")
end
	
function print2()
	print("2")
end
	
CoolerInput.Began[Enum.KeyCode.E] = {print1(), print2()}

thank you for your comment. :heartpulse::hear_no_evil:

2 Likes

Why is listening to input events done via __index and __newindex instead of via simple static functions like CoolerInput.combinationEnded(), CoolerInput.began(), etc? Not only is this slower, it’s also way uglier and way less readable, which is what your title claims to fix :confused:

> Also, typo!:
image

I quite like the idea of multiple being accepted at once!

I have a few assumptions that may need to be cleared up.

  1. The function input into RegisterSequence will run whenever the keys are pressed in a specific order, and can run multiple times.
  2. For timed RegisterSequences, the timer will only start when pressing the first key and will immediately stop when another key other than the second is pressed.

I have a few more ideas.

  1. Ability to exclude keys from registerSequences, mainly so we can move whilst performing the sequence.

  2. Ability to register a sequence that runs only once.

  3. Ability to register a sequence that has a cooldown period.

I never Stated that this is a faster approach,

Being honest here, I am not a great programmer, I don’t know hwat static functions are, :grin:. I will look into this though, especailly since its a faster and better approach.

And for code readability, I don’t frankly care about what people consider looks better, only what looks good to ME, if others really care about readability they can edit it themselves, since this module is just a helping module and many prolly wont edit it.

I’m not talking about the readability of the module, I’m talking about the readability of code using this module

Using __index and __newindex to register callbacks not only is confusing for even decently large codebases, it’s also just bad practice in general (luau extremely discourages using __newindex as a function in the first place, not to mention using it for stuff like this)

Static functions are just functions that don’t change and aren’t methods (aka are called with . instead of :), for functions which just do some specific thing unrelated to objects, they are recommended to be static, both for performance and usability (you can declare static functions as its own variable without needing to pass self as the first parameter)

Fair enough, I know a good few people who writes code like this :person_shrugging: Though C++ overloads << for stream writing, doesn’t mean it’s not bad practice.

Though, if you’re gonna make what’s readable only to you, I’d change the title. It generally declares that this module is gonna solve all your ugly input code problems :person_shrugging:

The function input into RegisterSequence will run whenever the keys are pressed in a specific order, and can run multiple times.

– Can fix that,

For timed RegisterSequences, the timer will only start when pressing the first key and will immediately stop when another key other than the second is pressed.

– Can fix that,

I like your ideas alot. Definitely alot on my plate to handle though, it is worth it to make the module as best as it can be for sure.

these fixes/ideas will take around and hour or 3,

2 Likes

useless bloat resource, created with AI, not point in using it and the syntax is not nice to look at

5 Likes

For this, I feel like if the types matched the intention is would be alright. Although I do agree that it requires a few extra glances and some time to consult the ancient one in order to understand what exactly is going on.

Oh… didn’t even know it could be a table. Thanks for that tidbit, although it means I will have to do alot more work.

For @Bamboorods: Encountered the same issue myself not too long ago, my solution was to do:

-- Was
local a = {}
a.b = function() end
-- Now
local a = {} :: {b: (func: (whateverArgs: any)->()) -> ()}
-- Has function autocomplete***
a.b(function(whateverArgs) end)
1 Like

Oh gosh, you misunderstood. I did not say there was an issue with them, only that I was uncertain the exact meaning behind them and wanted confirmation as to whether my assumptions were correct.

It’s not useless. Though I admit it has some bloat. It’s not AI-generated, except for a small part/quick fix version (1.1), where I used AI to help structure how multiple functions could be handled through a single input. However, I gave it good clear instructions, and the final code worked without issues.

I’m not an expert programmer, but hearing someone label my work as “AI-generated” is annoying, especially when I’ve put real effort into creating something I’m open to improving.

Sorry if the code looks like it came from AI, but that is not the case.

Edit : The post is ai, only reason why is I am not an english speaker/writer, and I also wanted some more comical feelings out of it, as a joke saying “Hey, robloxs userinputservice is hard to read”

4 Likes

Sorry, english is not my native language, I google translate. Your assumptions are probably correct, you can always test urself.

2 Likes

I feel like this is kinda solving a nonexistent problem when it comes to just detecting basic inputs, you can either use CAS, or even with UserInputService it’s either a few if statements, or you make a table describing all the inputs you wanna detect and 1 InputBegan connection which simply accesses an entry from it using the InputObject, in which case you know exactly what is going on at all times, and can easily make simple functions that just add an input and a callback to one of the tables

For combinations and sequences tho I do agree a free utility module is nice to have, though the way it is implemented is very hard to modify or even understand :frowning: It would be nice if you maybe stepped back and rethinked how the entire thing works, and how you could make it more straightforward to understand (Not only is this beneficial for people who wanna edit the module itself, it’s also beneficial for people who just use it, who now know exactly how it works and will know what bugs/issues in their game are perhaps caused by some usage of the module, and even yourself, who now is able to maintain the module better and more efficiently)

Again, I get your point and side. I will say 1 thing, this is a resource for many people to use that are don’t enjoy how robloxs UIS is used. Or for people that are too lazy or want atleast SOMETHING to refrence to if they wanted to make it, yet it may not be the best readable code, it is atleast something.

2 Likes

I’m just saying, if you’re gonna post resources on the devforum you should try improving them, for yourself and others too, instead of just saying “it is what it is” :V

2 Likes

I get where you’re coming from improving resources is always the goal, and feedback is key for that. My point was just that posting something with the intent to refine it (and being open to suggestions) is better than treating it as ‘final’ when it could be better.

I am not aurging about this, but I apprecitate you for telling me about static functions.

4 Likes

Sorry bro this aint it. regular connect is way superior and this just lacks functionality

1 Like

Shift+C → nothing
C+Shift → Left Shift + C Began

1 Like