Skip to content

Mac-like Keyboard in Linux

If you came to Linux from Mac and found the default keyboard shortcuts less than ideal, then this article is for you. It's actually quite easy to get a keyboard setup that is like Mac, maybe even better!

PC vs. Mac Keyboards

While some large keyboards may have an extra key, most laptop keyboards and common external keyboards have the following layout on the bottom row of keys:

PC:    Ctrl  FN  Super  Alt  [SPACE]  Alt  Ctrl
Mac:   Ctrl  FN   Opt   Cmd  [SPACE]  Cmd  Opt

My biggest complaint with the PC layout is that the Ctrl key is the most used modifier and it is not in the same position on both sides of the spacebar, nor is it the closest key to the spacebar. Remapping keys like this is far better in my opinion.

Ideal: Super FN   Alt  Ctrl  [SPACE]  Ctrl  Alt

Create a System-wide Keyboard Map

It's super easy to remap your keyboard with udev. Use a tool called evtest to record the codes produced when you press each key on your keyboard. Jot them down along with the event number (identifier) for the keyboard. In my case the keyboard event was 4. Use the event number to get the device identifier udev will match against (note the 4 in event4):

cat /sys/class/input/event4/device/modalias 
input:b0011v0001p0001eAB83-e0,1,4,11,14,k71,72,73,74,75,76,77,79,7A,7B,7C,7D,7E,7F,80,8C,8E,8F,9B,9C,9D,9E,9F,A3,A4,A5,A6,AC,AD,B7,B8,B9,D9,E2,ram4,l0,1,2,sfw

Copy that first bit to identify your keyboard. Then all you have to do is create a text file to map the keys how you like them. The text below is the mapping for the keyboard on my System76 Lemur Pro (lemp10) laptop. The codes like "3a" and "1d" are the result of using evtest above.

/etc/udev/hwdb.d/10-mod-keyboard-system76-lemp10.hwdb

evdev:input:b0011v0001p0001*    # AT Translated Set 2 keyboard"
##KEYBOARD_KEY_3a=leftctrl      # capslock to l_ctrl
 KEYBOARD_KEY_1d=leftmeta       # l_ctrl to super
 KEYBOARD_KEY_db=leftalt        # l_super to l_alt
 KEYBOARD_KEY_38=leftctrl       # l_alt to l_ctrl
 KEYBOARD_KEY_b8=rightctrl      # r_alt to r_ctrl
 KEYBOARD_KEY_9d=rightalt       # r_ctrl to r_alt

If you have external keyboards, repeat the process and create a similar file per keyboard. With those files in place, two quick commands will make the changes effective immediately:

# For systemd Linux systems (most will use this)
systemd-hwdb update

# For non-systemd (like Void Linux)
udevadm hwdb -u

udevadm trigger

VoilĂ ! Keys mapped! What's great about this approach is it's system-wide, i.e., it's not tied to GNOME or X. Your keys will be mapped no matter where you are.

Tweak Your Desktop Environment's Shortcuts

You'll probably want to tweak a few core keyboard shortcuts in your desktop environment to complete the Mac-like setup. The changes below are for GNOME, but should generally be the same in any DE. In GNOME, go to Settings > Keyboard. My suggested changes are:

close window                       =>  ctrl q
switch applications                =>  ctrl tab
switch windows of an application   =>  ctrl `
move to workspace left             =>  alt left
move to workspace right            =>  alt right
move to window to workspace left   =>  alt shift left
move to window to workspace right  =>  alt shift right
show the overview                  =>  ctrl space
show all apps                      =>  ctrl shift space

Kitty: A Highly Configurable Terminal

Kitty is my favorite terminal and one of the reasons why is how easy it is to configure the keyboard shortcuts. I took the approach below to have the control key act like more like the Cmd key by default, and Ctrl+Shift acts like a traditional control key. This also has the Mac convention of Cmd+. acting like Ctrl-c. The hex codes map to the control characters you get when pressing ctrl+key at a traditional terminal.

kitty_mod ctrl

# Map common terminal control+key shortcuts
map kitty_mod+.     send_text normal,application \x03
map ctrl+shift+a    send_text normal,application \x01
map ctrl+shift+b    send_text normal,application \x02
map ctrl+shift+c    send_text normal,application \x03
map ctrl+shift+d    send_text normal,application \x04
map ctrl+shift+e    send_text normal,application \x05
map ctrl+shift+f    send_text normal,application \x06
map ctrl+shift+g    send_text normal,application \x07
map ctrl+shift+h    send_text normal,application \x08
map ctrl+shift+i    send_text normal,application \x09
map ctrl+shift+j    send_text normal,application \x0A
map ctrl+shift+k    send_text normal,application \x0B
map ctrl+shift+l    send_text normal,application \x0C
map ctrl+shift+m    send_text normal,application \x0D
map ctrl+shift+n    send_text normal,application \x0E
map ctrl+shift+o    send_text normal,application \x0F
map ctrl+shift+p    send_text normal,application \x10
map ctrl+shift+q    send_text normal,application \x11
map ctrl+shift+r    send_text normal,application \x12
map ctrl+shift+s    send_text normal,application \x13
map ctrl+shift+t    send_text normal,application \x14
map ctrl+shift+u    send_text normal,application \x15
map ctrl+shift+v    send_text normal,application \x16
map ctrl+shift+w    send_text normal,application \x17
map ctrl+shift+x    send_text normal,application \x18
map ctrl+shift+y    send_text normal,application \x19
map ctrl+shift+z    send_text normal,application \x1A

# Assign no_op to control+key sequences to pass through
map kitty_mod+space   no_op
map kitty_mod+a       no_op
map kitty_mod+e       no_op