Compare commits

...

26 Commits
v2.2 ... master

Author SHA1 Message Date
Storm Dragon
8064eaa6e2 Added vivaldi as browser option. 2025-03-19 14:12:19 -04:00
Storm Dragon
416fdc7be4 Updated the README. 2025-03-09 23:21:05 -04:00
Storm Dragon
72721abb22 Toggle screen reader is now a gui, so you can see which one is currently running and switch if you want. 2025-03-09 23:00:32 -04:00
Storm Dragon
2f2eefddce Created a fake panel. It's technically an 11th workspace, but programs that need to be opened but don't often need interaction are automatically sent there. Use control+alt+tab to access the panel. 2025-03-04 19:59:51 -05:00
Storm Dragon
5229b3b18a Introduction to I38 help file loads on first start after config generation. 2025-03-03 22:49:46 -05:00
Storm Dragon
d66d60ee49 Added ability to toggle between Cthulhu and Orca with RP Mode - shift+T. 2024-12-20 06:47:55 -05:00
Storm Dragon
2990660e61 Added chrome's accessibility flag for the apps that still need it. 2024-12-03 07:50:56 -05:00
Storm Dragon
ca1b76302d Fixed a typo. 2024-10-23 06:09:21 -04:00
Storm Dragon
93127aeca3 Add .gitignore for python cache files. 2024-10-23 06:06:29 -04:00
Storm Dragon
d393677f00 Merge branch 'master' of git.stormux.org:storm/I38 2024-10-23 05:44:07 -04:00
Storm Dragon
9b8932aca6 Added the grayscale flag to mod+F5 command. This should speed it up quite a bit and make it more accurate for games. 2024-10-23 05:43:49 -04:00
13ba2b6dee Support the Flatpak path.
Now you can launch your Flatpaks from the I38 menu.
2024-09-25 17:32:52 -04:00
732c2b0240 Sway: when reloading the configuration, don't run the sound script always.
I don't think Sway's IPC works the same as it does under I38. It must
be running a different one per each reload, but not sure.

Regardless, you won't get extra sounds on reload now.
2024-09-25 15:57:46 -04:00
0eb4e494ff Adda a note about the custom version of xfce4-notifyd.
I've been using it for weeks now, but didn't think to check the README.
2024-09-23 19:19:40 -04:00
ce22b8347c Fix for reloading and restarting the configuration.
In Sway, you say "command" instead of "run_command" Additionally, take
out the restart since that's not available in Sway.
2024-09-21 16:10:02 -04:00
62c2c06904 Rename script. 2024-09-20 14:00:27 -04:00
12649c0f60 Directory local variables for Emacs contributors.
Sets some handy things for sending patches, might be useful for other contributors.
2024-09-20 14:00:27 -04:00
a63091b320 Put the sensible-terminal script into i38 itself.
There is no such --sensible-terminal flag to Sway, and given it's just
a script we may as well put it in our codebase instead.
2024-09-20 14:00:27 -04:00
faf7ca45e0 When using Sway, include the default distribution files for configuration.
Useful for things such as importing the proper dBus environment.
2024-09-20 14:00:27 -04:00
Storm Dragon
3769428fdf Added path to ps5 contoller to game controller battery script. 2024-09-17 18:08:36 -04:00
Storm Dragon
f2ab61b389 Added optional support for x11bell: https://github.com/jovanlanik/x11bell 2024-09-11 02:19:37 -04:00
Storm Dragon
8c29d40616 Found a sound missing -V0 flag. 2024-08-31 14:26:13 -04:00
Storm Dragon
31c920de8a OCR through speech-dispatcher added. Interrupt speech-dispatcher key added. 2024-08-13 00:37:39 -04:00
Storm Dragon
6cf1aac9de Merge branch 'master' of git.stormux.org:storm/I38 2024-07-13 18:55:55 -04:00
Storm Dragon
3f7f7d7b21 Fixed very chatty error messages on some systems with alsa. 2024-07-13 18:55:32 -04:00
Jeremiah Ticket
2c763ce6ea Fixed links to licenses. 2024-07-12 19:08:37 -08:00
13 changed files with 838 additions and 36 deletions

5
.dir-locals.el Normal file
View File

@ -0,0 +1,5 @@
;;; Directory Local Variables -*- no-byte-compile: t -*-
;;; For more information see (info "(emacs) Directory Variables")
((nil . ((vc-prepare-patches-separately . nil)
(vc-default-patch-addressee . "billy@wolfe.casa"))))

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
**/__pycache__/
*.pyc
*.pyo
*.pyd

566
I38.html Normal file
View File

@ -0,0 +1,566 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Welcome to I38</title>
<style>
html {
color: #1a1a1a;
background-color: #fdfdfd;
}
body {
margin: 0 auto;
max-width: 36em;
padding-left: 50px;
padding-right: 50px;
padding-top: 50px;
padding-bottom: 50px;
hyphens: auto;
overflow-wrap: break-word;
text-rendering: optimizeLegibility;
font-kerning: normal;
}
@media (max-width: 600px) {
body {
font-size: 0.9em;
padding: 12px;
}
h1 {
font-size: 1.8em;
}
}
@media print {
html {
background-color: white;
}
body {
background-color: transparent;
color: black;
font-size: 12pt;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3, h4 {
page-break-after: avoid;
}
}
p {
margin: 1em 0;
}
a {
color: #1a1a1a;
}
a:visited {
color: #1a1a1a;
}
img {
max-width: 100%;
}
svg {
height: auto;
max-width: 100%;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.4em;
}
h5, h6 {
font-size: 1em;
font-style: italic;
}
h6 {
font-weight: normal;
}
ol, ul {
padding-left: 1.7em;
margin-top: 1em;
}
li > ol, li > ul {
margin-top: 0;
}
blockquote {
margin: 1em 0 1em 1.7em;
padding-left: 1em;
border-left: 2px solid #e6e6e6;
color: #606060;
}
code {
font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
font-size: 85%;
margin: 0;
hyphens: manual;
}
pre {
margin: 1em 0;
overflow: auto;
}
pre code {
padding: 0;
overflow: visible;
overflow-wrap: normal;
}
.sourceCode {
background-color: transparent;
overflow: visible;
}
hr {
border: none;
border-top: 1px solid #1a1a1a;
height: 1px;
margin: 1em 0;
}
table {
margin: 1em 0;
border-collapse: collapse;
width: 100%;
overflow-x: auto;
display: block;
font-variant-numeric: lining-nums tabular-nums;
}
table caption {
margin-bottom: 0.75em;
}
tbody {
margin-top: 0.5em;
border-top: 1px solid #1a1a1a;
border-bottom: 1px solid #1a1a1a;
}
th {
border-top: 1px solid #1a1a1a;
padding: 0.25em 0.5em 0.25em 0.5em;
}
td {
padding: 0.125em 0.5em 0.25em 0.5em;
}
header {
margin-bottom: 4em;
text-align: center;
}
#TOC li {
list-style: none;
}
#TOC ul {
padding-left: 1.3em;
}
#TOC > ul {
padding-left: 0;
}
#TOC a:not(:hover) {
text-decoration: none;
}
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
</head>
<body>
<header id="title-block-header">
<h1 class="title">Welcome to I38</h1>
</header>
<h1 id="welcome-to-i38---accessible-i3-window-manager">Welcome to I38 -
Accessible i3 Window Manager</h1>
<blockquote>
<p><strong>Note:</strong> This help guide has been tailored to your
specific configuration. Youve chosen <strong>BROWSER</strong> as your
web browser, <strong>MODKEY</strong> as your mod key, and youre using
the <strong>SCREENREADER</strong> screen reader.</p>
</blockquote>
<h2 id="introduction-to-i38">Introduction to I38</h2>
<p>I38 is a configuration for the i3 window manager that makes it more
accessible for blind people. It features audio feedback, screen reader
integration, and keyboard shortcuts designed for non-visual
navigation.</p>
<p>Unlike traditional desktop environments like GNOME or MATE, i3 is a
tiling window manager, which means windows are arranged in a
non-overlapping layout. This can be more efficient to navigate by
keyboard, as windows are organized in a predictable structure.</p>
<h3 id="coming-from-gnome-or-mate">Coming from GNOME or MATE?</h3>
<p>If youre transitioning from GNOME or MATE, here are some key
differences to understand:</p>
<ul>
<li><strong>Window Management</strong>: In GNOME/MATE, windows can
overlap freely and are typically manipulated with a mouse. In i3/I38,
windows tile automatically and are primarily controlled with keyboard
shortcuts.</li>
<li><strong>Panels and Indicators</strong>: Instead of persistent panels
with menus and indicators, I38 uses keyboard shortcuts to access
functionality.</li>
<li><strong>Workspace Navigation</strong>: While GNOME/MATE have
workspaces that you can switch between, I38s workspaces are more
central to the workflow and are accessed via dedicated keyboard
shortcuts.</li>
<li><strong>Application Launching</strong>: Rather than using a start
menu or activities overview, I38 provides keyboard shortcuts for
launching applications.</li>
</ul>
<p>I38 has been configured to make this transition easier by providing a
tabbed layout (similar to browser tabs) and shortcuts that may feel
somewhat familiar.</p>
<h2 id="basic-concepts">Basic Concepts</h2>
<h3 id="workspaces">Workspaces</h3>
<p>Workspaces act like virtual desktops, allowing you to organize
applications. You have 10 workspaces available.</p>
<ul>
<li>Switch to workspace: <code>Control</code> + <code>F1</code> through
<code>F10</code></li>
<li>Move window to workspace: <code>Control</code> + <code>Shift</code>
+ <code>F1</code> through <code>F10</code></li>
</ul>
<p><em>GNOME/MATE comparison:</em> Similar to workspaces in GNOME/MATE,
but with dedicated keyboard shortcuts rather than overview modes or
workspace switchers.</p>
<h3 id="window-management">Window Management</h3>
<p>Windows in I38 are arranged in a tabbed layout by default, which
means windows take up the entire screen and you can switch between them
like browser tabs.</p>
<ul>
<li>Switch between windows: <code>Alt</code> + <code>Tab</code> (next)
or <code>Alt</code> + <code>Shift</code> + <code>Tab</code>
(previous)</li>
<li>Launch terminal: <code>MODKEY</code> + <code>Return</code></li>
<li>Close window: <code>MODKEY</code> + <code>F4</code></li>
<li>Toggle fullscreen: <code>MODKEY</code> + <code>BackSpace</code></li>
<li>List windows in current workspace: <code>RATPOISONKEY</code> then
<code>'</code> (apostrophe)</li>
</ul>
<p><em>GNOME/MATE comparison:</em> Alt+Tab works similarly to
GNOME/MATE, but window placement is automatic rather than manual.</p>
<h2 id="modes-in-i38">Modes in I38</h2>
<h3 id="default-mode">Default Mode</h3>
<p>This is the standard mode for working with applications. Most
commands start with your mod key (<code>MODKEY</code>).</p>
<h3 id="ratpoison-mode">Ratpoison Mode</h3>
<p>Ratpoison mode allows quick access to common actions using shorter
key combinations. To enter Ratpoison mode, press
<code>RATPOISONKEY</code>. After pressing this key, you can execute
commands with single keystrokes.</p>
<p>Common Ratpoison mode commands:</p>
<table>
<colgroup>
<col style="width: 38%" />
<col style="width: 61%" />
</colgroup>
<thead>
<tr>
<th>Key</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>c</code></td>
<td>Launch a terminal</td>
</tr>
<tr>
<td><code>e</code></td>
<td>Open text editor (TEXTEDITOR)</td>
</tr>
<tr>
<td><code>w</code></td>
<td>Launch web browser (BROWSER)</td>
</tr>
<tr>
<td><code>k</code></td>
<td>Kill (close) the current window</td>
</tr>
<tr>
<td><code>?</code></td>
<td>Show I38 help</td>
</tr>
<tr>
<td><code>Escape</code> or <code>Control</code> + <code>g</code></td>
<td>Exit Ratpoison mode without taking action</td>
</tr>
<tr>
<td><code>Shift</code> + <code>c</code></td>
<td>Restart Cthulhu screen reader</td>
</tr>
<tr>
<td><code>Shift</code> + <code>o</code></td>
<td>Restart Orca screen reader</td>
</tr>
<tr>
<td><code>Shift</code> + <code>t</code></td>
<td>Toggle screen reader</td>
</tr>
<tr>
<td><code>Control</code> + <code>;</code></td>
<td>Reload I38 configuration</td>
</tr>
<tr>
<td><code>Control</code> + <code>q</code></td>
<td>Exit i3 (log out)</td>
</tr>
<tr>
<td><code>!</code></td>
<td>Open run dialog</td>
</tr>
<tr>
<td><code>Alt</code> + <code>b</code></td>
<td>Check battery status</td>
</tr>
<tr>
<td><code>g</code></td>
<td>Check game controller status</td>
</tr>
</tbody>
</table>
<p><em>GNOME/MATE comparison:</em> This mode has no direct equivalent in
GNOME/MATE. Think of it as a command palette or quick launcher activated
by a single key.</p>
<h3 id="bypass-mode">Bypass Mode</h3>
<p>Bypass mode passes all keys directly to the application, which is
useful for applications that need many keyboard shortcuts. To enter
bypass mode, press <code>MODKEY</code> + <code>Shift</code> +
<code>BackSpace</code>. Use the same key combination to exit bypass
mode.</p>
<p><em>GNOME/MATE comparison:</em> In GNOME/MATE, applications always
receive keyboard input directly. Bypass mode simulates this behavior
within i3.</p>
<h2 id="accessibility-features">Accessibility Features</h2>
<h3 id="screen-reader">Screen Reader</h3>
<p>I38 is configured to work with your screen reader (SCREENREADER). The
screen reader will provide spoken feedback about whats happening on
screen so long as there is a window. If you dont have a window open and
need to change something SCREENREADER related, press Control+Alt+d to
bring up the desktop, then screen reader keys should work.</p>
<ul>
<li>Toggle screen reader: <code>RATPOISONKEY</code> then
<code>Shift</code> + <code>t</code></li>
<li>Restart screen reader: <code>RATPOISONKEY</code> then
<code>Shift</code> + <code>o</code> (for Orca) or <code>Shift</code> +
<code>c</code> (for Cthulhu)</li>
<li>Interrupt speech: <code>MODKEY</code> + <code>Shift</code> +
<code>F5</code></li>
</ul>
<p><em>GNOME/MATE comparison:</em> GNOME uses Orca by default with its
own keyboard shortcuts. I38 integrates screen readers more deeply with
the window manager.</p>
<h3 id="braille-display-support">Braille Display Support</h3>
<p>If youve enabled braille display support during setup, I38 will
start XBrlAPI automatically to provide braille output from your screen
reader.</p>
<h3 id="ocr-optical-character-recognition">OCR (Optical Character
Recognition)</h3>
<p>If installed, you can use OCR to read text from images or
inaccessible applications:</p>
<ul>
<li><code>MODKEY</code> + <code>F5</code>: Perform OCR on the entire
screen and speak the content</li>
<li>In Ratpoison mode: <code>Print</code> or <code>MODKEY</code> +
<code>r</code>: Perform OCR and save to clipboard</li>
</ul>
<p><em>GNOME/MATE comparison:</em> OCR features are typically not
integrated into GNOME/MATE by default.</p>
<h3 id="sound-effects">Sound Effects</h3>
<p>I38 provides audio feedback for many actions:</p>
<ul>
<li>Window open/close: Ascending/descending tones</li>
<li>Mode changes: Distinctive sounds for each mode</li>
<li>Workspace changes: Subtle audio cues</li>
<li>Fullscreen toggle: Special sound effect</li>
</ul>
<p>This audio feedback provides non-visual confirmation of actions and
state changes.</p>
<p><em>GNOME/MATE comparison:</em> GNOME/MATE typically have fewer sound
effects for window management actions.</p>
<h2 id="application-menu-and-running-programs">Application Menu and
Running Programs</h2>
<p>Access applications in multiple ways:</p>
<ul>
<li>Applications menu: <code>MODKEY</code> + <code>F1</code></li>
<li>Run dialog (enter a command): <code>MODKEY</code> + <code>F2</code>
or in Ratpoison mode, <code>!</code> (exclamation mark)</li>
<li>Common applications have dedicated shortcuts in Ratpoison mode (see
table above)</li>
</ul>
<p>The applications menu is organized by categories similar to
traditional desktop environments.</p>
<p><em>GNOME/MATE comparison:</em> Instead of clicking on application
icons or using a start menu, I38 provides keyboard shortcuts to access
applications.</p>
<h2 id="reminders-and-notifications">Reminders and Notifications</h2>
<p>I38 includes integration with the <code>remind</code> program for
managing reminders:</p>
<ul>
<li>Access the reminder tool: <code>RATPOISONKEY</code> then
<code>r</code></li>
<li>Create various types of reminders (one-time, daily, weekly,
monthly)</li>
<li>Get notification alerts for your reminders</li>
</ul>
<p>The reminder tool provides the following features:</p>
<ul>
<li><strong>One-time Reminders</strong>: Set for a specific date and
time</li>
<li><strong>Daily Reminders</strong>: Occur every day at the specified
time</li>
<li><strong>Weekly Reminders</strong>: Occur on specific days of the
week</li>
<li><strong>Monthly Reminders</strong>: Occur on a specific day each
month or the last day of each month</li>
<li><strong>Custom Reminders</strong>: Create complex reminder
patterns</li>
</ul>
<p><em>GNOME/MATE comparison:</em> Similar to calendar applications in
GNOME/MATE but with a simplified interface optimized for keyboard
navigation.</p>
<h2 id="volume-and-media-controls">Volume and Media Controls</h2>
<h3 id="system-volume">System Volume</h3>
<ul>
<li>Increase volume: <code>MODKEY</code> +
<code>XF86AudioRaiseVolume</code></li>
<li>Decrease volume: <code>MODKEY</code> +
<code>XF86AudioLowerVolume</code></li>
<li>Mute/unmute: <code>MODKEY</code> + <code>XF86AudioMute</code></li>
</ul>
<h3 id="media-player-controls">Media Player Controls</h3>
<ul>
<li>Play/Pause: <code>XF86AudioPlay</code></li>
<li>Next track: <code>XF86AudioNext</code></li>
<li>Previous track: <code>XF86AudioPrev</code></li>
<li>Stop: <code>XF86AudioStop</code></li>
<li>Media info: <code>MODKEY</code> + <code>XF86AudioPlay</code></li>
</ul>
<p>In Ratpoison mode, these are also available with Alt+Shift
combinations:</p>
<ul>
<li>Increase volume: <code>Alt</code> + <code>Shift</code> +
<code>=</code></li>
<li>Decrease volume: <code>Alt</code> + <code>Shift</code> +
<code>-</code></li>
<li>Previous track: <code>Alt</code> + <code>Shift</code> +
<code>z</code></li>
<li>Pause: <code>Alt</code> + <code>Shift</code> + <code>c</code></li>
<li>Play: <code>Alt</code> + <code>Shift</code> + <code>x</code></li>
<li>Stop: <code>Alt</code> + <code>Shift</code> + <code>v</code></li>
<li>Next track: <code>Alt</code> + <code>Shift</code> +
<code>b</code></li>
<li>Media info: <code>Alt</code> + <code>Shift</code> +
<code>u</code></li>
</ul>
<p><em>GNOME/MATE comparison:</em> Media controls are similar to those
in GNOME/MATE, with the addition of audio feedback.</p>
<h2 id="file-management">File Management</h2>
<p>I38 uses FILEBROWSER for file management. Launch it in Ratpoison mode
with the <code>f</code> key.</p>
<p><em>GNOME/MATE comparison:</em> Similar functionality to Nautilus
(GNOME) or Caja (MATE), but launched via keyboard shortcut rather than
from a desktop icon or menu.</p>
<h2 id="system-operations">System Operations</h2>
<ul>
<li>Reload I38 configuration: In Ratpoison mode, <code>Control</code> +
<code>;</code> (semicolon)</li>
<li>Exit i3 (log out): In Ratpoison mode, <code>Control</code> +
<code>q</code></li>
<li>Check battery status: In Ratpoison mode, <code>Alt</code> +
<code>b</code></li>
<li>Check game controller status: In Ratpoison mode, <code>g</code></li>
<li>Adjust screen brightness (if xrandr is available): In Ratpoison
mode, <code>Alt</code> + <code>s</code></li>
</ul>
<p><em>GNOME/MATE comparison:</em> These functions are typically
available through system menus or indicators in GNOME/MATE.</p>
<h2 id="keyboard-layouts">Keyboard Layouts</h2>
<p>Switch between layouts: <code>Super</code> + <code>Space</code></p>
<p>This is only available if you chose multiple keyboard layouts during
setup.</p>
<p><em>GNOME/MATE comparison:</em> Similar to keyboard layout switching
in GNOME/MATE, but with a different default shortcut.</p>
<h2 id="desktop-and-window-decorations">Desktop and Window
Decorations</h2>
<p>Unlike GNOME or MATE, i3 uses minimal window decorations. Windows
dont have title bars with minimize/maximize buttons. Instead, windows
fill their available space automatically, and interactions are performed
through keyboard shortcuts.</p>
<ul>
<li>Show desktop icons: <code>MODKEY</code> + <code>Control</code> +
<code>d</code></li>
</ul>
<h2 id="clipboard-management">Clipboard Management</h2>
<p>I38 includes clipboard management features:</p>
<ul>
<li>Access clipboard history: <code>MODKEY</code> + <code>Control</code>
+ <code>c</code></li>
</ul>
<h2 id="bookmark-management">Bookmark Management</h2>
<ul>
<li>Access bookmarks: <code>MODKEY</code> + <code>Control</code> +
<code>b</code></li>
</ul>
<p><em>GNOME/MATE comparison:</em> Bookmarks are typically managed
within applications in GNOME/MATE. I38 provides a system-wide bookmark
manager.</p>
<h2 id="tips-for-new-users">Tips for New Users</h2>
<ul>
<li><strong>Start with Ratpoison mode</strong>: Learn the single-key
commands first, as theyre easier to remember.</li>
<li><strong>Use the window list</strong>: When youre lost, use
<code>RATPOISONKEY</code> then <code>'</code> to show all windows in the
current workspace.</li>
<li><strong>Bookmark important websites</strong>: Use
<code>MODKEY</code> + <code>Control</code> + <code>b</code> to access
bookmarks.</li>
<li><strong>Remember the help shortcut</strong>: <code>MODKEY</code> +
<code>Shift</code> + <code>F1</code> is your friend when you need
guidance.</li>
<li><strong>Let the sound effects guide you</strong>: Pay attention to
the audio cues to understand whats happening.</li>
<li><strong>Take advantage of OCR</strong>: If an application isnt
accessible, try the OCR function.</li>
</ul>
<h3 id="transitioning-from-gnomemate">Transitioning from GNOME/MATE</h3>
<ul>
<li>Start by learning the basic navigation shortcuts before exploring
advanced features</li>
<li>The tabbed layout should feel somewhat familiar if youre used to
browser tabs</li>
<li>Alt+Tab works similarly to GNOME/MATE for switching between
windows</li>
<li>Focus on keyboard commands rather than looking for visual elements
like panels or docks</li>
</ul>
<h2 id="customization">Customization</h2>
<p>You can customize I38 by editing the file
<code>~/.config/i3/customizations</code>. This file will not be
overwritten when you update I38.</p>
<p>Example customizations:</p>
<pre><code># Change background color
exec_always --no-startup-id xsetroot -solid &quot;#2E3440&quot;
# Add custom keybinding
bindsym $mod+F12 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 100%</code></pre>
<p>To reconfigure I38 completely, run the <code>i38.sh</code> script
again.</p>
<p><em>GNOME/MATE comparison:</em> Much more text-based configuration
compared to the graphical settings dialogs in GNOME/MATE.</p>
<h2 id="getting-help">Getting Help</h2>
<p>If you need assistance with I38, you can:</p>
<ul>
<li>Press <code>MODKEY</code> + <code>Shift</code> + <code>F1</code> to
view the help documentation</li>
<li>Visit the Stormux website at <a
href="https://stormux.org">stormux.org</a></li>
<li>Check the i3 documentation at <a
href="https://i3wm.org/docs/userguide.html">i3wm.org/docs/userguide.html</a></li>
</ul>
<hr />
<p><em>I38 - Making i3 accessible. A Stormux project. License: GPL
v3</em></p>
</body>
</html>

View File

@ -3,7 +3,7 @@
Accessibility setup script for the i3 window manager.
## i38.sh
Released under the terms of the GPL License Version 3: http://www.wtfpl.net
Released under the terms of the GPL License Version 3: https://www.gnu.org/licenses/
This is a Stormux project: https://stormux.org
@ -16,15 +16,17 @@ An uppercase I looks like a 1, 3 from i3, and 8 because the song [We Are 138](ht
- i3-wm: The i3 window manager.
- acpi: [optional] for battery status. It will still work even without this package, but uses it if it is installed. Required for the battery monitor with sound alerts.
- bc: For the information panel.
- dex: [optional] Alternative method for auto starting applications.
- clipster: clipboard manager
- jq: for getting the current workspace
- libcanberra: [optional]To play the desktop login sound.
- libcanberra: [optional] To play the desktop login sound.
- libnotify: For sending notifications
- notification-daemon: To handle notifications
- xfce4-notifyd: For sending notifications Replaces notification-daemon requires Orca from git.
- xfce4-notifyd: For sending notifications Replaces notification-daemon (Sway user will need to install the customized variant at <https://github.com/icasdri/xfce4-notifyd-layer-shell>)
- ocrdesktop: For getting contents of the current window with OCR.
- pamixer: for the mute-unmute script
- pcmanfm: [optional] Graphical file manager.
- playerctl: music controls
- python-gobject: for applications menu.
- python-i3ipc: for sounds etc.
@ -32,6 +34,7 @@ An uppercase I looks like a 1, 3 from i3, and 8 because the song [We Are 138](ht
- sox: for sounds.
- transfersh: [optional] for file sharing GUI
- udiskie: [optional] for automatically mounting removable storage
- x11bell: [optional] Bell support if you do not have a PC speaker. Available from https://github.com/jovanlanik/x11bell
- xclip: Clipboard support
- xbacklight: [optional] for screen brightness adjustment
- xorg-setxkbmap: [optional] for multiple keyboard layouts

133
i38.sh
View File

@ -11,10 +11,11 @@
# 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 this program. If not, see <https://www.gnu.org/licenses/>.
# Flag for sway configurations
usingSway=1 # Not by default.
i3Path="${XDG_CONFIG_HOME:-$HOME/.config}/i3"
i3msg="i3-msg"
sensibleTerminal="i3-sensible-terminal"
# Dialog accessibility
export DIALOGOPTS='--no-lines --visit-items'
@ -174,7 +175,7 @@ yesno() {
help() {
echo "${0##*/}"
echo "Released under the terms of the WTFPL License: http://www.wtfpl.net"
echo "Released under the terms of the GPL V3 License: https://www.gnu.org/licenses/"
echo -e "This is a Stormux project: https://stormux.org\n"
echo -e "Usage:\n"
echo "With no arguments, create the i3 configuration."
@ -227,6 +228,7 @@ fi
cat << 'EOF' > ~/.xprofile
# Accessibility variables
export ACCESSIBILITY_ENABLED=1
export CHROME_FLAGS="--force-renderer-accessibility"
export GTK_MODULES=gail:atk-bridge
export GNOME_ACCESSIBILITY=1
export QT_ACCESSIBILITY=1
@ -258,9 +260,10 @@ while getopts "${args}" i ; do
case "$i" in
h) help;;
s)
swaySystemIncludesPath="/etc/sway/config.d"
usingSway=0
i3msg="swaymsg"
i3Path="${XDG_CONFIG_HOME:-$HOME/.config}/sway"
sensibleTerminal="sway --sensible-terminal"
;;
u) update_scripts;;
x) write_xinitrc ;&
@ -293,6 +296,23 @@ if [[ $(yesno "Do you want to use multiple keyboard layouts?") -eq 0 ]]; then
fi
# Volume jump
volumeJump=$(rangebox "How much should pressing the volume keys change the volume?" 1 15 5)
# Screen Reader
unset programList
for i in cthulhu orca ; do
if command -v ${i/#-/} &> /dev/null ; then
if [ -n "$programList" ]; then
programList="$programList $i"
else
programList="$i"
fi
fi
done
if [ "$programList" != "${programList// /}" ]; then
screenReader="$(menulist ":Screen Reader" $programList)"
else
screenReader="${programList/#-/}"
fi
export screenReader="$(command -v $screenReader)"
# Email client
unset programList
for i in betterbird evolution thunderbird ; do
@ -309,10 +329,10 @@ if [ "$programList" != "${programList// /}" ]; then
else
emailClient="${programList/#-/}"
fi
emailClient="$(command -v $emailClient)"
export emailClient="$(command -v $emailClient)"
# Web browser
unset programList
for i in brave chromium epiphany firefox google-chrome-stable google-chrome-unstable microsoft-edge-stable microsoft-edge-beta microsoft-edge-dev midori seamonkey ; do
for i in brave chromium epiphany firefox google-chrome-stable google-chrome-unstable microsoft-edge-stable microsoft-edge-beta microsoft-edge-dev midori seamonkey vivaldi ; do
if command -v ${i/#-/} &> /dev/null ; then
if [ -n "$programList" ]; then
programList="$programList $i"
@ -326,7 +346,7 @@ if [ "$programList" != "${programList// /}" ]; then
else
webBrowser="${programList/#-/}"
fi
webBrowser="$(command -v $webBrowser)"
export webBrowser="$(command -v $webBrowser)"
# Text editor
unset programList
for i in emacs geany gedit kate kwrite l3afpad leafpad libreoffice mousepad pluma ; do
@ -343,7 +363,7 @@ textEditor="$(menulist "Text editor:" $programList)"
else
textEditor="${programList/#-/}"
fi
textEditor="$(command -v $textEditor)"
export textEditor="$(command -v $textEditor)"
# File browser
# Configure file browser
unset programList
@ -361,7 +381,7 @@ if [ "$programList" != "${programList// /}" ]; then
else
fileBrowser="${programList/#-/}"
fi
fileBrowser="$(command -v $fileBrowser)"
export fileBrowser="$(command -v $fileBrowser)"
# Auto mount removable media
udiskie=1
if command -v udiskie &> /dev/null ; then
@ -373,14 +393,14 @@ if command -v dex &> /dev/null ; then
export dex=$(yesno "Would you like to autostart applications with dex?")
fi
if [[ $dex -eq 0 ]]; then
dex -t "${XDG_CONFIG_HOME:-${HOME}/.config}/autostart" -c $(command -v orca)
dex -t "${XDG_CONFIG_HOME:-${HOME}/.config}/autostart" -c $(command -v $screenReader)
fi
if command -v acpi &> /dev/null ; then
batteryAlert=1
batteryAlert=$(yesno "Do you want low battery notifications?")
fi
brlapi=1
brlapi=$(yesno "Do you want to use a braille display with Orca?")
brlapi=$(yesno "Do you want to use a braille display with ${screenReader##*/}?")
sounds=1
sounds=$(yesno "Do you want window event sounds?")
# Play Login Sound
@ -402,8 +422,18 @@ cp -rv scripts/ "${i3Path}/" | dialog --backtitle "I38" --progressbox "Moving sc
cat << EOF > ${i3Path}/config
# Generated by I38 (${0##*/}) https://git.stormux.org/storm/I38
# $(date '+%A, %B %d, %Y at %I:%M%p')
EOF
# If we are using Sway, we need to load in the system configuration
# Usually, this is for system specific dBus things that the distro knows how to manage; we should trust their judgment with that
if [[ $usingSway ]] && [[ -d "${swaySystemIncludesPath}" ]]; then
cat << EOF >> ${i3Path}/config
# Include your distribution Sway configuration files.
include ${swaySystemIncludesPath}/*
EOF
fi
cat << EOF >> ${i3Path}/config
# i3 config file (v4)
#
# Please see https://i3wm.org/docs/userguide.html for a complete reference!
@ -443,7 +473,7 @@ bindsym \$mod+Control+Delete exec --no-startup-id sgtk-bar
# Use pactl to adjust volume in PulseAudio.
bindsym \$mod+XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +${volumeJump}% & play -qnG synth 0.03 sin 440
bindsym \$mod+XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -${volumeJump}% & play -qnG synth 0.03 sin 440
bindsym \$mod+XF86AudioMute exec --no-startup-id ${i3Path}/scripts/mute-unmute.sh
bindsym \$mod+XF86AudioMute exec --no-startup-id ${i3Path}/scrip/ts/mute-unmute.sh
# Music player controls
# Requires playerctl.
@ -457,7 +487,7 @@ bindsym XF86AudioStop exec --no-startup-id play -qV0 "| sox -np synth 0.03 sin 2
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
bindsym \$mod+Return exec $sensibleTerminal
bindsym \$mod+Return exec ${i3Path}/scripts/i3-sensible-terminal.sh
# kill focused window
bindsym \$mod+F4 kill
@ -509,6 +539,9 @@ bindsym Control+F8 workspace number \$ws8, exec --no-startup-id ${i3Path}/script
bindsym Control+F9 workspace number \$ws9, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh
bindsym Control+F10 workspace number \$ws10, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh
# This is sort of a fake panel where some useful but seldom interacted with applications can live.
bindsym Control+Mod1+Tab workspace number 11, exec --no-startup-id ${i3Path}/scripts/announce_workspace.sh
# move focused container to workspace
bindsym Control+Shift+F1 move container to workspace number \$ws1, exec spd-say -P important -Cw "moved to workspace 1"
bindsym Control+Shift+F2 move container to workspace number \$ws2, exec spd-say -P important -Cw "moved to workspace 2"
@ -533,6 +566,13 @@ bindsym $mod+Shift+BackSpace mode "default"
EOF
# ocrdesktop through speech-dispatcher
if command -v ocrdesktop &> /dev/null ; then
echo "bindsym ${mod}+F5 exec bash -c 'spd-say -Cw \"performing O C R\" && ocrdesktop -cnog | spd-say -e --'" >> ${i3Path}/config
fi
# Interrupt speech-dispatcher output
echo "bindsym ${mod}+Shift+F5 exec spd-say -C" >> ${i3Path}/config
# Multiple keyboard layouts if requested.
if [[ ${#kbd[@]} -gt 1 ]]; then
echo "bindsym Mod4+space exec ${i3Path}/scripts/keyboard.sh cycle ${kbd[@]}" >> ${i3Path}/config
@ -604,12 +644,22 @@ bindsym Mod1+b exec --no-startup-id ${i3Path}/scripts/battery_status.sh, mode "d
bindsym g exec ${i3Path}/scripts/game_controler.sh -s, mode "default"
# Get a list of windows in the current workspace
bindsym apostrophe exec --no-startup-id ${i3Path}/scripts/window_list.sh, mode "default"
# Restart orca
# Restart Cthulhu
bindsym Shift+c exec $(command -v cthulhu) --replace, mode "default"
# Restart Orca
bindsym Shift+o exec $(command -v orca) --replace, mode "default"
# reload the configuration file
bindsym Control+semicolon exec bash -c '$i3msg -t run_command reload && spd-say -P important -Cw "I38 Configuration reloaded."', mode "default"
# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
bindsym Control+Shift+semicolon exec $i3msg -t run_command restart && spd-say -P important -Cw "I3 restarted.", mode "default"
# Toggle screen reader
bindsym Shift+t exec ${i3Path}/scripts/toggle_screenreader.sh, mode "default"
$(if [[ $usingSway -eq 0 ]]; then
echo "# reload the configuration file"
echo "bindsym Control+semicolon exec bash -c '$i3msg -t command reload && spd-say -P important -Cw "I38 Configuration reloaded."', mode "default""
else
echo "# reload the configuration file"
echo "bindsym Control+semicolon exec bash -c '$i3msg -t run_command reload && spd-say -P important -Cw "I38 Configuration reloaded."', mode "default""
echo "# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)"
echo "bindsym Control+Shift+semicolon exec $i3msg -t run_command restart && spd-say -P important -Cw "I3 restarted.", mode "default""
fi)
# Run dialog with exclamation
bindsym Shift+exclam exec ${i3Path}/scripts/run_dialog.sh, mode "default"
# exit i3 (logs you out of your X session)
@ -626,8 +676,12 @@ fi
cat << EOF >> ${i3Path}/config
# Auto start section
$(if [[ $sounds -eq 0 ]]; then
echo "exec_always --no-startup-id ${i3Path}/scripts/sound.py"
$(if [[ $sounzzds -eq 0 ]]; then
if [[ $usingSway -eq 0 ]]; then
echo "exec --no-startup-id ${i3Path}/scripts/sound.py"
else
echo "exec_always --no-startup-id ${i3Path}/scripts/sound.py"
fi
fi
if [[ $loginSound -eq 0 ]]; then
echo 'exec --no-startup-id canberra-gtk-play -i desktop-login'
@ -660,13 +714,48 @@ if [[ $dex -eq 0 ]]; then
echo 'exec --no-startup-id dex --autostart --environment i3'
else
echo '# Startup applications'
if command -v x11bell &> /dev/null ; then
echo 'exec --no-startup-id x11bell play -nqV0 synth .1 sq norm -12'
fi
echo 'exec --no-startup-id clipster -d'
echo 'exec orca'
echo "exec $screenReader"
echo "exec_always --no-startup-id ${i3Path}/scripts/desktop.sh"
fi)
# First run help documentation
exec --no-startup-id bash -c 'if [[ -f "${i3Path}/firstrun" ]]; then ${webBrowser} "${i3Path}/I38.html"& rm "${i3Path}/firstrun"; fi'
# Fake panel setup
exec --no-startup-id i3-msg 'workspace 11; workspace 1'
# If you want to add personal customizations to i3, add them in ${i3Path}/customizations
# It is not overwritten with the config file is recreated.
# It is not overwritten when the config file is recreated.
include "${i3Path}/customizations"
# Applications that will be placed in workspace 11, which we use as a sort of fake panel.
include "${i3Path}/panel.conf"
EOF
touch "${i3Path}/customizations"
cp -v panel.conf "${i3Path}/panel.conf"
# Move html help file to destination
cp -v I38.html "${i3Path}/I38.html"
# More readable version of variables.
escapeKey="${escapeKey//Mod1/Alt}"
escapeKey="${escapeKey//Mod4/Super}"
mod="${mod//Mod1/Alt}"
mod="${mod//Mod4/Super}"
webBrowser="${webBrowser##*/}"
screenReader="${screenReader##*/}"
textEditor="${textEditor##*/}"
fileBrowser="${fileBrowser##*/}"
# Customize the html file to the user's choices.
sed -i -e "s|BROWSER|${webBrowser}|g" \
-e "s|MODKEY|${mod}|g" \
-e "s|SCREENREADER|${screenReader}|g" \
-e "s|RATPOISONKEY|${escapeKey}|g" \
-e "s|TEXTEDITOR|${textEditor}|g" \
-e "s|FILEBROWSER|${fileBrowser}|g" "${i3Path}/I38.html"
# Create the firstrun file
touch "${i3Path}/firstrun"

2
panel.conf Normal file
View File

@ -0,0 +1,2 @@
assign [class="Solaar"] workspace number 11
assign [class="qjoypad"] workspace number 11

View File

@ -26,6 +26,11 @@ fi
left=9
right=0
msg="Workspace ${workSpace}"
if [[ "${workSpace}" == "11" ]]; then
play -qnV0 synth 1.5 pl A4 pl E5 pl C5 delay 0.0 0.1 0.2 remix - fade p 0 1.5 .5
spd-say -P important -Cw "I38 panel"
exit 0
fi
if ! [[ "${workSpace}" =~ ^[0-9]+$ ]]; then
right=9
else

View File

@ -19,7 +19,7 @@
batteryName=""
if [[ "$batteryName" == "" ]]; then
batteryName="$(find /sys/class/power_supply -name 'sony_controller_battery_*' | cut -d/ -f5)"
batteryName="$(find /sys/class/power_supply -name 'sony_controller_battery_*' -or -name 'ps-controller-battery-*' | cut -d/ -f5)"
fi
# If there's no file, we don't check it.

23
scripts/i3-sensible-terminal.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/sh
#
# This code is released in public domain by Han Boetes <han@mijncomputer.nl>
#
# This script tries to exec a terminal emulator by trying some known terminal
# emulators.
#
# We welcome patches that add distribution-specific mechanisms to find the
# preferred terminal emulator. On Debian, there is the x-terminal-emulator
# symlink for example.
#
# Invariants:
# 1. $TERMINAL must come first
# 2. Distribution-specific mechanisms come next, e.g. x-terminal-emulator
# 3. The terminal emulator with best accessibility comes first.
# 4. No order is guaranteed/desired for the remaining terminal emulators.
for terminal in "$TERMINAL" x-terminal-emulator mate-terminal gnome-terminal terminator xfce4-terminal urxvt rxvt termit Eterm aterm uxterm xterm roxterm termite lxterminal terminology st qterminal lilyterm tilix terminix konsole kitty guake tilda alacritty hyper wezterm; do
if command -v "$terminal" > /dev/null 2>&1; then
exec "$terminal" "$@"
fi
done
i3-nagbar -m 'i3-sensible-terminal could not find a terminal emulator. Please install one.'

View File

@ -29,8 +29,9 @@ def read_desktop_files(paths):
userApplicationsPath = Path.home() / '.local/share/applications'
systemApplicationsPath = Path('/usr/share/applications')
desktopEntries = read_desktop_files([userApplicationsPath, systemApplicationsPath])
userFlatpakApplicationsPath = Path.home() / '.local/share/flatpak/exports/share/applications'
systemFlatpakApplicationsPath = Path('/var/lib/flatpak/exports/share/applications')
desktopEntries = read_desktop_files([userApplicationsPath, systemApplicationsPath, userFlatpakApplicationsPath, systemFlatpakApplicationsPath])
# Combine some of the categories
categoryMap = {

View File

@ -16,6 +16,6 @@ if [ $(pamixer --get-mute) = false ]; then
pamixer -t
else
pamixer -t
play -qnG synth 0.05 sin 440
play -qnGV0 synth 0.05 sin 440
spd-say -P important -Cw 'Unmuted!'
fi

View File

@ -20,13 +20,13 @@ i3 = i3ipc.Connection()
def on_new_window(self,i3):
if i3.container.name == 'xfce4-notifyd':
system('play -n synth .05 sq 1800 tri 2400 delay 0 .03 remix - repeat 2 echo .55 0.7 20 1 norm -12 &')
system('play -nqV0 synth .05 sq 1800 tri 2400 delay 0 .03 remix - repeat 2 echo .55 0.7 20 1 norm -12 &')
else:
system('play -n synth .25 sin 440:880 sin 480:920 remix - norm -3 pitch -500 &')
system('play -nqV0 synth .25 sin 440:880 sin 480:920 remix - norm -3 pitch -500 &')
def on_close_window(self,i3):
if i3.container.name != 'xfce4-notifyd':
system('play -n synth .25 sin 880:440 sin 920:480 remix - norm -3 pitch -500 &')
system('play -nqV0 synth .25 sin 880:440 sin 920:480 remix - norm -3 pitch -500 &')
def on_mode(self,event):
mode= event.change
@ -37,7 +37,7 @@ def on_mode(self,event):
elif mode == 'default':
system('play -qV0 "|sox -np synth .07 sq 400" "|sox -np synth .5 sq 800" fade h 0 .5 .5 norm -20 reverse &')
else:
system('play -n synth 0.05 pluck F3 norm -8 : synth 0.05 pluck C4 norm -8 : synth 0.05 pluck F4 norm -8 : synth 0.05 pluck C5 norm -8')
system('play -nqV0 synth 0.05 pluck F3 norm -8 : synth 0.05 pluck C4 norm -8 : synth 0.05 pluck F4 norm -8 : synth 0.05 pluck C5 norm -8')
def on_workspace_focus(self,i3):
#system('play -qnV0 synth pi fade 0 .25 .15 pad 0 1 reverb overdrive riaa norm -8 speed 1 &')
@ -47,13 +47,13 @@ def on_workspace_move(self,i3):
system('play -qnV0 synth pi fade 0 .25 .15 pad 0 1 reverb overdrive riaa norm -8 speed 1 reverse &')
def on_restart(self,i3):
system('play -qn synth .25 saw 500:1200 fade .1 .25 .1 norm -8 &')
system('play -qnV0 synth .25 saw 500:1200 fade .1 .25 .1 norm -8 &')
def on_exit(self,i3):
system('play -qn synth .3 sin 700:200 fade 0 .3 0 &')
system('play -qnV0 synth .3 sin 700:200 fade 0 .3 0 &')
def on_fullscreen(self,i3):
system('play -qn synth br flanger fade h .3 .3 0 &')
system('play -qnV0 synth br flanger fade h .3 .3 0 &')
i3 = i3ipc.Connection()

104
scripts/toggle_screenreader.sh Executable file
View File

@ -0,0 +1,104 @@
#!/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 <https://www.gnu.org/licenses/>.
is_running() {
pgrep -x "$1" >/dev/null
return $?
}
speak() {
spd-say -P important -Cw -- "$*"
}
# Make sure screen readers are available
orcaAvailable=false
cthulhuAvailable=false
if command -v orca &> /dev/null; then
orcaAvailable=true
fi
if command -v cthulhu &> /dev/null; then
cthulhuAvailable=true
fi
# Check if at least one screen reader is available
if ! $orcaAvailable && ! $cthulhuAvailable; then
speak "No screen readers found. Please install Orca or Cthulhu."
yad --center --title="I38" --alert="No screen readers found.\nPlease install Orca or Cthulhu."
exit 1
fi
# Determine current state
currentReader="none"
if is_running "cthulhu"; then
currentReader="cthulhu"
elif is_running "orca"; then
currentReader="orca"
fi
# Build YAD command based on available screen readers
items=()
# First add the currently active screen reader
if [ "$currentReader" != "none" ]; then
if [ "$currentReader" = "cthulhu" ] && $cthulhuAvailable; then
items+=("Cthulhu (active)" "cthulhu")
elif [ "$currentReader" = "orca" ] && $orcaAvailable; then
items+=("Orca (active)" "orca")
fi
fi
if $cthulhuAvailable && [ "$currentReader" != "cthulhu" ]; then
items+=("Cthulhu" "cthulhu")
fi
if $orcaAvailable && [ "$currentReader" != "orca" ]; then
items+=("Orca" "orca")
fi
# Display the dialog
result=$(yad --center --title="Screen Reader Toggle" --text="Select screen reader:" \
--list --on-top --skip-taskbar \
--button="Cancel:1" --button="OK:0" \
--column="Screen Reader" --column=ID:HD "${items[@]}")
exitCode=$?
if [ $exitCode -ne 0 ]; then
exit 0
fi
if [ -n "$result" ]; then
# Extract the selected reader from the result
selectedReader=$(echo "$result" | cut -d'|' -f2)
# Don't do anything if selecting the already active reader
if [ "$selectedReader" = "$currentReader" ]; then
exit 0
fi
# Stop current screen reader
if [ "$currentReader" != "none" ]; then
speak "Switching from $currentReader to $selectedReader."
pkill -15 "$currentReader"
sleep 0.5
else
speak "Starting $selectedReader."
fi
if [ "$selectedReader" = "orca" ]; then
orca &
else
cthulhu &
fi
fi
exit 0