Linux KDE RGB keyboard G213

A priori the RGB keyboard appears to be somewhat pointless. Nevertheless, I found myself having an uncontrollable urge to own one. In a review of various models the author pondered what reaction people would have if he could take a current generation RGB keyboard back in time to the late nineties. They could marvel at the progress of computer technology and how far human civilization had progressed 20 years hence.

The model I ended up buying was the Logitech G213 Prodigy. It was available at OfficeWorks around the corner for $79, which is relatively cheap by gaming standards. My application of course is serious software engineering. It's also pretty clear that I've been living in a parallel universe blissfully unaware of the existence of such equipment.

It is  also clear from the amount of effort put in here to integrating an RGB KB into KDE that it has a serious deficiency (same for Windows and MacOS). RGB has been around for about 10 years now and is pretty much totally ignored. If human existence is to improve (even further) then RGB must be integrated seemlessly into the window context.

Linux Compatibility

The first issue to adding RGB to a linux keyboard environment is that of software support and compatibility.

Well the good news is that this keyboard will just plug in and run. If you do nothing else you can use the G213's built in ability to run effects directly by ifself. Searching the web and watching Youtube videos, however, will not reveal the needed, pretty much undocumented, key sequences:

  1. Light button + 1: Color wave left to right
  2. Light button + 2: Color wave right to left
  3. Light button + 3: Color wave centre out
  4. Light button + 4: Breathing effect
  5. Light button + 5: All color cycle together
  6. Light button + 0: Fixed color (keep pressing to cycle)

Software drivers

Update

Kubuntu (which has now become the OS of choice on the Ryzen desktop) has the g810-led package as part of the distro!! apt install g810-led it's that easy.

  1. g213-led -a ff0000

Your keyboard should now be red.

You can still compile everything if desired however.

    The very first thing you'll need to do is install g810-led by Mat Moul to allow "profiles" to loaded in to the keyboard. After attempting to use alternatives, this is by far and away the easiest and most reliable.
    Tips:

    1. How do I install g++
    2. How do I install git
    3. su -
    4. dnf install hidapi
    5. dnf install hidapi-devel
    6. exit
    7. cd /home/me/my_work_space
    8. git clone https://github.com/MatMoul/g810-led.git
    9. cd g810-led
    10. make
    11. su
    12. make install
    13. g213-led -a 00ff00

    Your keyboard should now be green.

    * Note: /usr/bin/g213-led is a symlink to /usr/bin/g810-led

    Security

    Update

    Kubuntu no longer needs any fixes to security. g213-led and g810-led now just do their thing.

    If you're using Fedora then read on.

    The second issue to overcome is that only the root user has sufficient security access to talk to the G213. That's essentially because g213-led tampers with the USB directly. Overcoming that restriction was done by using the trusty linux sudo mechanism.

    First, login as the root user and add a group named g213. Then add your userid to the new group.

    groupadd g213
    usermod -aG g213 myuserid

    Use the visudo command as the root user to edit the sudoers file and add this line.

    ## Allows people in group g213 to run /usr/bin/g810-led
    %g213           ALL=(root)              NOPASSWD:/usr/bin/g810-led

    Essentially it says any user in group g213 can run /usr/bin/g810-led with an effective user id of root.

    Profiles

    Once users in the g213 group have access to be able to setup the key colors and effects, they can do cool stuff from the commandline.

    To run the profiles below use:

    sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.login

    All profile files in /etc/g810-led have their permissions set to 755.

    Login profile

    The first profile needed is for login. This establishes a default keyboard color. For this I selected white for the main keyboard keys, green for the nav keys and blue for the numberics.

    This profile is produced by:
    /etc/g810-led/profile.g213.login.

    # Login profile by groups keys

    r 1 ffffff
    r 2 ffffff
    r 3 ffffff
    r 4 00ff00
    r 5 0000ff

    c # Commit changes

    Root login profile

    The "root" profile is simply an all red static color. Essentially it means you can do bad things here by accident.

    /etc/g810-led/profile.g213.root

    # Sample profile by groups keys

    a ff0000

    c # Commit changes

    Sleep profile

    Sleep profile uses the g213's breath effect where the keyboard slowly pulses on and off with all keys set to one color. The color is set to green with a moderate breathing speed.

    # Sleep profile by groups keys

    fx breathing all 00ff00 18

    c # Commit changes

    CapsLock (new for V2)

    CapsLock overwrites the color profile for the main part of the keyboard (with yellow) when the CapsLock key is active. Activation is detected by using xbindkeys (which is now an installation prerequisite).

    # Capslock profile by groups keys

    r 1 ffff00
    r 2 ffff00
    r 3 ffff00

    c # Commit changes

    NumLock (new for V2)

    Numlock also overwrites the color profile for the numpad with a sightly light blue.

    # Capslock profile by groups keys

    r 5 00ffff

    c # Commit changes

    KDE integration

    Once the G213 starts doing stuff the question becomes: how can this be integrated with KDE's desktop to become really cool?

    Essentially the color and effects profiles need to be triggered by various system events. The method used here is to use bash shell scripts which are activated by various system mechanisms. The simplest of these is the .bash_profile and .bash_logout with the root user's account.

    Root user login and logout color changes

    Login as the root user and add this line to the end of /root/.bash_profile to change the keyboard to red.

    /usr/bin/g810-led -p /etc/g810-led/profile.g213.root

    Similarly add this to /root/.bash_logout to change the keyboard back to the default login colors when the root user logs out of a terminal session:

    /usr/bin/g810-led -p /etc/g810-led/profile.g213.login

    KDE graphical login and logout color changes

    The next step is to get KDE's autostart function to run some bash shell scripts to light up the keyboard on graphical logins.

    For login:
    /etc/g810-led/g213-led-login.sh

    #!/bin/bash
    sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.login

    and for logout:
    /etc/g810-led/g213-led-logout.sh

    #!/bin/bash

    # Keyboard sleep (breathing effect).
    #
    sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.sleep

    # Kill session's dbus monitor as we're logging out.
    #
    screen -ls | grep 'g213-dbus-monitor' | cut -f 1 -d'.' | tr -d "\t" | xargs -I '{}' kill -SIGTERM {}

    ScreenLock mode breathing effect

    KDE uses dbus to send messages to various system service providers. One of the subsystems providing services is the screenlock program. It's possible to listen to the dbus and intercept these messages and use them to trigger bash scripts.

    A prerequisite for running this script is the ability to background it via "screen". So in Fedora, dnf install screen (or yum install screen for other Linux flavours).

    /etc/g810-led/g213-led-dbus-monitor.sh

    #!/bin/bash
    screen -dmS g213-dbus-monitor '/etc/g810-led/g213-led-screenlock.sh'

    /etc/g810-led/g213-led-screenlock.sh

    #!/bin/bash
    #
    # https://unix.stackexchange.com/questions/353998/run-script-on-screen-lock-in-kde
    #
    dbus-monitor --session "type='signal',interface='org.freedesktop.ScreenSaver'" |
      while read x; do
        case "$x" in
          # You can call your desired script in the following line instead of the echo:
          *"boolean true"*) echo "Locked"; sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.sleep;;
          *"boolean false"*) echo "Unlocked"; sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.login;;
        esac
      done

    xbindkeys: CAPS Lock and NUM Lock

    Use xbindkeys to execute g213-led-set-profile.sh with a profile when the CAPS Lock or the NUM Lock is pressed.

    • Reference
    • dnf install xbindkeys
    • Install a custom ~/.xbindkeyssrc
    • Add xbindkeys to the KDE autostart menu

    # For the benefit of emacs users: -*- shell-script -*-

    ###########################
    # xbindkeys configuration #
    ###########################
    #
    # Version: 1.8.5
    #
    # If you edit this file, do not forget to uncomment any lines
    # that you change.
    # The pound(#) symbol may be used anywhere for comments.
    #
    # To specify a key, you can use 'xbindkeys --key' or
    # 'xbindkeys --multikey' and put one of the two lines in this file.
    #
    # The format of a command line is:
    #    "command to start"
    #       associated key
    #
    #
    # A list of keys is in /usr/include/X11/keysym.h and in
    # /usr/include/X11/keysymdef.h
    # The XK_ is not needed.
    #
    # List of modifier:
    #   Release, Control, Shift, Mod1 (Alt), Mod2 (NumLock),
    #   Mod3 (CapsLock), Mod4, Mod5 (Scroll).
    #

    # The release modifier is not a standard X modifier, but you can
    # use it if you want to catch release events instead of press events

    # By defaults, xbindkeys does not pay attention with the modifiers
    # NumLock, CapsLock and ScrollLock.
    # Uncomment the lines above if you want to pay attention to them.

    #keystate_numlock = enable
    #keystate_capslock = enable
    #keystate_scrolllock= enable

    # Examples of commands:

    #"xbindkeys_show"
    #  control+shift + q

    # set directly keycode (here control + f with my keyboard)
    #"xterm"
    #  c:41 + m:0x4

    # specify a mouse button
    #"xterm"
    #  control + b:2

    #"xterm -geom 50x20+20+20"
    #   Shift+Mod2+alt + s
    #
    ## set directly keycode (here control+alt+mod2 + f with my keyboard)
    #"xterm"
    #  alt + c:0x29 + m:4 + mod2
    #
    ## Control+Shift+a  release event starts rxvt
    #"rxvt"
    #  release+control+shift + a
    #
    ## Control + mouse button 2 release event starts rxvt
    #"rxvt"
    #  Control + b:2 + Release

    #
    # Change KB color
    #
    "/etc/g810-led/g213-led-set-profile.sh xbindkeys"
        m:0x2 + c:66
        Caps_Lock
    #
    # Change numpad color
    #
    "/etc/g810-led/g213-led-set-profile.sh xbindkeys"
        m:0x10 + c:77
        Mod2 + Num_Lock

    ##################################
    # End of xbindkeys configuration #
    ##################################

    • and for general profile setup (as requested by @Radioactive_Tom, sorry for the ommission):
      /etc/g810-led/g213-led-set-profile.sh

    #!/bin/bash
    #
    # Setup G213 keyboard profile.
    #

    loginid_file="/tmp/g213-loginid.tmp"

    #
    # Save the optional loginid
    #
    if [ $# == 1 ]
    then
        if [ "${1}" == "xbindkeys" ]
        then
            loginid=`cat "$loginid_file"`
        else
            loginid=$1
        fi
    else
        loginid=`/usr/bin/whoami`
    fi
    if [ "${loginid}" != "idle" ]
    then
        echo -n "${loginid}" > "${loginid_file}"
    fi

    #
    # Get keyboard CapsLock, NumLock and ScrollLock settings
    #
    if [ "${DISPLAY}ZZZ" != "ZZZ" ]
    then
        sleep .2
        lcKBLocks=`/usr/bin/xset -q | grep Caps`
        lcCapsLock=`echo $lcKBLocks | cut -d ' ' -f 4`
        lcNumLock=`echo $lcKBLocks | cut -d ' ' -f 8`
        lcScrollLock=`echo $lcKBLocks | cut -d ' ' -f 12`
        #echo "ShiftLock=$lcCapsLock"
        #echo "NumLock=$lcNumLock"
        #echo "ScrollLock=$lcScrollLock"
    else
        lcCapsLock="off"
        lcNumLock="off"
        lcScrollLock="off"
    fi
        

    if [ "${loginid}" == "root" ]
    then
        #
        # Keyboard red.
        #
        sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.root

    elif [ "${loginid}" == "screenlock" ]
    then
        #
        # Keyboard heatbeat.
        #
        sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.sleep

    elif [ "${loginid}" == "idle" ]
    then
        #
        # Keyboard heatbeat.
        #
        sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.idle

    else
        #
        # Keyboard default.
        #
        sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.login
    fi

    if [ $lcCapsLock != 'off' ]
    then
        sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.capslock
    fi

    if [ $lcNumLock != 'off' ]
    then
        sudo /usr/bin/g810-led -p /etc/g810-led/profile.g213.numlock
    fi

    Listen to D-BUS for screen sleep and wake messages

    When the keyboard is left idle for a time, make it cycle through rainbow colors. Don't forget to add getIdle to the KDE autostart menu.

    getIdle.c (compile to getIdle)

    //
    // RGB Keyboard timer.
    //
    // https://unix.stackexchange.com/questions/120957/run-a-command-when-system-is-idle-and-when-is-active-again
    //

    #include <X11/extensions/scrnsaver.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    #define IDLE_TIME 50000

    int main(void) {
        Bool bIsIdle  = False;
        Bool bWasIdle = False;
        int  iReturnCode;

        Display *dpy = XOpenDisplay(NULL);

        if (!dpy) {
            return(1);
        }

        while (True) {
            XScreenSaverInfo *info = XScreenSaverAllocInfo();
            XScreenSaverQueryInfo(dpy, DefaultRootWindow(dpy), info);
            bIsIdle = info->idle > IDLE_TIME;
            if ( bIsIdle ) {
                    if ( !bWasIdle ) {
                            printf("Idling");
                            iReturnCode = system("/etc/g810-led/g213-led-set-profile.sh idle");
                            if ( iReturnCode != 0 ) printf("Failed to idle: %u\n", iReturnCode);
                    }
            } else {
                    if ( bWasIdle ) {
                            iReturnCode = system("/etc/g810-led/g213-led-set-profile.sh");
                            if ( iReturnCode != 0 ) printf("Failed to idle: %u\n", iReturnCode);
                    }
            }
            bWasIdle = bIsIdle;
    //      printf("%u\n", info->idle);
            usleep (10000);
        }

        return(0);
    }