3
\$\begingroup\$

I am implementing some software with Unity that needs to support Ctrl-<key> shortcuts such as Ctrl-c. I want to do this in a way that respects the user's operating system keyboard preferences; for example, these shortcuts must still be recognized when the user uses sticky keys, or when the user has mapped caps lock as control.

Many of the solutions I found online for implementing keyboard shortcuts look something like this:

if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKeyDown("c")) UnityEngine.MonoBehaviour.print("C-c");

This solution is totally unacceptable to me because it "hard-wires" holding down a control key as the method for sending a control-key modifier, bypassing the operating system's possibly-customized handling of the control key modifier.

Most games don't support keyboard preferences properly, but I am hell-bent on making sure the software I write will do this properly. I'm particularly concerned about supporting sticky keys because this is an accessibility issue - some more complicated shortcuts will not be available to users with disabilities if sticky keys isn't handled correctly.

How can I support keyboard shortcuts properly in Unity?

\$\endgroup\$
6
  • \$\begingroup\$ It should be noted that it is almost impossible to search for help about implementing in-game shortcuts in Unity due to the huge amount of interference from articles about Unity editor keyboard shortcuts. \$\endgroup\$ Commented Jul 31, 2019 at 10:23
  • \$\begingroup\$ Now that I've tested this more thoroughly, I'm curious what it was that led you to believe that this didn't work as desired out of the box. Every different configuration I've tried has the behaviour you want with no special tricks required. In future, I'd recommend doing a test yourself - you might save yourself time searching / asking / waiting for an answer if it turns out to be a non-issue in the first place. If your tests uncover a specific circumstance that deviates from the desired behaviour, you can describe those conditions in your question to be sure they're not overlooked. \$\endgroup\$
    – DMGregory
    Commented Jul 31, 2019 at 17:26
  • \$\begingroup\$ @DMGregory It doesn't work as desired out of the box, at least on Linux/X11. Is this expected to work on Windows? The reason I thought it wouldn't work was partially based on intuition (but mostly based on the empirical evidence it doesn't work) - programs that check the X11 state bitmap to check for Ctrl work, while those that roll their own solution for checking the Ctrl key don't. I'm guessing the Unity devs went with, or expect me to use, the latter solution. Should I file a bug report for this platform-dependent behavior? \$\endgroup\$ Commented Jul 31, 2019 at 19:11
  • \$\begingroup\$ I tested mapping caps lock to control, and enabling sticky keys. Neither resulted in Ctrl-c being detected by the code if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKeyDown("c")) UnityEngine.MonoBehaviour.print("C-c"); , wheras Chrome, emacs, etc. do. \$\endgroup\$ Commented Jul 31, 2019 at 19:14
  • \$\begingroup\$ I've now verified that this works out-of-the-box with no code changes in macOS in addition to Windows builds. So it sounds like what you're observing is a bug in the Linux version specifically. I'd recommend logging it with Unity's developers so they can correct it to match the other desktop platforms. \$\endgroup\$
    – DMGregory
    Commented Aug 1, 2019 at 0:34

1 Answer 1

4
\$\begingroup\$

Good news! This code:

bool ctrl = Input.GetKey(KeyCode.LeftControl) 
         || Input.GetKey(KeyCode.RightControl);

already respects the user's OS settings for sticky keys and key remapping on Windows and macOS at least. And this works whether you specify the key by KeyCode, by a "Conventional Game Input" string, or by a remappable GetButton("Some Custom Name") alias you've defined in the Input Manager.

That's because Unity isn't talking to the keyboard directly; it's asking the OS "Is the left control key pressed?"

The OS, knowing that you've remapped your left shift key to act as the left control, and that you've enabled sticky keys and double-tapped that shift key, is then free to lie to Unity and say "why yes it is!" even if the physical key on your keyboard labelled "CTRL" says otherwise.

Give this a try. Set up a script with some public boolean values that you set in Update based on various key states. Or use them to toggle visibility of some rendered objects. Then enable Sticky keys in your OS, or remap some keys in your registry (and log out / back in to use the updated settings). Run your game, and watch how the values change in reaction to your key presses.

I've just done this in both Windows and macOS, and both sticky keys and registry remapping are correctly respected by Unity, without any changes to my code.

Now of course you can still do one better by allowing players to remap controls within your game, rather than relying on OS-wide/OS-specific settings, but it's good to know that Unity won't disregard those configurations when they're in use on Windows.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .