Created
July 27, 2018 13:43
-
-
Save orange-kao/2f40455369e9eda18b6037098c4c72bf to your computer and use it in GitHub Desktop.
ThinkPad X280 brightness control script
This file contains 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 ruby | |
# encoding: utf-8 | |
require "io/console" | |
require "rb-inotify" | |
CURSOR_ON = "\e[?25h" | |
CURSOR_OFF = "\e[?25l" | |
BRIGHTNESS_FILE = "/sys/class/backlight/intel_backlight/brightness" | |
MAX_BRIGHTNESS_FILE = "/sys/class/backlight/intel_backlight/max_brightness" | |
class StdoutSingleLineUpdate | |
def initialize | |
@length = 0 | |
@mutex = Mutex.new | |
end | |
private | |
def self.get_str_console_length(str) | |
length = 0 | |
str.each_char{|char| | |
if char.bytesize == 3 | |
length += 2 | |
else | |
length += 1 | |
end | |
} | |
str.scan(/\x1B\[[0-9;]+m/).each{|colour_msg| | |
length -= colour_msg.size | |
} | |
return length | |
end | |
public | |
def update_message(msg) | |
@mutex.synchronize{ | |
padding_length = @length - self.class.get_str_console_length(msg) | |
padding = "" | |
if padding_length > 0 | |
padding = " " * padding_length | |
end | |
new_msg = msg + padding | |
$stdout.write"\r#{new_msg}" | |
@length = self.class.get_str_console_length(new_msg) | |
} | |
return | |
end | |
end | |
class Brightness | |
attr_reader :value | |
attr_reader :max_value | |
def initialize(filename, max_filename, &callback) | |
@filename = filename | |
File.open(max_filename, "rb"){|file| | |
@max_value = file.read().to_i | |
} | |
read_sysfs() | |
@callback = nil | |
if callback != nil | |
@callback = callback | |
@thread = Thread.new{ | |
run_inotify() | |
} | |
end | |
end | |
def close | |
if @callback != nil | |
@notifier.stop | |
@notifier.close | |
@thread.terminate | |
@thread.join | |
end | |
end | |
def run_inotify | |
@notifier = INotify::Notifier.new | |
@notifier.watch(File.dirname(BRIGHTNESS_FILE), :modify){|event| | |
if event.name == File.basename(BRIGHTNESS_FILE) | |
read_sysfs() | |
@callback.call(self) | |
end | |
} | |
@notifier.run | |
end | |
def read_sysfs | |
File.open(@filename, "rb"){|file| | |
@value = file.read().to_i | |
} | |
end | |
def write_sysfs | |
File.open(@filename, "wb"){|file| | |
file.write(@value.to_s) | |
} | |
end | |
def read | |
return @value | |
end | |
def write(value) | |
if (Integer === value) != true | |
raise ArgumentError, "Invalid value" | |
end | |
if value < 0 | |
return | |
elsif value > @max_value | |
return | |
end | |
@value = value | |
write_sysfs() | |
end | |
def increase(brightness_to_change) | |
write(@value + brightness_to_change) | |
end | |
end | |
class ReadKey | |
@@key_map = {} | |
(1..26).each{|x| | |
@@key_map[x.chr] = "ctrl_#{(96+x).chr}".to_sym | |
} | |
@@key_map["\e[A"] = :up | |
@@key_map["\e[B"] = :down | |
@@key_map["\e[D"] = :left | |
@@key_map["\e[C"] = :right | |
@@key_map["\x7f"] = :backspace | |
@@key_map["\e"] = :esc | |
@@key_map["\t"] = :tab | |
@@key_map["\r"] = :enter | |
@@key_map["\e[2~"] = :insert | |
@@key_map["\e[3~"] = :delete | |
@@key_map["\e[H"] = :home | |
@@key_map["\e[F"] = :end | |
@@key_map["\e[5~"] = :pageup | |
@@key_map["\e[6~"] = :pagedown | |
@@key_map["\eOP"] = :f1 | |
@@key_map["\eOQ"] = :f2 | |
@@key_map["\eOR"] = :f3 | |
@@key_map["\eOS"] = :f4 | |
@@key_map["\e[15~"] = :f5 | |
@@key_map["\e[17~"] = :f6 | |
@@key_map["\e[18~"] = :f7 | |
@@key_map["\e[19~"] = :f8 | |
@@key_map["\e[20~"] = :f9 | |
@@key_map["\e[21~"] = :f10 | |
@@key_map["\e[24~"] = :f11 | |
@@key_map["\e[24~"] = :f12 | |
def self.read | |
key = $stdin.getch | |
while true | |
temp = nil | |
temp = $stdin.read_nonblock(1) rescue nil | |
if temp == nil | |
break | |
end | |
key << temp | |
end | |
symbol = @@key_map[key] | |
if symbol != nil | |
return symbol | |
end | |
return key | |
end | |
end | |
def brightness_to_str(brightness) | |
return "Brightness: #{brightness.value} / #{brightness.max_value} (#{(brightness.value.to_f / brightness.max_value * 100).round(2)}%)" | |
end | |
def main | |
if File.writable?(BRIGHTNESS_FILE) != true | |
system("sudo chgrp sudo /sys/class/backlight/intel_backlight/brightness") | |
system("sudo chmod g+w /sys/class/backlight/intel_backlight/brightness") | |
end | |
begin | |
line_update = StdoutSingleLineUpdate.new | |
brightness = Brightness.new(BRIGHTNESS_FILE, MAX_BRIGHTNESS_FILE){|brightness_self| | |
line_update.update_message(brightness_to_str(brightness_self)) | |
} | |
$stdout.puts(" up/a:+1 right/s:+10 PageDown/d:+100") | |
$stdout.puts("down/z:-1 left/x:-10 PageUp/c:-100") | |
$stdout.puts("esc/q: quit") | |
$stdin.echo = false | |
begin | |
$stdin.cursor = false | |
rescue NotImplementedError | |
$stdout.write(CURSOR_OFF) | |
end | |
line_update.update_message(brightness_to_str(brightness)) | |
while true | |
brightness_updated = true | |
brightness_to_change = 0 | |
key = ReadKey.read() | |
if String === key | |
key.downcase! | |
end | |
case key | |
when "a", :up | |
brightness_to_change = 1 | |
when "s", :right | |
brightness_to_change = 10 | |
when "d", :pagedown | |
brightness_to_change = 100 | |
when "z", :down | |
brightness_to_change = -1 | |
when "x", :left | |
brightness_to_change = -10 | |
when "c", :pageup | |
brightness_to_change = -100 | |
when "q", :esc, :ctrl_c | |
brightness.close | |
break | |
else | |
brightness_updated = false | |
line_update.update_message("Unsupported key #{key.inspect}") | |
end | |
if brightness_updated == true | |
brightness.increase(brightness_to_change) | |
line_update.update_message(brightness_to_str(brightness)) | |
end | |
end | |
rescue Exception => e | |
raise e | |
ensure | |
$stdin.echo = true | |
begin | |
$stdin.cursor = true | |
rescue NotImplementedError | |
$stdout.write(CURSOR_ON) | |
end | |
$stdout.puts("") | |
end | |
end | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment