"Python AutoClicker" Part 2 I previously posted a question for codereview:
Python Autoclicker
And I received some great feedback and changes to do in the code.
I have done many of the changes mentioned in the answers and here is the final code:
from pynput.keyboard import Controller
from time import sleep


def auto_click(key: str, n_clicks: int, delay: float):
    keyboard = Controller()

    for _ in range(n_clicks):
        keyboard.tap(key)
        sleep(delay)


def main():
    key = input(&quot;Key to be autopressed: &quot;)

    try:
        n_clicks = int(input(&quot;Number of autopresses (integer): &quot;))
    except ValueError:
        print(&quot;\n The number of autopresses should be an integer value, defaulting to 1. \n&quot;)
        n_clicks = 1

    try:
        delay = float(input(&quot;Delay between each autopress in seconds (integer/float): &quot;))
    except ValueError:
        print(&quot;\n The delay between each autoclick should be an integer or a decimal value, defaulting to 1 (second). \n&quot;)
        delay = 1

    auto_click(key, n_clicks, delay)

if __name__ == '__main__':
    main()

What is it that you think should be made better in this code? Any feedback and suggestions would be much appreciated.
Here's the github repo:
https://github.com/SannanOfficial/AutoKeyPython
Your code is generally fine. I suspect you are not doing enough validation (for
example, to forbid negative values or multi-character keys). Also, if you want
to expand your toolkit, you can think about eliminating the duplication in your
code by generalizing the input collection process.
Collecting user input involves a few common elements: an input prompt, a
function to convert the string to a value, a function to validate that value,
an error message in the event of bad input, and possibly some other stuff (max
allowed attempts, fallback/default value in the event of bad input). If we
focus on just the basics, we end up with a function along the lines of this
sketch:
def get_input(convert, validate, prompt, errmsg):
    while True:
        try:
            x = convert(input(prompt + ': '))
            if validate(x):
                return x
            else:
                print(errmsg)
        except ValueError:
            print(errmsg)

With that in hand, all of the algorithmic detail will reside in that single
function, and your main() will be little more than straightforward,
step-by-step orchestration code.
def main():
    key = get_input(
        str.strip,
        lambda s: len(s) == 1,
        'Key to be autopressed',
        'Invalid, must be single character',
    )
    n_clicks = get_input(
        int,
        lambda n: n &gt; 0,
        'Number of autopresses',
        'Invalid, must be positive integer',
    )
    delay = get_input(
        float,
        lambda n: n &gt; 0,
        'Delay between autopresses',
        'Invalid, must be positive float',
    )
    auto_click(key, n_clicks, delay)

As shown in that sketch, I would also encourage you to favor a more compact
style in messages to users. Brevity usually scales better across a variety of
contexts than verbosity: it's easier to maintain; it's easier to make
consistent across an entire application; and most people don't appreciate
having to slog through long messages when an equally clear short one
is possible.
Finally, you might also consider whether input() is the best
mechanism to get this information from the user. In my experience,
it is almost always preferable to take such values from the
command-line, either from sys.argv directly or, more commonly,
using a library like argparse. The advantages
to this approach are numerous.