diff --git a/I38.md b/I38.md index d2b7f50..4e31b37 100644 --- a/I38.md +++ b/I38.md @@ -50,6 +50,8 @@ Windows in I38 are arranged in a tabbed layout by default, which means windows t This is the standard mode for working with applications. Most commands start with your mod key (`MODKEY`). +TOPLEVELKEYBINDINGS + ### Ratpoison Mode Ratpoison mode allows quick access to common actions using shorter key combinations. To enter Ratpoison mode, press `RATPOISONKEY`. After pressing this key, you can execute commands with single keystrokes. @@ -62,7 +64,7 @@ Common Ratpoison mode commands: | `e` | Open text editor (TEXTEDITOR) | | `w` | Launch web browser (BROWSER) | | `k` | Kill (close) the current window | -| `?` | Show I38 help | +| `F1` | Show ratpoison mode keybindings | | `Escape` or `Control` + `g` | Exit Ratpoison mode without taking action | | `Shift` + `c` | Restart Cthulhu screen reader | | `Shift` + `o` | Restart Orca screen reader | @@ -89,6 +91,7 @@ In Panel Mode, single keypresses launch different information panels: | Key | Action | |-----|--------| +| `F1` | Show panel mode keybindings | | `w` | Display weather information | | `Shift` + `w` | Open Magic Wormhole file transfer GUI | | `s` | Show system information | @@ -282,7 +285,9 @@ I38 includes clipboard management features: - **Use the window list**: When you're lost, use `RATPOISONKEY` then `'` to show all windows in the current workspace. - **Bookmark important websites**: Use `MODKEY` + `Control` + `b` to access bookmarks. -- **Remember the help shortcut**: `MODKEY` + `Shift` + `F1` is your friend when you need guidance. +- **Remember the help shortcuts**: + - `MODKEY` + `Shift` + `F1` opens the complete I38 HTML guide + - Press `F1` in ratpoison or panel mode for quick keybinding reference specific to that mode - **Let the sound effects guide you**: Pay attention to the audio cues to understand what's happening. - **Take advantage of OCR**: If an application isn't accessible, try the OCR function. diff --git a/i38.sh b/i38.sh index bc04d01..80c4e1e 100755 --- a/i38.sh +++ b/i38.sh @@ -437,15 +437,18 @@ done # Ratpoison mode is enabled by default export i3Mode=0 # Prevent setting ratpoison mode key to the same as default mode key -while [[ "$escapeKey" == "$mod" ]]; do - escapeKey="$(menulist "Ratpoison mode key:" Control+t Control+z Control+Escape Alt+Escape Control+space Super)" +while [[ "$escapeKey" == "$mod" ]] || [[ "$escapeKey" =~ ^Super_ && "$mod" == "Mod4" ]] || [[ "$mod" == "Mod4" && "$escapeKey" =~ ^Super_ ]]; do + escapeKey="$(menulist "Ratpoison mode key:" Control+t Control+z Control+Escape Alt+Escape Control+space "Super Left" "Super Right")" escapeKey="${escapeKey//Alt/Mod1}" - escapeKey="${escapeKey//Super/Mod4}" + escapeKey="${escapeKey//Super Left/Super_L}" + escapeKey="${escapeKey//Super Right/Super_R}" mod="$(menulist "I3 mod key, for top level bindings:" Alt Super)" mod="${mod//Alt/Mod1}" mod="${mod//Super/Mod4}" if [ "$escapeKey" == "$mod" ]; then dialog --title "I38" --msgbox "Ratpoison and mod key cannot be the same key." -1 -1 + elif [[ "$escapeKey" =~ ^Super_ && "$mod" == "Mod4" ]]; then + dialog --title "I38" --msgbox "Ratpoison mode key cannot be a Super key when mod key is Super." -1 -1 fi done # Multiple keyboard layouts @@ -613,8 +616,8 @@ focus_follows_mouse no # is used in the bar {} block below. font pango:monospace 8 -# I38 help -bindsym \$mod+Shift+F1 exec ${i3Path}/scripts/i38-help.sh +# I38 help - Open comprehensive HTML guide +bindsym \$mod+Shift+F1 exec $webBrowser ${i3Path}/I38.html # Run dialog bindsym \$mod+F2 exec ${i3Path}/scripts/run_dialog.sh @@ -629,19 +632,29 @@ bindsym \$mod+Control+c exec clipster -s bindsym \$mod+Control+Delete exec --no-startup-id sgtk-bar # Use pactl to adjust volume in PulseAudio. +# Increase system volume bindsym \$mod+XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +${volumeJump}% & play -qnG synth 0.03 sin 440 +# Decrease system volume bindsym \$mod+XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -${volumeJump}% & play -qnG synth 0.03 sin 440 +# Mute/unmute system volume bindsym \$mod+XF86AudioMute exec --no-startup-id ${i3Path}/scrip/ts/mute-unmute.sh # Music player controls -# Requires playerctl. +# Increase music volume bindsym XF86AudioRaiseVolume exec --no-startup-id ${i3Path}/scripts/music_controler.sh incvol $volumeJump +# Decrease music volume bindsym XF86AudioLowerVolume exec --no-startup-id ${i3Path}/scripts/music_controler.sh decvol $volumeJump +# Previous track bindsym XF86AudioPrev exec --no-startup-id play -qV0 "| sox -np synth 0.03 sin 2000 pad 0 .02" "| sox -np synth 0.03 sin 2000" norm 1.0 vol 0.4 & ${i3Path}/scripts/music_controler.sh prev +# Pause music playback bindsym XF86AudioMute exec --no-startup-id play -qV0 "| sox -np synth 0.03 sin 2000 pad 0 .02" "| sox -np synth 0.03 sin 2000" norm 1.0 vol 0.4 & ${i3Path}/scripts/music_controler.sh pause +# Play music bindsym XF86AudioPlay exec --no-startup-id play -qV0 "| sox -np synth 0.03 sin 2000 pad 0 .02" "| sox -np synth 0.03 sin 2000" norm 1.0 vol 0.4 & ${i3Path}/scripts/music_controler.sh play +# Get music player information bindsym \$mod+XF86AudioPlay exec --no-startup-id play -qV0 "| sox -np synth 0.03 sin 2000 pad 0 .02" "| sox -np synth 0.03 sin 2000" norm 1.0 vol 0.4 & ${i3Path}/scripts/music_controler.sh info +# Stop music playback bindsym XF86AudioStop exec --no-startup-id play -qV0 "| sox -np synth 0.03 sin 2000 pad 0 .02" "| sox -np synth 0.03 sin 2000" norm 1.0 vol 0.4 & ${i3Path}/scripts/music_controler.sh stop +# Next track bindsym XF86AudioNext exec --no-startup-id play -qV0 "| sox -np synth 0.03 sin 2000 pad 0 .02" "| sox -np synth 0.03 sin 2000" norm 1.0 vol 0.4 & ${i3Path}/scripts/music_controler.sh next # start a terminal @@ -657,8 +670,9 @@ bindsym \$mod+F1 exec --no-startup-id "${i3Path}/scripts/menu.py" bindsym \$mod+Control+d exec --no-startup-id ${i3Path}/scripts/desktop.sh # change focus -# alt+tab and alt+shift+tab +# Focus previous window (alt+shift+tab) bindsym Mod1+Shift+Tab focus left +# Focus next window (alt+tab) bindsym Mod1+Tab focus right # enter fullscreen mode for the focused container @@ -690,32 +704,52 @@ set \$ws9 "9" set \$ws10 "10" # switch to workspace +# Switch to workspace 1 bindsym Control+F1 workspace number \$ws1, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh +# Switch to workspace 2 bindsym Control+F2 workspace number \$ws2, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh +# Switch to workspace 3 bindsym Control+F3 workspace number \$ws3, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh +# Switch to workspace 4 bindsym Control+F4 workspace number \$ws4, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh +# Switch to workspace 5 bindsym Control+F5 workspace number \$ws5, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh +# Switch to workspace 6 bindsym Control+F6 workspace number \$ws6, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh +# Switch to workspace 7 bindsym Control+F7 workspace number \$ws7, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh +# Switch to workspace 8 bindsym Control+F8 workspace number \$ws8, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh +# Switch to workspace 9 bindsym Control+F9 workspace number \$ws9, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh +# Switch to workspace 10 bindsym Control+F10 workspace number \$ws10, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh # move focused container to workspace +# Move window to workspace 1 bindsym Control+Shift+F1 move container to workspace number \$ws1, exec spd-say -P important -Cw "moved to workspace 1" +# Move window to workspace 2 bindsym Control+Shift+F2 move container to workspace number \$ws2, exec spd-say -P important -Cw "moved to workspace 2" +# Move window to workspace 3 bindsym Control+Shift+F3 move container to workspace number \$ws3, exec spd-say -P important -Cw "moved to workspace 3" +# Move window to workspace 4 bindsym Control+Shift+F4 move container to workspace number \$ws4, exec spd-say -P important -Cw "moved to workspace 4" +# Move window to workspace 5 bindsym Control+Shift+F5 move container to workspace number \$ws5, exec spd-say -P important -Cw "moved to workspace 5" +# Move window to workspace 6 bindsym Control+Shift+F6 move container to workspace number \$ws6, exec spd-say -P important -Cw "moved to workspace 6" +# Move window to workspace 7 bindsym Control+Shift+F7 move container to workspace number \$ws7, exec spd-say -P important -Cw "moved to workspace 7" +# Move window to workspace 8 bindsym Control+Shift+F8 move container to workspace number \$ws8, exec spd-say -P important -Cw "moved to workspace 8" +# Move window to workspace 9 bindsym Control+Shift+F9 move container to workspace number \$ws9, exec spd-say -P important -Cw "moved to workspace 9" +# Move window to workspace 10 bindsym Control+Shift+F10 move container to workspace number \$ws10, exec spd-say -P important -Cw "moved to workspace 10" # A mode that will pass all keys except $mod+shift+backspace to the current application. -# Use $mod+shift+backspace to exit the mode. +# Enter bypass mode bindsym $mod+shift+BackSpace mode "bypass" mode "bypass" { # Exit bypass mode. @@ -725,9 +759,9 @@ bindsym $mod+Shift+BackSpace mode "default" EOF -# ocr through speech-dispatcher - echo "bindsym ${mod}+F5 exec ${i3Path}/scripts/ocr.py" >> ${i3Path}/config -# Interrupt speech-dispatcher output +# Perform OCR on screen +echo "bindsym ${mod}+F5 exec ${i3Path}/scripts/ocr.py" >> ${i3Path}/config +# Interrupt speech output echo "bindsym ${mod}+Shift+F5 exec spd-say -C" >> ${i3Path}/config # Multiple keyboard layouts if requested. @@ -740,6 +774,9 @@ cat << EOF >> ${i3Path}/config # Panel mode configuration bindsym Control+Mod1+Tab mode "panel" mode "panel" { + # Panel mode keybindings help bound to F1 + bindsym F1 exec ${i3Path}/scripts/i38-help-panel.sh, mode "default" + # Weather information bound to w bindsym w exec --no-startup-id ${i3Path}/scripts/weather.sh, mode "default" @@ -776,12 +813,11 @@ EOF # Create ratpoison mode if requested. if [[ -n "${escapeKey}" ]]; then cat << EOF >> ${i3Path}/config +# Enter ratpoison mode bindsym $escapeKey mode "ratpoison" mode "ratpoison" { -# I38 help bound to ? -bindsym Shift+slash exec ${i3Path}/scripts/i38-help.sh, mode "default" -# I38 HTML documentation bound to F1 -bindsym F1 exec $webBrowser ${i3Path}/I38.html, mode "default" +# Ratpoison mode keybindings help bound to F1 +bindsym F1 exec ${i3Path}/scripts/i38-help-rp.sh, mode "default" # Terminal emulator bound to c bindsym c exec $sensibleTerminal, mode "default" # Text editor bound to e @@ -952,7 +988,7 @@ else fi) # First run help documentation -exec --no-startup-id bash -c 'if [[ -f "${i3Path}/firstrun" ]]; then ${webBrowser} "${i3Path}/I38.html"& rm "${i3Path}/firstrun"; fi' +exec --no-startup-id bash -c 'if [[ -f "${i3Path}/firstrun" ]]; then ${webBrowser} "${i3Path}/I38.html" & sleep 1 && rm "${i3Path}/firstrun"; fi' # If you want to add personal customizations to i3, add them in ${i3Path}/customizations # It is not overwritten when the config file is recreated. @@ -986,7 +1022,8 @@ fi # More readable version of variables. escapeKey="${escapeKey//Mod1/Alt}" -escapeKey="${escapeKey//Mod4/Super}" +escapeKey="${escapeKey//Super_L/Super Left}" +escapeKey="${escapeKey//Super_R/Super Right}" mod="${mod//Mod1/Alt}" mod="${mod//Mod4/Super}" webBrowser="${webBrowser##*/}" @@ -994,6 +1031,133 @@ screenReader="${screenReader##*/}" textEditor="${textEditor##*/}" fileBrowser="${fileBrowser##*/}" +# Extract and categorize top-level keybindings for documentation +# Generate HTML directly since we're inserting into an already-converted HTML file + +# Extract comment+bindsym pairs from config (excluding mode blocks) +declare -a applications workspaceSwitch workspaceMove windowMgmt utilities modes media + +# Read the config and extract top-level bindings with their comments +while IFS= read -r line; do + if [[ "$line" =~ ^#.*$ ]]; then + # This is a comment line - save it + lastComment="${line#\# }" + elif [[ "$line" =~ ^bindsym.*$ ]]; then + # This is a bindsym line - pair it with the last comment + keybinding="${line#bindsym }" + keybinding="${keybinding//\\$/}" + + # Extract just the key combination (first 1-2 words before 'exec', 'workspace', etc) + keyCombo=$(echo "$keybinding" | awk '{print $1, $2}' | sed 's/workspace.*//' | sed 's/exec.*//' | sed 's/kill.*//' | sed 's/fullscreen.*//' | sed 's/scratchpad.*//' | sed 's/mode.*//' | sed 's/ *$//') + + # Clean up key combo + keyCombo="${keyCombo//\$mod/$mod}" + keyCombo="${keyCombo//Mod1/Alt}" + keyCombo="${keyCombo//Mod4/Super}" + + # Categorize based on the comment or the action + if [[ "$keybinding" =~ workspace.*number ]] && [[ "$keybinding" =~ Control+F ]]; then + # Switch to workspace + workspaceSwitch+=("$keyCombo|$lastComment") + elif [[ "$keybinding" =~ move.*container.*workspace ]] && [[ "$keybinding" =~ Control+Shift+F ]]; then + # Move to workspace + workspaceMove+=("$keyCombo|$lastComment") + elif [[ "$lastComment" =~ (menu|terminal|editor|browser|Run dialog) ]] || [[ "$keybinding" =~ (menu.py|sensible-terminal|run_dialog) ]]; then + applications+=("$keyCombo|$lastComment") + elif [[ "$lastComment" =~ (focus|window|fullscreen|scratchpad|kill|close) ]] || [[ "$keybinding" =~ (focus|kill|fullscreen|scratchpad) ]]; then + windowMgmt+=("$keyCombo|$lastComment") + elif [[ "$lastComment" =~ (mode|ratpoison|panel|bypass) ]] || [[ "$keybinding" =~ mode ]]; then + modes+=("$keyCombo|$lastComment") + elif [[ "$keybinding" =~ (Audio|music_controler|pactl) ]]; then + media+=("$keyCombo|$lastComment") + else + utilities+=("$keyCombo|$lastComment") + fi + + lastComment="" + fi +done < <(sed -n '/^mode "/,/^}$/!p' "${i3Path}/config" | grep -E '^#|^bindsym') + +# Build HTML tables +{ + echo "

Default Mode Keybindings

" + + # Applications + if [[ ${#applications[@]} -gt 0 ]]; then + echo "

Applications:

" + echo "" + for item in "${applications[@]}"; do + IFS='|' read -r key desc <<< "$item" + echo "" + done + echo "
KeyAction
$key$desc
" + fi + + # Workspace Navigation + if [[ ${#workspaceSwitch[@]} -gt 0 ]] || [[ ${#workspaceMove[@]} -gt 0 ]]; then + echo "

Workspace Navigation:

" + echo "" + echo "" + echo "" + echo "
KeyAction
Control+F1 through F10Switch to workspace 1-10
Control+Shift+F1 through F10Move window to workspace 1-10
" + fi + + # Window Management + if [[ ${#windowMgmt[@]} -gt 0 ]]; then + echo "

Window Management:

" + echo "" + for item in "${windowMgmt[@]}"; do + IFS='|' read -r key desc <<< "$item" + echo "" + done + echo "
KeyAction
$key$desc
" + fi + + # Utilities + if [[ ${#utilities[@]} -gt 0 ]]; then + echo "

Utilities:

" + echo "" + for item in "${utilities[@]}"; do + IFS='|' read -r key desc <<< "$item" + echo "" + done + echo "
KeyAction
$key$desc
" + fi + + # Modes + if [[ ${#modes[@]} -gt 0 ]]; then + echo "

Modes:

" + echo "" + for item in "${modes[@]}"; do + IFS='|' read -r key desc <<< "$item" + echo "" + done + echo "
KeyAction
$key$desc
" + fi + + # Media (if any) + if [[ ${#media[@]} -gt 0 ]]; then + echo "

Media Controls:

" + echo "" + for item in "${media[@]}"; do + IFS='|' read -r key desc <<< "$item" + echo "" + done + echo "
KeyAction
$key$desc
" + fi + +} > "${i3Path}/toplevel_temp.txt" + +# Replace TOPLEVELKEYBINDINGS placeholder with the generated HTML content +awk ' + /TOPLEVELKEYBINDINGS/ { + system("cat '"${i3Path}"'/toplevel_temp.txt") + next + } + { print } +' "${i3Path}/I38.html" > "${i3Path}/I38.html.tmp" && mv "${i3Path}/I38.html.tmp" "${i3Path}/I38.html" +rm -f "${i3Path}/toplevel_temp.txt" + # Customize the html file to the user's choices. sed -i -e "s|BROWSER|${webBrowser}|g" \ -e "s|MODKEY|${mod}|g" \ diff --git a/scripts/i38-help-panel.sh b/scripts/i38-help-panel.sh new file mode 100755 index 0000000..98d5f54 --- /dev/null +++ b/scripts/i38-help-panel.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# This file is part of I38. + +# I38 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, +# either version 3 of the License, or (at your option) any later version. + +# I38 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with I38. If not, see . + +configPath="$(readlink -f "$0")" +configPath="${configPath%/*/*}" + +if [[ -f "${configPath}/config" ]]; then + mod="$(grep 'set $mod ' "${configPath}/config" | cut -d ' ' -f3)" + mod="${mod//Mod1/Alt}" + mod="${mod//Mod4/Super}" + mapfile helpText < <(sed -n '/^mode "panel"/,/^}$/p' "${configPath}/config" | \ + sed -e '/^mode "panel"/d' \ + -e '/^}$/d' \ + -e 's/bindsym/Key:/g' \ + -e 's/Mod1/Alt/g' \ + -e 's/, mode "default"//g' \ + -e 's/--no-startup-id //g' \ + -e "s/\$mod/$mod/g") +else + exit 1 +fi + +for i in "${!helpText[@]}" ; do + helpText[$i]="${helpText[$i]//${configPath}\/scripts\//}" + helpText[$i]="${helpText[$i]/.sh/}" + helpText[$i]="${helpText[$i]/.py/}" +done + +header="Panel Mode Keybindings\n\nPress Control+Alt+Tab to enter panel mode, then use these shortcuts:\n\n" +helpText=("$header" "${helpText[@]}" "End of panel mode help. Press Control+Home to jump to the beginning.") + +echo "${helpText[@]}" | yad --text-info --show-cursor --title "I38 - Panel Mode Help" --button "Close:0" --listen + +exit 0 diff --git a/scripts/i38-help-rp.sh b/scripts/i38-help-rp.sh new file mode 100755 index 0000000..b847949 --- /dev/null +++ b/scripts/i38-help-rp.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# This file is part of I38. + +# I38 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, +# either version 3 of the License, or (at your option) any later version. + +# I38 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with I38. If not, see . + +configPath="$(readlink -f "$0")" +configPath="${configPath%/*/*}" + +if [[ -f "${configPath}/config" ]]; then + mod="$(grep 'set $mod ' "${configPath}/config" | cut -d ' ' -f3)" + mod="${mod//Mod1/Alt}" + mod="${mod//Mod4/Super}" + mapfile helpText < <(sed -n '/^mode "ratpoison"/,/^}$/p' "${configPath}/config" | \ + sed -e '/^mode "ratpoison"/d' \ + -e '/^}$/d' \ + -e 's/bindsym/Key:/g' \ + -e 's/Mod1/Alt/g' \ + -e 's/, mode "default"//g' \ + -e 's/--no-startup-id //g' \ + -e 's/play \(.*\)& //g' \ + -e "s/\$mod/$mod/g") +else + exit 1 +fi + +for i in "${!helpText[@]}" ; do + helpText[$i]="${helpText[$i]//${configPath}\/scripts\//}" + helpText[$i]="${helpText[$i]/.sh/}" + helpText[$i]="${helpText[$i]/, exec announce*/$'\n'}" + helpText[$i]="${helpText[$i]/, exec spd-say*/$'\n'}" +done + +header="Ratpoison Mode Keybindings\n\nEnter ratpoison mode with your configured escape key, then use these shortcuts:\n\n" +helpText=("$header" "${helpText[@]}" "End of ratpoison mode help. Press Control+Home to jump to the beginning.") + +echo "${helpText[@]}" | yad --text-info --show-cursor --title "I38 - Ratpoison Mode Help" --button "Close:0" --listen + +exit 0