BetterInput - A better UserInputService

Introduction

If you at some point in you’re scripting career experienced what is known as, elseif hell.
Using the elseif statement is makes code practically unreadable, and annoying to even look at.

To solve this issue, I have created BetterInput! It operates using csqrl’s RawSignal module, and is far easier to use than UserInputService. But it is not meant to be a total replacement, although in the future I will make it replace UserInputService completely.

Installation

If you would wish to try out BetterInput, simply get the module from the toolbox!

Documentation

local BetterInput = require(path.to.BetterInput)


-- We give it Enum.KeyCode.F for the key we want to pick up.
-- We also give it true to see if the input should be game processed or not. (Optional)
BetterInput.InputBegan(Enum.KeyCode.F, true):Connect(function()
    print("F was pressed!")
end)

-- InputEnded follows the same rules as InputBegan
BetterInput.InputEnded(Enum.KeyCode.F, true):Connect(function()
    print("F was pressed!")
end)

local dict = {
  [Enum.KeyCode.R] = function()
     print("R was pressed/released!")
  end
  [Enum.KeyCode.W] = function()
     print("W was pressed/released!")
  end
}

-- This registers a dictionary of inputs to InputBegan
BetterInput:InputBeganDict(dict)

-- There is also a InputEnded version
BetterInput:InputEndedDict(dict)

If you have any questions, comments, or feedback, please let me know!

21 Likes

What if you just wanted to check when it was pressed?

A simple and nice module. I like it. Though, why are there 2 RawSignal modules in the model?

Seems to be fixed now! I selected the RawSignal module as well, so it also provided that inside the model.

As explained in the documentation,

You can listen for a single button press like this;

local BetterInput = require(path.to.BetterInput)

BetterInput.InputBegan(Enum.KeyCode.F):Connect(function()
    print("F was pressed!")
end)

I’ve always been finding binding something specific using userinputservice tedious. Sure you can use ContextActionService, but this case works too. The issue is that, if you disconnect the signal, it only disconnects RawSignal and not the listener for inputs, causing a memory leak (and yes connections aren’t garbage collected).
The safer approach would be to make array/dictionary containing user input listeners and the listeners would be handled by a single UserInputService.InputBegan and UserInputService.InputEnded signal connections.
So yeah the resource has some use and potential, but the fatal flaw is that disconnecting the input listener will cause a memory leak. (which can end up fatal in long-term use if you rely on disconnecting user inputs from time to time.)

4 Likes

I am aware of this issue already, I have a fix implemented, I just haven’t pushed it yet due to me trying to add more features.

This has 0 use case at all. It would be better to set up your own architecture.

4 Likes

While zero use in practicality, yes. It is meant to make code way more readable, and comes with functions that connects a dictionary of inputs to their respective callbacks.

Then why not use a single BindInput function? Both of the functions you provided do the exact same thing.

1 Like

As I said a fix is in place, which uses only one bind event. I am trying to work out new features which is why its not released yet. Give me like 20min and it should be out.

An IF statement would be better than using this module.

Using this module will not only create lots of inputbegan options, but you will start to see a inputbegan chain instead of if chains. If chains are, more efficient obviously.

2 Likes

This is just a wrapper module that makes UserInputService slightly more complicated. It takes the same amount of time to write a dictionary then it does to just chain if statements, and typically your not even going to have enough cases where you would need something more dynamic.

You also stated that “elseifs” are unreadable. This is not even true because if they are really that unreadable to you, just utilize comments, as they exist for a reason.

2 Likes

This looks very interesting! Don’t listen to everyone else. I think this is very useful. I mean yes it doesn’t really make a difference when it comes to efficiency but it does very much help with readability. I see that was your goal and I think you have very much achieved it! Amazing job!

I will definitely consider using this! Thank you very much!

Why would we need to use this over this:

local UserInputService = game:GetService("UserInputService")

UserInputService.InputBegan:Connect(function(input, isProcessed)
   if isProcessed then return end
   if input.KeyCode == Enum.KeyCode.F then
      print("F was pressed!")
   end
end)

and when I look into the code, you still use normal userinputservice, so it’s still the same

5 Likes

ContextActionService is a better UserInputService. This doesn’t really reduce code at all, I would much rather use if statements or efficiency with tables and functions.

6 Likes

You cant state “don’t listen to everyone else” because that is just turning a blind eye to actual criticism. You are just supporting something that makes more work for people. You can never improve if you don’t listen to actual criticism, but you are just making things worse by encouraging a wrapper to exist, even though it just makes a more complicated solution for developers.

This doesn’t just apply to programming, but to every field of work. If you can’t take criticism, you will never improve, and will be stuck wondering why people are questioning what you have made.

4 Likes

I apologize if I sounded rude. I wasn’t saying to ignore the criticism but rather the negativity. Yes he should learn from the criticism but I don’t think everyone should be bashing him for this. That’s what he shouldn’t be listening to

In my personal experience with this module I have found it to be less work than UserInputService, and overall just easier to read. That’s just my experience and that may vary from person to person.

Overall I apologize that I came off rude and my intent was not to tell him to ignore the criticism but rather to ignore the negativity and bashing angled towards him.

1 Like

Yes, this is rhetorical if you’re script only needs a few keys, however for larger scripts (ex. a gun) it becomes a lot easier to read, and assign functions to those inputs. As for still using UserInputService, consider this module a wrapper. It only increases readability and gives some bonus functions to help out.

I don’t even need to use it because you have to do some dicts, and you’re wrong that elseif makes the code unreadable, if they’re unreadable to you, then why not utilize comments? And why not a single BindInput function?

1 Like