#!/bin/bash # Configures the i3 window manager to make it screen reader accessible # Written by Storm Dragon # Released under the terms of the WTFPL http://www.wtfpl.net i3Path="${XDG_CONFIG_HOME:-$HOME/.config}/i3" # Dialog accessibility export DIALOGOPTS='--no-lines --visit-items' # Check to make sure minimum requirements are installed. for i in dialog sgtk-menu yad ; do if ! command -v "$i" &> /dev/null ; then missing+=("$i") fi done if [[ -n "${missing}" ]]; then echo "Please install the following packages and run this script again:" echo "${missing[*]}" exit 1 fi menulist() { # Args: List of items for menu. # returns: selected tag local menuText="$1" shift local menuList for i in "${@}" ; do menuList+=("$i" "$i") done dialog --title "Strychnine" \ --backtitle "Use the arrow keys to find the option you want, and enter to select it." \ --clear \ --no-tags \ --menu "$menuText" 0 0 0 ${menuList[@]} --stdout return $? } # rangebox # $1 text to show # $2 minimum value # $3 maximum value # $4 Default value rangebox() { dialog --title "Strychnine" \ --backtitle "Use the arrow keys to select a number, then press enter." \ --rangebox "$1" -1 -1 $2 $3 $4 --stdout } yesno() { # Returns: Yes 0 or No 1 # Args: Question to user. dialog --clear --title "Strychnine" --yesno "$*" -1 -1 --stdout && return 0 } help() { echo "${0##*/}" echo "Released under the terms of the WTFPL License: http://www.wtfpl.net" echo -e "This is a Stormux project: https://stormux.org\n" echo -e "Usage:\n" echo "With no arguments, create the i3 configuration." for i in "${!command[@]}" ; do echo "-${i/:/ }: ${command[${i}]}" done | sort exit 0 } write_xinitrc() { if [[ -f "$HOME/.xinitrc" ]]; then continue="$(yesno "This will overwrite your existing $HOME/.xinitrc file. Do you want to continue?")" if [ "$continue" = "no" ]; then exit 0 fi fi cat << 'EOF' > ~/.xinitrc #!/bin/sh # # ~/.xinitrc # # Executed by startx (run your window manager from here) dbus-launch [[ -f ~/.Xresources ]] && xrdb -merge -I$HOME ~/.Xresources if [ -d /etc/X11/xinit/xinitrc.d ]; then for f in /etc/X11/xinit/xinitrc.d/*; do [ -x "$f" ] && . "$f" done unset f fi [ -f /etc/xprofile ] && . /etc/xprofile [ -f ~/.xprofile ] && . ~/.xprofile export DBUS_SESSION_BUS_PID export DBUS_SESSION_BUS_ADDRESS exec i3 EOF if [[ -f "$HOME/.xprofile" ]]; then continue="$(yesno "Would you like to add accessibility variables to your $HOME/.xprofile? Without these, accessibility will be limited or may not work at all. Do you want to continue?")" if [ "$continue" = "no" ]; then exit 0 fi fi cat << 'EOF' > ~/.xprofile # Accessibility variables export ACCESSIBILITY_ENABLED=1 export GTK_MODULES=gail:atk-bridge export GNOME_ACCESSIBILITY=1 export QT_ACCESSIBILITY=1 export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1 EOF } add_setting() { if [ -z "$rc" ]; then rc="$@" else rc="${rc}"$'\n'"$@" fi } # Array of command line arguments declare -A command=( [h]="This help screen." ) # Convert the keys of the associative array to a format usable by getopts args="${!command[*]}" args="${args//[[:space:]]/}" while getopts "${args}" i ; do case "$i" in h) help;; esac done # Create .xinitrc file if requested if [[ "$1" = "-x" || "$1" = "--xinitrc" ]]; then write_xinitrc exit 0 fi # Make sure rc variable is empty unset rc # Set path for helper scripts. path="$(readlink -f $0)" path="${path%/*}" if ! command -v notify-send &> /dev/null ; then timeOut="$(rangebox "Seconds for notifications:" 3 10 5)" notify="yad --info --timeout $timeOut --no-buttons --title 'notification' --text" else notify="notify-send" fi add_setting "# Generated by strychnine (${0##*/}) https://git.2mb.codes/~stormdragon2976/strychnine"$'\n'"# $(date '+%A, %B %d, %Y at %I:%M%p')"$'\n'$'\n'"# Miscellaneous" add_setting startup_message off add_setting set winname title add_setting "set bgcolor #000000" add_setting "set fgcolor #FFFFFF" add_setting 'set font -*-terminus-medium-r-normal-*-24-*-*-*-*-*-*-*' add_setting set waitcursor 1 add_setting banish # Unbind existing keys that lead to inaccessible things like xterm or keys that user wants to change, or don't make sense for blind users: add_setting $'\n'"# Unbind section" add_setting unbind C-A add_setting unbind A add_setting unbind C-a add_setting unbind a add_setting unbind c add_setting unbind C-c add_setting unbind C-f add_setting unbind F add_setting unbind r add_setting unbind C-r add_setting unbind S add_setting unbind C-S add_setting unbind s add_setting unbind C-s add_setting unbind C-t add_setting unbind C-v add_setting unbind v add_setting unbind C-w add_setting unbind C-Down add_setting unbind Down add_setting unbind C-exclam add_setting unbind exclam add_setting unbind C-Left add_setting unbind Left add_setting unbind question add_setting unbind C-Right add_setting unbind Right add_setting unbind C-Up add_setting unbind Up add_setting unbind C-apostrophe add_setting unbind apostrophe add_setting unbind colon escapeKey="$(menulist "Ratpoison escape key:" C-t C-z -C-Escape M-Escape C-space Super_L Super_R)" if [ "$escapeKey" != "C-t" ]; then add_setting unbind t fi # Key binding section add_setting $'\n'"# Key binding section" # Key binding section if [ "$escapeKey" != "C-t" ]; then add_setting escape $escapeKey fi add_setting "# Alt+f1 applications menu" add_setting definekey top M-F1 exec yad --icons --compact --no-buttons --title=\"Ratpoison Applications Menu\" --close-on-unfocus --read-dir=/usr/share/applications add_setting "# Alt+f2 executes the run dialog" add_setting definekey top M-F2 run_dialog add_setting "# Alt+f3 local applications menu" add_setting definekey top M-F3 exec yad --icons --compact --no-buttons --title=\"Ratpoison Local Applications Menu\" --close-on-unfocus --read-dir=${HOME}/.local/share/applications add_setting "# Control+Alt+d Desktop" add_setting definekey top C-M-d exec yad --icons --compact --no-buttons --title=\"Ratpoison Desktop Menu\" --close-on-unfocus --read-dir=${HOME}/Desktop add_setting "# Alt+tab switches through open windows" add_setting definekey top M-Tab next add_setting definekey top M-ISO_Left_Tab prev add_setting definekey top M-F4 close_window add_setting "# Media key bindings" add_setting definekey top XF86AudioPrev music_player_previous_track add_setting definekey top XF86AudioMute music_player_pause add_setting definekey top XF86AudioPlay music_player_play add_setting definekey top XF86AudioStop music_player_stop add_setting definekey top XF86AudioNext music_player_next_track add_setting definekey top XF86AudioLowerVolume music_player_decrease_volume add_setting definekey top XF86AudioRaiseVolume music_player_increase_volume add_alias alias close_window exec ratpoison -c 'delete' if command -v ocrdesktop &> /dev/null ; then add_setting definekey top Print exec $(command -v ocrdesktop) -d fi add_setting bind exclam run_dialog add_alias alias ratpoison_keybindings exec 'f=$(mktemp);ratpoison -c "help root" > $f && yad --text-info --show-cursor --title "Ratpoison Keybindings" --button "Close:0" --filename "$f";rm "$f"' add_setting bind question ratpoison_keybindings # Figure out which terminal emulator to use: unset programList for i in gnome-terminal lxterminal mate-terminal terminator tilda xfce4-terminal; do if hash ${i/#-/} &> /dev/null ; then if [ -n "$programList" ]; then programList="$programList $i" else programList="$i" fi fi done if [ -z "$programList" ]; then die "No terminal emulator found, please install one of lxterminal mate-terminal terminator, or xfce4-terminal." fi if [ "$programList" != "${programList// /}" ]; then terminal="$(menulist "Terminal emulator:" $programList)" else terminal="${programList/#-/}" fi # Configure file browser unset programList for i in caja nemo nautilus pcmanfm pcmanfm-qt thunar ; do if hash ${i/#-/} &> /dev/null ; then if [ -n "$programList" ]; then programList="$programList $i" else programList="$i" fi fi done if [ "$programList" != "${programList// /}" ]; then fileBrowser="$(menulist "File browser:" $programList)" else fileBrowser="${programList/#-/}" fi if [ -n "$fileBrowser" ]; then fileBrowser="$(command -v $fileBrowser)" fi add_setting bind f exec $fileBrowser # Configure web browser unset programList for i in brave chromium epiphany firefox google-chrome-stable midori seamonkey ; do if hash ${i/#-/} &> /dev/null ; then if [ -n "$programList" ]; then programList="$programList $i" else programList="$i" fi fi done if [ "$programList" != "${programList// /}" ]; then webBrowser="$(menulist "Web browser:" $programList)" else webBrowser="${programList/#-/}" fi if [ -n "$webBrowser" ]; then webBrowser="$(command -v $webBrowser)" fi add_setting bind w exec $webBrowser add_setting bind W exec $webBrowser '$(ratpoison -c getsel) # Open selected URI in web browser' # Configure text editor unset programList for i in geany gedit kate kwrite l3afpad leafpad libreoffice mousepad pluma ; do if hash ${i/#-/} &> /dev/null ; then if [ -n "$programList" ]; then programList="$programList $i" else programList="$i" fi fi done if [ "$programList" != "${programList// /}" ]; then textEditor="$(menulist "Text editor:" $programList)" else textEditor="${programList/#-/}" fi if [ -n "$textEditor" ]; then textEditor="/usr/bin/$textEditor" fi add_setting bind e exec $textEditor if hash gasher &> /dev/null ; then add_setting bind g exec EDITOR="$textEditor" gasher -p '# Post to GNU Social with Gasher' fi if hash mumble &> /dev/null ; then add_setting bind m exec /usr/bin/mumble fi if command -v pidgin &> /dev/null ; then add_setting bind p exec $(command -v pidgin) fi if command -v talking-clock &> /dev/null ; then add_setting bind M-t exec $(command -v talking-clock) '-c' fi add_setting bind c exec /usr/bin/$terminal add_setting bind C-c exec /usr/bin/$terminal add_setting "# Music player bindings:" add_alias "alias music_player_previous_track exec playerctl previous && $notify \"\$(playerctl metadata -f '"{{title}}" by "{{artist}}"')\"" add_alias "alias music_player_play exec playerctl play && $notify \"\$(playerctl metadata -f '"{{title}}" by "{{artist}}"')\"" add_alias "alias music_player_pause exec playerctl play-pause && $notify \"\$(playerctl metadata -f '"{{title}}" by "{{artist}}" {{status}}')\"" add_alias "alias music_player_stop exec playerctl stop" add_alias "alias music_player_next_track exec playerctl next && $notify \"\$(playerctl metadata -f '"{{title}}" by "{{artist}}"')\"" add_alias "alias music_player_decrease_volume exec playerctl volume 0.5-" add_alias "alias music_player_increase_volume exec playerctl volume 0.5+" add_alias "alias music_player_show_info exec $notify \"\$(playerctl metadata -f '"{{title}}" by "{{artist}}" from "{{album}}" via {{playerName}}')\"" add_setting "bind M-Z music_player_previous_track" add_setting "bind M-X music_player_play" add_setting "bind M-C music_player_pause" add_setting "bind M-V music_player_stop" add_setting "bind M-B music_player_next_track" add_setting "bind M-underscore music_player_decrease_volume" add_setting "bind M-plus music_player_increase_volume" add_setting "bind M-U music_player_show_info" add_alias 'alias run_dialog exec historyPath="${XDG_CONFIG_HOME:-$HOME/.config}/strychnine";if ! [ -d "$historyPath" ]; then mkdir -p "$historyPath";fi;write_history(){ oldHistory="$(grep -v "$txt" "$historyPath/history" | head -n 49)";echo -e "$txt\n$oldHistory" | sed '"'s/^$//g'"' > "$historyPath/history"; };if [ -f "$historyPath/history" ]; then txt=$(yad --entry --editable --title "Ratpoison" --text "Execute program or enter file" --button "Open:0" --separator "\n" --rest "$historyPath/history");else txt=$(yad --entry --title "Ratpoison" --text "Execute program or enter file" --button "Open:0");fi;if [ -z "$txt" ]; then exit 0;fi;if [[ "$txt" =~ ^ftp://|http://|https://|www.* ]]; then '"$webBrowser"' $txt;write_history;exit 0;fi;if [[ "$txt" =~ ^mailto://.* ]]; then xdg-email $txt;write_history;exit 0;fi;if [[ "$txt" =~ ^man://.* ]]; then eval "${txt/:\/\// }" | yad --text-info --show-cursor --button "Close:0" --title "Ratpoison" -;write_history;exit 0;fi;if command -v "$(echo "$txt" | cut -d " " -f1)" &> /dev/null ; then eval $txt& else xdg-open $txt&fi;write_history;exit 0' add_alias 'alias run_in_terminal_dialog exec c="$(yad --entry --title "Ratpoison" --text "Enter command:")" &&' /usr/bin/$terminal -e '$c' add_setting bind C-exclam run_in_terminal_dialog add_alias alias set_window_name exec 't="$(yad --entry --title "Ratpoison" --text "Enter window name") && ratpoison -c "title $t"' add_setting bind C-A set_window_name add_setting bind A set_window_name add_alias alias show_date exec "$notify" '"$(date +"%A, %B %d, %Y%n%I:%M%p")"' add_setting bind C-a show_date add_setting bind a show_date add_setting bind C-t show_date add_setting bind O exec /usr/bin/orca -r '# Restart Orca' add_alias alias ratpoison_version exec "$notify" '"$(ratpoison -c "version")"' add_setting bind C-v ratpoison_version add_setting bind v ratpoison_version add_alias alias window_menu exec 'ifs="$IFS";IFS=$'"'"\\n"'"';w="$(yad --list --title "Ratpoison" --text "Select Window" --column "Select" $(ratpoison -c "windows"))";IFS="$ifs";ratpoison -c "select ${w:0:1}"' add_setting bind C-apostrophe window_menu add_setting bind apostrophe window_menu add_alias alias run_ratpoison_command exec 'c="$(yad --entry --title "Ratpoison" --text="Enter Ratpoison command:")" && ratpoison -c "$c"' add_setting bind colon run_ratpoison_command add_alias alias reload_ratpoison_configuration exec ratpoison -c "\"source $HOME/.ratpoisonrc\"&&$notify \"Ratpoison configuration reloaded\"" add_setting bind C-colon reload_ratpoison_configuration add_setting bind C-M-r restart add_setting bind C-M-q quit # Sound for new window. windowSound="$(yesno "Should new windows, and ratpoison keys make sounds?")" #add_alias addhook switchwin speak_window_title if [[ "$windowSound" == "yes" ]]; then add_alias addhook newwindow announce_new_window add_alias addhook key announce_top_level_key add_alias alias announce_new_window exec bash -c $'\'excludedWindowNames="zenity";winName="$(ratpoison -c "info %t")";if ! [[ "$winName" =~ ^(${excludedWindowNames})$ ]]; then play -n synth .25 sin 440:880 sin 480:920 remix - norm -3 pitch -500;fi\'' add_alias alias announce_top_level_key exec 'play -qV0 "|sox -np synth .07 sq 400" "|sox -np synth .5 sq 800" fade h 0 .5 .5 norm -20' #add_alias alias 'speak_window_title exec bash -c' "'"'windowName="$(ratpoison -c "info %t")";socketFile="$(find /tmp -maxdepth 1 -name "orca-*.sock")"; [[ -w "$socketFile" ]] && echo "$windowName" | socat - UNIX-CLIENT:"<#APPEND#>${socketFile}"'"'" fi # Load user defined settings if [[ -r ~/.ratpoison_customizations ]]; then add_setting '# Load user defined settings' add_setting "source ${HOME}/.ratpoison_customizations" fi # Autostart section add_setting $'\n'"# Autostart section" if hash rpws &> /dev/null ; then workspaces="$(rangebox "Number of workspaces:" 1 8 4)" if [ $workspaces -gt 1 ]; then add_setting exec /usr/bin/rpws init $workspaces -a for i in $(seq $workspaces) ; do add_alias alias go_to_workspace_$i exec rpws $i add_alias alias move_current_application_to_workspace_$i rpwsm$i add_setting definekey top C-F$i go_to_workspace_$i add_setting definekey top C-S-F$i move_current_application_to_workspace_$i done fi fi if command -v transfersh &> /dev/null ; then add_setting bind u transfer_file add_alias alias transfer_file 'exec fileName="$(yad --title "Strychnine Upload File" --file)" && url="$(transfersh "${fileName}" | tee >(yad --title "Strychnine - Uploading ${fileName##*/} ..." --progress --pulsate --no-buttons --auto-close))" && echo "${url#*saved at: }" | tee >(yad --title "Strychnine - Upload URL" --show-cursor --show-uri --button yad-close --sticky --text-info) >(xclip -selection clipboard)' fi # Additional startup programs if [ -n "$(find /usr -type f -name 'notification-daemon' 2> /dev/null)" ] ; then add_setting "exec $(find /usr -type f -name 'notification-daemon' 2> /dev/null)" fi unset programs brlapi="$(yesno "Do you want to use a braille display with Orca?")" if [[ "$brlapi" == "yes" ]]; then programs+=("$( command -v xbrlapi) --quiet") fi if command -v clipster &> /dev/null ; then programs+=("$(command -v clipster) -d") add_setting definekey top M-C-c exec clipster -s fi echo "Enter any programs you want started automatically one per line. Press enter on a blank line when you are finished." | fold -s -w $(tput cols) read -p "Enter program or enter when done: " -e programName while [[ -n "${programName}" ]]; do programs+=("${programName}") read -p "Enter program or enter when done: " -e programName done if [[ -n "$programs" ]]; then for i in "${programs[@]}" ; do add_setting exec "$i" done fi add_setting exec 'if [ "$(gsettings get org.gnome.desktop.a11y.applications screen-reader-enabled)" != "true" ]; then gsettings set org.gnome.desktop.a11y.applications screen-reader-enabled true&&' "$notify \"QT5 accessibility enabled. You need to restart ratpoison for the changes to take affect.\""';fi' add_setting exec /usr/bin/orca if [ -f "$HOME/.ratpoisonrc" ]; then continue="$(yesno "$HOME/.ratpoisonrc exists. Over write it?")" if [ "$continue" = "no" ]; then exit 0 fi fi echo "$rc" > $HOME/.ratpoisonrc echo >> $HOME/.ratpoisonrc echo "# Alias Section">> $HOME/.ratpoisonrc echo "$rpAlias" >> $HOME/.ratpoisonrc exit 0