RSS Amplifier

Morgan Davis · Apr 15, 2026

Map Chromebook Keys in Linux

0
Sign in to vote or save

Morgan Davis · Morgan Davis

Diagram of function key layout on a Chromebook

Did you know you can convert a Chromebook into a Linux laptop? This is a great option for older Chromebooks that Google no longer supports, or if you've outgrown ChromeOS and need a more full-featured operating system.

But what about all those special keys at the top of the keyboard?

This script maps Chromebook function keys to system actions on Linux (any X11 + Cinnamon + Debian-based distro like Linux Mint).

In most cases, running it with --all is all you need. Then reboot and test the keys.

#!/bin/sh
# chromebook-fkey-setup.sh
# Maps Chromebook function keys to system actions on Linux Mint (Cinnamon).
# Run once after a fresh install. Safe to re-run.
#
# Usage: chromebook-fkey-setup.sh [OPTIONS]
# Options:
#   --brightness  Set up screen brightness (udev rule + video group)
#   --xkb         Write xkb symbols file (requires sudo) and apply to current session
#   --apply-xkb   Apply xkb remap to current session only (no sudo, used by autostart)
#   --xbindkeys   Write xbindkeys config and launch daemon
#   --autostart   Install ~/.config/autostart entries for persistence
#   --all         Run all setup functions
#   --help        Show this help message
set -e
SCRIPT_NAME="$(basename "$0")"
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
XKB_SYMBOLS_FILE="/usr/share/X11/xkb/symbols/chromebook"
UDEV_RULES_FILE="/etc/udev/rules.d/90-backlight.rules"
XBINDKEYS_CFG="$HOME/.xbindkeysrc.chromebook"
LOCK_SCREEN_HELPER="$HOME/bin/lock-screen-fkey.sh"
AUTOSTART_XKB="$HOME/.config/autostart/chromebook-fkeys-xkb.desktop"
AUTOSTART_XBINDKEYS="$HOME/.config/autostart/chromebook-fkeys-xbindkeys.desktop"
# ----------------------------------------------------------------------------
# Exit with install hint if a required command is missing.
check_cmd() {
    command -v "$1" > /dev/null 2>&1 && return 0
    echo "ERROR: $1 is not installed. Install with: sudo apt install $2" >&2
    exit 1
}
check_deps() {
    check_cmd xbindkeys xbindkeys
    check_cmd wmctrl    wmctrl
    check_cmd xdotool   xdotool
}
# ----------------------------------------------------------------------------
usage() {
    GRAY='\033[38;5;240m'
    MGRAY='\033[38;5;246m'
    YLLOW='\033[38;5;226m'
    WHITE='\033[1;37m'
    RESET='\033[0m'
    printf "Usage: %s [OPTIONS]\n" "$SCRIPT_NAME"
    cat <<EOF
Options:
  --brightness  Write backlight udev rule, add user to video group (sudo)
  --xkb         Write xkb symbols file (sudo) and apply to current session
  --apply-xkb   Apply xkb remap to current session only (no sudo, used by autostart)
  --xbindkeys   Write xbindkeys config and start daemon
  --autostart   Install ~/.config/autostart entries for xkb and xbindkeys
  --all         Run all of the above
  --help        Show this help message
Key map:
EOF
    printf "  F1   <-    back\n"
    printf "  F2   ->    forward\n"
    printf "  F3   @>    reload\n"
    printf "  F4   ☐     maximize/restore\n"
    printf "  F5   ☐‖    overview\n"
    printf "  F6   ${GRAY}*${RESET}     dim\n"
    printf "  F7   ${YLLOW}*${RESET}     bright\n"
    printf "  F8   ${GRAY}◄)${RESET}    mute\n"
    printf "  F9   ${MGRAY}◄)${RESET}    vol down\n"
    printf "  F10  ${WHITE}◄))${RESET}   vol up\n"
    printf "  F13  [x]   lock screen\n"
    cat <<EOF
Notes:
  - Run --all once after a fresh install.
  - Log out and back in after first run for video group membership to take effect.
EOF
}
# ----------------------------------------------------------------------------
# Writes a udev rule so the video group can write to intel_backlight,
# then adds the current user to the video group.
setup_backlight_udev() {
    echo "[brightness] Writing udev rule: $UDEV_RULES_FILE"
    sudo tee "$UDEV_RULES_FILE" > /dev/null <<'UDEV'
ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="intel_backlight", \
  RUN+="/bin/chgrp video /sys/class/backlight/intel_backlight/brightness", \
  RUN+="/bin/chmod g+w /sys/class/backlight/intel_backlight/brightness"
UDEV
    echo "[brightness] Adding $USER to video group"
    sudo usermod -aG video "$USER"
    echo "[brightness] Triggering udev for backlight subsystem"
    sudo udevadm trigger --subsystem-match=backlight
    echo "[brightness] Permissions: $(ls -la /sys/class/backlight/intel_backlight/brightness)"
}
# ----------------------------------------------------------------------------
# Writes the xkb symbols file to disk and applies it to the current session.
# Requires sudo for the write; apply is session-only with no sudo.
#
# Key map:
#   F1   (FK01) -> XF86Back              browser/app back
#   F2   (FK02) -> XF86Forward           browser/app forward
#   F3   (FK03) -> XF86Launch7           reload (xdotool ctrl+r via xbindkeys)
#   F4   (FK04) -> XF86Launch8           maximize/restore (wmctrl via xbindkeys)
#   F5   (FK05) -> XF86Launch5           overview (expo via xbindkeys)
#   F6   (FK06) -> XF86MonBrightnessDown screen brightness down
#   F7   (FK07) -> XF86MonBrightnessUp   screen brightness up
#   F8   (FK08) -> XF86AudioMute         mute toggle
#   F9   (FK09) -> XF86AudioLowerVolume  volume down
#   F10  (FK10) -> XF86AudioRaiseVolume  volume up
#   FK13 (kc191)-> XF86Launch6           lock screen (lock-screen-fkey.sh via xbindkeys)
#
# XF86Launch5/6/7/8 are used for keys needing custom xbindkeys commands.
# XF86Reload, XF86ScreenSaver, and XF86FullScreen are grabbed by csd-media-keys
# or applications (e.g. Vivaldi), preventing xbindkeys from owning them.
setup_xkb() {
    echo "[xkb] Writing xkb symbols: $XKB_SYMBOLS_FILE"
    sudo tee "$XKB_SYMBOLS_FILE" > /dev/null <<'XKB'
// Chromebook function key remaps
partial modifier_keys
xkb_symbols "fkeys" {
    key <FK01> { [ XF86Back              ] };
    key <FK02> { [ XF86Forward           ] };
    key <FK03> { [ XF86Launch7           ] };
    key <FK04> { [ XF86Launch8           ] };
    key <FK05> { [ XF86Launch5           ] };
    key <FK06> { [ XF86MonBrightnessDown ] };
    key <FK07> { [ XF86MonBrightnessUp   ] };
    key <FK08> { [ XF86AudioMute         ] };
    key <FK09> { [ XF86AudioLowerVolume  ] };
    key <FK10> { [ XF86AudioRaiseVolume  ] };
    key <FK13> { [ XF86Launch6           ] };
};
XKB
    apply_xkb
}
# ----------------------------------------------------------------------------
# Applies the xkb remap to the current X session. No sudo required.
# Called directly at login via autostart.
#
# Note: sed-pipe approach fails because setxkbmap -print closes with "};" not
# "}", so the substitution never matches. Instead we extract the active symbols
# include string with awk and build a complete keymap heredoc for xkbcomp.
apply_xkb() {
    [ -z "$DISPLAY" ] && echo "[xkb] ERROR: DISPLAY not set." >&2 && return 1
    [ ! -f "$XKB_SYMBOLS_FILE" ] && echo "[xkb] ERROR: $XKB_SYMBOLS_FILE not found. Run --xkb first." >&2 && return 1
    echo "[xkb] Applying remap to current X session"
    CURRENT_SYMBOLS="$(setxkbmap -print | awk '/xkb_symbols/ {
        match($0, /include "[^"]+"/)
        print substr($0, RSTART+9, RLENGTH-10)
    }')"
    xkbcomp -w0 -I/usr/share/X11/xkb - "$DISPLAY" <<EOF
xkb_keymap {
    xkb_keycodes  { include "evdev+aliases(qwerty)" };
    xkb_types     { include "complete" };
    xkb_compat    { include "complete" };
    xkb_symbols   { include "${CURRENT_SYMBOLS}+chromebook(fkeys)" };
    xkb_geometry  { include "pc(pc105)" };
};
EOF
    echo "[xkb] Done."
}
# ----------------------------------------------------------------------------
# Writes the xbindkeys config and launches the daemon.
# Handles keys that need custom commands:
#   XF86Launch5 -> Cinnamon expo toggle (overview, F5)
#   XF86Launch6 -> lock-screen-fkey.sh (padlock, F13)
#   XF86Launch7 -> xdotool ctrl+r (reload, F3)
#   XF86Launch8 -> wmctrl maximize/restore (F4)
#
# Delay notes:
#   - 0.1s on expo/lock: Cinnamon silently drops actions fired immediately on keypress.
#   - 0.2s on reload/maximize: focused window must reclaim focus before xdotool/wmctrl fires.
#
# lock-screen-fkey.sh is a separate script because the empty string argument '""'
# required by org.cinnamon.ScreenSaver.Lock cannot be reliably quoted in xbindkeys config.
setup_xbindkeys() {
    echo "[xbindkeys] Writing lock screen helper: $LOCK_SCREEN_HELPER"
    mkdir -p "$(dirname "$LOCK_SCREEN_HELPER")"
    cat > "$LOCK_SCREEN_HELPER" <<'LOCK'
#!/bin/sh
gdbus call --session \
    --dest org.cinnamon.ScreenSaver \
    --object-path /org/cinnamon/ScreenSaver \
    --method org.cinnamon.ScreenSaver.Lock \
    '""'
LOCK
    chmod +x "$LOCK_SCREEN_HELPER"
    echo "[xbindkeys] Writing config: $XBINDKEYS_CFG"
    cat > "$XBINDKEYS_CFG" <<EOF
"sleep 0.1 && gdbus call --session --dest org.Cinnamon --object-path /org/Cinnamon --method org.Cinnamon.Eval 'Main.expo.toggle();'"
    XF86Launch5
"sleep 0.1 && $LOCK_SCREEN_HELPER"
    XF86Launch6
"sleep 0.2 && xdotool key --clearmodifiers ctrl+r"
    XF86Launch7
"sleep 0.2 && wmctrl -r :ACTIVE: -b toggle,maximized_vert,maximized_horz"
    XF86Launch8
EOF
    pkill -f "xbindkeys.*chromebook" 2>/dev/null || true
    sleep 0.3
    echo "[xbindkeys] Starting daemon"
    xbindkeys -f "$XBINDKEYS_CFG"
    echo "[xbindkeys] Done."
}
# ----------------------------------------------------------------------------
# Writes a desktop file to the autostart directory.
# Usage: write_autostart <path> <name> <comment> <exec>
write_autostart() {
    echo "[autostart] Writing: $1"
    cat > "$1" <<EOF
[Desktop Entry]
Type=Application
Name=$2
Comment=$3
Exec=$4
X-GNOME-Autostart-Notify=false
X-GNOME-AutoRestart=false
NoDisplay=true
EOF
}
# Installs autostart entries for the xkb remap and xbindkeys daemon.
# OnlyShowIn omitted: Cinnamon reports X-Cinnamon but spec requires value
# without X- prefix, causing silent skip when OnlyShowIn=X-Cinnamon is set.
setup_autostart() {
    mkdir -p "$HOME/.config/autostart"
    write_autostart "$AUTOSTART_XKB" \
        "Chromebook Function Keys (xkb)" \
        "Applies xkb key remaps for Chromebook" \
        "$SCRIPT_PATH --apply-xkb"
    write_autostart "$AUTOSTART_XBINDKEYS" \
        "Chromebook Function Keys (xbindkeys)" \
        "Starts xbindkeys daemon for Chromebook" \
        "$SCRIPT_PATH --xbindkeys"
    echo "[autostart] Done."
    echo "[autostart]   $AUTOSTART_XKB"
    echo "[autostart]   $AUTOSTART_XBINDKEYS"
}
# ----------------------------------------------------------------------------
run_all() {
    setup_backlight_udev
    setup_xkb
    setup_xbindkeys
    setup_autostart
}
# ----------------------------------------------------------------------------
# Entry point
# ----------------------------------------------------------------------------
if [ $# -eq 0 ]; then
    usage
    exit 0
fi
for arg in "$@"; do
    case "$arg" in
        --help)       usage; exit 0 ;;
        --brightness|--xkb|--apply-xkb|--xbindkeys|--autostart|--all) ;;
        *) echo "Unknown option: $arg" >&2; usage >&2; exit 1 ;;
    esac
done
check_deps
for arg in "$@"; do
    case "$arg" in
        --brightness) setup_backlight_udev; apply_xkb ;;
        --xkb)        setup_xkb ;;
        --apply-xkb)  apply_xkb ;;
        --xbindkeys)  setup_xbindkeys ;;
        --autostart)  setup_autostart ;;
        --all)        run_all ;;
    esac
done

Read the original on morgandavis.net

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.