47

Apple's MacBook Pro has a slight delay on the caps lock key. That is, the caps lock key has to be held down slightly longer than normal to register the key press required to engage the caps lock.

This is super annoying. Does anyone know how to stop it from happening?

(Above copied over from stackoverflow as it was closed there as "off topic".)

To elaborate further: Apple deems this a feature, and their knowledge base article does not disclose how to disable this delay.

However, I have reason to believe it is possible to do so.

Notably, I have found that, at least in my experience, if you remap the caps-lock key on Mac OS X (in System Preferences .. Keyboard .. Modifier Keys), and e.g. map it to Control, then the delay goes away while I am logged into Mac OS X.

My problem is that the delay remains when I boot into Ubuntu Linux, and in that context, even when I remap the Caps Lock key to Control, the delay is still present.

So, the question is: How is Apple disabling the delay, and more importantly, how can one replicate that act in the context of a Linux installation atop the laptop?

Update: There is a thread on superuser that may provide workarounds. I have not yet tried the suggestions there (namely: (1) toggling CapsLock-NoAction off/on, and (2) a firmware upgrade). I cannot tell from the context of that thread whether the workarounds have been tested on an Ubuntu installation.

7
  • I have never noticed this before now, but I have had a play with mine and I can see what you mean. If you tap the caps lock key too quickly it does nothing. I never found it a problem before but just tried the disable/re-enable the caps lock key trick and it has made it instant! now no matter quickly I hit the key it always toggles caps lock. Very strange!
    – tom1990
    Mar 8, 2013 at 23:21
  • Always thought I was just going crazy :p I can see its benefit, but in some situations it really annoys me. Would be good to know if its possible!
    – OrangeBox
    Apr 1, 2013 at 22:47
  • Indeed, the disable/re-enable caps lock trick (on the Mac OS X side), does seem to make the problem go away once one subsequently reboots to Linux. But it is not clear to me if the effect is permanent -- I left my machine powered-off for some time (weeks or perhaps even more than a month), and when I booted it straight to Linux this morning, it seemed like the delay had returned. Still quite mysterious to me.
    – pnkfelix
    Apr 28, 2013 at 16:47
  • 1
    So just to check, there doesn't appear to be a fix for linux for this issue?
    – Mike H-R
    Jul 29, 2015 at 18:47
  • 1
    Here is a fix that works for macOS and can be run under macOS.
    – fel1x
    Feb 22, 2019 at 7:12

8 Answers 8

29

I've figured out how to do this. In short, you must send a "Feature Report" consisting of the bytes 0x9, 0x0, 0x0, 0x0 to the appropriate hidraw device as root.

You can find the right hidraw device with this command:

dmesg | grep Apple | grep Keyboard | grep input0 | tail -1 | sed -e 's/.*hidraw\([[:digit:]]\+\).*/\/dev\/hidraw\1/'

The code to send the magic control packet is below. Compiles with gcc, takes the hidraw device as parameter. So the entire flow is:

  1. save the code below as disable-capslock-delay.c
  2. gcc -o disable-capslock-delay disable-capslock-delay.c
  3. HIDDEVICE=$(dmesg | grep Apple | grep Keyboard | grep input0 | tail -1 | sed -e 's/.*hidraw\([[:digit:]]\+\).*/\/dev\/hidraw\1/')
  4. sudo ./disable-capslock-delay $HIDDEVICE

Steps 3 and 4 have to be done every time you reboot (or unplug and re-plug the keyboard); you can put them into /etc/rc.local (or your distro's equivalent) to execute them at boot (you don't need sudo in that case; and you might want to move the compiled binary into /usr/local/sbin/ or something).

I've put in some safety checks for vendor ID, device ID, and report descriptor length. You may have to change the latter two if your model differs from mine.


#include <linux/hidraw.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) { if (argc != 2 || strcmp(argv[1], "-h") == 0) { printf("Pass a hidraw device as the first and only parameter!\n"); printf("You may find the right device with:\n"); printf(" dmesg | grep Apple | grep Keyboard | grep input0 | tail -1 | " "sed -e 's/.hidraw\([[:digit:]]\+\)./\/dev\/hidraw\1/'\n"); return 1; } int fd, i, res, desc_size = 0; char buf[256]; struct hidraw_devinfo info; char *device = argv[1]; fd = open(device, O_RDWR | O_NONBLOCK); if (fd < 0) { perror("Unable to open device"); return 1; } memset(&info, 0, sizeof(info)); memset(buf, 0, sizeof(buf)); // Get Report Descriptor Size res = ioctl(fd, HIDIOCGRDESCSIZE, &desc_size); if (res < 0) { perror("HIDIOCGRDESCSIZE"); } if (desc_size != 75) { printf("Error: unexpected descriptor size %d; you've probably got " "the wrong hidraw device!\n", desc_size); return 1; } // Get Raw Info res = ioctl(fd, HIDIOCGRAWINFO, &info); if (res < 0) { perror("HIDIOCGRAWINFO"); } else { if (info.vendor != 0x05ac) { printf("Error: Wrong vendor ID, make sure you got the right " "hidraw device!\n"); return 1; } if (info.product != 0x0250) { printf("Warning: Unknown product ID 0x%x!\n", info.product); } } // Get Feature buf[0] = 0x09; // Report Number res = ioctl(fd, HIDIOCGFEATURE(256), buf); if (res < 0) { perror("HIDIOCGFEATURE"); } else { printf("HID Feature Report (before change):\n\t"); for (i = 0; i < res; i++) printf("%hhx ", buf[i]); puts("\n"); } // Set Feature buf[0] = 0x09; // Report Number buf[1] = 0x00; // Report data buf[2] = 0x00; // padding buf[3] = 0x00; // padding res = ioctl(fd, HIDIOCSFEATURE(4), buf); if (res < 0) { perror("HIDIOCSFEATURE"); } else { printf("Caps lock delay disabled.\n"); } // Get Feature buf[0] = 0x09; // Report Number res = ioctl(fd, HIDIOCGFEATURE(256), buf); if (res < 0) { perror("HIDIOCGFEATURE"); } else { printf("HID Feature Report (after change):\n\t"); for (i = 0; i < res; i++) printf("%hhx ", buf[i]); puts("\n"); } close(fd); return 0; }

7
  • 4
    This looks great, thanks! out of interest, how did you find this (the magic bytes required to be sent)?
    – Mike H-R
    Sep 16, 2015 at 9:25
  • 10
    @MikeH-R: I've spent a day learning how the HID protocol works: essentially, devices describe what data packets ("reports") they understand. Unfortunately the Apple keyboard doesn't mention the report in question in its HID descriptors. However I found a dump of a MacBook's internal keyboard's HID descriptors that someone had posted which did contain the right report description, and I simply tried that and found that it works for the external wired keyboard as well.
    – jmrk
    Sep 16, 2015 at 19:05
  • 1
    Oh wow I have to try this out!
    – pnkfelix
    Apr 5, 2016 at 8:35
  • 1
    (I do seem to get different descriptor sizes, at the very least. Still I'll adjust them and see how it works out.)
    – pnkfelix
    May 21, 2016 at 17:38
  • 1
    I'm going to accept this answer because it comes the closest to actually acknowledging the problem as described and providing a believable solution to it (even though in my own case the descriptor sizes are different).
    – pnkfelix
    Nov 19, 2016 at 2:05
20

Here is the fix for macOS Sierra.

Go to System Preferences > Accessibility

When the accessibility window is open — on the left part of the window – click Keyboard

Then there will be the 2 options — for sticky keys, and for slow keys — click the box next to slow keys to enable it — then click the Options... button – a new window will come up with a slider to change the acceptance delay — by default this is in the middle. Slide the button all the way to the left, so that it is the shortest time possible.

Now it should be fixed. Have not experimented to see if the fix stays upon restart, but I’m hopeful that it will.

4
  • I got excited for a sec but when I went to look here, slow keys wasn't enabled so only works for people who use slow keys :( one day I will have my precious caps lock key back!
    – Bradley
    Jan 4, 2018 at 9:56
  • 5
    This does reduce it a bit, but it's still slower to to turn on caps-lock than turn off. Also the key repeat rate slows down to a crawl, even though the setting is on fastest. (Sierra 10.12.6)
    – scipilot
    Jan 6, 2018 at 0:22
  • 5
    this isn't a proper solution to the problem at hand as it slows down keyrepat and you no longer can properly delete stuff when holding backspace.
    – Denialos
    May 30, 2018 at 6:14
  • 1
    On Monterey this works
    – Rafs
    Dec 22, 2021 at 10:11
8

EDIT: This seems to be a popular landing question for users looking to remove the delay on the caps lock key in OS X. As of OS X Mojave,

Go to System Preferences; Accessibility; Keyboard; enable Slow Keys and go into options; turn the delay down to the minimum. The only unwanted side-effect I've noticed so far is slow backspace action when holding it down. Generally I use CMD+A / CMD+SHIFT+L/R / CMD+SHIFT+CTRL+L/R anyway so it's not a big issue.

As of El Capitan and earlier,

The solution is quite elusive, and you wouldn't really know you removed it unless you were specifically trying to get rid of it in the first place. The way I am going to show you is purely for the (current)latest version of OSX, Yosemite. However you can absolutely apply this method to previous and future versions.

The solution is simple. If you navigate to Keyboard in the System preferences via the apple logo in the top left hand corner you will reach this screen

enter image description here

If you click the modifier keys button, you are able to change the function of each of the keys which are programmable. All you have to do is set the caps lock key to no action and press ok to bring you back to the keyboard menu. Once done, go back into the modifier keys and change the caps lock key back to caps lock and this will remove the delay! Do note that this fix remains in place until you sleep, restart or power down the device. At which point the delay is reinstated.

They're strange fixes, and it begs the question why do they not provide an option to remove the delay when this fix is purely software based. But hey, at least there is a way!

Happy capsing.

4
  • 1
    How does this solve my problem in Linux?
    – pnkfelix
    May 20, 2015 at 11:39
  • To be clearer: the original question said: "... the delay goes away while I am logged into Mac OS X. My problem is that the delay remains when I boot into Ubuntu Linux, and in that context, even when I remap the Caps Lock key to Control, the delay is still present."
    – pnkfelix
    May 20, 2015 at 11:39
  • Ah! I see, I guess I should read OP questions more carefully. I found on OSX that unbinding the caps key completely and rebinding solved the issue. Maybe the delay remains because you're binding to control instead? Worth trying everything if you don't yet have a work around :)
    – Bradley
    May 20, 2015 at 21:33
  • 1
    This approach didn't have any effect for me. (Sierra 10.12.6)
    – scipilot
    Jan 6, 2018 at 0:23
4

Elaborating on @jmrk answer. His code works well for the so called "aluminum" keyboard, but apple also released wireless keyboards, under the name "magic keyboard", with product id 0x022d. (They also have aluminum chassis, and I think that my model is from 2008 or so.) This product has the same caps lock issue, and almost the same code can fix it. Beside changing the product id, the descriptor size is 218, and the data to send is not 0x00, but 0x01:

buf[0] = 0x09;  // Report Number
buf[1] = 0x01;  // Report data

I found this today and thought to record my answer here in case it helps anyone, including my future self.

Here is a complete program fixing the issue on both kind of devices. You can pass extra hid devices, it'll apply only to known ones. So you can simply call it as ./a.out /dev/hidraw*

#include <linux/hidraw.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv) {
  printf("Pass all devices to configure. For example, like this: %s /dev/hidraw*\n", argv[0]);
  int expected_desc_size;
  char data_to_set;
  for (int argnum=1;argnum<argc;argnum++) {
    printf("Trying to configure %s...\n", argv[argnum]);
    
    int fd, i, res, desc_size = 0;
    char buf[256];
    struct hidraw_devinfo info;
    char *device = argv[argnum];
    fd = open(device, O_RDWR | O_NONBLOCK);
    if (fd < 0) {
      perror("Unable to open device");
      return 1;
    }
    memset(&info, 0, sizeof(info));
    memset(buf, 0, sizeof(buf));
    
    // Get Raw Info
    res = ioctl(fd, HIDIOCGRAWINFO, &info);
    if (res < 0) {
      perror("HIDIOCGRAWINFO");
      return 1;
    }
    if (info.vendor == 0x05ac) {
      printf("Apple device found!\n");
    } else {
      printf("Not an apple device.\n");
      continue;
    }
    if (info.product == 0x022d) {
      printf("We have a 'magic' keyboard\n");
      expected_desc_size = 218;
      data_to_set = 1;
    } else if (info.product == 0x0250) {
      printf("We have an 'aluminium' keyboard\n");
      expected_desc_size = 75;
      data_to_set = 0;
    }
    else {
      printf("Warning: Unknown product ID 0x%x!\n", info.product);
      continue;
    }
    // Get Report Descriptor Size
    res = ioctl(fd, HIDIOCGRDESCSIZE, &desc_size);
    if (res < 0) {
      perror("HIDIOCGRDESCSIZE");
      return 1;
    }
    if (desc_size != expected_desc_size) {
      printf("Error: unexpected descriptor size %d; panic'ing", desc_size);
      return 1;
    }
    // Get Feature
    buf[0] = 0x09;  // Report Number
    res = ioctl(fd, HIDIOCGFEATURE(256), buf);
    if (res < 0) {
      perror("HIDIOCGFEATURE");
    } else {
      printf("HID Feature Report (before change):\n\t");
      for (i = 0; i < res; i++) printf("%hhx ", buf[i]);
      puts("\n");
    }
      
    // Set Feature
    buf[0] = 0x09;  // Report Number
    buf[1] = data_to_set;  // Report data
    buf[2] = 0x00;  // padding
    buf[3] = 0x00;  // padding
    res = ioctl(fd, HIDIOCSFEATURE(4), buf);
    if (res < 0) {
      perror("HIDIOCSFEATURE");
    } else {
      printf("Caps lock delay disabled.\n");
    }
    // Get Feature
    buf[0] = 0x09;  // Report Number
    res = ioctl(fd, HIDIOCGFEATURE(256), buf);
    if (res < 0) {
      perror("HIDIOCGFEATURE");
      return 1;
    } 
    printf("HID Feature Report (after change):\n\t");
    for (i = 0; i < res; i++) printf("%hhx ", buf[i]);
    puts("\n");
    close(fd);
    }
  return 0;
}
4
  • 1
    Thank you so much! If you wanted to edit that at the end of the accepted answer or better - in the flow to call out the two codes for different devices, I would approve that edit.
    – bmike
    Feb 13, 2021 at 14:54
  • 1
    @bmike I've updated the program to be more flexible, which would cause a lot of edits in the original. So I've simply edited my answer to add the code. Once we're confident this works well for more people it'll still be time to improve the top answer.
    – jyp
    Feb 13, 2021 at 20:31
  • I'd +1 again, but I only get one vote - nicely done - this can stand alone much better now.
    – bmike
    Feb 13, 2021 at 20:41
  • 2
    When I searched for a way to disable this annoying delay, I expected quite a bit of manual work. I did not expect someone to hand me convenient code on a silver platter!
    – kqr
    Sep 30, 2021 at 7:42
3

Go to system preferences > accessibility > keyboard > enable slow keys > change acceptance delay all the way to the left (short)! This worked for me.

3
  • Are you describing a step in Mac OS X? How does this solve the problem in Ubuntu Linux, as described in the question?
    – pnkfelix
    Nov 19, 2016 at 2:03
  • Yes, correct. I don't know Ubuntu Linux, sorry. I think I'm solving the main title "How to remove caps lock delay on Apple MacBook Pro aluminum keyboard*" and maybe the question "How is Apple disabling the delay". :-) Best Regards Thomas, Sweden *That question is the reason I found and read this tread and nothing helped so I solved it myself :P Dec 6, 2016 at 14:28
  • 2
    As per Michelle's answer: This does reduce it a bit, but it's still slower to to turn on caps-lock than turn off. Also the key repeat rate slows down to a crawl, even though the setting is on fastest. (Sierra 10.12.6)
    – scipilot
    Jan 6, 2018 at 0:23
0

The "toggling CapsLock-NoAction off/on" solution that the OP refers to works on both my wired Mac keyboard and my MacBookPro keyboard. Bradley says this only works on Yosemite, but I've used it successfully on Snow Leopard (10.6.8) and Mavericks (10.9.5). I have also tested this inside a Kubuntu VM and Caps Lock continued working correctly inside the VM.

  • Open the Keyboard System Preference, and click on Modifier Keys...:

enter image description here

  • Set the Caps Lock key to No Action, and click OK:

                    enter image description here

  • Click on Modifier Keys... again, and set the Caps Lock key to Caps Lock, and click OK:

                    enter image description here

This only remains in effect until the next reboot.

2
  • 1
    This had no effect for me. (Sierra 10.12.6, Mac USB keyboard and internal on MBPro)
    – scipilot
    Jan 6, 2018 at 0:25
  • This is not how the dialogs look anymore, as of Big Sur 11.5.2 on a 2019 MBP at least. Caps Lock is not listed as a modifier key, so cannot be remapped. Also, I notice no delay, and in contrast with the question in question :) I am not using Linux, and I wish I could bring the delay back!
    – conny
    Aug 18, 2021 at 10:43
0
  1. Download and install the following software
  • Karabiner
  • Hammerspoon
  1. Use Karabiner maps CapsLock key to F19.
  2. Edit init.lua under the path ~/.hammerspoon, paste the code below.
pressedF19 = function()
    hs.hid.capslock.toggle()
end

hs.hotkey.bind({}, 'F19', pressedF19, nil)

Then reload the hammerspoon config for changes to take effect.

See my blog here http://hellohtml5.com/2019/04/25/best-way-to-disable-capslock-delay-on-mac/

2
  • Hi, welcome to Ask Different. Thank for your post, but note that the question is about Linux, the OP has already solved the problem on macOS.
    – jaume
    Aug 14, 2020 at 8:04
  • (Offtopic as it works on MacOS, not Linux) Currently it is enough to install Karabiner only, it (since 13.3.0, see here - karabiner-elements.pqrs.org/docs/help/how-to/…) automatically disables CapsLock delay without any manual action.
    – vlad2135
    Jun 16, 2021 at 16:32
0

I've written a very lightweight open source tool to fix exactly that:

https://github.com/gkpln3/CapsLockNoDelay

You must log in to answer this question.

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