4

Most laptops these days have the Page up/Page down/Home/End keys as Fn overlays of the arrow keys. It has always been a minor annoyance that Fn is on the other side of the keyboard, making one-handed use of the Page up etc. nearly impossible.

I recently thought of the idea of using Scroll Lock as a modifier, so that if scroll lock is on, the arrow keys would always be Page up etc. Here is my script:

#!/bin/bash
xmodmap -e 'add mod3 = Scroll_Lock'

arrow() {
    echo "arrow mode";
    xmodmap -e "keycode 111 = Up NoSymbol Up"
    xmodmap -e "keycode 116 = Down NoSymbol Down"
    xmodmap -e "keycode 113 = Left NoSymbol Left"
    xmodmap -e "keycode 114 = Right NoSymbol Right"
}
page() {
    echo "page mode";
    xmodmap -e "keycode 111 = Prior NoSymbol Prior"
    xmodmap -e "keycode 116 = Next NoSymbol Next"
    xmodmap -e "keycode 113 = Home NoSymbol Home"
    xmodmap -e "keycode 114 = End NoSymbol End"
}

arrow;

trap 'arrow; exit 255;' EXIT SIGINT

slock0="";
echo $slock;
while true; do
    slock="$(xset -q | sed -ne '/Scroll Lock/s/^.*Scroll Lock: \([a-z]*\).*$/\1/p')";
    if [ "$slock" != "$slock0" ]; then 
        slock0="$slock";
        if [ "$slock" == "on" ]; then
            page
        else
            arrow
        fi
    fi
    sleep 0.5
done

I'm just curious if there is a more elegant way to do this? Is there a problem with running xmodmap so frequently?

In the past I have dedicated a key (such as Menu between right Alt and Ctrl) as the AltGr key, and done xmodmap -e "keycode 111 = Up NoSymbol Prior", etc. However my current laptop doesn't have a "free" key in that region. And I'm not familiar with a way to make the scroll lock act like the AltGr modifier.

1

Your script is totally fine, there are just some minor things I’d change:

  • xmodmap allows you to specify multiple expressions per command line, so instead of calling it four times your can call it only once per function
  • printf "%s\n" "$slock" won’t print an empty line if slock is empty
  • grep -oP 'Scroll Lock:\s*\K\w+' does the same as your sed command, but if you insist on using sed:

    sed -nr 's/.*Scroll Lock:\s*(\w+).*/\1/p'
    
  • while : is the same as while true – it’s a matter of taste I guess

Script with changes

#!/bin/bash
xmodmap -e 'add mod3 = Scroll_Lock'

arrow() {
  echo "arrow mode"
  xmodmap -e "keycode 111 = Up NoSymbol Up" \
          -e "keycode 116 = Down NoSymbol Down" \
          -e "keycode 113 = Left NoSymbol Left" \
          -e "keycode 114 = Right NoSymbol Right"
}
page() {
  echo "page mode"
  xmodmap -e "keycode 111 = Prior NoSymbol Prior" \
          -e "keycode 116 = Next NoSymbol Next" \
          -e "keycode 113 = Home NoSymbol Home" \
          -e "keycode 114 = End NoSymbol End"
}

arrow
trap 'arrow; exit 255;' EXIT SIGINT

printf "%s\n" "$slock"
while :; do
  slock="$(xset -q | grep -oP 'Scroll Lock:\s*\K\w+')"
  if [ "$slock" != "$slock0" ]; then
    slock0="$slock"
    if [ "$slock" = "on" ]; then
      page
    else
      arrow
    fi
  fi
sleep 0.5
done

I suggest to even change the delay to sleep 1 – personally, I find that by far fast enough, and it saves your machine half the calls. Try what suits your needs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.