Last active
October 12, 2020 12:25
-
-
Save metatoaster/cc24aa628e5a9fc56b93a6dc721ddbb4 to your computer and use it in GitHub Desktop.
Caps lock LED for HDD Activity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| """ | |
| Make Caps Lock LED to show HDD activity, for Xorg/X11 on Linux | |
| This Python script uses ctypes on the libX11 shared object, /proc/vmstat | |
| pseudo-file provided by the Linux kernel to turn a keyboard's caps lock | |
| light to act like a HDD activity LED. | |
| The LED to be controlled must have allowExplicit enabled. Easiest way | |
| to achieve this is to write out a xkbcomp configuration file and replace | |
| all instaces of ``!allowExplicit`` with ``allowExplicit`` like so:: | |
| $ xkbcomp $DISPLAY /tmp/xkbconf | |
| $ sed -i 's/\!allowExplicit/allowExplicit/' /tmp/xkbconf | |
| $ xkbcomp /tmp/xkbconf $DISPLAY | |
| $ rm /tmp/xkbconf | |
| If the low level API calls to the above are known they can be included | |
| into this script. | |
| """ | |
| import os | |
| import sys | |
| from ctypes import Structure | |
| from ctypes import byref | |
| from ctypes import cdll | |
| from ctypes import c_int | |
| from ctypes import c_uint | |
| from time import sleep | |
| # library | |
| x11 = cdll.LoadLibrary("libX11.so") | |
| XCloseDisplay = x11.XCloseDisplay | |
| # this is actually wrapped later | |
| # XOpenDisplay = x11.XOpenDisplay | |
| # Constants and structures | |
| timeout = 0.04 | |
| KBLed = 1 << 4 | |
| KBLedMode = 1 << 5 | |
| OFF = 0 | |
| ON = 1 | |
| vmstat_filename = '/proc/vmstat' | |
| class XKeyboardControl(Structure): | |
| _fields_ = [ | |
| ("key_click_percent", c_int), | |
| ("bell_percent", c_int), | |
| ("bell_pitch", c_int), | |
| ("bell_duration", c_int), | |
| ("led", c_int), | |
| ("led_mode", c_int), | |
| ("key", c_int), | |
| # On, Off, Default */ | |
| ("auto_repeat_mode", c_int), | |
| ] | |
| # functions | |
| def error(*a): | |
| """ | |
| A dumb way to spit out an error message. | |
| """ | |
| for i in a: | |
| sys.stderr.write(i) | |
| sys.stderr.write('\n') | |
| sys.exit(1) | |
| def get_vmstat_pginout(fd): | |
| """ | |
| Extract the page in and page out values. Only grab the strings. | |
| """ | |
| fd.seek(0) | |
| return [s for s in fd.readlines() if s.startswith('pgpg')] | |
| def XOpenDisplay(): | |
| """ | |
| Just let the underlying lib do its job, but die in a fire otherwise. | |
| """ | |
| dpy = x11.XOpenDisplay(None) | |
| if not dpy: | |
| error('Failed to connect to X Server ', os.environ.get('DISPLAY')) | |
| return dpy | |
| def set_led(led, mode): | |
| """ | |
| Similar to the set_led function in xset, but without the display | |
| argument because it is opened from within here. | |
| """ | |
| dpy = XOpenDisplay() | |
| values = XKeyboardControl() | |
| values.led = led | |
| values.led_mode = mode | |
| x11.XChangeKeyboardControl(dpy, c_int(KBLed | KBLedMode), byref(values)) | |
| XCloseDisplay(dpy) | |
| def startup_check(): | |
| """ | |
| Gracefully exit rather than segfault when display is not found. | |
| """ | |
| dpy = XOpenDisplay() | |
| x11.XCloseDisplay(dpy) | |
| if not os.path.exists(vmstat_filename): | |
| error( | |
| '"', vmstat_filename, '" not found. ', | |
| 'Linux Kernel must be compiled with VM_EVENT_COUNTERS enabled.', | |
| ) | |
| def main(led): | |
| with open(vmstat_filename) as vmstat: | |
| status = get_vmstat_pginout(vmstat) | |
| try: | |
| while True: | |
| sleep(timeout) | |
| current = get_vmstat_pginout(vmstat) | |
| if current == status: | |
| set_led(led, OFF) | |
| else: | |
| set_led(led, ON) | |
| status = current | |
| except KeyboardInterrupt: | |
| print('Quitting...') | |
| if __name__ == '__main__': | |
| led = 1 # Caps Lock | |
| main(led) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment