commit 8f688f4105c5d24ebb5e7dab229780fd8e901af6 Author: rhiannon morris Date: Fri May 20 11:54:47 2022 +0200 first diff --git a/bin/find-parent b/bin/find-parent new file mode 100755 index 0000000..16a0aea --- /dev/null +++ b/bin/find-parent @@ -0,0 +1,32 @@ +#!/usr/bin/env execlineb + +elgetopt d +elgetpositionals +importas -D "" dironly ELGETOPT_d + +if -nt { test $# -eq 0 } + +define FOUND 69 +foreground { + # look for each file (in cwd) + forx -E -x$FOUND pat { $@ } + # if file exists, exit with $FOUND, which breaks the loop + elglob -0 files $pat + forx -E -x$FOUND file { $files } + ifthenelse { test -n $dironly } { pwd } { readlink -f $file } + exit $FOUND +} +importas result ? + +# if the loop exited with $FOUND then we're done +if -nt { test $result -eq $FOUND } +# if we're at / give up +if -n -x1 { + getcwd -E cwd + test $cwd = / +} + +cd .. +ifelse { test -n $dironly } { find-parent -d $@ } find-parent $@ + +# vim: set ft=execline : diff --git a/bin/little b/bin/little new file mode 100755 index 0000000..388080a --- /dev/null +++ b/bin/little @@ -0,0 +1,56 @@ +#!/usr/bin/env raku + +#| print arguments or stdin as superscript +unit sub MAIN(*@args); + +# char ranges {{{ +my %uc = ( +A => 'ᴬ', B => 'ᴮ', D => 'ᴰ', E => 'ᴱ', G => 'ᴳ', H => 'ᴴ', I => 'ᴵ', +J => 'ᴶ', K => 'ᴷ', L => 'ᴸ', M => 'ᴹ', N => 'ᴺ', O => 'ᴼ', P => 'ᴾ', +R => 'ᴿ', T => 'ᵀ', U => 'ᵁ', W => 'ᵂ' +); +my %lc = ( +a => 'ᵃ', b => 'ᵇ', c => 'ᶜ', d => 'ᵈ', e => 'ᵉ', f => 'ᶠ', +g => 'ᵍ', h => 'ʰ', i => 'ⁱ', j => 'ʲ', k => 'ᵏ', l => 'ˡ', +m => 'ᵐ', n => 'ⁿ', o => 'ᵒ', p => 'ᵖ', r => 'ʳ', s => 'ˢ', +t => 'ᵗ', u => 'ᵘ', v => 'ᵛ', w => 'ʷ', x => 'ˣ', y => 'ʸ', +z => 'ᶻ' +); +my %num = ( +0 => '⁰', 1 => '¹', 2 => '²', 3 => '³', ([4..9] Z ['⁴'..'⁹']).Map +); +my %other = ('!' => 'ꜝ', '.' => '·'); +# }}} +my %caseless = %lc, %num, %other; +my %cased = %uc, %caseless; + + +sub rejects(@chars, %map) { @chars.grep(* ∉ %map).unique.join(', ') } +sub non-ws($str) { $str.comb.grep(* !~~ /\s/) } + +sub shrink(Str $str) { + my $str-lc = lc $str; + my @chars = non-ws $str; + my @lc-chars = non-ws $str-lc; + + my $cased-rejects = rejects @chars, %cased; + my $caseless-rejects = rejects @lc-chars, %caseless; + + if !$cased-rejects { + $str.trans: %cased + } elsif !$caseless-rejects { + note "using lowercase because no superscripts for $cased-rejects"; + $str-lc.trans: %caseless; + } else { + note "no superscripts for $caseless-rejects"; + "" + } +} + +if @args > 0 { + say shrink @args.join: ' ' +} else { + say shrink $_ for $*IN.lines +} + +# vim: set ft=perl6 fdm=marker : diff --git a/bin/tablet_setup b/bin/tablet_setup new file mode 100755 index 0000000..9dd738f --- /dev/null +++ b/bin/tablet_setup @@ -0,0 +1,203 @@ +#!/usr/bin/env raku + +#| Sets up buttons etc on drawing tablets +unit sub MAIN( + #| Don't run the commands, just print them (implies -v) + Bool :n(:$dry-run), + #| Print each command before running it + Bool :v(:$verbose) is copy, + #| Print the output of queries too (implies -v) + Bool :V(:$very-verbose), +); + +$verbose ||= $dry-run || $very-verbose; + + +sub say-prefix(:$prefix = '### ', |c) { + say $prefix, |c +} + +sub say-vv(:$prefix = '### ', |c) { + say-prefix :$prefix, |c if $very-verbose +} + +sub say-v(:$prefix = '### ', |c) { + say-prefix :$prefix, |c if $verbose +} + +sub quote(Str() $_) { + when '' { '""' } + when /\s/ { qq|"$_"| } + default { $_ } +} + +sub say-cmd(*@cmd, Bool() :$query!) { + my $prefix = $dry-run && !$query ?? "# " !! "> "; + say-v :$prefix, @cmd»."e.join(' '); +} + +sub query(*@cmd) { + say-cmd @cmd, :query; + my @out = run(|@cmd, :out :!in).out.lines(:close); + say-vv :prefix('< '), $_ for @out; + @out +} + +sub update(*@cmd) { + say-cmd @cmd, :!query; + unless $dry-run { run(|@cmd, :!out :!in :err) } + Nil +} + + +class Subdev { ... } + +class Tablet { + has Str $.name; + + my @devices = lazy query ; + + method Str { $.name } + + method find($name) { + for @devices { + when /^ $=(.* $name .*) «Pen»/ { + return self.new: name => $.trim; + } + } + fail "!!! Tablet '$name' not found"; + } + + method subdev($type, $name) { Subdev.new: tablet => self, :$type, :$name; } + + method pad() { self.subdev: 'Pad', 'pad' } + method stylus() { self.subdev: 'Pen', 'stylus' } + method eraser() { self.subdev: 'Pen', 'eraser' } + method cursor() { self.subdev: 'Pen', 'cursor' } +} + +class Subdev { + has Tablet $.tablet; has Str $.type; has Str $.name; + + method Str { "$.tablet $.type $.name" } + + method set(*%params-args) { + for %params-args.kv -> $param, $args { + update , self, $param, |$args; + } + } +} + + +sub key($k, *%mods where *.values.all) { + my @mods = %mods.keys.map: { + when /:i alt [_ | \-]? gr/ { 'ISO_Level3_Shift' } + default { $_ } + }; + "key " ~ reduce { "+$^b $^a -$^b" }, $k, |@mods +} + + +sub external-connected { + for query { + when /^\h* \d+ ':' \h* '+'? '*'? $=(\S+)/ { + my $name = ~$; + return $name unless $name ~~ /eDP/; + } + } +} + +################################################################################ + +my $did-something = False; + +my $external = external-connected; + +with $external { say-prefix "using display '$_'" } + +with Tablet.find: 'Intuos4' { + say-v "Setting up \"$_\""; + $did-something = True; + + my $screen-dir = query()[0]; + with $screen-dir { + say-v "wacom_led directory: {quote($screen-dir)}"; + } else { + fail "!!! wacom_led directory not found"; + } + + for .stylus, .eraser, .cursor { + .set: :Rotate :Area<0 0 65024 36576>; # full 65024x40640 + + with $external -> $ { .set: :MapToOutput($external); } + } + + for .stylus, .eraser { + .set: :Button(3, key(:ctrl, 'z')); + } + + my %buttons = ( + # assuming left handed + # circle + 1 => {map => key('tab')}, + # upper four, top to bottom + 13 => {map => key('shift'), screen => 7, label => 'Sh/Rotate'}, + 12 => {map => key('ctrl'), screen => 6, label => 'Ctrl/Zoom'}, + 11 => {map => key('m'), screen => 5, label => 'Mirror'}, + 10 => {map => key('5'), screen => 4, label => 'Rotate 0°'}, + # lower four + 9 => {map => key('.'), screen => 3, label => 'Brush +'}, + 8 => {map => key(','), screen => 2, label => 'Brush −'}, + 3 => {map => key('insert'), screen => 1, label => 'Layer +'}, + 2 => {map => key('XF86AudioPlay'), screen => 0, label => 'Pause'}, + ); + + update , $screen-dir; + + spurt "$screen-dir/buttons_luminance", 15; + + given .pad { + .set: :AbsWheelDown(key('shift')) :AbsWheelUp(key('shift')); + + for %buttons.kv -> $button, % (:$map, :$screen, :$label) { + .set: :Button($button, $map); + + next without $label & $screen; + + my $path = "$screen-dir/button{$screen}_rawimg"; + fail "!!! no such device $path" unless $path.IO.f; + + update , $label, '-d', $path; + } + } +} + +with Tablet.find: 'H420' { + say-v "Setting up \"$_\""; + $did-something = True; + + given .stylus { + .set: :Rotate :Area<0 0 8320 4680> # full: 8340x4680 + :PressureCurve<0 50 50 100> :Button(3, key(:ctrl, 'z')); + + # FIXME do this properly + .set: :MapToOutput<960x540+480+270>; + + with $external -> $ { .set: :MapToOutput($external); } + } + + my %buttons = ( + # top to bottom assuming left handed + 3 => key(:ctrl, 'z'), + 2 => key(:ctrl:shift, 'z'), + 1 => key('tab'), + ); + + for %buttons.kv -> $b, $map { + .pad.set: :Button($b, $map); + } +} + +say "Didn't find any tablets" unless $did-something; + +# vim: set ft=raku : diff --git a/bin/wide b/bin/wide new file mode 100755 index 0000000..42cd982 --- /dev/null +++ b/bin/wide @@ -0,0 +1,19 @@ +#!/usr/bin/env raku + +#| convert arguments or stdin to fullwidth characters +unit sub MAIN(*@args); + +sub widen(Str $str) { + my %map = (['!'..'~'] Z ['!'..'~']).Map, ' ' => ' '; + my @rejects = $str.comb.grep: {$^x !~~ /\s/ && $^x ∉ %map}; + note "unknown characters: @rejects.join(', ')" if @rejects; + $str.trans: %map +} + +if @args > 0 { + say widen @args.join: ' ' +} else { + say widen $_ for $*IN.lines +} + +# vim: set ft=perl6 : diff --git a/sbin/i4oled-chgrp b/sbin/i4oled-chgrp new file mode 100755 index 0000000..c1e2dfc --- /dev/null +++ b/sbin/i4oled-chgrp @@ -0,0 +1,4 @@ +#!/bin/bash + +dir="$1"; shift +chgrp plugdev $dir/*