237 Commits
Author SHA1 Message Date
Storm Dragon 14227981cb Release 2026.08.06 2026-08-06 13:51:18 -04:00
Storm Dragon ee441c319a Improved progress bar detections. 2026-08-06 13:49:53 -04:00
Storm Dragon 5cf7a11260 Release candidate after bug fixes. 2026-07-30 04:57:29 -04:00
Storm Dragon 7593c8d0b3 Fix to socket routing for self-voicing. 2026-07-30 04:52:52 -04:00
Storm Dragon 312cb46f22 Release candidate. 2026-07-29 19:12:49 -04:00
Storm Dragon 122a6a38b3 Fix Unix remote watchdog socket leak 2026-07-29 14:13:53 -04:00
Storm Dragon 76b8f2f2cf Very scary test here. Trying to see if we can boost speed on very large terminals. 2026-07-26 22:01:11 -04:00
Storm Dragon d81565fbf5 Still attempting to kill off this delay. 2026-07-26 21:49:20 -04:00
Storm Dragon 186512f79a Another try for lag. 2026-07-26 21:42:53 -04:00
Storm Dragon 17b6e6f909 Attempt to decrease dectalk lag. Hoping you don't have to send settings over every time you want it to say something. 2026-07-26 21:34:04 -04:00
Storm Dragon fac3065c6a More tweaks to dectalk driver. Think we're nearly there. Hopefully. 2026-07-26 21:24:28 -04:00
Storm Dragon e93aba109a Fixes with the dectalk driver with rate, etc. 2026-07-26 21:10:39 -04:00
Storm Dragon 11a4244cc3 Fixed some errors with my dectalk protocol implementation. Thanks Codex. :) 2026-07-26 20:59:14 -04:00
Storm Dragon 9ac2e9e844 Found and hopefullyfixed a bug with fenrir watchdog. 2026-07-26 20:44:50 -04:00
Storm Dragon c863245c24 More attempts at getting this usb dectalk working. 2026-07-26 20:18:17 -04:00
Storm Dragon 45bd33f756 Improvements to Dectalk driver. 2026-07-26 19:44:10 -04:00
Storm Dragon 6d9260e79b Fixed 2 speech-dispatcher bugs. First, multiword voice names were not available. Next, when the module changed the old voice name was carried in causing some modules to fail. 2026-07-25 04:36:39 -04:00
Storm Dragon e180fd53fa Release candidate. 2026-07-19 16:02:24 -04:00
Storm Dragon 385356e745 Prevent incoming output from bypassing auto-read toggle 2026-07-19 15:59:51 -04:00
Storm Dragon 81f1757357 Release candidate. 2026-07-15 00:20:57 -04:00
Storm Dragon 28e4f8ab0c Progress bar beeps now work on ffmpeg output. 2026-07-12 15:06:44 -04:00
lilmike 4d94b56ee9 Fix very high cpu usage when a console fenrir under root and an x fenrir under your user are running at the same time. 2026-07-01 23:44:12 -07:00
Storm Dragon eb93a8aa62 Fixed a typo in tests/unit/test_hardware_speech_drivers.py. It was reading 9 bytes while comparing against a 10-byte payload. Thanks Samuel Thibault for finding and pointing this out. 2026-06-27 16:59:05 -04:00
Storm Dragon ad863ad706 Add ability for X clibpard and Fenrir's clipboard to stay in sync. 2026-06-27 16:55:00 -04:00
Storm Dragon 447e2cc896 Missed one commented setting. 2026-06-18 10:51:44 -04:00
Storm Dragon 2b7d205f06 Fixed some half-completed work in generic drivers. Minor -x bug fixes. 2026-06-18 10:35:48 -04:00
Storm Dragon fd5fe5b328 More progressbar updates. Removed Claud specific progress bar detection, hopefully caught now by generic progress bar updates. They do change it all the time, so it may work, but shouldn't be expected to do so. 2026-06-01 03:04:47 -04:00
Storm Dragon 4ed3f4d6ab Fixed version. 2026-05-31 22:37:59 -04:00
Storm Dragon 2cb83632f9 Fixed keyboard handling regression. 2026-05-31 22:36:35 -04:00
Storm Dragon 0c4fe50606 Updated log names. Should be easier to find if you forget to delete old logs. Now just called fenrir.log, we don't tend to need to have multiple logs anyway. 2026-05-30 14:16:23 -04:00
Storm Dragon 15f2435749 Hopefully fix some weirdness on tab completeion where it would read the entire screen instead of suggested tab completions. 2026-05-30 13:56:25 -04:00
Storm Dragon 3897b63068 Iproved logging for startup flags. 2026-05-29 20:22:06 -04:00
Storm Dragon f1a8e6af21 Fixed long standing bug where bottom of screen played for both top and bottom, found a couple other things that were off in the process. 2026-05-29 19:50:38 -04:00
Storm Dragon bd54ec0edb Fixed version. 2026-05-24 17:14:58 -04:00
Storm Dragon b9518f52ec Vmenu fixed I think. Hopefully last thing before new version. 2026-05-24 17:13:38 -04:00
Storm Dragon c143c9a561 Found a vmenu bug in -x. I thought we were close to a new release... 2026-05-24 17:03:41 -04:00
Storm Dragon 7e2f927596 fixed version. 2026-05-24 14:15:02 -04:00
Storm Dragon 788e678ed6 Attempted fix for some progress bars that were being skipped by progress bar detection. 2026-05-24 14:13:29 -04:00
Storm Dragon ea89e90c2f Merge branch 'testing' Hopefully final release candidate for the new version. 2026-05-23 18:59:14 -04:00
Storm Dragon ce43d64e77 Removed auto as a hardware synth device option. It was too flakey. 2026-05-23 18:58:55 -04:00
Storm Dragon 618987546a Adjust timeout for auto detection. I forgot these devices would be slow because most of them are very old with much less speed than would be expected today. 2026-05-23 18:41:42 -04:00
Storm Dragon 604221a29d Attempt to make auto at least somewhat more reliable. Recommend that device be explicitly set if possible. 2026-05-23 18:23:58 -04:00
Storm Dragon 89b85c6f17 Hardware synth code now verified working. New release candidate. 2026-05-23 18:05:55 -04:00
Storm Dragon 6e3d7fee94 Parse the settings correctly lol. 2026-05-23 17:57:02 -04:00
Storm Dragon 089850ac18 More hw synth refinement. 2026-05-23 17:39:16 -04:00
Storm Dragon 5b7c08260a Another iteration based on feedback from hardware synth testing. 2026-05-23 17:23:52 -04:00
Storm Dragon d4b2fec1db speculative fixes for hardware speech. 2026-05-23 17:10:46 -04:00
Storm Dragon 1f7aa99cc0 Release candidate. 2026-05-23 16:13:51 -04:00
Storm Dragon d853e1b24d Fixed the -x keyboard problem for real this time I'm pretty sure. 2026-05-22 20:23:31 -04:00
Storm Dragon e8bc34eaf5 Merge bug fixes, fix version. 2026-05-21 01:08:27 -04:00
Storm Dragon f84167a7fb Of course, soon as I feel things are stable enough to merge to master bugs come crawling out of the woodwork. Fix for being sure Fenrir switches out of its modal mode completely when leaving speech history. 2026-05-21 01:07:01 -04:00
Storm Dragon 29a6c3eb42 A few teaks. Maybe close to actual release. 2026-05-21 00:50:20 -04:00
Storm Dragon ac7348895f Speech history added, bound to fenrir+control+h. 2026-05-20 21:02:56 -04:00
Storm Dragon 4caef89f6b More work on sockets attempt to get socket command to standard daemon.sock to a running instance. Also, fixed a long standing misspelling in daemon, was deamon, so if your scripts that self-voice or whatever with fenrir no longer work, this is why, please update scripts to the new, correct, daemon.sock. 2026-05-20 20:11:21 -04:00
Storm Dragon 8467bd74c3 New hardware synth support added. Untested, so consider this experimental. 2026-05-20 18:02:51 -04:00
Storm Dragon f09437ea60 Speculative fix for a sometimes speech crash bug. 2026-05-19 01:54:09 -04:00
Storm Dragon 19194e73fc Fenrir was not cleaning up after itself properly. Fixed several possible stale file bugs and hopefully this problem is now gone. 2026-05-18 17:59:47 -04:00
Storm Dragon 096919a2da Hopefully fixed bug where keys like super weren't being forwarded with bypass mode. 2026-05-14 21:45:30 -04:00
Storm Dragon a8e4d7bb2a Forward keypress bug fixed. 2026-05-14 20:10:11 -04:00
Storm Dragon 8966275071 Missed a couple of keys in translation for -x. 2026-05-13 23:39:15 -04:00
Storm Dragon c48a9a6731 Fixed a regression in reading dialog based TUI. 2026-05-13 18:31:11 -04:00
Storm Dragon 6876547590 Update documentation. 2026-05-12 22:34:30 -04:00
Storm Dragon 116f254e11 Fixed scripts with simlinks. 2026-05-12 20:01:46 -04:00
Storm Dragon 5dccdd27c4 Another shot at squishing this bug. 2026-05-12 18:30:23 -04:00
Storm Dragon fa63ecadbe The freeze bug reared its ugly head again. 2026-05-12 18:18:37 -04:00
Storm Dragon 96c5184450 Tab completion fixes. 2026-05-12 17:39:56 -04:00
Storm Dragon b599a25945 Add more local sourced directories for scripts and sounds meaning each user can have own scripts and sound themes when using -x. Hopefully fixed the remainder of the random freeze bug. 2026-05-12 17:23:50 -04:00
Storm Dragon 4022fc4006 Work on tightening up keyboard handling. 2026-05-12 16:06:31 -04:00
Storm Dragon ab7818fd4c Attempt to prevent thread lock that is causing freeze. 2026-05-12 12:42:57 -04:00
Storm Dragon 878eef5c5b Tests updated. Attempt to fix remaining problems with forward keypress and numlock reporting. 2026-05-12 02:32:26 -04:00
Storm Dragon 38ef1c2d72 Attempt to fix forward keypress and numpad state. 2026-05-12 02:26:02 -04:00
Storm Dragon 57980225ad Implemented local settings save in ~/.local/share/stormux. Also, I think I got interrupt on any keypress working better when using -x. 2026-05-12 02:06:07 -04:00
Storm Dragon 9e2d5a89b3 Fixed horrible crash bug with opening vim. 2026-05-10 22:31:17 -04:00
Storm Dragon c7d74726da Bump testing version for tab completion verification 2026-05-09 00:30:42 -04:00
Storm Dragon be78db0d58 Hopefully final touches on the new tab completion. 2026-05-09 00:14:36 -04:00
Storm Dragon 0af7d94014 That does it, I'm breaking out codex on this one. Take that tab completion! 2026-05-08 23:38:59 -04:00
Storm Dragon 42ba3fdad2 Another attempt at improving tab completion detection. 2026-05-08 21:50:27 -04:00
Storm Dragon 6fb8298b9f More trouble with pty vs console behavior. 2026-05-08 21:26:58 -04:00
Storm Dragon 114a7b0da7 Hopefully make pty more similar to tested console behavior. 2026-05-08 20:10:08 -04:00
Storm Dragon 90efad362b More fixes to pty reading. 2026-05-08 19:58:42 -04:00
Storm Dragon 3c61b6629a Possibly fixed a bug in the pty code used by -x flag. 2026-05-08 19:45:59 -04:00
Storm Dragon b6689d93bf Use single shared remote command lock 2026-05-08 00:48:11 -04:00
Storm Dragon a60efdbe07 Use shared locks for Fenrir instance coordination 2026-05-08 00:01:58 -04:00
Storm Dragon b38b0a2dab Fix cross-user Fenrir instance registry pruning 2026-05-07 23:51:07 -04:00
Storm Dragon 37e281a1f7 Fix Fenrir Unix socket ownership reporting 2026-05-07 23:43:11 -04:00
Storm Dragon 6d4f55ffe5 A couple of socket fixes so root fenrir and user fenrir do not battle. 2026-05-07 23:37:01 -04:00
Storm Dragon 8638bca1d5 Improve socket handling for -x spawned fenrir instances. 2026-05-07 23:24:54 -04:00
Storm Dragon 0273f9b956 Make x support optional. 2026-05-07 12:50:45 -04:00
Storm Dragon 1670c5711b Few fixes with the -x X driver code. 2026-05-07 02:03:36 -04:00
Storm Dragon fed8f24126 Add X11 terminal input mode 2026-05-07 01:45:00 -04:00
Storm Dragon 40120f825c 2026.04.04 merged 2026-04-04 10:08:46 -04:00
Storm Dragon 17dea6b026 Fix IRC incoming announcements and add focus.tui default 2026-03-25 03:24:29 -04:00
Storm Dragon 57c09e0db9 Guard evdev uinput setup 2026-03-04 04:01:19 -05:00
Storm Dragon 4050c32a16 Add speech-first diff review mode with navigation and tests 2026-02-15 15:55:46 -05:00
Storm Dragon 2e10c1c43b Version bump for new release. 2026-01-28 16:41:44 -05:00
Storm Dragon 1e67876883 RC1 for next release. 2026-01-11 23:19:12 -05:00
Storm Dragon 14cf6b6088 Clarify other OS than Linux support. 2026-01-11 23:15:28 -05:00
Storm Dragon 900a027643 Merge branch 'testing' 2026-01-10 23:12:13 -05:00
Storm Dragon 0e50175463 Removed sound for echo switching. 2026-01-10 23:11:53 -05:00
Storm Dragon 7283f04778 Merge branch 'testing' 2026-01-10 23:03:50 -05:00
Storm Dragon 8d3495f74f Character echo settings toggle key added. Keyboard files updated. 2026-01-10 23:03:22 -05:00
Storm Dragon a6cd47dafc latest code. 2026-01-10 21:55:25 -05:00
Storm Dragon 0bb2e52deb Fixed fluttery caps speech shifts. 2026-01-10 20:49:22 -05:00
Storm Dragon b8eb815a86 Merged latest from testing. 2026-01-08 16:16:20 -05:00
Storm Dragon beca468338 Finally! Fixed bug that was causing interruption when prompt comes back. 2026-01-08 12:37:55 -05:00
Storm Dragon a26fe26c8c Log level now set to 0 by default so there's no longer a ton of log files created that aren't normally needed. 2026-01-05 08:32:07 -05:00
Storm Dragon 508fd11610 Redesigned the flood protection for incoming text, should hopefully be much better. 2026-01-04 00:33:06 -05:00
Storm Dragon afe0e71a1d A tiny bug fix in prompt checker. 2026-01-04 00:05:52 -05:00
Storm Dragon 9e8d0b3869 Latest changes. 2025-12-30 04:10:52 -05:00
Storm Dragon d7f86ca0de Setting added to choose caps notification type, beep, pitch, both or none. 2025-12-30 04:09:25 -05:00
Storm Dragon 49a79d2722 Removed promoted text option. It wasn't all that useful, and the new speech restore performs the same thing more affectively. 2025-12-28 19:07:54 -05:00
Storm Dragon 4ab024d115 Mostly progress bar fixes. 2025-12-22 12:51:15 -05:00
Storm Dragon c4ae27a01b More progress bar tweaks. 2025-12-20 06:59:19 -05:00
Storm Dragon 668d39b444 Merged for wider testing. 2025-12-19 12:56:33 -05:00
Storm Dragon 8b25afbf5a More progress bar updates. 2025-12-19 12:55:17 -05:00
Storm Dragon efeb040f75 Spelling error and case fixes. Everything seems to work so far. 2025-12-19 03:46:18 -05:00
Storm Dragon 7a17b36d50 More update work on readme and settings. 2025-12-19 03:07:46 -05:00
Storm Dragon 047a31b4bf Latest changes. 2025-12-19 00:11:04 -05:00
Storm Dragon 096aef9f08 Progress bar detection updates. 2025-12-14 19:05:18 -05:00
Storm Dragon 76472b83b5 Fixed a comment in settings file. 2025-12-10 20:20:56 -05:00
Storm Dragon a52bf624ec Merged changes from testing. WARNING: breaking changes, you will need to update or regenerate your settings file. Use the example provided in config/settings/settings.conf or on arch use the .pacnew as a guide. 2025-12-10 20:12:07 -05:00
Storm Dragon f4e28a246f Second pass on updating settings, missed a few the first go round. 2025-12-10 20:08:01 -05:00
Storm Dragon 560ceb26c9 Major: Convert all settings from camelCase to snake_case for PEP8 compliance (WARNING! BREAKING CHANGES)
Breaking change for v3.0 - users must update their settings.conf file.

  - Converted 45 settings across all sections
  - Updated 524 Python files, tests, and documentation
  - All tests passing, zero regressions
  - Moving forward the philosophy is clean code over backward compatibility
  - Next stable release will be considered a major release
2025-12-10 19:39:45 -05:00
Storm Dragon 61868c94e5 Experimental fix to hopefully let users who rebind their capslock key keep those settings while using Fenrir. 2025-12-10 08:22:17 -05:00
Storm Dragon f462ca7990 Merge branch 'testing' minor settings file update. 2025-12-03 16:25:47 -05:00
Storm Dragon f0bbcb8a38 Updated settings file to document that capslock as fenrir key and echo mode 2 are incompatible. 2025-12-03 16:25:22 -05:00
Storm Dragon aed627ec2a Discovered through much pain that echo mode 2 and capslock as fenrir key are incompatible. Documented in settings file. 2025-12-03 16:18:02 -05:00
Storm Dragon e62b887e9c Some socket improvements for remote manager I thought should make it into this release. 2025-12-03 12:20:14 -05:00
Storm Dragon bf0d134187 Tests added, see the documentation in the tests directory for details. Improved the socket code. 2025-12-03 02:51:49 -05:00
Storm Dragon c66a9ba9c2 Problems with voice selection fixed.: 2025-12-02 18:38:06 -05:00
Storm Dragon 2092a3e257 Fixed voice selection. 2025-12-02 18:36:46 -05:00
Storm Dragon d46d8de3ee Updated sound driver to gstreamer by default. 2025-12-02 16:25:25 -05:00
Storm Dragon 75a8447759 One more feature addition before hopefully releasing the new version. 2025-12-02 16:13:15 -05:00
Storm Dragon 1650eec768 Add ability to switch speech-dispatcher module and voice to the speeach keys. 2025-12-02 16:11:47 -05:00
Storm Dragon 5bb786ef4c Bug fix in vmenu for keyboard layouts. 2025-11-27 22:44:51 -05:00
Storm Dragon 7f7faa17d3 keyboard layout fixed in vmenu. 2025-11-27 22:42:36 -05:00
Storm Dragon 2766f70c5d Some cleanup and minor fixes in docs. 2025-11-24 09:07:45 -05:00
Storm Dragon 8d781643bc Remove group and user comments from the Arch service file, not being used, so just extra stuff. 2025-11-24 08:49:31 -05:00
Storm Dragon c184cf023a Code cleanups, fixes to systemd files, url corrections. 2025-11-24 08:44:49 -05:00
Storm Dragon 841c221c7b Preparing for new tagged release. 2025-11-23 18:51:02 -05:00
Storm Dragon 87553bdc38 more fixes for the pickle error. 2025-11-23 18:37:21 -05:00
Storm Dragon 77a3aae5a4 Attempt to fix cannot pickle 'TextIOWrapper' instances error for some distros. 2025-11-23 18:29:38 -05:00
Storm Dragon aabc202d83 Latest version of configure_pipewire.sh tested and appears to work. 2025-10-17 22:19:58 -04:00
Storm Dragon 2f3a114790 Pipewire configuration tool updated. In a bout of pure insanity I tested this on my production system and it worked without a hitch, so should be good to go. 2025-10-17 22:19:30 -04:00
Storm Dragon c797974560 Pre tag release. If no problems reported this will become the new stable release. 2025-10-17 21:27:36 -04:00
Storm Dragon af4740d5ad Various minor fixes in preparation for new release. 2025-10-17 21:26:13 -04:00
Storm Dragon 5ef5faaebe Progressbar tweaks. 2025-10-17 21:03:12 -04:00
Storm Dragon 7041d2567a Progress bar updates. 2025-09-26 18:07:35 -04:00
Storm Dragon 2c38bcf5f4 Another attempt at fixing external numpad detection. I *think* some of them send numlock state with every event. If that's the case, this should fix it. 2025-09-13 14:11:27 -04:00
Storm Dragon 96cdda99c4 Separate menu entries for some settings, improves usability. Fixed device detection for devices that do not contain what they do in their name, e.g. numpads that are not listed as numpads. This hopefully fixes a bug with some external numpads. 2025-09-12 12:09:00 -04:00
Storm Dragon 0658d37ae8 I don't wanna say this too loud, but I think tab completion is much more reliable now. No more not reading when you press tab and something appears. 2025-08-31 20:45:32 -04:00
Storm Dragon a6bb3e1301 A bit of code cleanup. Nothing should be changed at all functionally. 2025-08-31 20:30:06 -04:00
Storm Dragon 5ff653bd00 Progress bar and commit validator updates. 2025-08-31 14:54:07 -04:00
Storm Dragon 356f4b01c1 Got the version file wrong again. Need to be more careful. 2025-08-31 14:44:46 -04:00
Storm Dragon c7ad4d9200 merged to master. 2025-08-31 14:39:26 -04:00
Storm Dragon d274fe78f3 Rebind the keyboard layout switcher to fenrir+control+f4. 2025-08-31 14:37:48 -04:00
Storm Dragon f5344a7227 removing keyboard layouts that are no longer used 2025-08-23 18:30:35 -04:00
Storm Dragon 90ffc2fc08 removing keyboard layouts that are no longer used 2025-08-23 18:29:42 -04:00
Storm Dragon b635f7538b Latest changes merged. Minor fixes to progress bar detection. Fixed my old habbit of camel case variable names. :) 2025-08-23 12:20:05 -04:00
Storm Dragon 7f473b72a7 Minor updates to progress bar detection. 2025-08-23 12:16:10 -04:00
Storm Dragon e255651c28 Merged testing. 2025-08-22 00:29:02 -04:00
Storm Dragon b3d73102fc Fenrir will now read dots in the middle of or at the beginning of words regardless of punctuation settings. 2025-08-21 23:29:45 -04:00
Storm Dragon 78c1cbbb6b Improved progress bar detection for curl. Experimental flood protection for updates. 2025-08-21 19:59:40 -04:00
Storm Dragon 8c26d93001 Progress bar monitoring updates. Hopefully fixed some false positives, and updated claude-code progress monitoring. 2025-08-20 14:33:22 -04:00
Storm Dragon 98b9c56af7 Read all code added. It's definiately a work in progress and does not function currently. 2025-08-04 14:41:14 -04:00
Storm Dragon 8bada48a09 Fixed errors in README. Moved the audio configuration script stuff nearer the top. 2025-08-04 14:36:43 -04:00
Storm Dragon 0a2c8472c0 Fixed errors in README. Moved the audio configuration script stuff nearer the top. 2025-08-04 14:36:06 -04:00
Storm Dragon e9a0101fe7 Merged README.md 2025-08-04 14:26:55 -04:00
Storm Dragon 69eade3327 Updated documentation for stand-alone pipewire or pulse configuration scripts. 2025-08-04 14:24:41 -04:00
Storm Dragon 73f67c2a04 Multiple fixes to indentation beep code, including volume for lower ranged beeps using the gstreamer driver. 2025-08-04 12:38:14 -04:00
Storm Dragon 9ef9d762f4 A few emoji updates. 2025-07-31 03:16:02 -04:00
Storm Dragon 84293db6dc Another shot at fixing multiple numpads. 2025-07-25 14:17:17 -04:00
Storm Dragon 914535d12b A few bug fixes, better checking in place to make sure syntax and other errors do not make it to commits. 2025-07-24 18:34:12 -04:00
Storm Dragon 94a1acbaca A few improvements to validation. 2025-07-24 14:05:51 -04:00
Storm Dragon 8c233e0385 Some syntax errors fixed. Syntax checking added. Release checklist created. 2025-07-24 13:52:10 -04:00
Storm Dragon b6a9e1a692 Hopefully fixed problems with connection external numpads. 2025-07-23 00:01:46 -04:00
Storm Dragon d41ea8388f Fixed url exclusion detection for progress bars. 2025-07-21 06:58:49 -04:00
Storm Dragon 2dd732dc9d Emojis added, improvements to pyt mode. 2025-07-19 16:50:53 -04:00
Storm Dragon b68a28e857 Added more emojis. 2025-07-17 11:11:35 -04:00
Storm Dragon 8c668cc0cc Final batch of pty driver fixes... For now. 2025-07-16 19:48:48 -04:00
Storm Dragon 579bf0f0f0 More work on the pty driver. 2025-07-16 19:43:07 -04:00
Storm Dragon d1bad818cd initial improvements to pty driver. Improved clipboard handling of multibyte characters. Added emoji menu to vmenu. It places the emoji to the clipboard to be used wherever. 2025-07-16 19:35:26 -04:00
Storm Dragon e177c7f486 Final merge for version 2025.07.16. If no problems will tag later today. 2025-07-16 12:33:21 -04:00
Storm Dragon ae4c418323 A few minor progress bar beep tweaks. 2025-07-15 23:13:40 -04:00
Storm Dragon b9abf02b12 A few minor tweaks in preparation for release. 2025-07-13 15:31:57 -04:00
Storm Dragon 0c116adaf2 Progress bar detection updates. 2025-07-13 11:18:51 -04:00
Storm Dragon fe5e2c065e Merge branch 'testing' moving closer to tagged release. 2025-07-09 18:32:15 -04:00
Storm Dragon 5a14804d11 Updates to documentation. A few tidying up changes. 2025-07-09 18:31:58 -04:00
Storm Dragon ef3ebee10c Preparing for new tagged version. Please watch for bugs. 2025-07-09 09:33:19 -04:00
Storm Dragon 6876995d4c New punctuation setting added. 2025-07-09 09:30:45 -04:00
Storm Dragon 01f4b64390 Replace skipped punctuation with space. There's a setting in general, on by default, that will revert to old behavior if you replace it with false. 2025-07-09 01:17:36 -04:00
Storm Dragon 5e858cfde1 Expirmental improvements to highlight tracking. 2025-07-09 01:06:54 -04:00
Storm Dragon 2ad754a372 Some fixes to pep8 stuff. 2025-07-08 18:35:12 -04:00
Storm Dragon 271c4fc18f Table mode fixes and improvements to application detection. 2025-07-08 14:41:43 -04:00
Storm Dragon bb6dbc7186 Fixed character navigation in table mode. 2025-07-07 22:58:14 -04:00
Storm Dragon c7cc9d039b Improved application detection, now works inside screen and tmux. Fixed incosistancies in prev/next word navigation. 2025-07-07 11:17:12 -04:00
Storm Dragon d1a42835e4 Initial table mode added. Probably bugs. 2025-07-07 09:46:12 -04:00
Storm Dragon 3390c25dfe More pep8 fixes. A tiny bit of refactoring. 2025-07-07 00:42:23 -04:00
Storm Dragon ea56b90b48 Oops, getting used to this pep8 thing myself. Fixed codeName to code_name. 2025-07-06 18:51:43 -04:00
Storm Dragon 1268d989b7 Merge after mostly converting to pep8 compliance. 2025-07-06 18:34:28 -04:00
Storm Dragon d28c18faed Found and sniped a couple more pep8 migration errors. 2025-07-05 09:29:32 -04:00
Storm Dragon c90c726899 Fixed a bug in the remote manager. 2025-07-05 09:15:40 -04:00
Storm Dragon bab7c1a552 Removed double keybinding from laptop layout. 2025-07-03 16:11:13 -04:00
Storm Dragon 848844aae4 Oops, forgot to delete my traceback notes. 2025-07-03 13:24:23 -04:00
Storm Dragon 4c1bddbbd3 Most of the pep8 changes finished. Be careful, things may be horribly broken. 2025-07-03 13:23:25 -04:00
Storm Dragon 21bb9c6083 Most of the pep8 changes finished. Be careful, things may be horribly broken. 2025-07-03 13:22:00 -04:00
Storm Dragon 7408951152 To make Fenrir easier to approach for new developer, start code migration to be pep8 compliant. 2025-07-01 22:23:50 -04:00
Storm Dragon 23c3ad20a1 More code optmizations. Removed fenrir+pk_plus. The functionality of bringing back speech has been added to the temperary speech interruption key kp_enter. 2025-06-30 22:25:01 -04:00
Storm Dragon 4bcf82178e Updated configure_pipewire script. A bit more code refactor. Preparing to start moving everything over to pep8 compliance. 2025-06-28 22:52:21 -04:00
Storm Dragon beae1866bb Moved restore speech on prompt to existing temp interrupt speech command, Fenrir+kp_plus unbound now. 2025-06-28 01:49:20 -04:00
Storm Dragon 8af1cca879 Latest changes and bug fixes. 2025-06-27 21:18:27 -04:00
Storm Dragon 40b88efa34 Fix up a few errors that sneaked in while updating vmenu code and a couple other things. Logs should be much nicer now. 2025-06-25 10:56:08 -04:00
Storm Dragon b1edc53362 Added missing dependency to requirements.txt. 2025-06-20 12:43:49 -04:00
Storm Dragon dda84b9905 Final batch of code stability updates before anouther bout of extended testing. Still plenty to go, but making progress. 2025-06-20 03:34:50 -04:00
Storm Dragon 64e79f6945 Code cleanup, make sure race conditions can't happen, at least in theory. 2025-06-20 03:10:07 -04:00
Storm Dragon f4ed8da4c3 Forgot one in last commit. 2025-06-20 03:04:25 -04:00
Storm Dragon a5ca1d28e8 Make sure all except statements are no longer empty, should help a lot with debugging. 2025-06-20 03:03:43 -04:00
Storm Dragon a394ea0222 Code cleanup and bug fixes. 2025-06-20 02:19:57 -04:00
Storm Dragon 4e193f133f Fixed an error that crept into log permissions during code restructuring. 2025-06-20 02:19:07 -04:00
Storm Dragon 27dcff23bb Code optimization and bug fixes. Removed the broken, partial atspi driver implementation. 2025-06-18 15:08:36 -04:00
Storm Dragon efb308ac72 latest testing code merged. Nothing major reported from testing branch, so if we get no reports, this will become the next stable release. I'm waiting a bit to tag because major new features introduced. 2025-06-17 00:53:28 -04:00
Storm Dragon d81d563bb6 Add page up and page down to move through the voice browser by 10%. 2025-06-16 01:08:05 -04:00
Storm Dragon 43871cea3c Fixes to the voice driver. It should actually work completely now. 2025-06-15 19:52:18 -04:00
Storm Dragon 72bd334d65 Very experimental attempt to move the configure_fenrir script into fenrir itself using the vmenu system. Lots of testing please. 2025-06-15 14:04:14 -04:00
Storm Dragon f6be6c54fb Bug fixes mostlry, tested and seems to be working better. 2025-06-13 23:21:46 -04:00
Storm Dragon e76b914d6e Ignore screen 7 by default in case auto ignore screen doesn't work. 2025-06-12 18:43:12 -04:00
Storm Dragon 83cb330d34 Potential fixes to progress bar. Better handling of punctuation while reading. 2025-06-10 18:10:08 -04:00
Storm Dragon b0ac6e1409 improved documentation for the diff generation. 2025-06-09 16:53:05 -04:00
Storm Dragon 6998706934 Testing fixes for security improvement, thread safety, and memory management. 2025-06-09 14:41:33 -04:00
Storm Dragon 62e1001679 Add keybinding for progress bar monitoring for laptop mode. Fenrir+Shift+P. 2025-06-09 13:11:51 -04:00
Storm Dragon d935ef2e3c The fix for hopefully not reading all spaces broke review by character. Hopefully fix that. 2025-06-09 12:48:02 -04:00
Storm Dragon e2fb28d92f Attempt to fix the bug where fenrir sometimes reads all the spaces in a message. 2025-06-09 02:33:36 -04:00
Storm Dragon 8a223282df Some modifications to progress bar detection, can revert if needed. 2025-06-09 02:19:39 -04:00
Storm Dragon 91c97dd1dd Fixed error in settings file, Time and date need %% instead of just a single %. 2025-06-08 18:04:06 -04:00
Storm Dragon 5cc719a6f3 Commit 2 of 2, code refactor and cleanup. 2025-06-08 14:26:24 -04:00
Storm Dragon ddc1b43304 Commit 1 of 2, code refactor and cleanup. 2025-06-08 13:49:22 -04:00
Storm Dragon 6ad11effc6 Enhanced prompt detection 2025-06-08 13:31:37 -04:00
649 changed files with 41640 additions and 12270 deletions
+128
View File
@@ -0,0 +1,128 @@
## Development Philosophy
**Clean code over backward compatibility.** Breaking changes are acceptable in major versions.
- PEP8 compliance (snake_case for all variables/functions/settings)
- Remove deprecated code completely - no compatibility hacks
- Trust users to update configs when upgrading
**Exception**: Never break core accessibility (speech output, basic navigation).
## Core Architecture
### Drivers
- **Screen**: `vcsaDriver` (TTY), `ptyDriver` (terminal emulation)
- **Input**: `evdevDriver` (evdev), `x11Driver` (X11 terminal mode)
- **Speech**: `speechdDriver` (speech-dispatcher), `genericDriver` (subprocess)
- **Sound**: `gstreamerDriver` (GStreamer), `genericDriver` (Sox subprocess)
- **Remote**: `unixDriver` (Unix sockets), `tcpDriver`
### Command System
Commands in trigger folders execute automatically:
- `onKeyInput/`, `onCursorChange/`, `onScreenUpdate/`, `onScreenChanged/`, `onHeartBeat/`
- Numeric prefixes control priority (lower = higher priority): `15000-char_echo.py`
- Manual commands in `commands/commands/`
### Core Managers (in `src/fenrirscreenreader/core/`)
`fenrirManager.py`, `commandManager.py`, `eventManager.py`, `screenManager.py`, `inputManager.py`, `outputManager.py`
### Configuration
- Main: `config/settings/settings.conf`
- Keyboards: `config/keyboard/` (desktop.conf, laptop.conf)
- Sounds: `config/sound/`
- Punctuation: `config/punctuation/`
## 🚨 CRITICAL: Files to NEVER Modify
**These are timing-critical - only fix critical bugs, never refactor:**
- `evdevDriver.py` - Input event processing
- `vcsaDriver.py` - Screen monitoring
Symptoms of breakage: echo changes, input lag, missing screen updates, sync issues.
## Development Commands
```bash
# Run from source (requires root)
cd src/ && sudo ./fenrir -f -d # foreground with debug
# Validation before commit
python3 tools/validate_syntax.py --fix
python3 tools/validate_release.py --quick
# Tests
pytest tests/
pytest tests/ --cov=src/fenrirscreenreader --cov-report=html
```
**Note**: Standard TTY Fenrir blocks - only one instance at a time. `fenrir -x`
can run multiple foreground X terminal instances. Ask user to run tests that
need real Fenrir instances or root access.
## Creating Commands
Use `commands/command_template.py` as base. Required methods:
- `initialize(self, environment)`, `shutdown()`, `run()`, `get_description()`
### Import Pattern (Required)
Fenrir's command loader doesn't support relative imports:
```python
import os, importlib.util
_base_path = os.path.join(os.path.dirname(__file__), 'base_file.py')
_spec = importlib.util.spec_from_file_location("base_module", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
BaseClass = _module.BaseClass
```
### Consolidated Base Classes
- **Bookmarks**: `bookmark_base.py` - `BookmarkCommand(id, 'read'|'set'|'clear')`
- **Adjustments**: `adjustment_base.py` - `AdjustmentCommand('speech'|'sound', 'rate'|'pitch'|'volume', 'inc'|'dec')`
- **VMenu Search**: `vmenu_search_base.py` - `VMenuSearchCommand('a'-'z')`
## VMenu System
Application-specific menus in `vmenu-profiles/KEY/{app}/`:
- Directories = submenus, `.py` files = actions
- Activate: `Fenrir+F10`, navigate with arrows, Enter to execute
## Remote Control
Unix socket: `/tmp/fenrirscreenreader-daemon.sock`
TCP: localhost:22447
```bash
echo "command say Hello" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#rate=0.8" | nc localhost 22447
```
In `fenrir -x`, each instance has a private socket:
`/tmp/fenrirscreenreader-<pid>.sock`. One instance may also own the standard
socket. Use `ls`/`list` on the standard socket to discover registered instances
and their socket paths. Untargeted remote commands use a short cross-process
claim lock so only one instance handles the same broadcast command; direct
commands to a private instance socket still run on that instance.
Disable in untrusted environments: `[remote] enable=False`
## Key Implementation Details
- Commands via `command_mod.command()` instantiation
- Bookmark structure: `env['commandBuffer']['bookMarks'][ID][app]['1'/'2']`
- VMenu search: `env['runtime']['vmenuManager'].searchEntry(char)`
## Recent Fixes (Reference)
- Enhanced application detection for screen/tmux sessions
- Table navigation consistency (sound feedback)
- Blank line detection in 22 command files
- Character/space review during navigation
## Safe vs Risky Changes
**Safe**: Commands, VMenu profiles, config handling, sound/speech drivers, docs
**Risky (extra testing)**: Core managers, event processing
**Avoid**: evdevDriver, vcsaDriver, timing-critical code
+388 -106
View File
@@ -1,7 +1,6 @@
# Fenrir
A modern, modular, flexible and fast console screen reader.
It should run on any operating system. If you want to help, or write drivers to make it work on other systems, just let me know.
A modern, modular, flexible and fast console screen reader for Linux.
This software is licensed under the LGPL v3.
**Current maintainer:** Storm Dragon
@@ -9,9 +8,11 @@ This software is licensed under the LGPL v3.
## Key Features
- **Multiple Interface Support**: Works in Linux TTY, and terminal emulators
- **Linux Console Support**: Works as a Linux TTY screen reader, with optional X11 terminal mode
- **Flexible Driver System**: Modular architecture with multiple drivers for speech, sound, input, and screen
- **Review Mode**: Navigate and review screen content without moving the edit cursor
- **Table Navigation**: Advanced table mode with column headers, cell-by-cell navigation, and boundary feedback
- **Progress Bar Monitoring**: Automatic detection and audio feedback for progress indicators with ascending tones
- **Multiple Clipboard Support**: Manage multiple clipboard entries
- **Configurable Key Bindings**: Desktop and laptop keyboard layouts
- **Sound Icons**: Audio feedback for various events
@@ -22,12 +23,14 @@ This software is licensed under the LGPL v3.
- **Tutorial Mode**: Built-in help system for learning keyboard shortcuts
## OS Requirements
## Platform Support
- Linux (ptyDriver, vcsaDriver, evdevDriver) - Primary platform with full support
- macOS (ptyDriver) - Limited support
- BSD (ptyDriver) - Limited support
- Windows (ptyDriver) - Limited support
Fenrir is a Linux screen reader. Linux is the only officially supported platform.
**Other platforms (macOS, BSD, Windows):** Pull requests adding support for other operating systems may be accepted provided they do not break Linux functionality. However, no special care will be taken to preserve functionality on secondary platforms. If changes to Fenrir break support on a non-Linux OS, it is the responsibility of third-party contributors to submit fixes.
- Linux TTY (`vcsaDriver`, `evdevDriver`) - Full support
- X11 terminal emulators (`-x`, `ptyDriver`, `x11Driver`) - Supported
## Core Requirements
@@ -47,11 +50,8 @@ This software is licensed under the LGPL v3.
- ReadWrite permission:
- /dev/input
- /dev/uinput
2. **ptyDriver** - Terminal emulation input driver (cross-platform)
- python-pyte
3. **atspiDriver** - AT-SPI input driver for desktop environments
- python-pyatspi2
2. **x11Driver** - X11 terminal-scoped input driver for `fenrir -x`
- python-xlib
### Remote Drivers:
1. **unixDriver** - Unix socket remote control (default)
- socat (for command-line interaction)
@@ -68,7 +68,7 @@ This software is licensed under the LGPL v3.
- /dev/tty[1-64]
- /dev/vcsa[1-64]
- read logind DBUS
2. **ptyDriver** - Terminal emulation driver (cross-platform)
2. **ptyDriver** - Terminal emulation screen driver for `fenrir -x`
- python-pyte
@@ -79,7 +79,18 @@ This software is licensed under the LGPL v3.
- python-speechd
2. **genericDriver** - Generic subprocess speech driver
- espeak or espeak-ng (or any TTS command)
3. **debugDriver** - Debug speech driver for testing
3. **dectalkDriver** - Serial DECtalk-compatible hardware speech driver
- RPITalk gadget mode or a DECtalk-compatible serial device
4. **dectalkUsbDriver** - Native Access Solutions DECtalk USB driver
- USB ID `0dd0:2001`
- PyUSB and a libusb backend
5. **litetalkDriver** - Serial LiteTalk-compatible hardware speech driver
- RPITalk gadget mode or a LiteTalk-compatible serial device
6. **doubletalkDriver** - Serial DoubleTalk LT-compatible hardware speech driver
- DoubleTalk LT; does not support the internal DoubleTalk PC card
7. **tripletalkDriver** - Serial TripleTalk-compatible hardware speech driver
- External DB9 serial TripleTalk devices, or USB models that expose a tty serial device
8. **debugDriver** - Debug speech driver for testing
- No dependencies
@@ -123,14 +134,76 @@ Requires root privileges
sudo ./fenrir
Settings are located in:
- **After installation**: `/etc/fenrir/settings/settings.conf`
- **System-wide installation**: `/etc/fenrirscreenreader/settings/settings.conf`
- **User-local settings**: `~/.local/share/stormux/fenrirscreenreader/settings/settings.conf`
- **Development**: `config/settings/settings.conf`
When Fenrir runs as a regular user, including `fenrir -x`, it loads the
user-local settings file if it exists. If it does not exist, Fenrir falls back
to the system settings file, but saving settings writes to the user-local path.
When Fenrir runs as root, settings save to the system-wide path by default.
User sound themes are loaded before system themes from
`~/.local/stormux/fenrir/sounds/`. User scripts are loaded before configured
system scripts from `~/.local/stormux/fenrir/`.
By default Fenrir uses:
- **Sound driver**: genericDriver (via sox)
- **Speech driver**: speechdDriver (via speech-dispatcher)
- **Input driver**: evdevDriver (Linux) or ptyDriver (other platforms)
- **Screen driver**: vcsaDriver (Linux TTY) or ptyDriver (terminal emulation)
- **Input driver**: evdevDriver for Linux TTY, x11Driver for `fenrir -x`
- **Screen driver**: vcsaDriver for Linux TTY, ptyDriver for `fenrir -x`
## Audio Configuration
Both PulseAudio and PipeWire require special configuration to allow console applications running as root (like Fenrir) to route audio to your regular user session. This is normal audio system behavior, not a Fenrir issue.
### Quick Setup - Direct Script Download
For non-Fenrir users or quick setup, download and run these scripts directly:
#### PulseAudio Configuration
```bash
# Download the script
wget https://git.stormux.org/storm/fenrir/raw/branch/master/tools/configure_pulse.sh
chmod +x configure_pulse.sh
# Run twice: once as user, once as root
./configure_pulse.sh
sudo ./configure_pulse.sh
```
#### PipeWire Configuration
```bash
# Download the script
wget https://git.stormux.org/storm/fenrir/raw/branch/master/tools/configure_pipewire.sh
chmod +x configure_pipewire.sh
# Run twice: once as user, once as root
./configure_pipewire.sh
sudo ./configure_pipewire.sh
```
**Direct links:**
- [configure_pulse.sh](https://git.stormux.org/storm/fenrir/raw/branch/master/tools/configure_pulse.sh)
- [configure_pipewire.sh](https://git.stormux.org/storm/fenrir/raw/branch/master/tools/configure_pipewire.sh)
### Using Installed Scripts
If you have Fenrir installed, the scripts are available at:
**PulseAudio:**
```bash
/usr/share/fenrirscreenreader/tools/configure_pulse.sh
sudo /usr/share/fenrirscreenreader/tools/configure_pulse.sh
```
**PipeWire:**
```bash
/usr/share/fenrirscreenreader/tools/configure_pipewire.sh
sudo /usr/share/fenrirscreenreader/tools/configure_pipewire.sh
```
**Note:** These scripts work for any console application that needs root audio access, not just Fenrir.
## Getting Started
@@ -146,6 +219,7 @@ By default Fenrir uses:
2. **Basic Navigation**:
- **Fenrir Key**: By default `Insert`, `Keypad Insert`, or `Meta/Super` key
- **Tutorial Mode**: `Fenrir + H` to learn all commands interactively
- **Speech History**: `Fenrir + Ctrl + H` to review recent speech
- **Quit Fenrir**: `Fenrir + Q`
3. **Essential Commands**:
@@ -156,6 +230,7 @@ By default Fenrir uses:
- `Keypad 2` - Read current character
- `Fenrir + T` - Announce time
- `Fenrir + S` - Spell check current word
- `Fenrir + Keypad *` - Toggle table mode / highlight tracking
### Keyboard Layouts
@@ -164,10 +239,11 @@ Fenrir supports two main keyboard layouts:
- **Desktop Layout**: Uses numeric keypad for navigation (recommended for desktop users)
- **Laptop Layout**: Alternative bindings for keyboards without numeric keypad
Configure in `/etc/fenrir/settings/settings.conf`:
Configure in `/etc/fenrirscreenreader/settings/settings.conf` or your
user-local settings file:
```ini
[keyboard]
keyboardLayout=desktop # or 'laptop'
keyboard_layout=desktop # or 'laptop'
```
### First Time Setup
@@ -193,22 +269,24 @@ Fenrir includes a powerful remote control system that allows external applicatio
### Configuration
Enable remote control in `/etc/fenrir/settings/settings.conf`:
Enable remote control in `/etc/fenrirscreenreader/settings/settings.conf` or
your user-local settings file:
```ini
[remote]
enable=True
driver=unixDriver # or tcpDriver
port=22447 # for TCP driver
socketFile= # custom socket path (optional)
enableSettingsRemote=True # allow settings changes
enableCommandRemote=True # allow command execution
socket_file= # custom socket path (optional)
enable_settings_remote=True # allow settings changes
enable_command_remote=True # allow command execution
```
### Remote Drivers
1. **unixDriver** (recommended): Uses Unix domain sockets
- Socket location: `/tmp/fenrirscreenreader-deamon.sock` (TTY mode) or `/tmp/fenrirscreenreader-<pid>.sock`
- Socket location: `/tmp/fenrirscreenreader-daemon.sock` for the standard control socket
- `fenrir -x` instances also create private sockets: `/tmp/fenrirscreenreader-<pid>.sock`
- More secure, local-only access
- Works with `socat`
@@ -221,89 +299,105 @@ enableCommandRemote=True # allow command execution
The `socat` command provides the easiest way to send commands to Fenrir:
#### Instance Discovery
```bash
# List registered Fenrir instances and their socket paths
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
In X terminal mode (`fenrir -x`), multiple Fenrir instances can run at the same
time. Each instance has a private socket, and one instance may also own the
standard control socket. Use `ls` or `command ls` on the standard socket to find
the private socket for a specific instance. Commands sent to the standard socket
are handled by its owner when possible; otherwise they are forwarded to a
registered private socket, preferring the sender's Fenrir ancestor when one can
be found. Untargeted commands sent through a shared or broadcast path are
claimed by one instance so duplicate instances do not all perform the same
action.
#### Basic Speech Control
```bash
# Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Speak custom text
echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Temporarily disable speech (until next keystroke)
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
#### Settings Control
```bash
# Enable highlight tracking mode
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change speech parameters
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change punctuation level (none/some/most/all)
echo "setting set general#punctuationLevel=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set general#punctuationLevel=none" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set general#punctuation_level=none" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Voice and TTS engine control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#module=espeak-ng" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#module=espeak-ng" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Disable sound temporarily
echo "setting set sound#enabled=False" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set sound#volume=0.5" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set sound#enabled=False" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set sound#volume=0.5" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Keyboard and input settings
echo "setting set keyboard#charEchoMode=1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set keyboard#wordEcho=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set keyboard#char_echo_mode=1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set keyboard#word_echo=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Screen control (ignore specific TTYs)
echo "setting set screen#ignoreScreen=1,2,3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set screen#ignore_screen=1,2,3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuationLevel=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset all settings to defaults
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Save current settings
echo "setting save" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting saveas /tmp/my-fenrir-settings.conf" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting save" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting saveas /tmp/my-fenrir-settings.conf" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
#### Clipboard Operations
```bash
# Place text into clipboard
echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
#### Window Management
```bash
# Define a window area (x1 y1 x2 y2)
echo "command window 0 0 80 24" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command window 0 0 80 24" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset window to full screen
echo "command resetwindow" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command resetwindow" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
#### VMenu Control
```bash
# Set virtual menu context
echo "command vmenu nano/file" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command vmenu nano/file" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset virtual menu
echo "command resetvmenu" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command resetvmenu" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
#### Application Control
```bash
# Quit Fenrir
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
### Using TCP Driver
@@ -348,6 +442,9 @@ setting <action> [parameters]
**Application Commands:**
- `command quitapplication` - Quit Fenrir
**Instance Commands:**
- `ls` / `list` / `command ls` / `command list` - List registered Fenrir instances and their socket paths
#### Available Settings
**Settings Commands:**
@@ -365,8 +462,23 @@ setting <action> [parameters]
- `speech#volume=0.1-1.0` - Speech volume
- `speech#voice=voice_name` - Voice selection (e.g., "en-us+f3")
- `speech#module=module_name` - TTS module (e.g., "espeak-ng")
- `speech#driver=driver_name` - Speech driver (speechdDriver/genericDriver)
- `speech#autoReadIncoming=True/False` - Auto-read new text
- `speech#driver=driver_name` - Speech driver (speechdDriver/genericDriver/dectalkDriver/dectalkUsbDriver/litetalkDriver/doubletalkDriver/tripletalkDriver)
- `speech#hardware_device=/dev/ttyS0` - Hardware synth serial device for dectalkDriver/litetalkDriver
- `speech#hardware_baud_rate=9600` - Hardware synth serial baud rate
- `speech#history_size=50` - Number of spoken items kept in runtime speech history
The native Access Solutions DECtalk USB, USB ID `0dd0:2001`, uses
`dectalkUsbDriver`. It is autodetected and does not use
`speech#hardware_device` or `speech#hardware_baud_rate`. Install PyUSB and a
libusb backend first. From a source checkout, use
`python3 -m pip install '.[dectalk_usb]'`; distributions may package PyUSB as
`python3-usb` or `python-pyusb`. Root-run Fenrir can access the device directly.
A non-root Fenrir process needs a local udev rule granting its account
read/write access to `0dd0:2001`; do not make the device world-writable. Other
USB hardware synths are supported only when Linux exposes them as a serial tty
such as `/dev/ttyACM0` or `/dev/ttyUSB0`. Use an explicit
`speech#hardware_device` path for serial hardware speech.
- `speech#auto_read_incoming=True/False` - Auto-read new text
*Sound Settings:*
- `sound#enabled=True/False` - Enable/disable sound
@@ -375,32 +487,206 @@ setting <action> [parameters]
- `sound#theme=theme_name` - Sound theme
*General Settings:*
- `general#punctuationLevel=none/some/most/all` - Punctuation verbosity
- `general#debugLevel=0-3` - Debug level
- `general#punctuation_level=none/some/most/all` - Punctuation verbosity
- `general#debug_level=0-3` - Debug level
- `general#emoticons=True/False` - Enable emoticon replacement
- `general#autoSpellCheck=True/False` - Automatic spell checking
- `general#auto_spell_check=True/False` - Automatic spell checking
*Focus Settings:*
- `focus#cursor=True/False` - Follow text cursor
- `focus#highlight=True/False` - Follow text highlighting
*Keyboard Settings:*
- `keyboard#charEchoMode=0-2` - Character echo (0=none, 1=always, 2=capslock only)
- `keyboard#wordEcho=True/False` - Echo complete words
- `keyboard#charDeleteEcho=True/False` - Echo deleted characters
- `keyboard#interruptOnKeyPress=True/False` - Interrupt speech on key press
- `keyboard#char_echo_mode=0-2` - Character echo (0=none, 1=always, 2=capslock only)
- `keyboard#word_echo=True/False` - Echo complete words
- `keyboard#char_delete_echo=True/False` - Echo deleted characters
- `keyboard#interrupt_on_key_press=True/False` - Interrupt speech on key press
*Screen Settings:*
- `screen#ignoreScreen=1,2,3` - TTY screens to ignore
- `screen#autodetectIgnoreScreen=True/False` - Auto-detect screens to ignore
- `screen#screenUpdateDelay=float` - Screen update delay
- `screen#ignore_screen=1,2,3` - TTY screens to ignore
- `screen#autodetect_ignore_screen=True/False` - Auto-detect screens to ignore
- `screen#screen_update_delay=float` - Screen update delay
*Time Settings:*
- `time#enabled=True/False` - Enable time announcements
- `time#presentTime=True/False` - Announce time
- `time#presentDate=True/False` - Announce date changes
- `time#delaySec=seconds` - Announcement interval
- `time#onMinutes=00,30` - Specific minutes to announce
- `time#present_time=True/False` - Announce time
- `time#present_date=True/False` - Announce date changes
- `time#delay_sec=seconds` - Announcement interval
- `time#on_minutes=00,30` - Specific minutes to announce
## Table Navigation
Fenrir includes advanced table navigation capabilities for working with tabular data in terminal applications, CSV files, and formatted text output.
### Entering Table Mode
Table mode is activated through the **toggle_highlight_tracking** command, which cycles through three focus modes:
1. **Highlight tracking mode** (default) - Follows text highlighting
2. **Cursor tracking mode** - Follows text cursor movement
3. **Table mode** - Enables table navigation
**Key bindings:**
- **Desktop layout**: `Fenrir + Keypad *` (asterisk)
- **Laptop layout**: `Fenrir + Y`
Press the key combination repeatedly to cycle through modes until you hear "table mode enabled".
### Table Navigation Commands
#### Column Navigation (Desktop Layout)
- **Next column**: `Keypad 6` - Move to next table column
- **Previous column**: `Keypad 4` - Move to previous table column
- **First column**: `Fenrir + Keypad 4` - Jump to first column of current row
- **Last column**: `Fenrir + Keypad 6` - Jump to last column of current row
#### Column Navigation (Laptop Layout)
- **Next column**: `Fenrir + L` - Move to next table column
- **Previous column**: `Fenrir + J` - Move to previous table column
- **First column**: `Fenrir + Shift + J` - Jump to first column of current row
- **Last column**: `Fenrir + Shift + L` - Jump to last column of current row
#### Cell Character Navigation
- **First character in cell**: `Fenrir + Keypad 1` (desktop) or `Fenrir + Ctrl + J` (laptop)
- **Last character in cell**: `Fenrir + Keypad 3` (desktop) or `Fenrir + Ctrl + L` (laptop)
### Setting Column Headers
For better navigation experience, you can set column headers:
1. **Navigate to header row**: Use normal navigation to reach the row containing column headers
2. **Set headers**: Press `Fenrir + X` to mark the current line as the header row
3. **Navigation feedback**: Column headers will be announced along with cell content
### Table Detection
Fenrir automatically detects table structures using multiple strategies:
- **Delimited text**: CSV, pipe-separated (`|`), semicolon-separated (`;`), tab-separated
- **Aligned columns**: Space-aligned columns (2+ spaces between columns)
- **Flexible parsing**: Handles various table formats commonly found in terminal applications
### Table Mode Features
- **Cell-by-cell navigation**: Navigate through table cells with precise positioning
- **Column header support**: Set and announce column headers for better context
- **Boundary feedback**: Audio cues when reaching start/end of rows
- **Empty cell handling**: Blank cells are announced as "blank"
- **Independent tracking**: Table position is maintained independently of cursor movement
### Speech Output in Table Mode
When navigating in table mode, Fenrir announces:
- **Cell content** followed by **column header/name**
- **Boundary notifications**: "end of line", "start of line"
- **Position indicators**: "first character in cell [column name]"
### Example Usage
```bash
# Working with CSV data
cat data.csv
Name,Age,City
Alice,30,New York
Bob,25,Los Angeles
# 1. Press Fenrir + Keypad * until "table mode enabled"
# 2. Navigate to "Name,Age,City" line
# 3. Press Fenrir + X to set headers
# 4. Use Keypad 4/6 to navigate between columns
# 5. Each cell will be announced with its column header
```
## Progress Bar Monitoring
Fenrir provides intelligent progress bar detection and audio feedback for various progress indicators commonly found in terminal applications.
### Enabling Progress Monitoring
**Command**: `progress_bar_monitor` (no default key binding - assign manually)
To enable progress monitoring:
1. Add a key binding in your keyboard layout file
2. Or use the remote control system: `echo "command progress_bar_monitor" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock`
### Progress Detection Patterns
Fenrir automatically detects various progress indicator formats:
#### 1. Percentage Progress
```
Download: 45%
Processing: 67.5%
Installing: 100%
```
#### 2. Fraction Progress
```
Files: 15/100
Progress: 3 of 10
Step 7/15
```
#### 3. Progress Bars
```
[#### ] 40%
[====> ] 50%
[**********] 100%
```
#### 4. Activity Indicators
```
Loading...
Processing...
Working...
Installing...
Downloading...
Compiling...
Building...
```
### Audio Feedback
#### Progress Tones
- **Ascending tones**: 400Hz to 1200Hz frequency range
- **Percentage mapping**: 0% = 400Hz, 100% = 1200Hz
- **Smooth progression**: Frequency increases proportionally with progress
#### Activity Indicators
- **Steady beep**: 800Hz tone every 2 seconds for ongoing activity
- **Non-intrusive**: Beeps don't interrupt speech or other audio
### Progress Monitoring Features
- **Automatic detection**: No manual configuration required
- **Multiple format support**: Handles various progress indicator styles
- **Prompt awareness**: Automatically pauses when command prompts are detected
- **Non-blocking**: Progress tones don't interrupt speech or other functionality
- **Configurable**: Can be enabled/disabled as needed
Fenrir detects stable progress structures rather than application-specific
status formats. Application-specific formats change too frequently to support
reliably.
### Usage Examples
```bash
# Enable progress monitoring
echo "command progress_bar_monitor" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Common scenarios where progress monitoring is useful:
wget https://example.com/large-file.zip # Download progress
tar -xvf archive.tar.gz # Extraction progress
make -j4 # Compilation progress
pacman -S package # Package installation
rsync -av source/ destination/ # File synchronization
```
### Customization
Progress monitoring can be configured through settings:
- **Default enabled**: Set `progress_monitoring=True` in sound section
- **Sound integration**: Works with all sound drivers (sox, gstreamer)
- **Remote control**: Enable/disable through remote commands
### Scripting Examples
@@ -409,7 +695,7 @@ setting <action> [parameters]
#!/bin/bash
# notify_fenrir.sh - Send notifications to Fenrir
SOCKET="/tmp/fenrirscreenreader-deamon.sock"
SOCKET="/tmp/fenrirscreenreader-daemon.sock"
fenrir_say() {
echo "command say $1" | socat - UNIX-CLIENT:$SOCKET
@@ -432,7 +718,7 @@ import os
def send_fenrir_command(command):
"""Send command to Fenrir via Unix socket"""
socket_path = "/tmp/fenrirscreenreader-deamon.sock"
socket_path = "/tmp/fenrirscreenreader-daemon.sock"
if os.path.exists(socket_path):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
@@ -452,8 +738,8 @@ send_fenrir_command("setting set speech#rate=0.9")
- TCP driver binds only to localhost (127.0.0.1)
- Socket file permissions are set to write-only (0o222)
- Commands are processed with Fenrir's privileges
- Settings changes can be disabled via `enableSettingsRemote=False`
- Command execution can be disabled via `enableCommandRemote=False`
- Settings changes can be disabled via `enable_settings_remote=False`
- Command execution can be disabled via `enable_command_remote=False`
### Troubleshooting
@@ -463,34 +749,9 @@ send_fenrir_command("setting set speech#rate=0.9")
- Ensure remote driver is enabled in settings
**Commands not working:**
- Verify `enableCommandRemote=True` in settings
- Check Fenrir debug logs: `/var/log/fenrir.log`
- Test with simple command: `echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock`
## Configure pulseaudio
Pulseaudio by default only plays sound for the user its currently running for. As fenrir is running as root, your local user does not hear the sound and speech produced by fenrir.
for this fenrir provides a script to configure pulseaudio to stream the sound played as root to your local user. This is not a issue of fenrir but this is how pulseaudio works.
just run the configuration script twice (once as user, once as root):
/usr/share/fenrirscreenreader/tools/configure_pulse.sh
sudo /usr/share/fenrirscreenreader/tools/configure_pulse.sh
The script is also located in the tools directory in git
## Configure pipewire
Pipewire by default only plays sound for the user its currently running for. As fenrir is running as root, your local user does not hear the sound and speech produced by fenrir.
for this fenrir provides a script to configure pipewire to stream the sound played as root to your local user. This is not a issue of fenrir but this is how pipewire works.
just run the configuration script twice (once as user, once as root):
/usr/share/fenrirscreenreader/tools/configure_pipewire.sh
sudo /usr/share/fenrirscreenreader/tools/configure_pipewire.sh
The script is also located in the tools directory in git
- Verify `enable_command_remote=True` in settings
- Check Fenrir debug logs: `/tmp/fenrir.log`
- Test with simple command: `echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock`
## Command Line Options
@@ -508,9 +769,9 @@ fenrir [OPTIONS]
- `-o, --options SECTION#SETTING=VALUE;..` - Override settings file options
- `-d, --debug` - Enable debug mode
- `-p, --print` - Print debug messages to screen
- `-e, --emulated-pty` - Use PTY emulation with escape sequences for input (enables desktop/X/Wayland usage)
- `-E, --emulated-evdev` - Use PTY emulation with evdev for input (single instance)
- `-F, --force-all-screens` - Force Fenrir to respond on all screens, ignoring ignoreScreen setting
- `-x, --x11` - Use PTY emulation with X11 keyboard input scoped to the terminal window
- `--x11-window-id WINDOWID` - X11 window id to use for `--x11` terminal mode
- `-F, --force-all-screens` - Force Fenrir to respond on all screens, ignoring ignore_screen setting
- `-i, -I, --ignore-screen SCREEN` - Ignore specific screen(s). Can be used multiple times. Combines with existing ignore settings.
### Examples:
@@ -518,13 +779,16 @@ fenrir [OPTIONS]
# Run in foreground with debug output
sudo fenrir -f -d
# Use PTY emulation for desktop use
sudo fenrir -e
# Use PTY emulation with X11 terminal-scoped keybindings
fenrir -x
# Use X11 mode with an explicit terminal window id
fenrir -x --x11-window-id 0x123456
# Override settings via command line
sudo fenrir -o "speech#rate=0.8;sound#volume=0.5"
# Force Fenrir to work on all screens (ignore ignoreScreen setting)
# Force Fenrir to work on all screens (ignore ignore_screen setting)
sudo fenrir -F
# Ignore specific screens
@@ -532,6 +796,24 @@ sudo fenrir --ignore-screen 1
sudo fenrir -i 1 -i 2 # Ignore screens 1 and 2
```
### X11 Terminal Mode
`fenrir -x` runs Fenrir inside a GUI terminal without root. It uses the PTY screen driver for terminal contents and the X11 input driver for Fenrir keybindings. Unlike evdev mode, it does not listen to the whole desktop; key grabs are scoped to the target terminal window so desktop screen readers can keep their own global bindings outside that terminal.
By default, Fenrir targets the X11 window from `WINDOWID`, falling back to the active X11 window. If a terminal does not set `WINDOWID`, pass the window explicitly with `--x11-window-id`.
X11 terminal mode uses the normal keyboard layout files, including desktop and laptop bindings. It supports Fenrir keys such as numpad Insert/`KEY_KP0`, CapsLock/`KEY_CAPSLOCK`, Insert/`KEY_INSERT`, and Super/Windows/`KEY_META`. Script keys such as Compose use `KEY_COMPOSE`.
In this mode Fenrir runs as a regular user. Settings are loaded from
`~/.local/share/stormux/fenrirscreenreader/settings/settings.conf` when present,
otherwise from `/etc/fenrirscreenreader/settings/settings.conf`; saving settings
creates or updates the user-local file. User sound themes and scripts are read
first from `~/.local/stormux/fenrir/sounds/` and `~/.local/stormux/fenrir/`.
This mode requires `python-xlib`.
For users who want a dedicated PTY/terminal screen reader instead of Fenrir's Linux console focus, see TDSR: https://github.com/tspivey/tdsr
## Localization
Translation files are located in the `locale/` directory. To install translations:
+192
View File
@@ -0,0 +1,192 @@
# Fenrir Release Validation Checklist
This checklist ensures thorough validation before releasing Fenrir packages.
## 🔧 Setup Tools (One-time setup)
### Install Pre-commit Hook
```bash
# Safely install composite hook (preserves existing version management)
./tools/install_validation_hook.sh
# Test the hook
./.git/hooks/pre-commit
```
### Validation Scripts
- `tools/validate_syntax.py` - Python syntax validation
- `tools/validate_pep8.py` - PEP8 compliance checking with safe auto-fix
- `tools/validate_release.py` - Comprehensive release validation
- `tools/cleanup_cache.py` - Remove Python cache files and directories
- `tools/pre-commit-hook` - Git pre-commit validation
## 📋 Pre-Release Checklist
### 1. Code Quality Validation ✅
```bash
# Comprehensive release validation (includes syntax, imports, structure)
python3 tools/validate_release.py
# If issues found, try auto-fix
python3 tools/validate_release.py --fix
# Quick validation (skips slow dependency checks)
python3 tools/validate_release.py --quick
```
**Expected Result**: All tests pass, no syntax errors
### 2. Dependency Validation ✅
```bash
# Validate all dependencies are available
python3 check-dependencies.py
```
**Expected Result**: All required dependencies reported as available
### 3. Core Functionality Test ✅
```bash
# Test core imports (safe to run without sudo)
cd src
python3 -c "
import fenrirscreenreader.core.fenrirManager
import fenrirscreenreader.core.commandManager
import fenrirscreenreader.core.eventManager
print('Core imports successful')
"
cd ..
```
**Expected Result**: No import errors
### 4. Installation Script Validation ✅
```bash
# Validate setup.py syntax
python3 -m py_compile setup.py
# Check setup.py can be parsed
python3 setup.py --help-commands >/dev/null
```
**Expected Result**: No syntax errors, setup.py functional
### 5. Configuration Validation ✅
```bash
# Verify config files exist and are parseable
ls -la config/settings/settings.conf
ls -la config/keyboard/desktop.conf
ls -la config/punctuation/default.conf
```
**Expected Result**: All core config files present
### 6. Manual Testing (User/Package Maintainer) ⚠️
**Important**: These require user interaction as they need sudo access or specific hardware.
```bash
# Test basic functionality (ask user to run)
sudo ./src/fenrir --help
# Test version output
./src/fenrir --version
# Quick console functionality test (3-5 seconds, ask user to run on a TTY)
sudo timeout 5 ./src/fenrir -f || echo "Timeout reached (expected)"
```
**Expected Result**: No immediate crashes, basic help/version output works
### 7. Package-Specific Validation ✅
```bash
# Test the same compilation process used by package managers
python3 -m compileall src/fenrirscreenreader/ -q
# Verify no __pycache__ permission issues
find src/ -name "*.pyc" -delete
find src/ -name "__pycache__" -delete
```
**Expected Result**: Clean compilation, no permission errors
## 🚨 Known Issue Categories
### Critical Issues (Block Release)
- **Python syntax errors** (SyntaxError, unterminated strings)
- **Missing core dependencies** (dbus-python, evdev, etc.)
- **Import failures in core modules** (fenrirManager, commandManager)
- **Missing critical config files** (settings.conf, desktop.conf)
### Warning Issues (Address if Possible)
- **PEP8 violations** (cosmetic, don't block release)
- **Missing optional dependencies** (for specific features)
- **Command structure issues** (missing methods in command files)
- **Very long lines** (>120 characters)
## 🔍 Root Cause Analysis
### Why These Errors Weren't Caught Previously
1. **No automated syntax validation** - The codebase relied on manual testing
2. **No pre-commit hooks** - Syntax errors could be committed
3. **No CI/CD pipeline** - Package compilation happens only during release
4. **Manual PEP8 cleanup** - F-string refactoring introduced syntax errors during batch cleanup
## 📖 Usage Instructions
### For Developers
```bash
# Before committing changes
git add .
git commit # Pre-commit hook will run automatically
# Before creating tags/releases
python3 tools/validate_release.py
```
### For Package Maintainers
```bash
# Before packaging
python3 tools/validate_release.py
# If validation fails
python3 tools/validate_release.py --fix
# Quick check (if dependencies are known good)
python3 tools/validate_release.py --quick
```
### For Release Managers
```bash
# Complete validation before tagging
python3 tools/validate_release.py
# Manual verification (requires sudo)
sudo ./src/fenrir --version
# Tag release only after all validations pass
git tag -a v2.x.x -m "Release v2.x.x"
```
## 🎯 Future Improvements
### Recommended Additions
1. **GitHub Actions CI/CD** - Automated validation on every push
2. **Automated testing** - Unit tests for core functionality
3. **Integration testing** - Test driver interactions
4. **Package testing** - Validate actual package installation
### Modern Python Packaging
- Consider migrating to `pyproject.toml` (PEP 621)
- Use `build` instead of `setup.py` directly
- Add `tox.ini` for multi-environment testing
## 📞 Support
If validation fails and auto-fix doesn't resolve issues:
1. **Check the specific error messages** in validation output
2. **Review recent commits** that might have introduced issues
3. **Run individual validation steps** to isolate problems
Remember: **Working code is better than perfect code** - especially for accessibility software where reliability is critical.
-3
View File
@@ -1,3 +0,0 @@
V2.0
Cleanup folders and config files.
+1 -3
View File
@@ -4,12 +4,10 @@ Wants=systemd-udev-settle.service
After=systemd-udev-settle.service getty.target
[Service]
Type=forking
PIDFile=/var/run/fenrir.pid
PIDFile=/run/fenrir.pid
ExecStart=/usr/bin/fenrir
ExecReload=/usr/bin/kill -HUP $MAINPID
Restart=always
#Group=fenrirscreenreader
#User=fenrirscreenreader
[Install]
WantedBy=getty.target
+1 -1
View File
@@ -4,7 +4,7 @@ Wants=systemd-udev-settle.service
After=systemd-udev-settle.service sound.target
[Service]
Type=forking
PIDFile=/var/run/fenrir.pid
PIDFile=/run/fenrir.pid
ExecStart=/usr/local/bin/fenrir
ExecReload=/usr/bin/kill -HUP $MAINPID
Restart=always
+7 -7
View File
@@ -1,15 +1,15 @@
Please report Bugs and feature requests to:
https://github.com/chrys87/fenrir/issues
Please report bugs and feature requests to:
https://git.stormux.org/storm/fenrir/issues
For bugs, please provide a debug file that shows the issue.
How to create a debug file:
1. first delete old stuff:
sudo rm /var/log/fenrir.log
2. start fenrir in debug mode
1. start fenrir in debug mode
sudo fenrir -d
<do your stuff>
3.
2.
stop fenrir (fenrirKey + q)
the debug file is in /var/log/fenrir.log
the debug file is in /tmp/fenrir.log
if another Fenrir debug instance is already using it, check /tmp/fenrir2.log,
/tmp/fenrir3.log, etc.
please be as precise as possible to make it easy to solve the problem.
+7 -4
View File
@@ -50,7 +50,13 @@ def check_dependency(dep: Dependency) -> bool:
dependencyList = [
# Core dependencies
Dependency('FenrirCore', 'core', 'core',
pythonImports=['daemonize', 'enchant']),
pythonImports=[
'daemonize',
'enchant',
'pyperclip',
'setproctitle',
'xdg'
]),
# Screen drivers
Dependency('DummyScreen', 'screen', 'dummyDriver'),
@@ -65,9 +71,6 @@ dependencyList = [
Dependency('DebugInput', 'input', 'debugDriver'),
Dependency('Evdev', 'input', 'evdevDriver',
pythonImports=['evdev', 'evdev.InputDevice', 'evdev.UInput', 'pyudev']),
Dependency('PTYInput', 'input', 'ptyDriver',
pythonImports=['pyte']),
# Sound drivers
Dependency('DummySound', 'sound', 'dummyDriver'),
Dependency('DebugSound', 'sound', 'debugDriver'),
+46 -1
View File
@@ -1,4 +1,50 @@
# Fenrir Keyboard Configuration
This directory contains keyboard layout files for Fenrir screen reader.
## Available Layouts
- **desktop.conf** - Desktop layout using numeric keypad (recommended)
- **laptop.conf** - Laptop layout for keyboards without numeric keypad
## Key Features
### Table Navigation
- **Toggle table mode**: `Fenrir + Keypad *` (desktop) or `Fenrir + Y` (laptop)
- **Column navigation**: `Keypad 4/6` (desktop) or `Fenrir + J/L` (laptop)
- **Row boundaries**: `Fenrir + Keypad 4/6` (desktop) or `Fenrir + Shift + J/L` (laptop)
- **Set headers**: `Fenrir + X` in table mode
### Progress Bar Monitoring
- **Monitor progress**: `progress_bar_monitor` command (assign key binding manually)
- **Auto-detection**: Percentage, fractions, progress bars, activity indicators
- **Audio feedback**: Ascending tones (400Hz-1200Hz) for progress
### Review Mode
- **Basic navigation**: `Keypad 7/8/9` (lines), `Keypad 4/5/6` (words), `Keypad 1/2/3` (characters)
- **Exit review**: `Fenrir + Keypad .`
- **Screen reading**: `Fenrir + Keypad 5` (current screen)
### Speech History
- **Open speech history**: `Fenrir + Ctrl + H`
- **Navigate history**: `Up` and `Down`
- **Copy current item**: `Enter`
- **Exit speech history**: `Escape`
## Configuration
To change keyboard layout, edit `/etc/fenrirscreenreader/settings/settings.conf`
or your user-local settings file at
`~/.local/share/stormux/fenrirscreenreader/settings/settings.conf`:
```ini
[keyboard]
keyboard_layout=desktop # or laptop
```
## Available Key Constants
Keymap for Fenrir
KEY_RESERVED
KEY_ESC
@@ -540,4 +586,3 @@ BTN_TRIGGER_HAPPY37
BTN_TRIGGER_HAPPY38
BTN_TRIGGER_HAPPY39
BTN_TRIGGER_HAPPY40
+10 -4
View File
@@ -1,4 +1,5 @@
KEY_FENRIR,KEY_H=toggle_tutorial_mode
KEY_FENRIR,KEY_CTRL,KEY_H=speech_history
KEY_CTRL=shut_up
KEY_FENRIR,KEY_KP9=review_bottom
KEY_FENRIR,KEY_KP7=review_top
@@ -74,7 +75,7 @@ KEY_FENRIR,KEY_0=bookmark_10
KEY_FENRIR,KEY_KPSLASH=set_window_application
2,KEY_FENRIR,KEY_KPSLASH=clear_window_application
KEY_KPPLUS=progress_bar_monitor
KEY_FENRIR,KEY_KPPLUS=silence_until_prompt
#KEY_FENRIR,KEY_KPPLUS=silence_until_prompt
KEY_FENRIR,KEY_F2=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F4=toggle_speech
@@ -83,6 +84,8 @@ KEY_FENRIR,KEY_CTRL,KEY_P=toggle_punctuation_level
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
KEY_FENRIR,KEY_BACKSLASH=toggle_output
KEY_FENRIR,KEY_CTRL,KEY_E=toggle_emoticons
KEY_FENRIR,KEY_CTRL,KEY_D=toggle_diff_mode
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_E=cycle_key_echo
key_FENRIR,KEY_KPENTER=toggle_auto_read
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
KEY_FENRIR,KEY_KPASTERISK=toggle_highlight_tracking
@@ -114,6 +117,8 @@ KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_X=remove_marks
KEY_FENRIR,KEY_X=set_mark
KEY_FENRIR,KEY_SHIFT,KEY_X=marked_text
KEY_FENRIR,KEY_F10=toggle_vmenu_mode
KEY_FENRIR,KEY_SHIFT,KEY_F10=voice_browser_safe
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_F10=apply_tested_voice
KEY_FENRIR,KEY_SPACE=current_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value
KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry
@@ -124,7 +129,8 @@ KEY_FENRIR,KEY_CTRL,KEY_S=save_settings
# linux specific
KEY_FENRIR,KEY_F7=import_clipboard_from_x
KEY_FENRIR,KEY_F8=export_clipboard_to_x
KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume
KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume
# Read-all functionality
KEY_FENRIR,KEY_CTRL,KEY_DOWN=read_all_by_line
KEY_FENRIR,KEY_CTRL,KEY_PAGEDOWN=read_all_by_page
KEY_FENRIR,KEY_SHIFT,KEY_V=announce_fenrir_version
KEY_F4=cycle_keyboard_layout
KEY_FENRIR,KEY_LEFTCTRL,KEY_F4=cycle_keyboard_layout
+11 -5
View File
@@ -1,4 +1,5 @@
KEY_FENRIR,KEY_H=toggle_tutorial_mode
KEY_FENRIR,KEY_CTRL,KEY_H=speech_history
KEY_CTRL=shut_up
KEY_FENRIR,KEY_SHIFT,KEY_O=review_bottom
KEY_FENRIR,KEY_SHIFT,KEY_U=review_top
@@ -75,12 +76,14 @@ KEY_FENRIR,KEY_F2=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F4=toggle_speech
KEY_FENRIR,KEY_ENTER=temp_disable_speech
KEY_FENRIR,KEY_SHIFT,KEY_ENTER=silence_until_prompt
KEY_FENRIR,KEY_SHIFT,KEY_P=progress_bar_monitor
KEY_FENRIR,KEY_SHIFT,KEY_ENTER=toggle_auto_read
KEY_FENRIR,KEY_SHIFT,KEY_CTRL,KEY_P=toggle_punctuation_level
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_ENTER=toggle_output
KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons
KEY_FENRIR,KEY_ENTER=toggle_auto_read
KEY_FENRIR,KEY_CTRL,KEY_D=toggle_diff_mode
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_E=cycle_key_echo
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
KEY_FENRIR,KEY_Y=toggle_highlight_tracking
#=toggle_barrier
@@ -112,6 +115,8 @@ KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_X=remove_marks
KEY_FENRIR,KEY_X=set_mark
KEY_FENRIR,KEY_SHIFT,KEY_X=marked_text
KEY_FENRIR,KEY_F10=toggle_vmenu_mode
KEY_FENRIR,KEY_SHIFT,KEY_F10=voice_browser_safe
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_F10=apply_tested_voice
KEY_FENRIR,KEY_SPACE=current_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value
KEY_FENRIR,KEY_RIGHT=next_quick_menu_entry
@@ -124,7 +129,8 @@ KEY_FENRIR,KEY_CTRL,KEY_S=save_settings
# linux specific
KEY_FENRIR,KEY_F7=import_clipboard_from_x
KEY_FENRIR,KEY_F8=export_clipboard_to_x
KEY_FENRIR,KEY_CTRL,KEY_UP=inc_alsa_volume
KEY_FENRIR,KEY_CTRL,KEY_DOWN=dec_alsa_volume
# Read-all functionality
KEY_FENRIR,KEY_CTRL,KEY_DOWN=read_all_by_line
KEY_FENRIR,KEY_CTRL,KEY_PAGEDOWN=read_all_by_page
KEY_FENRIR,KEY_SHIFT,KEY_V=announce_fenrir_version
KEY_F4=cycle_keyboard_layout
KEY_FENRIR,KEY_LEFTCTRL,KEY_F4=cycle_keyboard_layout
-130
View File
@@ -1,130 +0,0 @@
KEY_FENRIR,KEY_F1=toggle_tutorial_mode
KEY_FENRIR,KEY_H=toggle_tutorial_mode
KEY_CTRL=shut_up
KEY_SHIFT,KEY_KP9=review_bottom
KEY_SHIFT,KEY_KP7=review_top
KEY_KP8=review_curr_line
KEY_KP7=review_prev_line
KEY_KP9=review_next_line
KEY_SHIFT,KEY_KP1=review_line_begin
KEY_SHIFT,KEY_KP3=review_line_end
KEY_FENRIR,KEY_KP1=review_line_first_char
KEY_FENRIR,KEY_KP3=review_line_last_char
KEY_FENRIR,KEY_ALT,KEY_1=present_first_line
KEY_FENRIR,KEY_ALT,KEY_2=present_last_line
KEY_KP5=review_curr_word
KEY_KP4=review_prev_word
KEY_KP6=review_next_word
2,KEY_KP5=review_curr_word_phonetic
2,KEY_KP4=review_prev_word_phonetic
2,KEY_KP6=review_next_word_phonetic
KEY_KP2=review_curr_char
KEY_KP1=review_prev_char
KEY_KP3=review_next_char
2,KEY_KP2=review_curr_char_phonetic
2,KEY_KP1=review_prev_char_phonetic
2,KEY_KP3=review_next_char_phonetic
KEY_FENRIR,KEY_CTRL,KEY_KP8=review_up
KEY_FENRIR,KEY_CTRL,KEY_KP2=review_down
KEY_FENRIR,KEY_KPDOT=exit_review
KEY_KPDOT=cursor_position
KEY_FENRIR,KEY_I=indent_curr_line
KEY_FENRIR,KEY_B=curr_screen
KEY_FENRIR,KEY_KP8=curr_screen_before_cursor
KEY_FENRIR,KEY_KP2=curr_screen_after_cursor
KEY_FENRIR,KEY_SHIFT,KEY_PAGEDOWN=cursor_read_to_end_of_line
#=cursor_column
#=cursor_lineno
#=braille_flush
KEY_FENRIR,KEY_CTRL,KEY_T=braille_return_to_cursor
#=braille_pan_left
#=braille_pan_right
KEY_FENRIR,KEY_CTRL,KEY_1=clear_bookmark_1
KEY_FENRIR,KEY_SHIFT,KEY_1=set_bookmark_1
KEY_FENRIR,KEY_1=bookmark_1
KEY_FENRIR,KEY_K=bookmark_1
KEY_FENRIR,KEY_CTRL,KEY_2=clear_bookmark_2
KEY_FENRIR,KEY_SHIFT,KEY_2=set_bookmark_2
KEY_FENRIR,KEY_2=bookmark_2
KEY_FENRIR,KEY_CTRL,KEY_3=clear_bookmark_3
KEY_FENRIR,KEY_SHIFT,KEY_3=set_bookmark_3
KEY_FENRIR,KEY_3=bookmark_3
KEY_FENRIR,KEY_CTRL,KEY_4=clear_bookmark_4
KEY_FENRIR,KEY_SHIFT,KEY_4=set_bookmark_4
KEY_FENRIR,KEY_4=bookmark_4
KEY_FENRIR,KEY_CTRL,KEY_5=clear_bookmark_5
KEY_FENRIR,KEY_SHIFT,KEY_5=set_bookmark_5
KEY_FENRIR,KEY_5=bookmark_5
KEY_FENRIR,KEY_CTRL,KEY_6=clear_bookmark_6
KEY_FENRIR,KEY_SHIFT,KEY_6=set_bookmark_6
KEY_FENRIR,KEY_6=bookmark_6
KEY_FENRIR,KEY_CTRL,KEY_7=clear_bookmark_7
KEY_FENRIR,KEY_SHIFT,KEY_7=set_bookmark_7
KEY_FENRIR,KEY_7=bookmark_7
KEY_FENRIR,KEY_CTRL,KEY_8=clear_bookmark_8
KEY_FENRIR,KEY_SHIFT,KEY_8=set_bookmark_8
KEY_FENRIR,KEY_8=bookmark_8
KEY_FENRIR,KEY_CTRL,KEY_9=clear_bookmark_9
KEY_FENRIR,KEY_SHIFT,KEY_9=set_bookmark_9
KEY_FENRIR,KEY_9=bookmark_9
KEY_FENRIR,KEY_CTRL,KEY_0=clear_bookmark_10
KEY_FENRIR,KEY_SHIFT,KEY_0=set_bookmark_10
KEY_FENRIR,KEY_0=bookmark_10
KEY_FENRIR,KEY_KPSLASH=set_window_application
2,KEY_FENRIR,KEY_KPSLASH=clear_window_application
KEY_KPPLUS=progress_bar_monitor
KEY_FENRIR,KEY_KPPLUS=silence_until_prompt
#=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F4=toggle_speech
KEY_KPENTER=temp_disable_speech
KEY_FENRIR,KEY_P=toggle_punctuation_level
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
KEY_FENRIR,KEY_S=toggle_output
KEY_FENRIR,KEY_CTRL,KEY_E=toggle_emoticons
key_FENRIR,KEY_5=toggle_auto_read
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
KEY_FENRIR,KEY_KPASTERISK=toggle_highlight_tracking
KEY_FENRIR,KEY_KPMINUS=toggle_barrier
KEY_FENRIR,KEY_Q=quit_fenrir
KEY_FENRIR,KEY_T=time
KEY_FENRIR,KEY_F12=time
2,KEY_FENRIR,KEY_T=date
2,KEY_FENRIR,KEY_F12=date
KEY_KPSLASH=toggle_auto_indent
KEY_FENRIR,KEY_F=attribute_cursor
#=toggle_has_attribute
KEY_FENRIR,KEY_F7=spell_check
2,KEY_FENRIR,KEY_S=add_word_to_spell_check
KEY_FENRIR,KEY_SHIFT,KEY_S=remove_word_from_spell_check
KEY_FENRIR,KEY_F2=forward_keypress
KEY_FENRIR,KEY_ALT,KEY_UP=inc_sound_volume
KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_sound_volume
#=clear_clipboard
KEY_FENRIR,KEY_HOME=first_clipboard
KEY_FENRIR,KEY_END=last_clipboard
KEY_FENRIR,KEY_PAGEUP=prev_clipboard
KEY_FENRIR,KEY_PAGEDOWN=next_clipboard
KEY_FENRIR,KEY_SHIFT,KEY_C=curr_clipboard
KEY_FENRIR,KEY_C=copy_marked_to_clipboard
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_C=copy_last_echo_to_clipboard
KEY_FENRIR,KEY_V=paste_clipboard
KEY_FENRIR,KEY_F5=import_clipboard_from_file
KEY_FENRIR,KEY_F6=export_clipboard_to_file
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_X=remove_marks
KEY_FENRIR,KEY_F9=set_mark
KEY_FENRIR,KEY_F10=marked_text
KEY_FENRIR,KEY_F10=toggle_vmenu_mode
KEY_FENRIR,KEY_SPACE=current_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value
KEY_FENRIR,KEY_CTRL,KEY_RIGHT=next_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_UP=next_quick_menu_value
KEY_FENRIR,KEY_CTRL,KEY_LEFT=prev_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_DOWN=prev_quick_menu_value
KEY_FENRIR,KEY_CTRL,KEY_C=save_settings
# linux specific
#=import_clipboard_from_x
KEY_FENRIR,KEY_F8=export_clipboard_to_x
KEY_FENRIR,KEY_ALT,KEY_UP=inc_alsa_volume
KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_alsa_volume
KEY_F4=cycle_keyboard_layout
-129
View File
@@ -1,129 +0,0 @@
KEY_FENRIR,KEY_F1=toggle_tutorial_mode
KEY_FENRIR,KEY_H=toggle_tutorial_mode
KEY_CTRL=shut_up
KEY_FENRIR,KEY_CTRL,KEY_END=review_bottom
KEY_FENRIR,KEY_CTRL,KEY_HOME=review_top
KEY_FENRIR,KEY_SHIFT,KEY_DOT=review_curr_line
KEY_FENRIR,KEY_U=review_prev_line
KEY_FENRIR,KEY_O=review_next_line
KEY_FENRIR,KEY_HOME=review_line_begin
KEY_FENRIR,KEY_END=review_line_end
KEY_FENRIR,KEY_CTRL,KEY_J=review_line_first_char
KEY_FENRIR,KEY_CTRL,KEY_L=review_line_last_char
KEY_FENRIR,KEY_ALT,KEY_1=present_first_line
KEY_FENRIR,KEY_ALT,KEY_2=present_last_line
KEY_FENRIR,KEY_CTRL,KEY_DOT=review_curr_word
KEY_FENRIR,KEY_J=review_prev_word
KEY_FENRIR,KEY_L=review_next_word
2,KEY_FENRIR,KEY_CTRL,KEY_DOT=review_curr_word_phonetic
2,KEY_FENRIR,KEY_J=review_prev_word_phonetic
2,KEY_FENRIR,KEY_L=review_next_word_phonetic
KEY_FENRIR,KEY_COMMA=review_curr_char
KEY_FENRIR,KEY_M=review_prev_char
KEY_FENRIR,KEY_DOT=review_next_char
2,KEY_FENRIR,KEY_COMMA=curr_char_phonetic
2,KEY_FENRIR,KEY_M=prev_char_phonetic
2,KEY_FENRIR,KEY_DOT=next_char_phonetic
KEY_FENRIR,KEY_CTRL,KEY_I=review_up
KEY_FENRIR,KEY_CTRL,KEY_COMMA=review_down
KEY_FENRIR,KEY_SLASH=exit_review
KEY_FENRIR,KEY_SHIFT,KEY_DOT=cursor_position
2,KEY_FENRIR,KEY_I=indent_curr_line
KEY_FENRIR,KEY_B=curr_screen
KEY_FENRIR,KEY_SHIFT,KEY_I=curr_screen_before_cursor
KEY_FENRIR,KEY_SHIFT,KEY_COMMA=curr_screen_after_cursor
KEY_FENRIR,KEY_SHIFT,KEY_PAGEDOWN=cursor_read_to_end_of_line
#=cursor_column
#=cursor_lineno
#=braille_flush
KEY_FENRIR,KEY_CTRL,KEY_T=braille_return_to_cursor
#=braille_pan_left
#=braille_pan_right
KEY_FENRIR,KEY_CTRL,KEY_1=clear_bookmark_1
KEY_FENRIR,KEY_SHIFT,KEY_1=set_bookmark_1
KEY_FENRIR,KEY_1=bookmark_1
KEY_FENRIR,KEY_K=bookmark_1
KEY_FENRIR,KEY_CTRL,KEY_2=clear_bookmark_2
KEY_FENRIR,KEY_SHIFT,KEY_2=set_bookmark_2
KEY_FENRIR,KEY_2=bookmark_2
KEY_FENRIR,KEY_CTRL,KEY_3=clear_bookmark_3
KEY_FENRIR,KEY_SHIFT,KEY_3=set_bookmark_3
KEY_FENRIR,KEY_3=bookmark_3
KEY_FENRIR,KEY_CTRL,KEY_4=clear_bookmark_4
KEY_FENRIR,KEY_SHIFT,KEY_4=set_bookmark_4
KEY_FENRIR,KEY_4=bookmark_4
KEY_FENRIR,KEY_CTRL,KEY_5=clear_bookmark_5
KEY_FENRIR,KEY_SHIFT,KEY_5=set_bookmark_5
KEY_FENRIR,KEY_5=bookmark_5
KEY_FENRIR,KEY_CTRL,KEY_6=clear_bookmark_6
KEY_FENRIR,KEY_SHIFT,KEY_6=set_bookmark_6
KEY_FENRIR,KEY_6=bookmark_6
KEY_FENRIR,KEY_CTRL,KEY_7=clear_bookmark_7
KEY_FENRIR,KEY_SHIFT,KEY_7=set_bookmark_7
KEY_FENRIR,KEY_7=bookmark_7
KEY_FENRIR,KEY_CTRL,KEY_8=clear_bookmark_8
KEY_FENRIR,KEY_SHIFT,KEY_8=set_bookmark_8
KEY_FENRIR,KEY_8=bookmark_8
KEY_FENRIR,KEY_CTRL,KEY_9=clear_bookmark_9
KEY_FENRIR,KEY_SHIFT,KEY_9=set_bookmark_9
KEY_FENRIR,KEY_9=bookmark_9
KEY_FENRIR,KEY_CTRL,KEY_0=clear_bookmark_10
KEY_FENRIR,KEY_SHIFT,KEY_0=set_bookmark_10
KEY_FENRIR,KEY_0=bookmark_10
KEY_FENRIR,KEY_CTRL,KEY_8=set_window_application
2,KEY_FENRIR,KEY_CTRL,KEY_8=clear_window_application
KEY_FENRIR,KEY_SEMICOLON=last_incoming
#=toggle_braille
KEY_FENRIR,KEY_F3=toggle_sound
KEY_FENRIR,KEY_F4=toggle_speech
KEY_FENRIR,KEY_ENTER=temp_disable_speech
KEY_FENRIR,KEY_P=toggle_punctuation_level
KEY_FENRIR,KEY_RIGHTBRACE=toggle_auto_spell_check
KEY_FENRIR,KEY_S=toggle_output
KEY_FENRIR,KEY_SHIFT,KEY_E=toggle_emoticons
KEY_FENRIR,KEY_5=toggle_auto_read
KEY_FENRIR,KEY_CTRL,KEY_T=toggle_auto_time
KEY_FENRIR,KEY_Y=toggle_highlight_tracking
#=toggle_barrier
KEY_FENRIR,KEY_Q=quit_fenrir
KEY_FENRIR,KEY_T=time
KEY_FENRIR,KEY_F12=time
2,KEY_FENRIR,KEY_T=date
2,KEY_FENRIR,KEY_F12=date
KEY_FENRIR,KEY_BACKSLASH=toggle_auto_indent
KEY_FENRIR,KEY_F=attribute_cursor
#=toggle_has_attribute
KEY_FENRIR,KEY_F7=spell_check
2,KEY_FENRIR,KEY_S=add_word_to_spell_check
KEY_FENRIR,KEY_SHIFT,KEY_S=remove_word_from_spell_check
KEY_FENRIR,KEY_F2=forward_keypress
KEY_FENRIR,KEY_ALT,KEY_UP=inc_sound_volume
KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_sound_volume
#=clear_clipboard
#=first_clipboard
#=last_clipboard
KEY_FENRIR,KEY_PAGEUP=prev_clipboard
KEY_FENRIR,KEY_PAGEDOWN=next_clipboard
KEY_FENRIR,KEY_SHIFT,KEY_C=curr_clipboard
KEY_FENRIR,KEY_C=copy_marked_to_clipboard
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_C=copy_last_echo_to_clipboard
KEY_FENRIR,KEY_V=paste_clipboard
KEY_FENRIR,KEY_F5=import_clipboard_from_file
KEY_FENRIR,KEY_F6=export_clipboard_to_file
KEY_FENRIR,KEY_CTRL,KEY_SHIFT,KEY_X=remove_marks
KEY_FENRIR,KEY_F9=set_mark
KEY_FENRIR,KEY_F10=marked_text
KEY_FENRIR,KEY_SHIFT,KEY_F10=toggle_vmenu_mode
KEY_FENRIR,KEY_SPACE=current_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_SPACE=current_quick_menu_value
KEY_FENRIR,KEY_CTRL,KEY_RIGHT=next_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_UP=next_quick_menu_value
KEY_FENRIR,KEY_CTRL,KEY_LEFT=prev_quick_menu_entry
KEY_FENRIR,KEY_CTRL,KEY_DOWN=prev_quick_menu_value
KEY_FENRIR,KEY_CTRL,KEY_C=save_settings
# linux specific
#=import_clipboard_from_x
KEY_FENRIR,KEY_F8=export_clipboard_to_x
KEY_FENRIR,KEY_ALT,KEY_UP=inc_alsa_volume
KEY_FENRIR,KEY_ALT,KEY_DOWN=dec_alsa_volume
KEY_F4=cycle_keyboard_layout
-89
View File
@@ -1,89 +0,0 @@
# This file contains terminal escape sequences as shortcut
# It is used for PTY screen / Input driver (Terminal emulation)
# ^[ is used as escape
# f1 - fenrir help
^[OP=toggle_tutorial_mode
# double tap control+end read attributes
2,^[[1;5F=attribute_cursor
#=toggle_has_attribute
# escape - stop speech
^[=shut_up
# context menu key - stop speech
^[[29~=shut_up
# alt+shift+down - review to bottom
^[[1;4B=review_bottom
# alt+shift_up - review to top
^[[1;4A=review_top
# alt+down - review current line
^[[1;3B=review_curr_line
# alt+left - review previous line
^[[1;3D=review_prev_line
# alt+right - review next line
^[[1;3C=review_next_line
# alt+shift+left - beginning of line
^[[1;4D=review_line_begin
# alt+shift+right - end of line
^[[1;4C=review_line_end
# control+down - review current word
^[[1;5B=review_curr_word
# control+left - review previous word
^[[1;5D=review_prev_word
# control+right - review next word
^[[1;5C=review_next_word
# shift+down - review current character
^[[1;2B=review_curr_char
# shift+left - review previous character
^[[1;2D=review_prev_char
# shift+right - review next character
^[[1;2C=review_next_char
# control+shift+down - current character phonetic
^[[1;6B=curr_char_phonetic
# control+shift+left - previous character phonetic
^[[1;6D=prev_char_phonetic
# control+shift+right - next character phonetic
^[[1;6C=next_char_phonetic
# f2 - toggle sound
^[OQ=toggle_sound
# f3 - toggle highlight tracking
^[OR=toggle_highlight_tracking
alt+f12 - quit fenrir
^[[24;3~=quit_fenrir
# alt+f12 - time
^[[24;3~=time
# 2,alt+f12 - date
2,^[[24;3~=date
# alt+[ - previous clipboard
^[[=prev_clipboard
# alt+] - next clipboard
^[]=next_clipboard
# control+f6 - Read current clipboard
^[[17;5~=curr_clipboard
# f6 - copy to clipboard
^[[17~=copy_marked_to_clipboard
# shift+f6 - clear clipboard
^[[17;2~=clear_clipboard
# f7 - paste clipboard
^[[18~=paste_clipboard
# alt+f8 - export clipboard to X
^[[19;3~=export_clipboard_to_x
# control+f8 - import clipboard from X
^[[19;5~=import_clipboard_from_x
# alt+f9 - export clipboard to file
^[[20;3~=export_clipboard_to_file
# control+f9 - import clipboard from file
^[[20;5~=import_clipboard_from_file
# shift+f5 - remove marks
^[[15;2~=remove_marks
# f5 - set mark
^[[15~=set_mark
# f8 - Last utterance to clipboard
^[[19~=copy_last_echo_to_clipboard
# lat+\ Toggle auto announcement of indentation
^[\=toggle_auto_indent
# alt+end - temperarily disable speech
^[[1;3F=temp_disable_speech
# control+end - toggle auto read
^[[1;5F=toggle_auto_read
# F12 - cycle keyboard layout
^[[24~=cycle_keyboard_layout
-46
View File
@@ -1,46 +0,0 @@
# This file contains terminal escape sequences as shortcut
# It is used for PTY screen / Input driver (Terminal emulation)
# ^[ is used as escape
^[h=toggle_tutorial_mode
^[/=shut_up
^[[D=shut_up
^[O=review_bottom
^[U=review_top
#^[[1;3B=review_curr_line
^[i=review_curr_line
^[u=review_prev_line
^[o=review_next_line
^[J=review_line_begin
^[L=review_line_end
^[j=review_line_first_char
^[L=review_line_last_char
^[k=review_curr_word
^[j=review_prev_word
^[l=review_next_word
^[,=review_curr_char
^[m=review_prev_char
^[.=review_next_char
^[<=curr_char_phonetic
^[M=prev_char_phonetic
^[>=next_char_phonetic
^[OR=toggle_sound
^[OS=toggle_speech
^[8=toggle_highlight_tracking
^[Q=quit_fenrir
^[t=time
^[T=date
^[[5~=prev_clipboard
^[[6~=next_clipboard
^[C=curr_clipboard
^[c=copy_marked_to_clipboard
^[v=paste_clipboard
^[[15~=import_clipboard_from_file
^[X=remove_marks
^[x=set_mark
^[\=toggle_auto_indent
^[B=copy_last_echo_to_clipboard
# alt+f8 - export clipboard to X
# ^[[19;3~=export_clipboard_to_x
# # control+f8 - import clipboard from X
# ^[[19;5~=import_clipboard_from_x
+254 -125
View File
@@ -3,14 +3,14 @@
enabled=True
# Select the driver used to play sounds, choices are genericDriver and gstreamerDriver.
# Sox is the default.
#driver=gstreamerDriver
driver=genericDriver
# Generic driver uses fewer dependencies but spawns a process for each sound played including progress bar beeps
# Gstreamer is the default.
driver=gstreamerDriver
#driver=genericDriver
# Sound themes. These are the pack of sounds used for sound alerts.
# Sound packs may be located at /usr/share/sounds
# For system wide availability, or ~/.local/share/fenrirscreenreader/sounds
# For the current user.
# Sound packs may be located at ~/.local/stormux/fenrir/sounds,
# /usr/share/sounds/fenrir, or /usr/share/sounds/fenrirscreenreader.
theme=default
# Sound volume controls how loud the sounds for your selected soundpack are.
@@ -19,25 +19,32 @@ volume=0.7
# shell commands for generic sound driver
# the folowing variable are substituted
# fenrirVolume = the current volume setting
# fenrirSoundFile = the soundfile for an soundicon
# fenrirFrequence = the frequency to play
# fenrirDuration = the duration of the frequency
# fenrir_volume = the current volume setting
# fenrir_sound_file = the soundfile for an soundicon
# fenrir_frequency = the frequency to play
# fenrir_duration = the duration of the frequency
# the following command is used to play a soundfile
genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile
generic_play_file_command=play -q -v fenrir_volume fenrir_sound_file
#the following command is used to generate a frequency beep
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
generic_frequency_command=play -q -v fenrir_volume -n -c1 synth fenrir_duration sine fenrir_frequency
# Enable progress bar monitoring with ascending tones by default
progressMonitoring=True
progress_monitoring=True
[speech]
# Turn speech on or off:
enabled=True
# Select speech driver, options are speechdDriver or genericDriver:
# Select speech driver, options are speechdDriver, genericDriver,
# dectalkDriver, dectalkUsbDriver, litetalkDriver, doubletalkDriver,
# or tripletalkDriver:
driver=speechdDriver
#driver=genericDriver
#driver=dectalkDriver
#driver=dectalkUsbDriver
#driver=litetalkDriver
#driver=doubletalkDriver
#driver=tripletalkDriver
# The rate selects how fast Fenrir will speak. Options range from 0, slowest, to 1.0, fastest.
rate=0.5
@@ -45,7 +52,13 @@ rate=0.5
# Pitch controls the pitch of the voice, select from 0, lowest, to 1.0, highest.
pitch=0.5
# Pitch for capital letters
capitalPitch=0.9
capital_pitch=0.9
# How to indicate capital letters:
# pitch = change speech pitch (uses capital_pitch value)
# beep = play Caps.wav sound icon
# both = play beep AND change pitch
# none = no special indication
capital_indicator=pitch
# Volume controls the loudness of the voice, select from 0, quietest, to 1.0, loudest.
volume=1.0
@@ -64,118 +77,211 @@ volume=1.0
# Select the language you want Fenrir to use.
#language=en
# Hardware speech synthesizer serial device.
# Used by dectalkDriver, litetalkDriver, doubletalkDriver, and tripletalkDriver.
# dectalkUsbDriver autodetects the Access Solutions device and ignores this.
# USB serial devices are supported if Linux exposes them as /dev/ttyACM*
# or /dev/ttyUSB*. USB-only synths with no tty device need a separate driver.
# Set an explicit device for hardware speech.
# Examples:
# hardware_device=/dev/ttyACM0 # RPITalk USB gadget mode
# hardware_device=/dev/ttyUSB0 # USB serial adapter
# hardware_device=/dev/ttyS0 # built-in serial port
hardware_device=/dev/ttyS0
# Serial baud rate for hardware speech synthesizers.
hardware_baud_rate=9600
# Read new text as it happens?
autoReadIncoming=True
auto_read_incoming=True
# Speak individual numbers instead of whole string.
readNumbersAsDigits = False
read_numbers_as_digits = False
# genericSpeechCommand is the command that is executed for talking
# Number of spoken items kept in runtime speech history.
history_size=50
# Flood control: batch rapid updates instead of speaking each one
# Number of updates within rapid_update_window to trigger batching
rapid_update_threshold=5
# Time window (seconds) for detecting rapid updates
rapid_update_window=0.3
# How often to speak batched content (seconds)
batch_flush_interval=0.5
# Maximum lines to keep when batching (keeps newest, drops oldest)
max_batch_lines=100
# Only enable flood control if this many new lines appear in the window
flood_line_threshold=500
# generic_speech_command is the command that is executed for talking
# the following variables are replaced with values
# fenrirText = is the text that should be spoken
# fenrirModule = may be the speech module like used in speech-dispatcher, not every TTY need this
# fenrirLanguage = the language
# fenrirVoice = is the current voice that should be used. Set the voice variable above.
# fenrir_text = is the text that should be spoken
# fenrir_module = may be the speech module like used in speech-dispatcher, not every TTY need this
# fenrir_language = the language
# fenrir_voice = is the current voice that should be used. Set the voice variable above.
# the current volume, pitch and rate is calculated like this
# value = min + settingValue * (min - max )
# fenrirVolume = is replaced with the current volume
# fenrirPitch = is replaced with the current pitch
# fenrirRate = is replaced with the current speed (speech rate)
genericSpeechCommand=espeak-ng -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice -- "fenrirText"
# fenrir_volume = is replaced with the current volume
# fenrir_pitch = is replaced with the current pitch
# fenrir_rate = is replaced with the current speed (speech rate)
generic_speech_command=espeak-ng -a fenrir_volume -s fenrir_rate -p fenrir_pitch -v fenrir_voice -- "fenrir_text"
# min and max values of the TTS system that is used in genericSpeechCommand
fenrirMinVolume=0
fenrirMaxVolume=200
fenrirMinPitch=0
fenrirMaxPitch=99
fenrirMinRate=80
fenrirMaxRate=450
# min and max values of the TTS system that is used in generic_speech_command
fenrir_min_volume=0
fenrir_max_volume=200
fenrir_min_pitch=0
fenrir_max_pitch=99
fenrir_min_rate=80
fenrir_max_rate=450
[screen]
# Screen driver: vcsaDriver (Linux TTY/virtual console), ptyDriver (terminal emulation)
driver=vcsaDriver
# Text encoding: auto (auto-detect), utf-8, latin1, etc.
encoding=auto
screenUpdateDelay=0.05
ignoreScreen=
autodetectIgnoreScreen=True
# Delay in seconds between screen updates (lower = more responsive, higher = less CPU)
# Recommended: 0.05 for most systems
screen_update_delay=0.05
# TTY number to completely ignore (e.g., 7 for X11/graphical login screen)
ignore_screen=7
# Automatically detect and ignore graphical TTYs (X11, Wayland sessions)
autodetect_ignore_screen=True
[keyboard]
driver=evdevDriver
# filter input devices NOMICE, ALL or a DEVICE NAME
device=ALL
# gives Fenrir exclusive access to the keyboard and lets it control keystrokes.
grabDevices=True
ignoreShortcuts=False
grab_devices=True
# Optional X11 target window id for x11Driver. Empty uses WINDOWID or active window.
x11_window_id=
# Ignore shortcut bindings and pass all keys through without processing Fenrir commands.
# When True, Fenrir will only monitor screen content without intercepting keyboard input.
# the current shortcut layout located in /etc/fenrirscreenreader/keyboard
keyboardLayout=desktop
ignore_shortcuts=False
keyboard_layout=desktop
# echo chars while typing.
# 0 = None
# 1 = always
# 2 = only while capslock
charEchoMode=1
# 2 = only while capslock (not compatible with capslock as fenrir key)
char_echo_mode=1
# echo deleted chars
charDeleteEcho=True
char_delete_echo=True
# echo word after pressing space
wordEcho=False
word_echo=False
# interrupt speech on any keypress
interruptOnKeyPress=True
interrupt_on_key_press=True
# you can filter the keys on that the speech should interrupt (empty = all keys, otherwhise the given keys)
interruptOnKeyPressFilter=
interrupt_on_key_press_filter=
# timeout for double tap in sec
doubleTapTimeout=0.2
double_tap_timeout=0.2
[general]
debugLevel=0
# Debug levels: 0=NONE, 1=ERROR, 2=WARNING, 3=INFO (most verbose)
# For production use, WARNING (2) provides good balance of useful info without spam
# The default is 0, no logging.
debug_level=0
# debugMode sets where the debug output should send to:
# debugMode=File writes to debugFile (Default:/tmp/fenrir-PID.log)
# debugMode=File writes to debug_file (Default:/tmp/fenrir.log)
# If the default log is already in use, Fenrir uses /tmp/fenrir2.log, etc.
# debugMode=Print just prints on the screen
debugMode=File
debugFile=
punctuationProfile=default
punctuationLevel=some
respectPunctuationPause=True
newLinePause=True
numberOfClipboards=50
debug_mode=File
debug_file=
# Punctuation settings control how punctuation is spoken during text review.
# Profile selects a punctuation definition file from config/punctuation/ (e.g., default.conf)
punctuation_profile=default
punctuation_level=some
respect_punctuation_pause=True
# Replace undefined punctuation with spaces instead of removing them
# This improves readability of text with punctuation like [X]mute, IP addresses, etc.
replace_undefined_punctuation_with_space=True
# Pause speech briefly at newline characters for better readability
new_line_pause=True
# Convert text emoticons like :) to descriptive text (e.g., "smiling face")
emoticons=True
# Define the Fenrir modifier key(s) - used to trigger Fenrir commands
# Examples: KEY_KP0 (numpad 0), KEY_META (Super/Windows), KEY_INSERT
# Multiple keys: KEY_KP0,KEY_META,KEY_INSERT
fenrir_keys=KEY_KP0,KEY_META,KEY_INSERT
# Script key - used to execute custom scripts in script_path
script_keys=KEY_COMPOSE
# Time format using Python strftime codes (https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior)
# Default: %%I:%%M%%P (12-hour format, e.g., "06:38pm")
# 24-hour format: %%H:%%M (e.g., "18:38")
# Common codes: %%I=12hr hour, %%H=24hr hour, %%M=minute, %%S=second, %%P=am/pm lowercase, %%p=AM/PM uppercase
time_format=%%I:%%M%%P
# Date format using Python strftime codes
# Default: %%A, %%B %%d, %%Y (e.g., "Tuesday, December 10, 2024")
# ISO format: %%Y-%%m-%%d (e.g., "2024-12-10")
# Common codes: %%A=weekday name, %%B=month name, %%d=day, %%Y=year with century, %%m=month number
date_format=%%A, %%B %%d, %%Y
# Automatically spell check words when reviewing character-by-character
auto_spell_check=True
# Language for spell checking (format: language_COUNTRY, e.g., en_US, en_GB, es_ES)
spell_check_language=en_US
# path for your scripts "script_keys" functionality.
# User-local scripts in ~/.local/stormux/fenrir are loaded first.
script_path=/usr/share/fenrirscreenreader/scripts
# Override default commands or add custom commands without modifying Fenrir installation
# Leave empty to use default commands only
command_path=
# Format string for announcing text attributes (colors, formatting)
# Available variables:
# fenrirBGColor = the background color
# fenrirFGColor = the foreground color
# fenrirUnderline = speak the underline attribute
# fenrirBold = speak the bold attribute
# fenrirBlink = speak the blink attribute
# fenrirFont = the font name
# fenrirFontSize = the font size
attribute_format_string=Background fenrirBGColor,Foreground fenrirFGColor,fenrirUnderline,fenrirBold,fenrirBlink, Font fenrirFont,Fontsize fenrirFontSize
# Automatically announce indentation level changes (useful for Python, YAML, etc.)
auto_present_indent=False
# How to present indentation changes:
# 0 = sound and speak (both audio feedback and voice announcement)
# 1 = sound only (just play a tone)
# 2 = speak only (just voice announcement)
auto_present_indent_mode=1
# Play a sound when text attributes (color, bold, etc.) change
has_attributes=True
# Shell to use for PTY emulation mode (empty = use system default shell)
# Examples: /bin/bash, /bin/zsh, /usr/bin/fish
shell=
# Diff review presentation mode:
# speech = spoken feedback only
# sound = sound cues only (falls back to speech when cue is unavailable)
# both = speech and sound cues
diff_presentation=both
# Diff review verbosity:
# compact = concise role/location feedback
# verbose = include diff line content during navigation
diff_verbosity=compact
[clipboard]
# Number of clipboard history entries Fenrir keeps.
number_of_clipboards=50
# used path for "export_clipboard_to_file"
# $user is replaced by username
#clipboardExportPath=/home/$user/fenrirClipboard
clipboardExportPath=/tmp/fenrirClipboard
emoticons=True
# define the current Fenrir key
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
scriptKeys=KEY_COMPOSE
timeFormat=%H:%M:%P
dateFormat=%A, %B %d, %Y
autoSpellCheck=True
spellCheckLanguage=en_US
# path for your scripts "scriptKeys" functionality
scriptPath=/usr/share/fenrirscreenreader/scripts
# overload commands, and create new one without changing Fenrir default
commandPath=
#fenrirBGColor = the backgroundcolor
#fenrirFGColor = the foregroundcolor
#fenrirUnderline = speak the underline attribute
#fenrirBold = speak the bold attribute
#fenrirBlink = speak the blink attribute
#fenrirFont = the font
#fenrirFontSize = the fontsize
attributeFormatString=Background fenrirBGColor,Foreground fenrirFGColor,fenrirUnderline,fenrirBold,fenrirBlink, Font fenrirFont,Fontsize fenrirFontSize
# present indentation
autoPresentIndent=False
# speak is only invoked on changeing ident level, sound always
# 0 = sound and speak
# 1 = sound only
# 2 = speak only
autoPresentIndentMode=1
# play a sound when attributes change
hasAttributes=True
# shell for PTY emulatiun (empty = default shell)
shell=
#clipboard_export_path=/home/$user/fenrirClipboard
clipboard_export_path=/tmp/fenrirClipboard
# Keep Fenrir's clipboard history and the X clipboard synchronized.
# In fenrir -x, an empty sync_display uses the current DISPLAY.
# In console/TTY mode, set sync_display explicitly, for example :0.
sync_enabled=False
sync_display=
sync_interval=0.5
[focus]
#follow the text cursor
# Follow and announce text cursor position changes
cursor=True
#follow highlighted text changes
# Follow and announce highlighted/selected text changes (useful in menus)
highlight=False
# Suppress generic incoming announcements for full-screen TUIs that redraw often
tui=False
[remote]
enable=True
@@ -186,63 +292,86 @@ driver=unixDriver
# tcp port
port=22447
# socket filepath
socketFile=
socket_file=
# allow settings to overwrite
enableSettingsRemote=True
enable_settings_remote=True
# allow commands to be executed
enableCommandRemote=True
enable_command_remote=True
[barrier]
# Enable barrier detection - automatically detects table/box borders for improved navigation
enabled=False
leftBarriers=│└┌─
rightBarriers=│┘┐
# Characters that represent left-side barriers/borders (for table/box detection)
left_barriers=│└┌
# Characters that represent right-side barriers/borders (for table/box detection)
right_barriers=│┘┐─
[review]
lineBreak=True
endOfScreen=True
# leave the review when pressing a key
leaveReviewOnCursorChange=True
# leave the review when changing the screen
leaveReviewOnScreenChange=True
[promote]
enabled=True
inactiveTimeoutSec=120
list=
# Announce line breaks during review mode
line_break=True
# Announce when reaching the end of screen during review
end_of_screen=True
# Exit review mode when cursor position changes (e.g., when typing)
leave_review_on_cursor_change=True
# Exit review mode when switching to a different TTY/screen
leave_review_on_screen_change=True
[menu]
vmenuPath=
quickMenu=speech#rate;speech#pitch;speech#volume
# Custom path for VMenu (virtual menu) profiles
# Leave empty to use default location (/etc/fenrirscreenreader/vmenu-profiles/)
vmenu_path=
# Quick menu: Semicolon-separated list of settings for rapid adjustment via VMenu
# Access with Fenrir+F10, navigate to "Quick Settings"
# Format: section#setting;section#setting;...
# Supported settings:
# - speech#rate, speech#pitch, speech#volume (0.0-1.0)
# - speech#module, speech#voice (speechdDriver only, auto-added)
# Note: speech#module and speech#voice are automatically added when
# speechdDriver is active. Do not add them manually.
quick_menu=speech#rate;speech#pitch;speech#volume
[prompt]
# Custom prompt patterns for silence until prompt feature
# You can add your own shell prompt patterns as regular expressions
# Each pattern should be on a separate line, format: customPatterns=pattern1,pattern2,pattern3
# Examples:
#
# Built-in patterns include:
# - Shell prompts: $, #, >, user@host$, [user@host]$, bash-5.1$
# - Package manager prompts: [Y/n], [y/N], [Yes/No], (Y/n), (y/N)
# - sudo prompts: [sudo] password for user:, Password:, user's password:
# - Confirmation prompts: Press any key, Are you sure?, Please confirm
#
# Custom pattern examples:
# For PS1='[\u@\h \W] \$ ' use: \[.*@.*\s.*\]\s*[$#>]\s*
# For "[user@hostname ~] $" use: \[.*@.*\s.*\]\s*[$#>]\s*
# For custom prompts ending with specific strings, use patterns like: .*your_prompt_ending$
customPatterns=
# For custom package manager prompts: .*your_package_manager.*\[[YyNn]/[YyNn]\].*
custom_patterns=
# Specific prompt strings to match exactly (useful for very specific custom prompts)
# Format: exactMatches=prompt1,prompt2,prompt3
# Format: exact_matches=prompt1,prompt2,prompt3
# Examples:
# exactMatches=[storm@fenrir ~] $,[root@fenrir ~] #
exactMatches=
# exact_matches=[storm@fenrir ~] $,[root@fenrir ~] #,Continue installation? [Y/n]
exact_matches=
[time]
# automatic time announcement
# Enable automatic time announcements
enabled=False
# present time
presentTime=True
# present date (on change)
presentDate=True
# present time after a given period of seconds
delaySec=0
# present time after to given minutes example every 15 minutes: 00,15,30,45
# if delaySec is >0 onMinutes is ignored
onMinutes=00,30
# announce via soundicon (not interrupting)
# Announce the current time
present_time=True
# Announce the date (only when it changes, e.g., at midnight)
present_date=True
# Announce time every N seconds (0 = disabled)
# If delay_sec > 0, on_minutes is ignored
delay_sec=0
# Announce time at specific minutes of each hour (comma-separated)
# Examples:
# 00 = Only on the hour (1:00, 2:00, 3:00, etc.)
# 00,30 = On the hour and half-hour (1:00, 1:30, 2:00, 2:30, etc.)
# 00,15,30,45 = Every 15 minutes
# Note: This is ignored if delay_sec > 0
on_minutes=00,30
# Play a sound icon before time announcement (non-interrupting)
announce=True
# interrupt current speech for time announcement
# Interrupt current speech to announce time immediately
interrupt=False
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -9
View File
@@ -1,8 +1,6 @@
# Screen Reader Turned On or Off
ScreenReaderOn='ScreenReaderOn.wav'
ScreenReaderOff='ScreenReaderOff.wav'
# PTY bypass
PTYBypass='PTYBypass.wav'
# Cancel the current command
Cancel='Cancel.wav'
# Accept command
@@ -30,9 +28,6 @@ ContentChanged='ContentChanged.wav'
# Speech has turned On or Off
SpeechOn='SpeechOn.wav'
SpeechOff='SpeechOff.wav'
# Braille has turned On or Off
BrailleOn='BrailleOn.wav'
BrailleOff='BrailleOff.wav'
# SoundIcons has turned On or Off
SoundOn='SoundOn.wav'
SoundOff='SoundOff.wav'
@@ -44,14 +39,11 @@ PlaceEndMark='PlaceEndMark.wav'
CopyToClipboard='CopyToClipboard.wav'
# Pasted on the screen
PasteClipboardOnScreen='PasteClipboardOnScreen.wav'
# An error accoured while speech or braille output or reading the screen
# An error accoured while speech output or reading the screen
ErrorSpeech='ErrorSpeech.wav'
ErrorBraille='ErrorBraille.wav'
ErrorScreen='ErrorScreen.wav'
# If you cursor over an text that has attributs (like color)
HasAttributes='has_attribute.wav'
# fenrir can promote strings if they appear on the screen.
PromotedText='PromotedText.wav'
# missspelled indicator
mispell='mispell.wav'
# the for capital letter
-4
View File
@@ -1,8 +1,6 @@
# Screen Reader Turned On or Off
ScreenReaderOn=''
ScreenReaderOff=''
# PTY bypass
PTYBypass=''
# Cancel the current command
Cancel=''
# Accept command
@@ -50,8 +48,6 @@ ErrorBraille=''
ErrorScreen=''
# If you cursor over an text that has attributs (like color)
HasAttributes=''
# fenrir can promote strings if they appear on the screen.
PromotedText=''
# misspelled indicator
mispell=''
# the for capital letter:
+4 -6
View File
@@ -22,7 +22,7 @@ src/fenrirscreenreader/
│ ├── onKeyInput/ # Key input hooks
│ └── help/ # Tutorial system
├── drivers/ # Driver implementations
│ ├── inputDriver/ # Input drivers (evdev, pty, atspi)
│ ├── inputDriver/ # Input drivers (evdev, x11)
│ ├── screenDriver/ # Screen drivers (vcsa, pty)
│ ├── speechDriver/ # Speech drivers (speechd, generic)
│ └── soundDriver/ # Sound drivers (generic, gstreamer)
@@ -36,8 +36,7 @@ Fenrir uses a pluggable driver architecture:
1. **Input Drivers**: Capture keyboard input
- evdevDriver: Linux evdev (recommended)
- ptyDriver: Terminal emulation
- atspiDriver: AT-SPI for desktop
- x11Driver: X11 terminal-scoped input
2. **Screen Drivers**: Read screen content
- vcsaDriver: Linux VCSA devices
@@ -83,7 +82,6 @@ Fenrir supports various event hooks:
- **onCursorChange**: Triggered when cursor moves
- **onScreenUpdate**: Triggered on screen content changes
- **onKeyInput**: Triggered on key presses
- **onByteInput**: Triggered on byte-level input
- **onScreenChanged**: Triggered when switching screens
## Development Setup
@@ -116,7 +114,7 @@ sudo ./fenrir -f -d -p
# Debug output goes to:
# - Console (with -p flag)
# - /var/log/fenrir.log
# - /tmp/fenrir.log
```
## Creating Commands
@@ -386,4 +384,4 @@ current_line = lines[self.env['screen']['newCursor']['y']]
- **Wiki**: https://git.stormux.org/storm/fenrir/wiki
- **Issues**: Use repository issue tracker
- **Community**: IRC irc.stormux.org #stormux
- **Email**: stormux+subscribe@groups.io
- **Email**: stormux+subscribe@groups.io
+48
View File
@@ -0,0 +1,48 @@
# Diff Review Mode
Diff review mode provides read-only navigation for unified and classic diff files with speech-first output.
## Quick Workflow
1. Copy the full absolute path of a diff file to the Fenrir clipboard.
2. Press `Fenrir + Ctrl + D` to toggle diff mode on.
3. Review the diff using the keys below.
4. Press `Esc` to leave diff mode.
If the clipboard does not contain a full absolute file path, Fenrir announces an error and does not enter diff mode.
## Keys (Active Only In Diff Mode)
- `h` - Next hunk
- `Shift + h` - Previous hunk
- `f` - Next file section
- `Shift + f` - Previous file section
- `a` - Next added line
- `Shift + a` - Previous added line
- `d` - Next removed line
- `Shift + d` - Previous removed line
- `Up` - Previous line
- `Down` - Next line
- `Left` - Previous character
- `Right` - Next character
- `Ctrl + Left` - Previous word
- `Ctrl + Right` - Next word
- `s` - Diff summary
- `F1` - Speak key help
- `Esc` - Exit diff mode
## Speech Behavior
- Added and removed content is spoken as `Added:` and `Removed:` lines.
- Marker-only lines are normalized for speech:
- `+++` is spoken as `added`
- `---` is spoken as `removed`
- Classic diff markers are spoken in plain language:
- `17c17` -> `line 17 changed`
- `17d16` -> `line 17 deleted`
- `16a17` -> `line 17 added`
## Notes
- Diff mode is read-only and does not modify the diff file.
- Normal Fenrir key bindings are restored when diff mode exits.
+96 -49
View File
@@ -13,13 +13,16 @@ fenrir \- A modern, modular console screen reader for Linux
.IR SECTION#SETTING=VALUE;.. ]
.RB [ \-d ]
.RB [ \-p ]
.RB [ \-e ]
.RB [ \-E ]
.RB [ \-x ]
.RB [ \-\-x11-window-id
.IR WINDOWID ]
.RB [ \-F ]
.RB [ \-i
.IR SCREEN ]
.SH DESCRIPTION
Fenrir is a modern, modular, flexible and fast console screen reader written in Python 3.
It provides spoken feedback for Linux console applications and supports multiple interface types including TTY, terminal emulators, and desktop environments.
It provides spoken feedback for Linux console applications and supports Linux TTYs plus X11 terminal mode.
Fenrir features a modular driver architecture supporting multiple speech synthesizers, sound systems, input methods, and screen reading techniques. It includes advanced features like review mode, multiple clipboards, spell checking, bookmarks, and configurable key bindings.
@@ -38,7 +41,7 @@ Run Fenrir in the foreground instead of as a daemon. Useful for debugging and te
.TP
.BR \-s ", " \-\-setting " " \fISETTING-FILE\fR
Path to a custom settings file. Default is /etc/fenrir/settings/settings.conf.
Path to a custom settings file. Default is /etc/fenrirscreenreader/settings/settings.conf for root and ~/.local/share/stormux/fenrirscreenreader/settings/settings.conf for regular-user saves.
.TP
.BR \-o ", " \-\-options " " \fISECTION#SETTING=VALUE;..\fR
@@ -47,27 +50,29 @@ Multiple settings can be separated by semicolons.
.TP
.BR \-d ", " \-\-debug
Enable debug mode. Debug information will be logged to /var/log/fenrir.log.
Enable debug mode. Debug information will be logged to /tmp/fenrir.log by
default. If another Fenrir debug instance is already using it, Fenrir uses
/tmp/fenrir2.log, /tmp/fenrir3.log, etc.
.TP
.BR \-p ", " \-\-print
Print debug messages to screen in addition to logging them.
.TP
.BR \-e ", " \-\-emulated-pty
Use PTY emulation with escape sequences for input. This enables usage in desktop/X11/Wayland environments and terminal emulators.
.TP
.BR \-E ", " \-\-emulated-evdev
Use PTY emulation with evdev for input (single instance mode).
.TP
.BR \-F ", " \-\-force-all-screens
Force Fenrir to respond on all screens, ignoring the ignoreScreen setting. This temporarily overrides screen filtering for the current session.
Force Fenrir to respond on all screens, ignoring the ignore_screen setting. This temporarily overrides screen filtering for the current session.
.TP
.BR \-i ", " \-I ", " \-\-ignore-screen " \fISCREEN\fR"
Ignore specific screen(s). Can be used multiple times to ignore multiple screens. This is equivalent to setting ignoreScreen in the configuration file and will be combined with any existing ignore settings.
Ignore specific screen(s). Can be used multiple times to ignore multiple screens. This is equivalent to setting ignore_screen in the configuration file and will be combined with any existing ignore settings.
.TP
.BR \-x ", " \-\-x11
Run in X11 terminal mode using PTY screen monitoring and X11 keyboard input scoped to the terminal window.
.TP
.BR \-\-x11-window-id " " \fIWINDOWID\fR
Use a specific X11 terminal window id for X11 terminal mode.
.SH KEY CONCEPTS
@@ -186,12 +191,24 @@ Announce marked text
.SS Settings File
The main configuration file is located at:
.IP \[bu] 2
.B /etc/fenrir/settings/settings.conf
.B /etc/fenrirscreenreader/settings/settings.conf
(system-wide installation)
.IP \[bu] 2
.B ~/.local/share/stormux/fenrirscreenreader/settings/settings.conf
(user-local settings)
.IP \[bu] 2
.B config/settings/settings.conf
(development/git version)
When Fenrir runs as a regular user, including fenrir -x, it loads the
user-local settings file if it exists. If it does not exist, Fenrir falls back
to the system settings file, but saving settings writes to the user-local path.
When Fenrir runs as root, settings save to the system-wide path by default.
User sound themes are loaded before system themes from
~/.local/stormux/fenrir/sounds/. User scripts are loaded before configured
system scripts from ~/.local/stormux/fenrir/.
.SS Key Sections
.TP
.B [speech]
@@ -223,6 +240,16 @@ speechdDriver - Speech-dispatcher (recommended)
.IP \[bu] 4
genericDriver - Command-line TTS (espeak, etc.)
.IP \[bu] 4
dectalkDriver - DECtalk-compatible serial hardware speech
.IP \[bu] 4
dectalkUsbDriver - Native Access Solutions DECtalk USB hardware speech
.IP \[bu] 4
litetalkDriver - LiteTalk-compatible serial hardware speech
.IP \[bu] 4
doubletalkDriver - DoubleTalk LT-compatible serial hardware speech
.IP \[bu] 4
tripletalkDriver - TripleTalk-compatible serial hardware speech
.IP \[bu] 4
debugDriver - Debug/testing
.TP
@@ -234,14 +261,12 @@ gstreamerDriver - GStreamer-based
.IP \[bu] 4
debugDriver - Debug/testing
.TP
.TP
.B Input Drivers:
.IP \[bu] 4
evdevDriver - Linux evdev (recommended for Linux)
.IP \[bu] 4
ptyDriver - Terminal emulation (cross-platform)
.IP \[bu] 4
atspiDriver - AT-SPI for desktop environments
x11Driver - X11 terminal-scoped input for fenrir -x
.TP
.B Screen Drivers:
@@ -267,17 +292,13 @@ Start Fenrir as a daemon with default settings.
.B fenrir -f -d
Run Fenrir in foreground with debug output.
.TP
.B fenrir -e
Run Fenrir with PTY emulation for desktop/terminal use.
.TP
.B fenrir -o "speech#rate=0.8;sound#volume=0.5"
Override speech rate and sound volume settings.
.TP
.B fenrir -F
Force Fenrir to work on all screens, ignoring ignoreScreen settings.
Force Fenrir to work on all screens, ignoring ignore_screen settings.
.TP
.B fenrir -s /home/user/my-fenrir.conf
@@ -288,61 +309,77 @@ Use a custom configuration file.
Fenrir includes a powerful remote control system for automation and integration with external applications.
.SS Configuration
Enable remote control in /etc/fenrir/settings/settings.conf:
Enable remote control in /etc/fenrirscreenreader/settings/settings.conf or the user-local settings file:
.EX
[remote]
enable=True
driver=unixDriver
enableSettingsRemote=True
enableCommandRemote=True
enable_settings_remote=True
enable_command_remote=True
.EE
.SS Using socat with Unix Sockets
.TP
.B Instance Discovery:
.EX
# List registered Fenrir instances and their socket paths
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.EE
In X terminal mode (fenrir -x), multiple Fenrir instances can run at the
same time. Each instance has a private socket at
/tmp/fenrirscreenreader-<pid>.sock, and one instance may also own the
standard control socket. Use ls or "command ls" on the standard socket to
find the private socket for a specific instance. Commands sent to the standard
socket are handled by its owner when possible; otherwise they are forwarded to a
registered private socket, preferring the sender's Fenrir ancestor when one can
be found.
.TP
.B Basic Speech Control:
.EX
# Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Speak custom text
echo "command say Hello, this is a test" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command say Hello, this is a test" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Temporarily disable speech
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.EE
.TP
.B Settings Control:
.EX
# Enable highlight tracking
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change speech rate
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change punctuation level (none/some/most/all)
echo "setting set general#punctuationLevel=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Voice and TTS control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuationLevel=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset all settings
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.EE
.TP
.B Clipboard Operations:
.EX
# Add text to clipboard
echo "command clipboard Text to copy" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command clipboard Text to copy" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
.EE
.SS Command Reference
@@ -355,6 +392,8 @@ command say <text> - Speak the specified text
command interrupt - Stop current speech
.IP \[bu] 2
command tempdisablespeech - Disable speech until next key press
.IP \[bu] 2
ls / list / command ls / command list - List registered Fenrir instances
.TP
.B Settings Commands:
@@ -385,7 +424,7 @@ command quitapplication - Quit Fenrir
.TP
.B Speech Control:
.IP \[bu] 2
general#punctuationLevel=none/some/most/all - Punctuation verbosity
general#punctuation_level=none/some/most/all - Punctuation verbosity
.IP \[bu] 2
speech#rate=0.1-1.0 - Speech rate
.IP \[bu] 2
@@ -400,28 +439,32 @@ speech#module=module_name - TTS module
.TP
.B Screen Control:
.IP \[bu] 2
screen#ignoreScreen=1,2,3 - TTY screens to ignore
screen#ignore_screen=1,2,3 - TTY screens to ignore
.IP \[bu] 2
focus#highlight=True/False - Follow text highlighting
.TP
.B Input Control:
.IP \[bu] 2
keyboard#charEchoMode=0-2 - Character echo mode
keyboard#char_echo_mode=0-2 - Character echo mode
.IP \[bu] 2
keyboard#wordEcho=True/False - Word echo
keyboard#word_echo=True/False - Word echo
.SH FILES
.TP
.B /etc/fenrir/settings/settings.conf
.B /etc/fenrirscreenreader/settings/settings.conf
Main configuration file
.TP
.B /etc/fenrir/keyboard/
.B ~/.local/share/stormux/fenrirscreenreader/settings/settings.conf
User-local configuration file
.TP
.B /etc/fenrirscreenreader/keyboard/
Keyboard layout definitions
.TP
.B /etc/fenrir/punctuation/
.B /etc/fenrirscreenreader/punctuation/
Punctuation level definitions
.TP
@@ -429,11 +472,15 @@ Punctuation level definitions
System sound themes
.TP
.B ~/.local/share/fenrirscreenreader/sounds/
.B ~/.local/stormux/fenrir/sounds/
User sound themes
.TP
.B /var/log/fenrir.log
.B ~/.local/stormux/fenrir/
User scripts
.TP
.B /tmp/fenrir.log
Debug log file
.TP
@@ -516,4 +563,4 @@ This software is licensed under the LGPL v3.
Full documentation: https://git.stormux.org/storm/fenrir/wiki
.PP
Support: stormux+subscribe@groups.io
Support: stormux+subscribe@groups.io
+138 -136
View File
@@ -7,14 +7,14 @@ configurable and easy to customize and extend.
=== Credit and intended audience
This document is just a customization for Slint of the genuine
https://github.com/chrys87/fenrir/blob/master/docu/user.txt[Fenrir User
https://git.stormux.org/storm/fenrir/src/branch/master/docs/user.txt[Fenrir User
Manual] motly written by Chrys, main developer of Fenrir.
It has been adapted to its intended audience: end users of Fenrir on
Slint where it is already installed, thus concentrates on its setting
and usage. You will find more information about its features,
installation and how customize and troubleshoot it and contribute to its
development on https://github.com/chrys87/fenrir[the Fenrir Git
development on https://git.stormux.org/storm/fenrir[the Fenrir Git
repository].
=== Getting started with Fenrir
@@ -27,9 +27,12 @@ and voices provided by Speech Dispatcher. +
Keyboard shortcuts are bound to commands to read the screen, review it
and perform other actions like modify the settings on the fly, switch
languages, copy and paste text, provide miscellaneous information. +
=== Configuration file === The permanent settings are recorded in the
configuration file /etc/fenrirscreenreader/settings.conf, that is
heavily commented. +
=== Configuration file === The system-wide settings are recorded in the
configuration file /etc/fenrirscreenreader/settings/settings.conf, that is
heavily commented. Regular-user sessions, including `+fenrir -x+`, load
`+~/.local/share/stormux/fenrirscreenreader/settings/settings.conf+` when it
exists, otherwise they fall back to the system settings file. Saving settings
as a regular user creates or updates the user-local file. +
These settings are described in this user guide.
To start Fenrir once type as root:
@@ -1095,23 +1098,6 @@ announce=True
interrupt=False
....
==== Promoted List
Promoted Lists are a nice feature if you are away from your computer or
performing more longer tasks. you can define a list of words which you
want to hear a sound icon for after a period of inactivity. Example if
the word "Chrys" appears after 120 Seconds of inactivity:
....
[promote]
enabled=True
inactiveTimeoutSec=120
list=Chrys
....
See section link:#Promote[Promote] in `+settings.conf+` for more
information.
=== Dictionary
You can make use of different kinds of built-in dictionary's. A
@@ -1231,17 +1217,11 @@ Enable debug mode. Debug information will be logged.
`+-p, --print+`::
Print debug messages to screen in addition to logging them.
`+-e, --emulated-pty+`::
Use PTY emulation with escape sequences for input. This enables usage in desktop/X11/Wayland environments and terminal emulators.
`+-E, --emulated-evdev+`::
Use PTY emulation with evdev for input (single instance mode).
`+-F, --force-all-screens+`::
Force Fenrir to respond on all screens, ignoring the ignoreScreen setting. This temporarily overrides screen filtering for the current session.
Force Fenrir to respond on all screens, ignoring the ignore_screen setting. This temporarily overrides screen filtering for the current session.
`+-i, -I, --ignore-screen <SCREEN>+`::
Ignore specific screen(s). Can be used multiple times to ignore multiple screens. This is equivalent to setting ignoreScreen in the configuration file and will be combined with any existing ignore settings.
Ignore specific screen(s). Can be used multiple times to ignore multiple screens. This is equivalent to setting ignore_screen in the configuration file and will be combined with any existing ignore settings.
==== Set settings options
@@ -1286,64 +1266,80 @@ Enable remote control in settings.conf:
[remote]
enable=True
driver=unixDriver
enableSettingsRemote=True
enableCommandRemote=True
enable_settings_remote=True
enable_command_remote=True
....
==== Using socat with Unix Sockets
The `+socat+` command provides the easiest way to send commands to Fenrir:
===== Instance Discovery
....
# List registered Fenrir instances and their socket paths
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
....
In X terminal mode (`+fenrir -x+`), multiple Fenrir instances can run at the
same time. Each instance has a private socket at
`+/tmp/fenrirscreenreader-<pid>.sock+`, and one instance may also own the
standard control socket. Use `+ls+` or `+command ls+` on the standard socket to
find the private socket for a specific instance. Commands sent to the standard
socket are handled by its owner when possible; otherwise they are forwarded to a
registered private socket, preferring the sender's Fenrir ancestor when one can
be found.
===== Basic Speech Control
....
# Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Speak custom text
echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command say Hello, this is a test message" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Temporarily disable speech (until next keystroke)
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
....
===== Settings Control
....
# Enable highlight tracking mode
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change speech rate
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change punctuation level (none/some/most/all)
echo "setting set general#punctuationLevel=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Voice and TTS control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuationLevel=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset all settings to defaults
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
....
===== Clipboard Operations
....
# Place text into clipboard
echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command clipboard This text will be copied to clipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
....
===== Application Control
....
# Quit Fenrir
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
....
==== Command Reference
@@ -1355,6 +1351,7 @@ echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-dea
* `+command say <text>+` - Speak the specified text
* `+command interrupt+` - Stop current speech
* `+command tempdisablespeech+` - Disable speech until next key press
* `+ls+` / `+list+` / `+command ls+` / `+command list+` - List registered Fenrir instances
*Clipboard Commands:*
@@ -1394,8 +1391,8 @@ echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-dea
* `+speech#module=module_name+` - TTS module (e.g., "espeak-ng")
*General Settings:*
* `+general#punctuationLevel=none/some/most/all+` - Punctuation verbosity
* `+general#autoSpellCheck=True/False+` - Automatic spell checking
* `+general#punctuation_level=none/some/most/all+` - Punctuation verbosity
* `+general#auto_spell_check=True/False+` - Automatic spell checking
* `+general#emoticons=True/False+` - Enable emoticon replacement
*Sound Settings:*
@@ -1407,11 +1404,11 @@ echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-dea
* `+focus#highlight=True/False+` - Follow text highlighting
*Keyboard Settings:*
* `+keyboard#charEchoMode=0-2+` - Character echo (0=none, 1=always, 2=capslock only)
* `+keyboard#wordEcho=True/False+` - Echo complete words
* `+keyboard#char_echo_mode=0-2+` - Character echo (0=none, 1=always, 2=capslock only)
* `+keyboard#word_echo=True/False+` - Echo complete words
*Screen Settings:*
* `+screen#ignoreScreen=1,2,3+` - TTY screens to ignore
* `+screen#ignore_screen=1,2,3+` - TTY screens to ignore
==== settings.conf syntax
@@ -1492,6 +1489,8 @@ By default we ship two sound packs.
. `+default-wav+` wav encoded, just for compatibility
Sound packs are located at /usr/share/sounds/fenrirscreenreader/
User sound packs in `+~/.local/stormux/fenrir/sounds/+` are loaded before
system sound packs.
Sound volume controls how loud the sounds for your selected sound pack
are.
@@ -1507,38 +1506,38 @@ Values: `+0.0+` is quietest, `+1.0+` is loudest.
The generic sound driver uses shell commands for play sound and
frequencies.
`+genericPlayFileCommand+` defines the command that is used to play a
`+generic_play_file_command+` defines the command that is used to play a
sound file.
....
genericPlayFileCommand=<your command for playing a file>
generic_play_file_command=<your command for playing a file>
....
`+genericFrequencyCommand+` defines the command that is used playing
`+generic_frequency_command+` defines the command that is used playing
frequencies.
....
genericFrequencyCommand=<your command for playing a frequence>
generic_frequency_command=<your command for playing a frequence>
....
The following variables are substituted in `+genericPlayFileCommand+`
and `+genericFrequencyCommand+`:
The following variables are substituted in `+generic_play_file_command+`
and `+generic_frequency_command+`:
* `+fenrirVolume+` = the current volume setting
* `+fenrirSoundFile+` = the sound file for an sound icon
* `+fenrirFrequence+` = the frequency to play
* `+fenrirDuration+` = the duration of the frequency
* `+fenrir_volume+` = the current volume setting
* `+fenrir_sound_file+` = the sound file for an sound icon
* `+fenrir_frequency+` = the frequency to play
* `+fenrir_duration+` = the duration of the frequency
Example genericPlayFileCommand (default)
Example generic_play_file_command (default)
....
genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile
generic_play_file_command=play -q -v fenrir_volume fenrir_sound_file
....
Example genericFrequencyCommand (default)
Example generic_frequency_command (default)
....
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
generic_frequency_command=play -q -v fenrir_volume -n -c1 synth fenrir_duration sine fenrir_frequency
....
==== Speech
@@ -1552,8 +1551,14 @@ enabled=True
Values: on=`+True+`, off=`+False+`
# Select speech driver, options are speechdDriver (default),
genericDriver or espeakDriver: driver=speechdDriver #driver=espeakDriver
genericDriver, dectalkDriver, dectalkUsbDriver, litetalkDriver,
doubletalkDriver or tripletalkDriver: driver=speechdDriver
#driver=genericDriver
#driver=dectalkDriver
#driver=dectalkUsbDriver
#driver=litetalkDriver
#driver=doubletalkDriver
#driver=tripletalkDriver
This Selects the driver used to generate speech output.
@@ -1579,7 +1584,7 @@ Values: Range Minimum:`+0.0+` is lowest, Maximum:`+1.0+` is highest.
A Pitch for capital letters can be set.
....
capitalPitch=0.9
capital_pitch=0.9
....
Values: Range Minimum:`+0.0+` is lowest, Maximum:`+1.0+` is highest.
@@ -1681,13 +1686,39 @@ the pico module:
language=de-DE
....
Read new text as it occurs autoReadIncoming=True Values: on=`+True+`,
Serial hardware speech drivers use a serial device. Set an explicit path.
....
hardware_device=/dev/ttyACM0
hardware_device=/dev/ttyUSB0
hardware_device=/dev/ttyS0
....
Hardware speech drivers use 9600 baud by default.
....
hardware_baud_rate=9600
....
The `+doubletalkDriver+` targets DoubleTalk LT-style serial devices. It does
not support the internal DoubleTalk PC ISA card.
The `+dectalkUsbDriver+` autodetects the native Access Solutions DECtalk USB,
USB ID `+0dd0:2001+`. It requires PyUSB and a libusb backend and ignores the
serial device and baud-rate settings. From a source checkout, install the USB
dependencies with `+python3 -m pip install '.[dectalk_usb]'+`. A non-root
Fenrir process needs a local udev rule granting its account read/write access
to `+0dd0:2001+`; do not make the device world-writable. Other USB hardware
speech synthesizers are supported only when Linux exposes them as a serial tty
such as `+/dev/ttyACM0+` or `+/dev/ttyUSB0+`.
Read new text as it occurs auto_read_incoming=True Values: on=`+True+`,
off=`+False+`
==== Screen
The settings for screens, (TTY, PTY) are configured in the `+[screen]+`
section.
The settings for screen access are configured in the `+[screen]+`
section. `+vcsaDriver+` is used for Linux TTYs, and `+ptyDriver+` is
used by X11 terminal mode.
The driver to get the information from the screen:
@@ -1711,7 +1742,7 @@ Values:`+cp850+` is used for Western languages like USA or Europe.
The driver updates Fenrir with changes on the screen.
....
screenUpdateDelay=0.05
screen_update_delay=0.05
....
Values: in Seconds
@@ -1776,7 +1807,7 @@ Gives Fenrir exclusive access to the keyboard and lets it control
keystrokes. This is needed to intercept Fenrir related shortcuts.
....
grabDevices=True
grab_devices=True
....
Values: on=`+True+`, off=`+False+`
@@ -1785,7 +1816,7 @@ The following makes sense if you are using a second screenreader and
want to have some hooked events. Fenrir ignores all shortcuts then.
....
ignoreShortcuts=False
ignore_shortcuts=False
....
Values: on=`+True+`, off=`+False+`
@@ -1793,11 +1824,11 @@ Values: on=`+True+`, off=`+False+`
The current keyboard layout used for shortcuts.
....
keyboardLayout=desktop
keyboard_layout=desktop
....
Values: An absolute Path to a Keyboard definition file or a Filename
without extension located in `+/etc/fenrir/keyboard+`
without extension located in `+/etc/fenrirscreenreader/keyboard+`
Announce characters while typing.
@@ -1810,7 +1841,7 @@ Values: on=`+True+`, off=`+False+`
Announce deleted characters
....
charDeleteEcho=True
char_delete_echo=True
....
Values: on=`+True+`, off=`+False+`
@@ -1818,7 +1849,7 @@ Values: on=`+True+`, off=`+False+`
Announce word after pressing space
....
wordEcho=False
word_echo=False
....
Values: on=`+True+`, off=`+False+`
@@ -1826,7 +1857,7 @@ Values: on=`+True+`, off=`+False+`
Interrupt speech on any keypress
....
interruptOnKeyPress=False
interrupt_on_key_press=False
....
Values: on=`+True+`, off=`+False+`
@@ -1834,7 +1865,7 @@ Values: on=`+True+`, off=`+False+`
You can filter the keys that speech should interrupt
....
interruptOnKeyPressFilter=
interrupt_on_key_press_filter=
....
Values: (List) empty = all keys, otherwise interrupt with specified keys
@@ -1842,7 +1873,7 @@ Values: (List) empty = all keys, otherwise interrupt with specified keys
The timeout that is used for double tap shortcuts
....
doubleTapTimeout=0.2
double_tap_timeout=0.2
....
Values: Seconds
@@ -1862,16 +1893,16 @@ Values: off=0, error=1, warning=2, info=3
the current punctuation and dict file in use:
....
punctuationProfile=default
punctuation_profile=default
....
Values: Text, see available profiles in `+/etc/fenrir/punctuation+` or
Values: Text, see available profiles in `+/etc/fenrirscreenreader/punctuation+` or
in `+sourceTree/config/punctuation+`
The current punctuation level in use:
....
punctuationLevel=some
punctuation_level=some
....
Values: Text, See available levels in the used punctuation file.
@@ -1879,7 +1910,7 @@ Values: Text, See available levels in the used punctuation file.
Respect pause for punctuations:
....
respectPunctuationPause=True
respect_punctuation_pause=True
....
Values: on=`+True+`, off=`+False+`
@@ -1887,7 +1918,7 @@ Values: on=`+True+`, off=`+False+`
Add a pause on Line break:
....
newLinePause=True
new_line_pause=True
....
Values: on=`+True+`, off=`+False+`
@@ -1897,7 +1928,8 @@ link:#export clipboard to file[export clipboard to file]. The variable
`+$user+` is replaced by the current logged username.
....
clipboardExportPath=/tmp/fenrirClipboard
[clipboard]
clipboard_export_path=/tmp/fenrirClipboard
....
Values: Text, Systemfilepath
@@ -1905,7 +1937,8 @@ Values: Text, Systemfilepath
The number of available clipboards:
....
numberOfClipboards=10
[clipboard]
number_of_clipboards=10
....
Values: Integer, 1 - 999
@@ -1921,7 +1954,7 @@ Values: on=`+True+`, off=`+False+`
Define the current Fenrir keys:
....
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
fenrir_keys=KEY_KP0,KEY_META,KEY_INSERT
....
Values, Text list, separated by comma.
@@ -1955,7 +1988,7 @@ https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior[d
Enable or Disable spellcheck whilst typing:
....
autoSpellCheck=True
auto_spell_check=True
....
Values: on=`+True+`, off=`+False+`
@@ -1963,7 +1996,7 @@ Values: on=`+True+`, off=`+False+`
The use of the dictionary with spellcheck:
....
spellCheckLanguage=en_US
spell_check_language=en_US
....
Values: Text, see aspell dictionary's.
@@ -1971,19 +2004,20 @@ Values: Text, see aspell dictionary's.
Folder Path for your scripts "scriptKey" functionality:
....
scriptPath=/usr/share/fenrirscreenreader/scripts
script_path=/usr/share/fenrirscreenreader/scripts
....
Values: Text, Existing path on file system.
Values: Text, Existing path on file system. User scripts in
`+~/.local/stormux/fenrir/+` are loaded before this configured path.
Override commands or create new ones without changing the Fenrir
defaults:
....
commandPath=/usr/share/fenrirscreenreader/commands
command_path=/usr/share/fenrirscreenreader/commands
....
Values: Text, Existing path on file system. Subfolders in commandPath
Values: Text, Existing path on file system. Subfolders in command_path
are:
* `+commands+` = to create shortcut commands
@@ -2044,44 +2078,11 @@ Values: on=`+True+`, off=`+False+`
Leave the review mode when changing the screen (From TTY3 to TTY4):
....
leaveReviewOnScreenChange=True
leave_review_on_screen_change=True
....
Values: on=`+True+`, off=`+False+`
==== Promote
"Promoted Lists" are configured in the section `+[promote]+`. Turn
Promoted Lists" on or off:
....
enabled=True
....
Values: on=`+True+`, off=`+False+`
The minimum time interval of inactivity to activate promoting. By
default it promotes after 120 Seconds inactivity:
....
inactiveTimeoutSec=120
....
Values: in Seconds
Define a list of promoted words comma seperated:
....
list=
....
Values: text (comma seperated) Example to promote the word "nickname" or
a bash prompt:
....
list=nickname,$:,#:
....
==== Time
The automated time announcement is configured in the section `+[time]+`.
@@ -2152,14 +2153,15 @@ Values: on=`+True+`, off=`+False+`
=== Scripting
Scripts can be in any language, bash, python, sh or others. Place your
scripts in the directory /usr/share/fenrirscreenreader/scripts/ (the
path is configurable in settings.conf). The script key is the
personal scripts in `+~/.local/stormux/fenrir/+`, or place system scripts in
the directory /usr/share/fenrirscreenreader/scripts/ (the path is configurable
in settings.conf). The script key is the
applications key. Usually this key can be found on the keyboard located
just left of the right most control key. When you name a script, the key
name appears in the script seperated by the sequence [.underline]#-#.
So, for example, if you have a python weather script you want assigned
to the script key plus the letter w you would name the script
/usr/share/fenrirscreenreader/scripts/weather[.underline]##-##key_w.py
~/.local/stormux/fenrir/weather[.underline]##-##key_w.py
Then, to access the script, simply press the script key and the letter
w. Scripts must be executable. So, make sure to chmod 755 your script
when you place it in the scripts directory. The script gets some
@@ -2193,9 +2195,9 @@ settings.conf). Commands are python files with a special scheme. You can
assign them to a shortcut using the filename without an extension or
place them in a hook trigger like OnInput or OnScreenChange. For further
information see developer guide. Good Examples:
https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/commands/date.py["date.py"]
https://git.stormux.org/storm/fenrir/src/branch/master/src/fenrirscreenreader/commands/commands/date.py["date.py"]
(announce the Date),
https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/commands/shut_up.py["shut_up.py"]
https://git.stormux.org/storm/fenrir/src/branch/master/src/fenrirscreenreader/commands/commands/shut_up.py["shut_up.py"]
(interrupt output) the basic scheme for a command is as follows:
....
@@ -2218,7 +2220,7 @@ class command():
pass
....
* https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/command_template.py[Template
* https://git.stormux.org/storm/fenrir/src/branch/master/src/fenrirscreenreader/commands/command_template.py[Template
lives here]
* The class needs to have the name "command".
* "initialize" is running once whilst loading the command.
@@ -2276,20 +2278,20 @@ root.
=== Bugreports and feature requests
Please report Bugs and feature requests to:
https://github.com/chrys87/fenrir/issues
https://git.stormux.org/storm/fenrir/issues
for bugs please provide a link:#Howto create a debug file[debug] file
that shows the issue.
==== How-to create a debug file
. Delete old debug stuff +
`+sudo rm /var/log/fenrir.log+`
. Start fenrir in debug mode +
`+sudo fenrir -d+`
. Do your stuff to reproduce the problem
. Stop fenrir (`+fenrirKey + q+`)
the debug file is located in `+/var/log/fenrir.log+`
the debug file is located in `+/tmp/fenrir.log+`. If another Fenrir debug
instance is already using it, check `+/tmp/fenrir2.log+`,
`+/tmp/fenrir3.log+`, etc.
Please be as precise as possible to make it easy to solve the problem.
+154 -35
View File
@@ -38,6 +38,7 @@ Navigate the screen without moving the text cursor. Essential for examining cont
### Navigation (Desktop Layout)
- `Ctrl` - Stop speech (shut up)
- `Fenrir + H` - Tutorial mode
- `Fenrir + Ctrl + H` - Speech history
- `Fenrir + Q` - Quit Fenrir
- `Fenrir + Keypad 5` - Read current screen
- `Keypad 8` - Read current line
@@ -50,6 +51,12 @@ Navigate the screen without moving the text cursor. Essential for examining cont
- `Keypad 1/3` - Previous/next character
- `Fenrir + Keypad dot` - Exit review mode
### Table Navigation
- `Fenrir + Keypad *` - Toggle table mode / highlight tracking
- `Keypad 4/6` - Previous/next column (in table mode)
- `Fenrir + Keypad 4/6` - First/last column (in table mode)
- `Fenrir + X` - Set column headers (in table mode)
### Information
- `Fenrir + T` - Announce time
- `Fenrir + T T` - Announce date
@@ -71,7 +78,13 @@ Navigate the screen without moving the text cursor. Essential for examining cont
## Configuration
### Settings File
Main configuration: `/etc/fenrir/settings/settings.conf`
Main configuration:
- **System-wide**: `/etc/fenrirscreenreader/settings/settings.conf`
- **User-local**: `~/.local/share/stormux/fenrirscreenreader/settings/settings.conf`
When Fenrir runs as a regular user, including `fenrir -x`, it loads the user-local settings file if it exists. If it does not exist, Fenrir falls back to the system settings file, but saving settings creates or updates the user-local file. When Fenrir runs as root, settings save to the system-wide file by default.
User sound themes are loaded before system themes from `~/.local/stormux/fenrir/sounds/`. User scripts are loaded before configured system scripts from `~/.local/stormux/fenrir/`.
### Key Sections
- `[speech]` - Speech synthesis settings
@@ -88,6 +101,9 @@ driver=speechdDriver
rate=0.5
pitch=0.5
volume=1.0
hardware_device=/dev/ttyS0
hardware_baud_rate=9600
history_size=50
[sound]
enabled=True
@@ -96,17 +112,17 @@ volume=0.7
[keyboard]
driver=evdevDriver
keyboardLayout=desktop
keyboard_layout=desktop
[screen]
driver=vcsaDriver
ignoreScreen=
ignore_screen=
[remote]
enable=True
driver=unixDriver
enableSettingsRemote=True
enableCommandRemote=True
enable_settings_remote=True
enable_command_remote=True
```
## Remote Control
@@ -120,65 +136,79 @@ Enable remote control in settings:
enable=True
driver=unixDriver # or tcpDriver
port=22447 # for TCP driver
enableSettingsRemote=True # allow settings changes
enableCommandRemote=True # allow command execution
enable_settings_remote=True # allow settings changes
enable_command_remote=True # allow command execution
```
### Basic Usage with socat
#### Instance Discovery
```bash
# List registered Fenrir instances and their socket paths
echo "ls" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
In X terminal mode (`fenrir -x`), multiple Fenrir instances can run at the same
time. Each instance has a private socket at `/tmp/fenrirscreenreader-<pid>.sock`,
and one instance may also own the standard control socket. Use `ls` or
`command ls` on the standard socket to find the private socket for a specific
instance. Commands sent to the standard socket are handled by its owner when
possible; otherwise they are forwarded to a registered private socket,
preferring the sender's Fenrir ancestor when one can be found.
#### Speech Control
```bash
# Interrupt current speech
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command interrupt" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Speak custom text
echo "command say Hello, this is a test" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command say Hello, this is a test" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Temporarily disable speech
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command tempdisablespeech" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
#### Settings Control
```bash
# Enable highlight tracking
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change speech parameters
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#rate=0.8" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#pitch=0.6" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#volume=0.9" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Change punctuation level (none/some/most/all)
echo "setting set general#punctuationLevel=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set general#punctuation_level=all" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Voice and TTS control
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#module=espeak-ng" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#voice=en-us+f3" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting set speech#module=espeak-ng" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Multiple settings at once
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuationLevel=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting set speech#rate=0.8;sound#volume=0.7;general#punctuation_level=most" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Reset all settings
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting reset" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Save settings
echo "setting save" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting saveas /tmp/my-settings.conf" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "setting save" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
echo "setting saveas /tmp/my-settings.conf" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
#### Clipboard Operations
```bash
# Add text to clipboard
echo "command clipboard Text to copy" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command clipboard Text to copy" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
# Export clipboard to file
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command exportclipboard" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
#### Application Control
```bash
# Quit Fenrir
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
```
### Command Reference
@@ -187,6 +217,7 @@ echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-dea
- `command say <text>` - Speak text
- `command interrupt` - Stop speech
- `command tempdisablespeech` - Disable until next key
- `ls` / `list` / `command ls` / `command list` - List registered Fenrir instances
**Settings Commands:**
- `setting set <section>#<key>=<value>` - Change setting
@@ -202,18 +233,18 @@ echo "command quitapplication" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-dea
- `command resetvmenu` - Reset virtual menu
**Key Settings You Can Change:**
- Punctuation level: `setting set general#punctuationLevel=all`
- Punctuation level: `setting set general#punctuation_level=all`
- Speech parameters: `setting set speech#rate=0.8;speech#pitch=0.6`
- Voice selection: `setting set speech#voice=en-us+f3`
- Character echo: `setting set keyboard#charEchoMode=1`
- Screen ignore: `setting set screen#ignoreScreen=1,2,3`
- Character echo: `setting set keyboard#char_echo_mode=1`
- Screen ignore: `setting set screen#ignore_screen=1,2,3`
### Scripting Integration
#### Bash Helper Function
```bash
fenrir_say() {
echo "command say $1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
echo "command say $1" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
}
# Usage
@@ -226,7 +257,7 @@ import socket
import os
def send_fenrir_command(command):
socket_path = "/tmp/fenrirscreenreader-deamon.sock"
socket_path = "/tmp/fenrirscreenreader-daemon.sock"
if os.path.exists(socket_path):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
@@ -240,6 +271,50 @@ send_fenrir_command("command say Process complete")
## Advanced Features
### Table Navigation Mode
Fenrir includes advanced table navigation capabilities for working with tabular data in terminal applications, CSV files, and formatted text output.
#### Entering Table Mode
1. Press `Fenrir + Keypad *` (desktop) or `Fenrir + Y` (laptop)
2. Cycle through: Highlight tracking → Cursor tracking → Table mode
3. Listen for "table mode enabled" announcement
#### Table Navigation Commands
- **Column navigation**: `Keypad 4/6` - Move between columns
- **Row boundaries**: `Fenrir + Keypad 4/6` - Jump to first/last column
- **Cell characters**: `Fenrir + Keypad 1/3` - First/last character in cell
- **Set headers**: `Fenrir + X` - Mark current line as column headers
#### Table Features
- **Automatic detection**: Supports CSV, pipe-separated, space-aligned columns
- **Column headers**: Set and announce headers for better context
- **Boundary feedback**: Audio cues when reaching row boundaries
- **Cell-by-cell navigation**: Precise positioning within tables
### Progress Bar Monitoring
Fenrir automatically detects and provides audio feedback for progress indicators.
#### Progress Detection
- **Percentage**: 45%, 67.5%, 100%
- **Fractions**: 15/100, 3 of 10, Step 7/15
- **Progress bars**: [#### ], [====> ]
- **Activity indicators**: Loading..., Processing...
#### Audio Feedback
- **Progress tones**: Ascending 400Hz-1200Hz frequency range
- **Activity beeps**: 800Hz tone every 2 seconds
- **Non-intrusive**: Doesn't interrupt speech or other audio
#### Usage
- **Enable**: Use `progress_bar_monitor` command (assign key binding)
- **Automatic**: Works with downloads, compilations, installations
- **Remote control**: Enable via socket commands
Fenrir detects stable progress structures rather than application-specific
status formats, which change too frequently to support reliably.
### Spell Checking
- `Fenrir + S` - Spell check current word
- `Fenrir + S S` - Add word to dictionary
@@ -264,6 +339,25 @@ send_fenrir_command("command say Process complete")
### Speech Drivers
- **speechdDriver** - Speech-dispatcher (recommended)
- **genericDriver** - Command-line TTS (espeak, etc.)
- **dectalkDriver** - Serial DECtalk-compatible hardware speech
- **dectalkUsbDriver** - Native Access Solutions DECtalk USB (`0dd0:2001`)
- **litetalkDriver** - Serial LiteTalk-compatible hardware speech
- **doubletalkDriver** - Serial DoubleTalk LT-compatible hardware speech
- **tripletalkDriver** - Serial TripleTalk-compatible hardware speech
For serial hardware speech, set `speech#hardware_device` to an explicit path.
RPITalk gadget mode usually appears as `/dev/ttyACM0`; USB serial adapters
usually appear as `/dev/ttyUSB0`; built-in serial ports may be `/dev/ttyS0`.
The default baud rate is `9600`. `doubletalkDriver` targets
DoubleTalk LT-style serial devices, not the internal DoubleTalk PC ISA card.
The `dectalkUsbDriver` autodetects the native Access Solutions DECtalk USB and
ignores both serial settings. It requires PyUSB and a libusb backend. From a
source checkout, install them with
`python3 -m pip install '.[dectalk_usb]'`. A non-root Fenrir process also needs
a local udev rule granting its account read/write access to USB ID
`0dd0:2001`; do not make the device world-writable. USB TripleTalk devices work
only if Linux exposes them as a serial tty such as `/dev/ttyACM0` or
`/dev/ttyUSB0`.
### Sound Drivers
- **genericDriver** - Sox-based (default)
@@ -271,7 +365,7 @@ send_fenrir_command("command say Process complete")
### Input Drivers
- **evdevDriver** - Linux evdev (recommended for Linux)
- **ptyDriver** - Terminal emulation (cross-platform)
- **x11Driver** - X11 terminal-scoped input for `fenrir -x`
### Screen Drivers
- **vcsaDriver** - Linux VCSA devices (TTY)
@@ -294,11 +388,35 @@ fenrir [OPTIONS]
- `-o, --options SECTION#SETTING=VALUE;..` - Override settings
- `-d, --debug` - Enable debug mode
- `-p, --print` - Print debug to screen
- `-e, --emulated-pty` - PTY emulation for desktop use
- `-E, --emulated-evdev` - PTY + evdev emulation
- `-F, --force-all-screens` - Ignore ignoreScreen setting
- `-x, --x11` - PTY + X11 keyboard input scoped to the terminal window
- `--x11-window-id WINDOWID` - X11 window id to use for `--x11` terminal mode
- `-F, --force-all-screens` - Ignore ignore_screen setting
- `-i, -I, --ignore-screen SCREEN` - Ignore specific screen(s), can be used multiple times
### X11 Terminal Mode
Use `fenrir -x` to run Fenrir in an X11 terminal as a normal user:
```bash
fenrir -x
```
This mode uses PTY screen monitoring and X11 keyboard input. It is intended for GUI terminals such as xterm and VTE-based terminals, while keeping Fenrir key handling scoped to that terminal window. Desktop screen readers keep their global bindings outside the focused terminal.
Fenrir normally detects the target terminal from `WINDOWID` or the active X11 window. If needed, pass a window id explicitly:
```bash
fenrir -x --x11-window-id 0x123456
```
X11 terminal mode uses the same keyboard layout files as TTY Fenrir. Supported Fenrir keys include numpad Insert/`KEY_KP0`, CapsLock/`KEY_CAPSLOCK`, Insert/`KEY_INSERT`, and Super/Windows/`KEY_META`. Compose script keys are exposed as `KEY_COMPOSE`.
In this mode Fenrir runs as a regular user. Settings are loaded from `~/.local/share/stormux/fenrirscreenreader/settings/settings.conf` when present, otherwise from `/etc/fenrirscreenreader/settings/settings.conf`; saving settings creates or updates the user-local file. User sound themes and scripts are read first from `~/.local/stormux/fenrir/sounds/` and `~/.local/stormux/fenrir/`.
This mode requires `python-xlib`.
For a dedicated PTY/terminal screen reader, see TDSR: https://github.com/tspivey/tdsr
## Troubleshooting
### No Speech
@@ -319,7 +437,7 @@ fenrir [OPTIONS]
### Debug Mode
```bash
sudo fenrir -f -d
# Debug output goes to /var/log/fenrir.log
# Debug output goes to /tmp/fenrir.log
```
## Getting Help
@@ -332,5 +450,6 @@ sudo fenrir -f -d
## See Also
- [README.md](../README.md) - Installation and basic setup
- [diff_review_mode.md](./diff_review_mode.md) - Diff review workflow and key bindings
- [settings.conf](../config/settings/settings.conf) - Configuration reference
- `man fenrir` - Manual page
- `man fenrir` - Manual page
+87 -90
View File
@@ -160,7 +160,7 @@ For Arch there are PKGBUILDs in the AUR:
- Download the latest stable version from the [[https://linux-a11y.org/index.php?page=fenrir-screenreader|Fenrir-Project]] site.
- Unpack the archive
- Check the needed Dependencys by running [[https://github.com/chrys87/fenrir/blob/master/check-dependencies.py|check-dependencys.py]] script
- Check the needed Dependencys by running [[https://git.stormux.org/storm/fenrir/src/branch/master/check-dependencies.py|check-dependencys.py]] script
- install the missing dependencies an standard installation requires the following:
* python3 >= 3.3 (and all the following is needed for python3 )
* python3-speechd (screen)
@@ -171,7 +171,7 @@ For Arch there are PKGBUILDs in the AUR:
* python3-pyenchant (spellchecker)
* your language for aspell (aspell-<lang>) (spellchecker)
* sox (sound)
* For an individual installation see [[#Support and Requirements|Support and Requirements]] or consult the [[https://github.com/chrys87/fenrir/blob/master/README.md|Readme]])
* For an individual installation see [[#Support and Requirements|Support and Requirements]] or consult the [[https://git.stormux.org/storm/fenrir/src/branch/master/README.md|Readme]])
- run "install.sh" as root
this installs Fenrir as the following
@@ -185,7 +185,7 @@ to remove Fenrir just run uninstall.sh as root
if you want to get the latest code you can use git to get a development snapshot:
git clone https://github.com/chrys87/fenrir.git
git clone https://git.stormux.org/storm/fenrir.git
===== Auto Start =====
@@ -729,15 +729,6 @@ Example on fix minutes in an hour. example every quarter "delaySec=0" and "onMin
onMinutes=00,15,30,45
announce=True
interrupt=False
==== Promoted List ====
Promoted Lists are a nice feature if you are away from your computer or performing more longer tasks.
you can define a list of words which you want to hear a sound icon for after a period of inactivity.
Example if the word "Chrys" appears after 120 Seconds of inactivity:
[promote]
enabled=True
inactiveTimeoutSec=120
list=Chrys
See section [[#Promote|Promote]] in ''settings.conf'' for more information.
==== Punctuation ====
Fenrir handles punctuation levels and names for you with several provided dictionaries.
@@ -866,31 +857,35 @@ Values: ''0.0'' is quietest, ''1.0'' is loudest.
=== Generic Driver ===
The generic sound driver uses shell commands for play sound and frequencies.
''genericPlayFileCommand'' defines the command that is used to play a sound file.
genericPlayFileCommand=<your command for playing a file>
''genericFrequencyCommand'' defines the command that is used playing frequencies.
genericFrequencyCommand=<your command for playing a frequence>
''generic_play_file_command'' defines the command that is used to play a sound file.
generic_play_file_command=<your command for playing a file>
''generic_frequency_command'' defines the command that is used playing frequencies.
generic_frequency_command=<your command for playing a frequence>
The following variables are substituted in ''genericPlayFileCommand'' and ''genericFrequencyCommand'':
* ''fenrirVolume'' = the current volume setting
* ''fenrirSoundFile'' = the sound file for an sound icon
* ''fenrirFrequence'' = the frequency to play
* ''fenrirDuration'' = the duration of the frequency
The following variables are substituted in ''generic_play_file_command'' and ''generic_frequency_command'':
* ''fenrir_volume'' = the current volume setting
* ''fenrir_sound_file'' = the sound file for an sound icon
* ''fenrir_frequency'' = the frequency to play
* ''fenrir_duration'' = the duration of the frequency
Example genericPlayFileCommand (default)
genericPlayFileCommand=play -q -v fenrirVolume fenrirSoundFile
Example genericFrequencyCommand (default)
genericFrequencyCommand=play -q -v fenrirVolume -n -c1 synth fenrirDuration sine fenrirFrequence
Example generic_play_file_command (default)
generic_play_file_command=play -q -v fenrir_volume fenrir_sound_file
Example generic_frequency_command (default)
generic_frequency_command=play -q -v fenrir_volume -n -c1 synth fenrir_duration sine fenrir_frequency
==== Speech ====
Speech is configured in section ''[speech]''.
Turn speech on or off:
enabled=True
Values: on=''True'', off=''False''
# Select speech driver, options are speechdDriver (default), genericDriver or espeakDriver:
# Select speech driver, options are speechdDriver (default), genericDriver, dectalkDriver, dectalkUsbDriver, litetalkDriver, doubletalkDriver or tripletalkDriver:
driver=speechdDriver
#driver=espeakDriver
#driver=genericDriver
#driver=dectalkDriver
#driver=dectalkUsbDriver
#driver=litetalkDriver
#driver=doubletalkDriver
#driver=tripletalkDriver
Select the driver used to generate speech output.
@@ -899,7 +894,11 @@ Select the driver used to generate speech output.
Available Drivers:
* ''genericDriver'' using the generic driver, for Fenrir <1.5 this is not available
* ''speechdDriver'' using speech-dispatcher, for Fenrir <1.5 just use ''speechd''
* ''espeakDriver'' using the espeak directly, for Fenrir <1.5 just use ''espeak''
* ''dectalkDriver'' using DECtalk-compatible serial hardware or RPITalk
* ''dectalkUsbDriver'' using the native Access Solutions DECtalk USB
* ''litetalkDriver'' using LiteTalk-compatible serial hardware or RPITalk
* ''doubletalkDriver'' using DoubleTalk LT-compatible serial hardware
* ''tripletalkDriver'' using TripleTalk-compatible serial hardware
The rate selects how fast Fenrir will speak.
rate=0.65
@@ -910,7 +909,7 @@ Pitch controls the pitch of the voice.
Values: Range Minimum:''0.0'' is lowest, Maximum:''1.0'' is highest.
A Pitch for capital letters can be set.
capitalPitch=0.9
capital_pitch=0.9
Values: Range Minimum:''0.0'' is lowest, Maximum:''1.0'' is highest.
The Volume controls the loudness of the voice.
@@ -930,34 +929,45 @@ Select the language you want Fenrir to use.
language=english-us
Values: Text, see your TTS synths documentation what is available.
Serial hardware speech drivers use a serial device. Set an explicit path.
hardware_device=/dev/ttyACM0
hardware_device=/dev/ttyUSB0
hardware_device=/dev/ttyS0
Hardware speech drivers use 9600 baud by default.
hardware_baud_rate=9600
The doubletalkDriver targets DoubleTalk LT-style serial devices. It does not support the internal DoubleTalk PC ISA card.
The dectalkUsbDriver autodetects the native Access Solutions DECtalk USB, USB ID 0dd0:2001. It requires PyUSB and a libusb backend and ignores the serial device and baud-rate settings. Other USB hardware speech synthesizers are supported only when Linux exposes them as a serial tty such as /dev/ttyACM0 or /dev/ttyUSB0.
Read new text as it occurs
autoReadIncoming=True
auto_read_incoming=True
Values: on=''True'', off=''False''
=== Generic Driver ===
The generic speech driver uses shell commands for speech synthisus.
''genericSpeechCommand'' defines the command that is executed for creating speech
The following variables are substituted in ''genericSpeechCommand'':
* ''FenrirText'' = is the text that should be spoken
* ''fenrirModule'' = may be the speech module like used in speech-dispatcher, not every TTY needs this
* ''fenrirLanguage'' = the language to speak in
* ''fenrirVoice'' = is the current voice that should be used
* ''fenrirVolume'' = is replaced with the current volume
* ''fenrirPitch'' = is replaced with the current pitch
* ''fenrirRate'' = is replaced with the current speed (speech rate)
''generic_speech_command'' defines the command that is executed for creating speech
The following variables are substituted in ''generic_speech_command'':
* ''fenrir_text'' = is the text that should be spoken
* ''fenrir_module'' = may be the speech module like used in speech-dispatcher, not every TTY needs this
* ''fenrir_language'' = the language to speak in
* ''fenrir_voice'' = is the current voice that should be used
* ''fenrir_volume'' = is replaced with the current volume
* ''fenrir_pitch'' = is replaced with the current pitch
* ''fenrir_rate'' = is replaced with the current speed (speech rate)
Example genericSpeechCommand (default):
genericSpeechCommand=espeak -a fenrirVolume -s fenrirRate -p fenrirPitch -v fenrirVoice "fenrirText"
Example generic_speech_command (default):
generic_speech_command=espeak -a fenrir_volume -s fenrir_rate -p fenrir_pitch -v fenrir_voice "fenrir_text"
These are the minimum and maximum values of the TTS system used in genericSpeechCommand. They are needed to calculate the abstract range in volume, rate and pitch 0.0 - 1.0.
These are the minimum and maximum values of the TTS system used in generic_speech_command. They are needed to calculate the abstract range in volume, rate and pitch 0.0 - 1.0.
FenrirMinVolume=0
fenrirMaxVolume=200
fenrirMinPitch=0
fenrirMaxPitch=99
fenrirMinRate=80
fenrirMaxRate=450
fenrir_min_volume=0
fenrir_max_volume=200
fenrir_min_pitch=0
fenrir_max_pitch=99
fenrir_min_rate=80
fenrir_max_rate=450
The current volume, pitch and rate is calculated like this
value = min + [volume,pitch,rate] * (min - max )
@@ -1022,7 +1032,8 @@ Values: Integer,
* ''0'' = display size
* ''>0'' number of cells
==== Screen ====
The settings for screens, (TTY, PTY) are configured in the ''[screen]'' section.
The settings for screen access are configured in the ''[screen]'' section.
''vcsaDriver'' is used for Linux TTYs, and ''ptyDriver'' is used by X11 terminal mode.
The driver to get the information from the screen:
driver=vcsaDriver
@@ -1033,7 +1044,7 @@ The encoding of the screen
Values:''cp850'' is used for Western languages like USA or Europe.
The driver updates Fenrir with changes on the screen.
screenUpdateDelay=0.05
screen_update_delay=0.05
Values: in Seconds
If you want Fenrir to not be active on any screen for various reasons. Maybe an X server or Wayland is running on that screen. You can make Fenrir ignore it or multiple screens seperated by '','' with:
@@ -1064,15 +1075,15 @@ Values:
* ''<Device Name>'' just use the device with the given name.
Gives Fenrir exclusive access to the keyboard and lets it control keystrokes. This is needed to intercept Fenrir related shortcuts.
grabDevices=True
grab_devices=True
Values: on=''True'', off=''False''
The following makes sense if you are using a second screenreader and want to have some hooked events. Fenrir ignores all shortcuts then.
ignoreShortcuts=False
ignore_shortcuts=False
Values: on=''True'', off=''False''
The current keyboard layout used for shortcuts.
keyboardLayout=desktop
keyboard_layout=desktop
Values: An absolute Path to a Keyboard definition file or a Filename without extension located in ''/etc/fenrir/keyboard''
Announce characters while typing.
@@ -1080,23 +1091,23 @@ Announce characters while typing.
Values: on=''True'', off=''False''
Announce deleted characters
charDeleteEcho=True
char_delete_echo=True
Values: on=''True'', off=''False''
Announce word after pressing space
wordEcho=False
word_echo=False
Values: on=''True'', off=''False''
Interrupt speech on any keypress
interruptOnKeyPress=False
interrupt_on_key_press=False
Values: on=''True'', off=''False''
You can filter the keys that speech should interrupt
interruptOnKeyPressFilter=
interrupt_on_key_press_filter=
Values: (List) empty = all keys, otherwise interrupt with specified keys
The timeout that is used for double tap shortcuts
doubleTapTimeout=0.2
double_tap_timeout=0.2
Values: Seconds
==== General ====
Overall settings can be configured from the section ''[general]''.
@@ -1106,29 +1117,31 @@ Set the current debug level:
Values: off=0, error=1, warning=2, info=3
the current punctuation and dict file in use:
punctuationProfile=default
punctuation_profile=default
Values: Text, see available profiles in ''/etc/fenrir/punctuation'' or in ''sourceTree/config/punctuation''
The current punctuation level in use:
punctuationLevel=some
punctuation_level=some
Values: Text, See available levels in the used punctuation file.
Respect pause for punctuations:
respectPunctuationPause=True
respect_punctuation_pause=True
Values: on=''True'', off=''False''
Add a pause on Line break:
newLinePause=True
new_line_pause=True
Values: on=''True'', off=''False''
Specify the path where the clipboard should be exported to.
See [[#export clipboard to file|export clipboard to file]].
The variable ''$user'' is replaced by the current logged username.
clipboardExportPath=/tmp/fenrirClipboard
[clipboard]
clipboard_export_path=/tmp/fenrirClipboard
Values: Text, Systemfilepath
The number of available clipboards:
numberOfClipboards=10
[clipboard]
number_of_clipboards=10
Values: Integer, 1 - 999
Replace emoticons like :) or ;) with text insertions:
@@ -1136,7 +1149,7 @@ Replace emoticons like :) or ;) with text insertions:
Values: on=''True'', off=''False''
Define the current Fenrir keys:
fenrirKeys=KEY_KP0,KEY_META,KEY_INSERT
fenrir_keys=KEY_KP0,KEY_META,KEY_INSERT
Values, Text list, separated by comma.
Define the current script keys:
@@ -1152,11 +1165,11 @@ The date format to be used for (date command) output:
Values: see python specification for [[https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior|datetime.strftime]]
Enable or Disable spellcheck whilst typing:
autoSpellCheck=True
auto_spell_check=True
Values: on=''True'', off=''False''
The use of the dictionary with spellcheck:
spellCheckLanguage=en_US
spell_check_language=en_US
Values: Text, see aspell dictionary's.
Folder Path for your scripts "scriptKey" functionality:
@@ -1197,25 +1210,8 @@ Leave the review mode when pressing a key:
Values: on=''True'', off=''False''
Leave the review mode when changing the screen (From TTY3 to TTY4):
leaveReviewOnScreenChange=True
leave_review_on_screen_change=True
Values: on=''True'', off=''False''
==== Promote ====
"Promoted Lists" are configured in the section ''[promote]''.
Turn Promoted Lists" on or off:
enabled=True
Values: on=''True'', off=''False''
The minimum time interval of inactivity to activate promoting.
By default it promotes after 120 Seconds inactivity:
inactiveTimeoutSec=120
Values: in Seconds
Define a list of promoted words comma seperated:
list=
Values: text (comma seperated)
Example to promote the word "nickname" or a bash prompt:
list=nickname,$:,#:
==== Time ====
The automated time announcement is configured in the section ''[time]''.
Time announcement is disabled by default.
@@ -1270,7 +1266,7 @@ File: ''/usr/share/fenrirscreenreader/scripts/helloWorld__-__key_h.sh'':
===== Commands =====
You can place your own commands in "/usr/share/fenrirscreenreader/commands" (path is configurable in settings.conf).
Commands are python files with a special scheme. You can assign them to a shortcut using the filename without an extension or place them in a hook trigger like OnInput or OnScreenChange. For further information see developer guide.
Good Examples: [[https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/commands/date.py|"date.py"]] (announce the Date), [[https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/commands/shut_up.py|"shut_up.py"]] (interrupt output)
Good Examples: [[https://git.stormux.org/storm/fenrir/src/branch/master/src/fenrirscreenreader/commands/commands/date.py|"date.py"]] (announce the Date), [[https://git.stormux.org/storm/fenrir/src/branch/master/src/fenrirscreenreader/commands/commands/shut_up.py|"shut_up.py"]] (interrupt output)
the basic scheme for a command is as follows:
from core import debug
@@ -1289,7 +1285,7 @@ the basic scheme for a command is as follows:
def setCallback(self, callback):
pass
* [[https://github.com/chrys87/fenrir/blob/master/src/fenrir/commands/command_template.py|Template lives here]]
* [[https://git.stormux.org/storm/fenrir/src/branch/master/src/fenrirscreenreader/commands/command_template.py|Template lives here]]
* The class needs to have the name "command".
* "initialize" is running once whilst loading the command.
* "shutdown" is running on unload like the command (quit fenrir)
@@ -1319,14 +1315,15 @@ the basic scheme for a command is as follows:
- You can test if speech-dispatcher works by invoking it as root\\ ''sudo spd-say "hello world"''
===== Bugreports and feature requests =====
Please report Bugs and feature requests to:
[[https://github.com/chrys87/fenrir/issues|https://github.com/chrys87/fenrir/issues]]
[[https://git.stormux.org/storm/fenrir/issues|https://git.stormux.org/storm/fenrir/issues]]
for bugs please provide a [[#Howto create a debug file|debug]] file that shows the issue.
==== How-to create a debug file ====
- Delete old debug stuff\\ ''sudo rm /var/log/fenrir.log''
- Start fenrir in debug mode\\ ''sudo fenrir -d''
- Do your stuff to reproduce the problem
- Stop fenrir (''fenrirKey + q'')
the debug file is located in ''/var/log/fenrir.log''
the debug file is located in ''/tmp/fenrir.log''. If another Fenrir debug
instance is already using it, check ''/tmp/fenrir2.log'',
''/tmp/fenrir3.log'', etc.
Please be as precise as possible to make it easy to solve the problem.
+1 -1
View File
@@ -56,7 +56,7 @@ To test Fenrir:
sudo fenrir
To have Fenrir start on system boot using systemd:
download service file: https://raw.githubusercontent.com/chrys87/fenrir/master/autostart/systemd/Arch/fenrir.service
download service file: https://git.stormux.org/storm/fenrir/raw/branch/master/autostart/systemd/Arch/fenrir.service
move the service file to: /etc/systemd/system/fenrir.service
sudo systemctl enable fenrir
-12
View File
@@ -744,7 +744,6 @@ msgid "Script file is not executable"
msgstr "Файл скрипта не исполняемый"
#: ../src/fenrirscreenreader/commands/commands/temp_disable_speech.py:17
#: ../src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py:17
#: ../src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py:17
msgid "disables speech until next keypress"
msgstr "Отключить речь пока не нажата следующая клавиша"
@@ -898,7 +897,6 @@ msgid "speech disabled"
msgstr "Речь выключена"
#: ../src/fenrirscreenreader/commands/commands/toggle_speech.py:25
#: ../src/fenrirscreenreader/commands/onByteInput/15000-enable_temp_speech.py:24
#: ../src/fenrirscreenreader/commands/onKeyInput/15000-enable_temp_speech.py:28
msgid "speech enabled"
msgstr "Речь включена"
@@ -1089,15 +1087,6 @@ msgstr "Мерцание"
msgid "default"
msgstr "По умолчанию"
#: ../src/fenrirscreenreader/core/byteManager.py:103
#: ../src/fenrirscreenreader/core/byteManager.py:105
msgid "Sticky Mode On"
msgstr "Режим залипания включен"
#: ../src/fenrirscreenreader/core/byteManager.py:109
msgid "bypass"
msgstr ""
#: ../src/fenrirscreenreader/core/fenrirManager.py:26
msgid "Start Fenrir"
msgstr "fenrir запущен"
@@ -1216,4 +1205,3 @@ msgstr "Меню"
#: ../src/fenrirscreenreader/core/vmenuManager.py:234
msgid "Action"
msgstr "Действие"
+69
View File
@@ -0,0 +1,69 @@
[pytest]
# Pytest configuration for Fenrir screen reader
# Test discovery patterns
python_files = test_*.py *_test.py
python_classes = Test*
python_functions = test_*
# Test paths
testpaths = tests
# Minimum Python version
minversion = 3.7
# Output options
addopts =
# Verbose output with test names
-v
# Show extra test summary info
-ra
# Enable strict markers (only registered markers allowed)
--strict-markers
# Show local variables in tracebacks
--showlocals
# Warnings configuration
-W ignore::DeprecationWarning
# Optional plugins (uncomment if installed):
# --timeout=30 # Requires pytest-timeout
# --cov-report=term-missing # Requires pytest-cov
# -x # Stop on first failure
# Register custom markers
markers =
unit: Unit tests (fast, no mocking)
integration: Integration tests (require mocking)
driver: Driver tests (require root access)
slow: Tests that take more than 1 second
remote: Tests for remote control functionality
settings: Tests for settings and configuration
commands: Tests for command system
vmenu: Tests for VMenu system
# Coverage configuration
[coverage:run]
source = src/fenrirscreenreader
omit =
*/tests/*
*/vmenu-profiles/*
*/__pycache__/*
*/site-packages/*
[coverage:report]
# Fail if coverage falls below this percentage
# fail_under = 70
exclude_lines =
# Standard pragma
pragma: no cover
# Don't complain about missing debug code
def __repr__
# Don't complain if tests don't hit defensive assertion code
raise AssertionError
raise NotImplementedError
# Don't complain about abstract methods
@abstractmethod
# Don't complain about initialization
if __name__ == .__main__.:
[coverage:html]
directory = htmlcov
+1 -1
View File
@@ -1,6 +1,6 @@
daemonize
dbus-python
evdev
pexpect
pyenchant
pyperclip
pyte
+5 -2
View File
@@ -37,7 +37,7 @@ for directory in directories:
if not forceSettingsFlag:
try:
files = [f for f in files if not f.endswith('settings.conf')]
except:
except Exception as e:
pass
elif 'config/scripts' in directory:
destDir = '/usr/share/fenrirscreenreader/scripts'
@@ -103,9 +103,12 @@ setup(
"pyudev>=0.21.0",
"setuptools",
"setproctitle",
"pexpect",
"pyte>=0.7.0",
],
extras_require={
"dectalk_usb": ["pyusb>=1.2.1"],
"x11": ["python-xlib>=0.33"],
},
)
if not forceSettingsFlag:
+60 -25
View File
@@ -4,19 +4,22 @@
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
import argparse
import inspect
import os
import sys
import inspect
import argparse
from daemonize import Daemonize
from fenrirscreenreader import fenrirVersion
from fenrirscreenreader.core import fenrirManager
# Get the fenrir installation path
fenrirPath = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe()))))
if not fenrirPath in sys.path:
fenrirPath = os.path.dirname(os.path.realpath(
os.path.abspath(inspect.getfile(inspect.currentframe()))))
if fenrirPath not in sys.path:
sys.path.append(fenrirPath)
from fenrirscreenreader.core import fenrirManager
from fenrirscreenreader import fenrirVersion
def create_argument_parser():
"""Create and return the argument parser for Fenrir"""
@@ -27,7 +30,7 @@ def create_argument_parser():
argumentParser.add_argument(
'-v', '--version',
action='version',
version=f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.codeName}',
version=f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.code_name}',
help='Show version information and exit'
)
argumentParser.add_argument(
@@ -38,7 +41,7 @@ def create_argument_parser():
argumentParser.add_argument(
'-s', '--setting',
metavar='SETTING-FILE',
default='/etc/fenrir/settings/settings.conf',
default=None,
help='Path to custom settings file'
)
argumentParser.add_argument(
@@ -58,20 +61,21 @@ def create_argument_parser():
help='Print debug messages to screen'
)
argumentParser.add_argument(
'-e', '--emulated-pty',
'-x', '--x11',
action='store_true',
help='Use PTY emulation with escape sequences for input (enables desktop/X/Wayland usage)'
help='Use PTY emulation with X11 keyboard input scoped to the terminal window'
)
argumentParser.add_argument(
'-E', '--emulated-evdev',
action='store_true',
help='Use PTY emulation with evdev for input (single instance)'
'--x11-window-id',
metavar='WINDOWID',
default='',
help='X11 window id to use for --x11 terminal mode'
)
argumentParser.add_argument(
'-F', '--force-all-screens',
'-F',
'--force-all-screens',
action='store_true',
help='Force Fenrir to respond on all screens, ignoring ignoreScreen setting'
)
help='Force Fenrir to respond on all screens, ignoring ignoreScreen setting')
argumentParser.add_argument(
'-i', '-I', '--ignore-screen',
metavar='SCREEN',
@@ -80,36 +84,66 @@ def create_argument_parser():
)
return argumentParser
def validate_arguments(cliArgs):
"""Validate command line arguments"""
if cliArgs.options:
for option in cliArgs.options.split(';'):
if option and ('#' not in option or '=' not in option):
return False, f"Invalid option format: {option}\nExpected format: SECTION#SETTING=VALUE"
if cliArgs.emulated_pty and cliArgs.emulated_evdev:
return False, "Cannot use both --emulated-pty and --emulated-evdev simultaneously"
if cliArgs.x11_window_id and not cliArgs.x11:
return False, "--x11-window-id requires --x11"
return True, None
def run_fenrir():
"""Main function that runs Fenrir"""
fenrirApp = fenrirManager.fenrirManager(cliArgs)
fenrirApp.proceed()
del fenrirApp
fenrirApp = None
try:
fenrirApp = fenrirManager.FenrirManager(cliArgs)
fenrirApp.proceed()
except Exception as e:
print(f"Error starting Fenrir: {e}", file=sys.stderr)
sys.exit(1)
except KeyboardInterrupt:
print("Interrupted", file=sys.stderr)
sys.exit(1)
finally:
if fenrirApp and hasattr(fenrirApp, 'cleanup_on_error'):
try:
fenrirApp.cleanup_on_error()
except Exception as cleanup_error:
print(
f"Error during cleanup: {cleanup_error}", file=sys.stderr)
if fenrirApp:
del fenrirApp
# Clean up PID file if it exists
pidFile = "/run/fenrir.pid"
if os.path.exists(pidFile):
try:
os.remove(pidFile)
except Exception:
pass
def should_run_foreground(cliArgs):
return cliArgs.foreground or cliArgs.x11
def main():
global cliArgs
argumentParser = create_argument_parser()
cliArgs = argumentParser.parse_args()
# Validate arguments
isValid, errorMsg = validate_arguments(cliArgs)
if not isValid:
argumentParser.error(errorMsg)
sys.exit(1)
if cliArgs.foreground or cliArgs.emulated_pty:
if should_run_foreground(cliArgs):
# Run directly in foreground
run_fenrir()
else:
@@ -123,5 +157,6 @@ def main():
)
daemonProcess.start()
if __name__ == "__main__":
main()
@@ -2,20 +2,27 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return 'No description found'
def get_description(self):
return "No description found"
def run(self):
pass
def setCallback(self, callback):
def set_callback(self, callback):
pass
@@ -2,25 +2,38 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
# this command is just to initialize stuff.
# like init index lists in memoryManager
# like init index lists in MemoryManager
# it is not useful to execute it
class command():
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
# clipboard
self.env['runtime']['memoryManager'].addIndexList('clipboardHistory', self.env['runtime']['settingsManager'].getSettingAsInt('general', 'numberOfClipboards'))
self.env["runtime"]["MemoryManager"].add_index_list(
"clipboardHistory",
self.env["runtime"]["SettingsManager"].get_setting_as_int(
"clipboard", "number_of_clipboards"
),
)
def shutdown(self):
pass
def getDescription(self):
return 'No description found'
def get_description(self):
return "No description found"
def run(self):
pass
def setCallback(self, callback):
def set_callback(self, callback):
pass
@@ -2,53 +2,92 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import word_utils
import string
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import word_utils
initialized = False
try:
import enchant
initialized = True
except:
except Exception as e:
pass
class command():
class command:
def __init__(self):
self.language = ''
self.language = ""
self.spellChecker = None
def initialize(self, environment):
self.env = environment
self.updateSpellLanguage()
self.update_spell_language()
def shutdown(self):
pass
def getDescription(self):
return _('adds the current word to the exceptions dictionary')
def updateSpellLanguage(self):
self.spellChecker = enchant.Dict(self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage'))
self.language = self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage')
pass
def get_description(self):
return _("adds the current word to the exceptions dictionary")
def update_spell_language(self):
self.spellChecker = enchant.Dict(
self.env["runtime"]["SettingsManager"].get_setting(
"general", "spell_check_language"
)
)
self.language = self.env["runtime"]["SettingsManager"].get_setting(
"general", "spell_check_language"
)
def run(self):
if not initialized:
return
if self.env['runtime']['settingsManager'].getSetting('general', 'spellCheckLanguage') != self.language:
return
if (
self.env["runtime"]["SettingsManager"].get_setting(
"general", "spell_check_language"
)
!= self.language
):
try:
self.updateSpellLanguage()
self.update_spell_language()
except Exception as e:
return
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
return
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
# get the word
newContent = self.env['screen']['newContentText'].split('\n')[cursorPos['y']]
x, y, currWord, endOfScreen, lineBreak = word_utils.getCurrentWord(cursorPos['x'], 0, newContent)
currWord = currWord.strip(string.whitespace + r'!"#$%&\()*+,-./:;<=Â?@[\\]^_{|}~')
new_content = self.env["screen"]["new_content_text"].split("\n")[
cursor_pos["y"]
]
x, y, curr_word, end_of_screen, line_break = (
word_utils.get_current_word(cursor_pos["x"], 0, new_content)
)
curr_word = curr_word.strip(
string.whitespace + r'!"#$%&\()*+,-./:;<=Â?@[\\]^_{|}~'
)
if currWord != '':
if self.spellChecker.is_added(currWord):
self.env['runtime']['outputManager'].presentText(_('{0} is already in dictionary').format(currWord,), soundIcon='Cancel', interrupt=True)
if curr_word != "":
if self.spellChecker.is_added(curr_word):
self.env["runtime"]["OutputManager"].present_text(
_("{0} is already in dictionary").format(
curr_word,
),
sound_icon="Cancel",
interrupt=True,
)
else:
self.spellChecker.add(currWord)
self.env['runtime']['outputManager'].presentText(_('{0} added to dictionary').format(currWord,), soundIcon='Accept', interrupt=True)
self.spellChecker.add(curr_word)
self.env["runtime"]["OutputManager"].present_text(
_("{0} added to dictionary").format(
curr_word,
),
sound_icon="Accept",
interrupt=True,
)
def setCallback(self, callback):
def set_callback(self, callback):
pass
@@ -0,0 +1,108 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
import math
from fenrirscreenreader.core.i18n import _
class adjustment_command:
"""Base class for speech and sound adjustment commands"""
def __init__(self, section, setting, direction, step=0.1):
self.section = section # 'speech' or 'sound'
self.setting = setting # 'rate', 'pitch', 'volume'
self.direction = direction # 'inc' or 'dec'
self.step = step
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def get_description(self):
action = "Increase" if self.direction == "inc" else "Decrease"
if self.section == "speech":
return _(f"{action} the speech {self.setting}")
else:
return _(f"{action} the {self.section} {self.setting}")
def run(self):
if self.section == "sound" and self.setting == "volume":
# Sound volume uses different method
self._adjust_sound_volume()
else:
# Speech rate, pitch, volume use standard method
self._adjust_speech_setting()
def _adjust_speech_setting(self):
"""Adjust speech settings (rate, pitch, volume)"""
value = self.env["runtime"]["SettingsManager"].get_setting_as_float(
self.section, self.setting
)
# Apply adjustment with rounding
if self.direction == "inc":
value = round((math.ceil(10 * value) / 10) + self.step, 2)
if value > 1.0:
value = 1.0
else: # dec
value = round((math.ceil(10 * value) / 10) - self.step, 2)
if value < 0.0:
value = 0.0
# Set the new value
self.env["runtime"]["SettingsManager"].set_setting(
self.section, self.setting, str(value)
)
# Present feedback
percentage = int(value * 100)
if self.section == "speech":
feedback = _("{0} percent speech {1}").format(
percentage, self.setting
)
else:
feedback = _("{0} percent {1} {2}").format(
percentage, self.section, self.setting
)
self.env["runtime"]["OutputManager"].present_text(
feedback, sound_icon="", interrupt=True
)
def _adjust_sound_volume(self):
"""Adjust sound volume using same logic as speech"""
value = self.env["runtime"]["SettingsManager"].get_setting_as_float(
self.section, self.setting
)
# Sound volume uses same math as speech settings
if self.direction == "inc":
value = round((math.ceil(10 * value) / 10) + self.step, 2)
if value > 1.0:
value = 1.0
else: # dec
value = round((math.ceil(10 * value) / 10) - self.step, 2)
if value < 0.0:
value = 0.0
# Set the new value
self.env["runtime"]["SettingsManager"].set_setting(
self.section, self.setting, str(value)
)
# Present feedback with appropriate sound icon
percentage = int(value * 100)
sound_icon = "SoundOn" if self.direction == "inc" else "SoundOff"
feedback = _("{0} percent sound volume").format(percentage)
self.env["runtime"]["OutputManager"].present_text(
feedback, sound_icon=sound_icon, interrupt=True
)
def set_callback(self, callback):
pass
@@ -2,26 +2,36 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader import fenrirVersion
from fenrirscreenreader.core.i18n import _
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Present the version of Fenrir currrrently in use.')
def get_description(self):
return _("Present the version of Fenrir currently in use.")
def run(self):
try:
self.env['runtime']['outputManager'].presentText(f'Fenrir screen reader version {fenrirVersion.version}-{fenrirVersion.codeName}', interrupt=True)
except exception as e:
self.env['runtime']['outputManager'].presentText(_('Version information is unavailable.'), interrupt=True)
def setCallback(self, callback):
self.env["runtime"]["OutputManager"].present_text(
f"Fenrir screen reader version "
f"{fenrirVersion.version}-{fenrirVersion.code_name}",
interrupt=True,
)
except Exception as e:
self.env["runtime"]["OutputManager"].present_text(
_("Version information is unavailable."), interrupt=True
)
def set_callback(self, callback):
pass
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
from fenrirscreenreader.core.i18n import _
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def get_description(self):
return "Apply the last tested voice from safe voice browser"
def run(self):
try:
# Check if we have a tested voice
if (
"commandBuffer" not in self.env
or "lastTestedModule" not in self.env["commandBuffer"]
or "lastTestedVoice" not in self.env["commandBuffer"]
):
self.env["runtime"]["OutputManager"].present_text(
"No voice has been tested yet", interrupt=True
)
self.env["runtime"]["OutputManager"].present_text(
"Use voice browser first", interrupt=True
)
return
module = self.env["commandBuffer"]["lastTestedModule"]
voice = self.env["commandBuffer"]["lastTestedVoice"]
self.env["runtime"]["OutputManager"].present_text(
f"Applying {voice} from {module}", interrupt=True
)
# Apply to runtime settings only (temporary until saved)
SettingsManager = self.env["runtime"]["SettingsManager"]
# Store old values for safety
old_driver = SettingsManager.get_setting("speech", "driver")
old_module = SettingsManager.get_setting("speech", "module")
old_voice = SettingsManager.get_setting("speech", "voice")
try:
# Apply new settings to runtime only (use set_setting to update
# settingArgDict)
SettingsManager.set_setting(
"speech", "driver", "speechdDriver"
)
SettingsManager.set_setting("speech", "module", module)
SettingsManager.set_setting("speech", "voice", voice)
# Apply to speech driver instance directly
if "SpeechDriver" in self.env["runtime"]:
SpeechDriver = self.env["runtime"]["SpeechDriver"]
# Set the module and voice on the driver instance
SpeechDriver.set_module(module)
SpeechDriver.set_voice(voice)
self.env["runtime"]["OutputManager"].present_text(
"Voice applied successfully!", interrupt=True
)
self.env["runtime"]["OutputManager"].present_text(
"Use save settings to make permanent", interrupt=True
)
self.env["runtime"]["OutputManager"].play_sound("Accept")
except Exception as e:
# Revert on failure
SettingsManager.set_setting("speech", "driver", old_driver)
SettingsManager.set_setting("speech", "module", old_module)
SettingsManager.set_setting("speech", "voice", old_voice)
self.env["runtime"]["OutputManager"].present_text(
f"Failed to apply voice, reverted: {str(e)}",
interrupt=True,
)
self.env["runtime"]["OutputManager"].play_sound("Error")
except Exception as e:
self.env["runtime"]["OutputManager"].present_text(
f"Apply voice error: {str(e)}", interrupt=True
)
self.env["runtime"]["OutputManager"].play_sound("Error")
def set_callback(self, callback):
pass
@@ -2,29 +2,45 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import screen_utils
class command():
class command:
def __init__(self):
pass
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('Reads attributes of current cursor position')
def get_description(self):
return _("Reads attributes of current cursor position")
def run(self):
cursorPos = self.env['runtime']['cursorManager'].getReviewOrTextCursor()
cursor_pos = self.env["runtime"][
"CursorManager"
].get_review_or_text_cursor()
try:
attributes = self.env['runtime']['attributeManager'].getAttributeByXY( cursorPos['x'], cursorPos['y'])
attributes = self.env["runtime"][
"AttributeManager"
].get_attribute_by_xy(cursor_pos["x"], cursor_pos["y"])
except Exception as e:
print(e)
attributeFormatString = self.env['runtime']['settingsManager'].getSetting('general', 'attributeFormatString')
attributeFormatString = self.env['runtime']['attributeManager'].formatAttributes(attributes, attributeFormatString)
self.env['runtime']['outputManager'].presentText(attributeFormatString, soundIcon='', interrupt=True)
def setCallback(self, callback):
print(e)
attribute_format_string = self.env["runtime"][
"SettingsManager"
].get_setting("general", "attribute_format_string")
attribute_format_string = self.env["runtime"][
"AttributeManager"
].format_attributes(attributes, attribute_format_string)
self.env["runtime"]["OutputManager"].present_text(
attribute_format_string, sound_icon="", interrupt=True
)
def set_callback(self, callback):
pass
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '1'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(1, "read")
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '10'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(10, "read")
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '2'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_("blank"), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(2, "read")
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '3'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(3, "read")
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '4'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(4, "read")
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '5'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(5, "read")
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '6'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(6, "read")
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '7'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(7, "read")
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '8'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(8, "read")
@@ -2,47 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import mark_utils
from fenrirscreenreader.utils import line_utils
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '9'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('read Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
if not self.env['commandBuffer']['bookMarks'][self.ID]:
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} not set').format(self.ID,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
if not self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1']:
self.env['runtime']['outputManager'].presentText(_('Bookmark for application {0} not set').format(currApp,), interrupt=True)
return
# set marks
marked = ''
startMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['1'].copy()
if self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2']:
endMark = self.env['commandBuffer']['bookMarks'][self.ID][currApp]['2'].copy()
marked = mark_utils.getTextBetweenMarks(startMark, endMark, self.env['screen']['newContentText'])
else:
x, y, marked = \
line_utils.getCurrentLine(startMark['x'], startMark['y'], self.env['screen']['newContentText'])
if marked.isspace():
self.env['runtime']['outputManager'].presentText(_('blank'), soundIcon='EmptyLine', interrupt=True)
else:
self.env['runtime']['outputManager'].presentText(marked, interrupt=True)
def setCallback(self, callback):
pass
super().__init__(9, "read")
@@ -0,0 +1,211 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core.i18n import _
from fenrirscreenreader.utils import line_utils
from fenrirscreenreader.utils import mark_utils
class bookmark_command:
"""Base class for bookmark operations - read, set, clear"""
def __init__(self, bookmark_id, action="read"):
self.ID = str(bookmark_id)
self.action = action
def initialize(self, environment):
self.env = environment
# Always initialize bookmark structure - all commands need this
if self.ID not in self.env["commandBuffer"]["bookMarks"]:
self.env["commandBuffer"]["bookMarks"][self.ID] = {}
def shutdown(self):
pass
def get_description(self):
if self.action == "read":
return _("read Bookmark {0}").format(self.ID)
elif self.action == "set":
return _("set Bookmark {0}").format(self.ID)
elif self.action == "clear":
return _("remove Bookmark {0}").format(self.ID)
return f"{self.action} Bookmark {self.ID}"
def run(self):
if self.action == "read":
self._read_bookmark()
elif self.action == "set":
self._set_bookmark()
elif self.action == "clear":
self._clear_bookmark()
def _read_bookmark(self):
curr_app = self.env["runtime"][
"ApplicationManager"
].get_current_application()
if not self.env["commandBuffer"]["bookMarks"][self.ID]:
self.env["runtime"]["OutputManager"].present_text(
"Bookmark {0} not set".format(self.ID), interrupt=True
)
return
if curr_app not in self.env["commandBuffer"]["bookMarks"][self.ID]:
self.env["runtime"]["OutputManager"].present_text(
"Bookmark for application {0} not set".format(curr_app),
interrupt=True,
)
return
if not self.env["commandBuffer"]["bookMarks"][self.ID][curr_app].get(
"1"
):
self.env["runtime"]["OutputManager"].present_text(
"Bookmark for application {0} not set".format(curr_app),
interrupt=True,
)
return
# Get bookmarked text
marked = ""
start_mark = self.env["commandBuffer"]["bookMarks"][self.ID][curr_app][
"1"
].copy()
if self.env["commandBuffer"]["bookMarks"][self.ID][curr_app]["2"]:
end_mark = self.env["commandBuffer"]["bookMarks"][self.ID][
curr_app
]["2"].copy()
marked = mark_utils.get_text_between_marks(
start_mark, end_mark, self.env["screen"]["new_content_text"]
)
else:
x, y, marked = line_utils.get_current_line(
start_mark["x"],
start_mark["y"],
self.env["screen"]["new_content_text"],
)
if marked.isspace():
self.env["runtime"]["OutputManager"].present_text(
_("blank"), sound_icon="EmptyLine", interrupt=True
)
else:
self.env["runtime"]["OutputManager"].present_text(
marked, interrupt=True
)
def _set_bookmark(self):
if not self.env["commandBuffer"]["Marks"]["1"]:
self.env["runtime"]["OutputManager"].present_text(
_("No mark found"), interrupt=True
)
return
curr_app = self.env["runtime"][
"ApplicationManager"
].get_current_application()
self.env["commandBuffer"]["bookMarks"][self.ID][curr_app] = {}
bookmarks = self.env["commandBuffer"]["bookMarks"][self.ID][curr_app]
bookmarks["1"] = self.env["commandBuffer"]["Marks"]["1"].copy()
if self.env["commandBuffer"]["Marks"]["2"]:
bookmarks["2"] = self.env["commandBuffer"]["Marks"]["2"].copy()
else:
bookmarks["2"] = None
self.env["runtime"]["OutputManager"].present_text(
_("Bookmark {0} set for application {1}").format(
self.ID, curr_app
),
interrupt=True,
)
# Clear marks after setting bookmark
self.env["commandBuffer"]["Marks"]["1"] = None
self.env["commandBuffer"]["Marks"]["2"] = None
def _clear_bookmark(self):
curr_app = self.env["runtime"][
"ApplicationManager"
].get_current_application()
bookmarks = self.env["commandBuffer"]["bookMarks"]
if self.ID in bookmarks and curr_app in bookmarks[self.ID]:
del self.env["commandBuffer"]["bookMarks"][self.ID][curr_app]
self.env["runtime"]["OutputManager"].present_text(
_("Bookmark {0} removed for application {1}").format(
self.ID, curr_app
),
interrupt=True,
)
else:
self.env["runtime"]["OutputManager"].present_text(
_("Bookmark {0} not set for application {1}").format(
self.ID, curr_app
),
interrupt=True,
)
def set_callback(self, callback):
pass
# Factory function to create bookmark command instances
def create_bookmark_commands():
"""Create all bookmark command instances"""
commands = {}
# Create read bookmark commands (bookmark_1 through bookmark_10)
for i in range(1, 11):
commands[f"bookmark_{i}"] = lambda i=i: bookmark_command(i, "read")
# Create set bookmark commands (set_bookmark_1 through set_bookmark_10)
for i in range(1, 11):
commands[f"set_bookmark_{i}"] = lambda i=i: bookmark_command(i, "set")
# Create clear bookmark commands (clear_bookmark_1 through
# clear_bookmark_10)
for i in range(1, 11):
commands[f"clear_bookmark_{i}"] = lambda i=i: bookmark_command(
i, "clear"
)
return commands
# For backwards compatibility, provide individual command classes
# This allows the existing command loading system to work unchanged
def _make_command_class(bookmark_id, action):
"""Create a command class for a specific bookmark and action"""
class command(bookmark_command):
def __init__(self):
super().__init__(bookmark_id, action)
return command
# Generate individual command classes for each bookmark operation
# These will be used by the existing command loading system
# Read bookmarks (bookmark_1.py style)
for i in range(1, 11):
globals()[f"bookmark_{i}_command"] = _make_command_class(i, "read")
# Set bookmarks (set_bookmark_1.py style)
for i in range(1, 11):
globals()[f"set_bookmark_{i}_command"] = _make_command_class(i, "set")
# Clear bookmarks (clear_bookmark_1.py style)
for i in range(1, 11):
globals()[f"clear_bookmark_{i}_command"] = _make_command_class(i, "clear")
@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '1'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(1, "clear")
@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '10'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(10, "clear")
@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '2'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(2, "clear")
@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__), "bookmark_base.py")
_spec = importlib.util.spec_from_file_location("bookmark_base", _base_path)
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
bookmark_command = _module.bookmark_command
class command(bookmark_command):
def __init__(self):
self.ID = '3'
def initialize(self, environment):
self.env = environment
def shutdown(self):
pass
def getDescription(self):
return _('remove Bookmark {0}').format(self.ID,)
def run(self):
currApp = self.env['runtime']['applicationManager'].getCurrentApplication()
del self.env['commandBuffer']['bookMarks'][self.ID][currApp]
self.env['runtime']['outputManager'].presentText(_('Bookmark {0} removed for application {1}').format(self.ID, currApp), interrupt=True)
def setCallback(self, callback):
pass
super().__init__(3, "clear")
@@ -2,26 +2,20 @@
# -*- coding: utf-8 -*-
# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.
# By Chrys, Storm Dragon, and contributors.
from fenrirscreenreader.core import debug
import importlib.util
import os
class command():
from fenrirscreenreader.core.i18n import _
_base_path = os.path.join(os.path.dirname(__file__<