#!/usr/bin/perl -w # TODO: I reworked the argument parsing and broke the formatted output # It was terrible in the first place, so rework that too. # # Work on a `date`-like format like: # "+%c/%m = %p\%" # %c - Current absolute # %m - Maximum absolute value # %p - Current percent # # to output like: # 1000/10000 = 10% # # Create a new array of hashes to classify the ARGV elements, eg: # $0 + "+%c" -= 10 +=4 =1 =100 "+%p" # [ # { # "action" => "increment", # "value" => 1 # },{ # "action" => "print", # "value" => "+%c" # },{ # "action" => "decrement", # "value" => 10 # },{ # "action" => "increment", # "value" => 4 # },{ # "action" => "set", # "value" => 1 # },{ # "action" => "set", # "value" => 100 # },{ # "action" => "print", # "value" => "+%p" # } # ] # # Process all of these in order. Add an option to show/hide action output # so you can either get (shown): # 100% 100000 90% 94% 1% 100% 100% # or (hidden): # 100000 100% # # All of the events would still occur between the output values. # # Add a delay option between increments and a delay between actions (does not # apply to 'print'). This could be used to make a gradual sweep with: # # --delay-increment=100 --delay-action=0 # # or to blink with: # # --delay-increment=0 --delay-action=1000 # # With the latter, you could even have the backlight do morse code: # clear | S ( . . . ) |pause| O ( _ _ _ ) |pause| # =0 =100 =0 =100 =0 =100 =0 =0 =100 =100 =0 =100 =100 =0 =100 =100 =0 =0 ... # # Perhaps add an argument to repeat indefinitely. This is all getting a bit # silly, but kinda fun to think about. # Files containing current and max brightness values my $cur_file = "/sys/class/backlight/intel_backlight/brightness"; my $max_file = "/sys/class/backlight/intel_backlight/max_brightness"; my $last_file = "/home/jpm/.config/blc.last"; sub to_percent { my $value = shift; $value = int($value/get_max()*100); return $value . '%'; } sub get_offset { return int(get_max()/100); } sub get_current { open(my $c,'<',"$cur_file"); my $current = <$c>; close $c; chomp $current; return $current; } sub get_max { open(my $m,'<',"$max_file"); my $max = <$m>; close $m; chomp $max; return $max; } sub get_min { return int((get_max()/100)+2); } sub writable { if (! -w $cur_file) { die "You don't have permission to write $cur_file\n"; } return 1; } sub increment { if (writable()) { my $current = get_current(); my $max = get_max(); my $target = $current+get_offset(); if ($target > $max) { $target = $max; } open(my $c,'>',"$cur_file"); print $c $target; close $c; return $target; } } sub decrement { if (writable()) { my $current = get_current(); my $min = get_min(); my $target = $current-get_offset(); if ($target < $min) { $target = $min; } open(my $c,'>',"$cur_file"); print $c $target; close $c; return $target; } } sub set { my $value = shift; if (writable()) { $current = get_current(); if ($value > $current) { for (my $i=$current;$i<=$value;$i++) { open(my $c,'>',"$cur_file"); print $c $i; close $c; } } else { for (my $i=$current;$i>=$value;$i--) { open(my $c,'>',"$cur_file"); print $c $i; close $c; } } return $value; } } sub help { print " Backlight Control Usage: blc.pl [--silent|--notify] [OPTION] [VALUE] With no option the backlight information is printed as JSON. Output printed to STDOUT unless: --silent Do not display output (overrides --notify) --notify Send output to notification daemon. --notify=N will change the display duration in ms. Default is 200ms Output option must preceed the first Action option. Actions: = VALUE Set backlight to specific value. VALUE greater than 100 will be treated as absolute value. VALUE eqaul to or less than 100 will be treated as a percentage + Increment by 1% += VALUE Increment by VALUE percent - Decrement by 1% -= VALUE Decrement by VALUE percent Actions corrected to 1% or 100% if over or under. All actions provide output as a percentage, with the % symbol. Final percentage printed as below, skipping other options. Print: == Print current absolute value ^ Print maximum absolute value % Print current percentage (does not include % symbol) --help Help (not impacted by --silent or --notify) --HELP Advanced help (same as above) Any other option will be printed literally"; } sub advanced { $current = get_current(); $max = get_max(); print ". Print functions can be strung together but command will exit with the first non-print option. eg. \$ blc.pl == / ^ 21/100 \$ blc.pl == ++ ('==' ignored) (Backlight incremented) Escape options with \\ in quotes to display them literally. eg. \$ blc.pl == / ^ '\\=' % \'\\%\' " . $current . "/" . $max . "=" . int($current/$max*100) . "% Only one \'\\' is removed per block. eg. \$ blc.pl '\\% \\' % \\ "; } my $current = get_current(); my (@output, $target, $silent, $notify); my $operation_found = 0; if (scalar @ARGV) { while ($arg = shift) { if ($arg eq '%') { push @output,int(get_current()/get_max()*100); } elsif ($arg eq '^') { push @output,get_max(); } elsif ($arg eq '==') { push @output,get_current(); } elsif ($arg eq '--help') { help(); print " (see --HELP).\n\n"; exit(); } elsif ($arg eq '--HELP') { help(); advanced(); exit(); } elsif ($arg eq '--silent') { $silent = 1; } elsif ($arg =~ /^--notify/) { $notify = 1; if ($arg =~ /=[0-9]+$/) { $duration = $arg; $duration =~ s/.*=([0-9]+)/$1/; } else { $duration = 1000; } } elsif ($arg eq '+') { unshift(@ARGV,1); unshift(@ARGV,'+='); } elsif ($arg =~ /^\+=/) { my $offset; if ($arg =~ m/^\+=(.+)$/) { $offset = $1; } else { $offset = shift || die "+= without accompanying offset value\n"; } unless ($offset =~ /^\d+$/) { die "+= is not a number ($offset)\n"; } for (my $j=0;$j<$offset;$j++) { $target = increment(); @output = to_percent($target); } $operation_found = 1; } elsif ($arg eq '-') { unshift(@ARGV,1); unshift(@ARGV,'-='); } elsif ($arg =~ /^-=/) { my $offset; if ($arg =~ m/^-=(.+)$/) { $offset = $1; } else { $offset = shift || die "-= without accompanying offset value\n"; } unless ($offset =~ /^\d+$/) { die "-= is not a number ($offset)\n"; } for (my $j=0;$j<$offset;$j++) { $target = decrement(); @output = to_percent($target); } $operation_found = 1; } elsif ($arg =~ m/^=/) { my $value; if ($arg =~ m/^=(.+)$/) { $target = $1; } else { $target = shift || die "= without accompanying absolute value\n"; } unless ($target =~ /^\d+$/) { die "= is not a number ($target)\n"; } if ($target < 1) { $target = set(get_min()); } elsif ($target > get_max()) { $target = set(get_max()); } elsif ($target > 100) { $target = set($target); } else { $target = set( int((get_max()*$target/100)+1) ); } @output = to_percent($target); $operation_found = 1; } else { push(@output,$arg); } } } else { @output = ( '{"Backlight":{"Max":"' . get_max() . '","Current":"' . get_current() . '","Percentage","' . int(get_current()/get_max()*100) . '%"}}' ); } open(my $fh,'>',$last_file); print $fh get_current(); close($fh); print $_."\n" foreach(@output); if ($silent) { exit(); } elsif ($notify) { my $concat = ''; foreach (@output) { $concat .= $_; } =pod use Gtk2::Notify -init, "Backlight"; my $notification = Gtk2::Notify::new('Backlight', $concat, '', "notification-display-brightness"); $notification->set_hint_string('x-canonical-private-synchronous','blc'); $notification->set_urgency('NOTIFY_URGENCY_LOW'); $notification->set_hint_int32('value',(split('%',$concat))[0]); $notification->set_timeout($duration); $notification->show(); exit; print "notify-send --urgency=normal" . ' --icon="notification-display-brightness"' . ' --hint=string:x-canonical-private-synchronous:blc' . ' --expire-time=' . $duration . ' "Backlight"' . ' "' . $concat . " '" . join("','", @output) . "'\""; system "notify-send --urgency=normal" . ' --icon="notification-display-brightness"' . ' --hint=string:x-canonical-private-synchronous:blc' . ' --hint=int:value:' . (split('%',$concat))[0] . ' --expire-time=' . $duration . ' "' . $concat . "\""; =cut exit(); } else { print foreach @output; print "\n"; exit(); }