A Note on the Use of AI in JAWS Scripting
Introduction
The rapid advancement of Large Language Models (LLMs) and Artificial Intelligence (AI) has fundamentally transformed software development practices across the industry. Tools such as GitHub Copilot, ChatGPT, Claude, and various open-source alternatives have become integral to modern development workflows, with Google reporting that "the same amount of characters in the code are now completed with AI-based assistance as are manually typed by developers". This transformation has led many developers to explore AI-assisted code generation for specialized scripting languages, including JAWS Scripting Language (JSL).
However, the application of LLMs to specialized, low-resource programming languages like JAWS Scripting Language presents unique challenges that warrant careful examination. This chapter explores both the potential benefits and significant limitations of using AI for JAWS script generation, supported by current research on LLM code generation capabilities and their particular struggles with domain-specific languages.
The Promise and Reality of AI-Assisted Code Generation
Advantages of Using LLMs for Code Generation
When applied appropriately, LLMs and AI can offer several advantages in software development:
-
Increased productivity: LLMs can automate routine code generation tasks, allowing developers to focus on higher-level aspects of projects such as architecture, design decisions, and complex problem-solving.
-
Faster development cycles: By leveraging LLMs, developers can rapidly prototype and iterate on their ideas, potentially reducing time-to-market for new features and applications.
-
Reduced human error: Automated code generation can minimize certain types of human errors, such as typos or basic syntax mistakes, when the model has sufficient training data and the language is well-represented.
-
Consistent formatting: LLMs can help ensure that generated code adheres to consistent formatting and coding conventions, improving code readability and maintainability when properly configured.
-
Learning assistance: For developers new to a language or framework, LLMs can provide examples and explanations that facilitate learning, though these must be carefully verified.
-
Boilerplate generation: LLMs excel at generating repetitive code structures and standard implementations that follow well-established patterns.
General Disadvantages and Limitations
Despite these advantages, LLMs face significant challenges in code generation:
-
Lack of deep understanding: LLMs struggle to grasp intricate details and nuances of specific project requirements, leading to potential inaccuracies or incomplete code that may appear correct superficially but fail under real-world conditions.
-
Functional correctness issues: Generated code may run successfully but fail to pass all unit tests due to logic errors and misunderstandings, producing output that does not fully satisfy intended functionality or performance criteria.
-
Complex requirement handling: LLMs often struggle with generating code for complex or highly specific scenarios that require domain expertise and manual intervention.
-
Security vulnerabilities: AI-generated code can inadvertently introduce security vulnerabilities or expose sensitive information if proper security measures are not rigorously validated.
-
Dynamic content challenges: LLMs may struggle to generate code that effectively handles dynamic or user-generated content, such as robust input validation or real-time data processing.
-
Hallucination problems: LLMs frequently "hallucinate" by fabricating package names, APIs, or functions that do not exist, creating code that appears plausible but is fundamentally broken.
-
Overconfidence: LLMs deliver outputs with unshakable confidence, even when generating incorrect or fabricated code, making it difficult for less experienced developers to identify problems.
The Challenge of Low-Resource Programming Languages
Understanding Low-Resource and Domain-Specific Languages
JAWS Scripting Language falls into the category of Low-Resource Programming Languages (LRPLs) and Domain-Specific Languages (DSLs). Research has shown that LRPLs and DSLs face unique challenges, including severe data scarcity and highly specialized syntax and semantics that are poorly represented in general-purpose datasets.
The lack of specialized datasets and benchmarks, combined with limited research focus on LRPLs and DSLs, has resulted in fewer advancements in handling these languages effectively. This creates a significant gap in LLM capabilities when developers attempt to use these tools for specialized scripting tasks.
Technical Architecture of JAWS Scripting
Before examining the specific challenges LLMs face with JAWS scripting, it is essential to understand the technical architecture and compilation model that makes JAWS scripting fundamentally different from interpreted scripting languages that LLMs encounter more frequently.
The Compiled Nature of JAWS Scripts
JAWS Scripting Language is a compiled, proprietary language, not an interpreted scripting language. This distinction has profound implications for development workflow and for LLM-generated code:
-
Source to binary compilation: JAWS scripts are written in human-readable source files (.jss) that must be compiled into machine-readable binary files (.jsb) before execution. The compilation process is performed by either:
-
SCompile.exe - A command-line compiler located in the JAWS program directory (typically
C:\Program Files\Freedom Scientific\JAWS[version]\scompile.exe) -
The JAWS Script Manager - An integrated development environment accessed via INSERT+F2, which provides compilation, editing, and debugging capabilities
-
-
Compilation syntax checking: The compiler performs strict syntax validation, rejecting any code that violates JSL grammar rules. Error messages report the specific file, line number, and column where syntax violations occur (e.g., "file notepad.jss, line 5, column 1: Unknown variable ioi").
-
Language-specific compilation: A critical technical limitation is that scompile.exe always compiles scripts for the language of the currently-running JAWS instance. This means that generating a .jsb file in a folder for another language actually compiles the script for the running language, not the target language. Multi-language script distribution requires specialized build tools or JAWSUtil.vbs scripts.
-
Binary protection: The compiled .jsb files serve a dual purpose - performance optimization and intellectual property protection through source code obscuration. Users cannot read .jsb files to understand script logic without access to the original .jss source files.
-
Deployment requirements: For scripts to function, the compiled .jsb files must be placed in specific directory structures:
-
User-specific settings:
C:\Users[username]\AppData\Roaming\Freedom Scientific\JAWS[version]\Settings\enu\ -
All-users settings:
C:\ProgramData\Freedom Scientific\JAWS[version]\Settings\enu\
-
-
Script reloading: After compilation, JAWS must reload the scripts to recognize changes. This typically requires either restarting JAWS or explicitly reloading the script file for the active application.
The Multi-File Architecture
Professional JAWS script development involves coordinating multiple file types, each serving distinct purposes:
-
.jss (JAWS Script Source): Contains the executable script code, user-defined functions, and event handlers. This is the primary file that developers write and that must be compiled.
-
.jsb (JAWS Script Binary): The compiled machine code generated from .jss files. JAWS reads only .jsb files at runtime; .jss files serve solely as source for development.
-
.jsh (JAWS Script Header): Defines global variables, constants, window names, window classes, and external function declarations. By convention, constants for window names use "wn" prefix, window classes use "wc", and global variables use "g" prefixes (gi for global integer, gs for global string, etc.).
-
.jsm (JAWS Script Messages): Contains all localizable strings, spoken messages, and on-screen text used for comparison. Messages use "msg" prefix, comparison strings use "sc" prefix. This separation enables internationalization without modifying script logic.
-
.jkm (JAWS Key Map): Defines keyboard shortcuts that trigger specific scripts. Uses a proprietary syntax for mapping key combinations to script names. Organized by keyboard layout (Desktop, Laptop, etc.).
-
.jsd (JAWS Script Documentation): Contains structured documentation for each script and function, including synopsis, description, parameters, and return values. JAWS reads this file to provide Keyboard Help (INSERT+F1) information to users.
-
.jcf (JAWS Configuration): Stores application-specific configuration settings and user preferences for how JAWS should behave with particular applications.
-
.jdf (JAWS Default): Defines default settings and behaviors that JAWS should apply when no custom scripts exist for an application.
The coordination between these files follows strict conventions detailed in Chapter [scripting-standards]{reference-type="ref" reference="scripting-standards"}. For example, a message defined in the .jsm file as msgButtonText = "Click the button" would be referenced in the .jss file using SayFormattedMessage(msgButtonText, sButtonName) where sButtonName is a string variable containing the actual button name.
The Windows Accessibility API Layer
JAWS scripts operate at the intersection of multiple Windows accessibility APIs, each with different characteristics and capabilities:
MSAA (Microsoft Active Accessibility) The legacy API introduced in Windows 95, based on the Component Object Model (COM). MSAA exposes basic information such as object name, role, location, and state through the IAccessible interface. MSAA uses a hierarchical model with parent-child relationships and supports simple child elements identified by numeric Child IDs.
IAccessible2 An extension of MSAA developed by IBM and placed under the Linux Foundation. IAccessible2 fills perceived omissions in MSAA by adding support for:
- Complex text attributes and text formatting
- Table navigation with row/column headers
- Relations between objects (e.g., labels for controls)
- Unique object identifiers that persist across sessions
- Enhanced state information beyond MSAA's basic states
IAccessible2 does not support child IDs; full accessible objects must be created for each element. JAWS scripts must use QueryService to switch between MSAA IAccessible and IAccessible2 interfaces.
UI Automation (UIA) Microsoft's modern accessibility API introduced in Windows Vista and .NET Framework 3.0. UIA marks a radical architectural departure from MSAA, using a provider/client model rather than COM-based interfaces. Key differences include:
- Separate provider-side (application) and client-side (AT) APIs
- Rich support for patterns (interfaces) that controls implement
- More detailed element property exposure
- Event model based on property changes rather than focus changes
- Out-of-process operation for improved security and stability
UIA Express (IAccessibleEx) A bridge interface that allows mapping between UI Automation elements and MSAA interfaces, enabling interoperability during the MSAA-to-UIA transition period.
JAWS provides native support for all these APIs, but scripters must understand which API is being used by target applications and choose appropriate functions accordingly. The JAWS UIA Script API, introduced in JAWS 2020, gives scripters direct access to the UI Automation infrastructure through functions like:
-
FSUIA_CreateElement() - Creates a UIA element object from a window handle
-
FSUIA_GetProperty() - Retrieves UIA property values (returns VARIANT type)
-
FSUIA_FindFirst() and FSUIA_FindAll() - Search for elements using UIA tree walker patterns
-
ComAttachEvents() - Registers event handlers for UIA property changes, structure changes, and automation events
The UIA API uses pre-defined integer constants for element types, property identifiers, pattern identifiers, and control types, all declared in the UIA.jsh header file provided with JAWS.
Specific Challenges for JAWS Scripting Language
Given this technical architecture, JAWS Scripting Language presents several unique challenges that make it particularly problematic for LLM-based code generation:
-
Extremely limited training data: Unlike popular languages such as Python, JavaScript, or Java, JAWS scripts are rarely published in open-source repositories. The proprietary nature of many JAWS scripts and the small size of the JAWS scripting community mean that LLMs have minimal exposure to actual JSL code during training.
-
Unique syntax and semantics: JAWS Scripting Language is a proprietary compiled language with syntax patterns that differ significantly from mainstream languages. Without substantial training examples, LLMs frequently confuse JSL with more common languages like JavaScript, Python, Visual basic, and C#.
-
Cross-contamination with other screen reader languages: NVDA uses Python for scripting, while other assistive technologies use different languages. LLMs often generate hybrid code that borrows inappropriately from these other ecosystems, producing syntactically invalid JSL.
-
Specialized domain knowledge: Effective JAWS scripting requires deep understanding of:
-
Windows accessibility APIs
-
Screen reader interaction patterns
-
Application-specific behaviors
-
User experience considerations for blind and low-vision users
-
JAWS-specific functions and event handlers
-
-
Compilation requirements: A critical issue that LLMs consistently fail to address is that JAWS scripts must be compiled from .jss source files into .jsb binary files using either SCompile.exe or the JAWS Script Manager. LLMs rarely mention this essential step, leading users to wonder why their generated scripts do not function. The compilation process involves:
-
Running scompile.exe application.jss from the command line in the appropriate settings directory
-
Or using CTRL+S in the JAWS Script Manager to save and compile simultaneously
-
Receiving either "Compile Complete" (success) or detailed error messages with line/column information
-
Understanding that syntax errors completely prevent .jsb generation - there is no partial compilation
-
Recognizing that even successfully compiled scripts require JAWS to reload them before changes take effect
-
-
File structure complexity: JAWS scripting involves multiple coordinated files:
-
.jss (JAWS script source files)
-
.jsm (JAWS script message files for localization)
-
.jsh (JAWS script header files for constants and globals)
-
.jkm (JAWS key map files)
-
.jcf (JAWS configuration files)
-
.jdf (JAWS default files)
-
.jsb (compiled script binaries)
LLMs typically generate only .jss content and fail to properly structure the supporting files required for professional script development.
-
Evidence from Research
Research on code generation for low-resource languages provides empirical evidence for these challenges. On the HumanEval benchmark, Codex could solve about 28.8% of tasks on the first attempt for well-represented languages, but performance drops dramatically for languages with limited training data.
General-purpose LLMs consistently fail at scale when faced with deep interdependencies, language-specific constraints, and intricate build systems. For JAWS scripting, these challenges are compounded by the language's specialized nature and the limited feedback available to train models.
Package Hallucination: A Critical Security Concern
The Nature of Package Hallucinations
One of the most serious issues with LLM-generated code is the phenomenon of "package hallucination" or "API hallucination." Package hallucination occurs when LLMs generate code that references or recommends packages that do not exist in any public repositories.
Research has found alarming rates of hallucination:
-
21.7% of package names recommended by open-source AI models were hallucinations, while commercial models hallucinated 5.2% of package names
-
In testing across four LLMs, between 22.5% and 64.5% of conversations generated hallucinated packages
-
Code generators referenced some 440,445 hallucinated packages, including 205,474 unique examples of totally invented package names
Security Implications
The security implications of package hallucinations are severe. An adversary can create a malicious package with the same name as a hallucinated package and inject malicious code, which unsuspecting users will download and execute.
This attack vector is similar to phishing, exploiting the trust users have in the model and relying on users not performing due diligence. For JAWS scripting, where scripts often have deep system access and can monitor user activity, the security risks of executing malicious code are particularly severe.
Persistence and Exploitability
The hallucination problem is not just pervasive but also persistent, with LLMs repeatedly recommending the same fictitious packages. This persistence makes the attack vector more viable, as malicious actors can reliably predict which hallucinated names to register.
Research shows that even when different developers ask LLMs questions about the same topic but craft questions differently, there is a likelihood the LLM would recommend the same hallucinated package in each case.
The "Vibe Coding" Phenomenon and Its Risks
Defining Vibe Coding
A troubling trend in AI-assisted development is "vibe coding"--the practice of rapidly prototyping or building entire applications by following LLM suggestions without deeply understanding or reviewing the code. The focus is on speed rather than security or verification, with developers accepting AI-generated suggestions without hesitation.
Risks for JAWS Scripting
For JAWS scripting, vibe coding poses exceptional risks:
-
Accessibility Impact: Poorly written JAWS scripts directly affect users who are blind or have low vision, potentially making applications less accessible rather than more accessible.
-
System Stability: Buggy scripts can cause JAWS to crash or behave unpredictably, disrupting critical assistive technology that users depend on for computer access.
-
Privacy Concerns: JAWS scripts can access screen content, keystrokes, and other sensitive information. Malicious or poorly vetted code poses significant privacy risks.
-
False Confidence: Users may believe LLM-generated scripts are correct because they compile and appear to run, not realizing they may contain subtle bugs or security issues.
-
Maintenance Burden: Scripts generated without deep understanding become technical debt, difficult to maintain or debug when issues arise.
Code Quality Issues in LLM-Generated Code
Types of Hallucinations and Errors
Research has identified several categories of problems in LLM-generated code:
-
Syntax violations: State-of-the-art models like GPT-4.1, Codex, and GPT-4o exhibit high frequencies of syntax violations, particularly in less common languages.
-
Invalid reference errors: Generated code frequently contains invalid reference errors, calling functions or using variables that do not exist.
-
API knowledge conflicts: LLMs demonstrate API knowledge conflicts, mixing APIs from different frameworks or versions.
-
Definition missing: LLMs occasionally omit variable or function definitions that are required before use.
-
Incorrect boundary conditions: Generated programs fail to verify boundary conditions properly, leading to runtime errors.
-
Logic errors and misunderstandings: LLMs struggle to extract information from natural language and establish correct logic, particularly for algorithmic problems.
-
Timeout issues: While LLM-generated code may be correct, algorithms are often suboptimal with high time complexity.
Recent studies on DSL code generation provide quantitative evidence. Research on DSLs with approximately 700 custom API functions found:
-
Fine-tuned models achieved lower hallucination rates but higher syntax error rates
-
RAG-based models demonstrated better syntax correctness (2 percentage points higher compilation rates)
-
Both approaches struggled with custom function names, with hallucination rates between 22.5% and 64.5% of conversations generating hallucinated packages
-
Multiple iterations were required to achieve correct syntax - in one robotics DSL study, LLMs required up to 117 rounds of refinement
For DSLs specifically, research highlights that "performance drops noticeably" compared to general-purpose languages, with hallucinations and syntax errors increasing particularly for DSLs with high numbers of custom function names.
JAWS-Specific Code Quality Concerns
For JAWS scripting, LLMs exhibit additional quality issues:
-
Generating pseudocode rather than valid JSL syntax
-
Mixing Python constructs from NVDA scripting with JSL
-
Failing to use proper JAWS function names and signatures
-
Incorrectly handling event-driven programming patterns
-
Omitting required message file (.jsm) and header file (.jsh) definitions
-
Generating scripts that violate Freedom Scientific's scripting standards
-
Creating code that compiles but produces incorrect speech output or behavior
-
Failing to properly handle cursor management and state restoration
Detailed examination of common LLM failures reveals specific patterns:
Syntax Confusion Between Screen Readers
LLMs frequently mix syntax from different screen reader scripting languages:
Python/NVDA contamination LLMs often generate code like:
``` {style="Alabaster"}
\# INCORRECT - Python/NVDA syntax, not JAWS
def AutoStartEvent():
ui.message("Application started")
return True
```
Correct JAWS syntax would be:
``` {style="Alabaster"}
; CORRECT - JAWS Script Language syntax
Void Function AutoStartEvent()
SayMessage(OT_USER_BUFFER, msgAppStarted)
EndFunction
```
Lua/SuperNova contamination Occasionally LLMs mix Lua-like syntax:
``` {style="Alabaster"}
-- INCORRECT - Lua syntax, not JAWS
function sayWindowName()
local windowName = getWindowName()
speak(windowName)
end
```
Javascript Occasionally LLMs mix javascript-like syntax:
``` {style="Alabaster"}
// Javascript (not JAWS scripting), Often seen in web-related contexts and .js can be confused with .jss
// INCORRECT for JAWS: browser/DOM-focused example
function sayApplicationName() {
const windowName = document.title || window.name;
console.log(windowName); // or use a TTS API in a browser
}
```
C# Occasionally LLMs mix C-Sharp-like syntax:
``` {style="Alabaster"}
// C\# (desktop example using System.Windows.Forms; not JAWS code)
// INCORRECT for JAWS: managed WinForms example
using System;
using System.Windows.Forms;
public void SayApplicationName()
{
string windowName = Form.ActiveForm?.Text ?? "Unknown";
Console.WriteLine(windowName); // placeholder for speech API
}
```
VB.NET Occasionally LLMs mix Visual Basic .NET-like syntax:
``` {style="Alabaster"}
// Visual Basic .NET (not JAWS scripting)
' INCORRECT for JAWS: VB.NET example
Sub SayApplicationName()
Dim windowName As String = If(Application.OpenForms.Count > 0, Application.OpenForms(0).Text, "Unknown")
Console.WriteLine(windowName) ' placeholder for speech API
End Sub
```
Generic pseudocode Most commonly, LLMs generate syntactically invalid pseudocode:
``` {style="Alabaster"}
// INCORRECT - Generic pseudocode
script SayApplicationName() {
windowName = GetWindowName();
Speak(windowName);
}
```
Function Name and Signature Errors
LLMs frequently hallucinate function names or use incorrect parameters:
-
Non-existent functions: Generating calls like GetControlText(handle), SpeakText(string), or ReadCurrentLine() - functions that sound plausible but do not exist in the JAWS API.
-
Incorrect parameter types: Calling existing functions with wrong parameter types, such as:
; INCORRECT - SayString takes int for output mode, not string SayString("Text to speak", "user_buffer") ; CORRECT SayString("Text to speak", OT_USER_BUFFER) -
Missing required parameters: Omitting mandatory parameters like the output type parameter in Say() functions.
-
API version conflicts: Mixing functions from different JAWS versions, calling functions not available until JAWS 17 in code supposedly targeting JAWS 13.
Event Handler Misunderstandings
LLMs demonstrate poor understanding of JAWS event-driven architecture:
-
Incorrect event signatures: Generating Function FocusChangedEvent() without the required handle hWindow parameter.
-
Missing return types: Omitting Void or proper return type declarations for event functions.
-
Failure to call default handlers: Not including FocusChangedEvent(hWindow) calls to invoke default behavior after custom processing.
-
Global variable management errors: Not updating necessary global variables like gCurrentWindow or ghLastFocus within event handlers.
-
Performance-critical event misuse: Placing computationally expensive operations in frequently-called events like KeyPressedEvent(), causing JAWS to become sluggish.
File Structure and Organization Failures
LLMs typically generate only .jss content and fail to properly structure supporting files:
-
Message definition omission: Using string literals directly in scripts instead of defining messages in .jsm files:
; INCORRECT - Hardcoded string, not localizable SayString("Click the OK button") ; CORRECT - Message from .jsm file SayMessage(OT_USER_BUFFER, msgClickOK) -
Constant definition failures: Not defining window names, window classes, or comparison strings as constants in .jsh files.
-
Global variable declaration errors: Defining global variables in .jss files instead of .jsh files, causing scope issues.
-
Key mapping omission: Generating scripts without corresponding .jkm entries, leaving scripts impossible to trigger.
-
Documentation generation failures: Not creating proper .jsd documentation with Synopsis and Description fields required for Keyboard Help.
Cursor Management and State Restoration Bugs
LLMs generate code that violates critical cursor management principles:
; INCORRECT - Activates JAWS Cursor without saving/restoring PC Cursor
Function GetStatusBarText()
JAWSCursorHome()
JAWSCursorDown()
Let sText = GetLine()
Return sText
EndFunction
; CORRECT - Proper cursor save/restore
Function GetStatusBarText()
Var
String sText,
Int iSavedCursor
Let iSavedCursor = SaveCursor()
RouteJAWSToPC()
JAWSCursorHome()
JAWSCursorDown()
Let sText = GetLine()
RestoreCursor(iSavedCursor)
Return sText
EndFunction
Common cursor-related errors include:
-
Not calling SaveCursor() before cursor activation
-
Not calling RestoreCursor() afterward
-
Using JAWS Cursor when Invisible Cursor would be appropriate
-
Not considering whether PC Cursor, JAWS Cursor, or UIA Scan Cursor is most appropriate
Why LLMs Struggle with JAWS Scripting
Training Data Scarcity
The efficacy of language models is constrained by both the volume and quality of available annotated data, a limitation especially pronounced in low-resource programming languages. For JAWS scripting:
-
Few JAWS scripts are available in public repositories
-
Most professional scripts are proprietary (ie., sold by Freedom Scientific, third-party developers, or free but shipped as .exe binaries that install .jsb and .jkm files without the .jss source)
-
Freedom Scientific's documentation exists but is limited compared to mainstream language resources
-
The community is small relative to general programming communities
-
Script examples in forums and documentation are often incomplete snippets rather than full implementations
Specialized Knowledge Requirements
LLMs struggle with specialized hardware or software platforms and industries with strict regulatory requirements. JAWS scripting requires understanding of:
-
Assistive technology principles and best practices
-
Screen reader user experience patterns
-
Windows accessibility API hierarchies (MSAA, UI Automation, IAccessible2)
-
Application-specific object models
-
Proper cursor management techniques
-
Event-driven programming in the JAWS context
-
Speech and braille output considerations
-
Localization and internationalization for screen readers
Each of these areas requires deep technical knowledge that extends far beyond syntax:
Assistive Technology Design Principles
Effective JAWS scripts must embody AT-specific design principles that have no analogs in general-purpose programming:
-
Non-visual information architecture: Understanding how to present information sequentially that sighted users perceive simultaneously. For example, a dashboard with multiple panels requires careful script design to announce each panel's heading and content in logical order.
-
Cognitive load management: Scripts must avoid overwhelming users with excessive speech while providing sufficient information for task completion. This balance differs fundamentally from visual UI design.
-
Progressive disclosure: JAWS scripts typically announce summary information first, with detailed information available through subsequent keystrokes (e.g., first keystroke speaks synopsis, double-press speaks description).
-
Braille vs. speech considerations: Information displayed in Braille often requires different formatting than spoken output. Speech can use inflection and pacing; Braille must rely on punctuation and structure.
Windows Accessibility API Expertise
Understanding the technical differences between accessibility APIs is essential for effective scripting:
MSAA Limitations MSAA's IAccessible interface provides only basic information: name, role, description, value, state, location. For complex applications, scripters must often work around MSAA's limitations by:
- Using the Invisible Cursor to read on-screen text when object information is insufficient
- Parsing concatenated strings that applications incorrectly expose as single values
- Implementing workarounds for controls that expose incorrect or incomplete role information
IAccessible2 Capabilities When applications support IAccessible2, scripters can access rich text attributes, table structures, and object relations. However, this requires:
-
Using QueryService to obtain IAccessible2 interfaces from MSAA IAccessible references
-
Understanding that IAccessible2 does not support child IDs - full accessible objects must exist
-
Working with unique IDs that persist for object lifetime within the current window
-
Handling relation sets to navigate from controls to their labels or vice versa
UI Automation Complexity The UIA API introduces pattern-based programming where controls implement specific patterns (Value, Selection, Grid, etc.). Scripters must:
- Create FSUIA objects and attach event handlers using ComAttachEvents()
- Understand that UIA elements are tree-structured with multiple tree views (Raw, Control, Content)
- Work with VARIANT return types that may contain strings, integers, booleans, or element references
- Implement proper element caching strategies to avoid performance issues
- Handle the asynchronous nature of UIA events properly
- Manage object lifetime carefully to prevent memory leaks or dangling references
Cursor Management Patterns
JAWS provides multiple cursor types, each with specific use cases and technical requirements:
PC Cursor The standard Windows focus/caret. Scripts should respect PC Cursor position and avoid disrupting it unnecessarily.
JAWS Cursor An on-screen cursor that can read any visible text, including text that applications do not expose through accessibility APIs. Technical considerations include:
- Storing PC Cursor position before activating JAWS Cursor: SaveCursor()
- Positioning the JAWS Cursor: RouteJAWSToPC(), JAWSCursorUp(), etc.
- Reading text: GetLine(), GetWord(), GetCharacter()
- Restoring PC Cursor: RestoreCursor()
- Performance implications of Off-Screen Model (OSM) rendering
Invisible Cursor Similar to JAWS Cursor but operates without moving the user's focus. Critical for reading information without disrupting user workflow. Used via:
- RouteInvisibleToPC(), InvisibleCursorUp(), etc.
- GetLineWithCursor(Invisible_Cursor)
- Must save/restore PC Cursor position identically to JAWS Cursor
UIA Scan Cursors Introduced in JAWS 2020 to work with applications using UI Automation that render poorly in the traditional OSM. Technical differences include:
- JAWS Scan Cursor: GetLineWithCursor(JAWSScan_Cursor)
- Invisible Scan Cursor: GetLineWithCursor(InvisibleScan_Cursor)
- Navigate through UIA tree structure rather than screen coordinates
- More reliable for modern applications but with different navigation semantics
- Require understanding of UIA element tree hierarchies
The choice of cursor depends on application architecture, available accessibility API support, and specific task requirements. LLMs cannot reliably make these architectural decisions without deep understanding of screen reader internals.
Event-Driven Programming Patterns
JAWS scripting is fundamentally event-driven, with specific event functions that the JAWS engine calls when conditions occur:
-
AutoStartEvent() - Called when JAWS loads for an application
-
WindowCreatedEvent(handle hWindow) - Called when windows are created
-
FocusChangedEvent(handle hWindow) - Called when focus moves between windows
-
ActiveItemChangedEvent() - Called when active item changes in lists/trees
-
ValueChangedEvent() - Called when control values change
-
NewTextEvent() - Called when new text appears
-
KeyPressedEvent(string sKey) - Called before keys are passed to applications
-
MenuModeEvent(int iMode) - Called when menus are activated/deactivated
Effective use of these events requires understanding:
-
When each event fires relative to application state changes
-
How to avoid performance problems by keeping event handlers efficient
-
Which global variables must be updated within each event handler
-
How events interact with user buffer state and virtual cursor modes
-
When to call default event handlers vs. implementing custom behavior
LLMs frequently generate key-driven code (scripts bound to keystrokes) when event-driven code would be more appropriate and reliable.
The Compilation Knowledge Gap
A particularly problematic gap is LLMs' consistent failure to inform users about compilation requirements. From extensive experience, even advanced models neglect to mention that:
-
Source files (.jss) must be compiled to binary files (.jsb)
-
Compilation can be done via SCompile.exe or the JAWS Script Manager
-
The compiled files must be placed in the correct directory structure
-
Scripts must be reloaded in JAWS after compilation
-
Syntax errors prevent compilation and provide error messages
-
Different JAWS versions may have different compilation requirements
This omission leaves users frustrated, unable to understand why their "completed" scripts do not function.
Trust and Reliability Concerns
The Trust Problem
One of the major concerns about language models today is trust--they can give strikingly amazing results in some cases but are often subtly wrong in others, and some are non-deterministic.
For JAWS scripting, trust issues are particularly acute:
-
Users cannot easily verify script correctness without deep JSL knowledge
-
Testing requires actual blind or low-vision users or extensive simulation
-
Errors may not be immediately apparent but emerge in edge cases
-
Security vulnerabilities may be hidden in plausible-looking code
-
Performance issues may only manifest during heavy usage
The Need for Human Expertise
It becomes critical to design languages to be read, not just written, so humans can review and approve generated code. For JAWS scripting:
-
Scripts should be written following Freedom Scientific's coding standards (Chapter [scripting-standards]{reference-type="ref" reference="scripting-standards"})
-
All scripts must be thoroughly tested by experienced screen reader users
-
Security implications must be carefully evaluated
-
Performance impact must be assessed
-
Scripts must be documented for future maintainability
FSCompanion Lacks Data to guide JAWS Scripting
FSCompanion was created as a help and support assistant, not as a code generator. Its training and tuning were focused on Freedom Scientific's public help articles, forum posts, FAQs, and other user-facing documentation; it was not trained on a curated corpus of JAWS scripting source code or on the multi-file project layouts that real JAWS scripts require. Consequently, any code-like output it produces is a byproduct of document-driven retrieval and general LLM pattern completion, not a reflection of direct knowledge of JAWS Script Language (JSL) internals.
Because FSCompanion's fine-tuning data is primarily documentation and support content, it lacks many of the concrete, executable examples and API usages that experienced scripters rely on. When prompted for script snippets, the assistant will often fall back to generic programming patterns learned by the underlying model (either GPT-3.5, GTP-4, or GPT-4o) rather than Freedom Scientific's precise APIs, compilation constraints, or recommended file organization. That leads to outputs that may look plausible -- and even syntactically similar to JSL at a glance -- but which can contain subtle API mismatches, incorrect parameter types, or references to functions that do not exist in a given JAWS version.
From a technical standpoint, FSCompanion does not know about several crucial aspects of JAWS development: the need to split definitions across .jss, .jsm, and .jsh files, the requirement to compile sources into .jsb artifacts, the event signatures and cursor-management patterns that preserve user state, or the nuances of UIA/MSAA/IA2 integration. Because those details are rarely present in support articles, the assistant cannot reliably generate scaffolding that respects the runtime and compilation model; code it suggests may omit necessary save/restore cursor calls, fail to call default handlers, or assume synchronous behaviors that are incorrect in JAWS's event-driven environment.
Using FSCompanion-generated code without careful vetting therefore carries real accessibility and safety risks. A superficially working snippet can still degrade the experience for users who rely on JAWS: announcing the wrong information, disrupting focus or cursor position, introducing regressions across JAWS versions, or creating performance bottlenecks in frequently fired events. Those outcomes can be more harmful than no script at all, because they may silently reduce usability in ways that are difficult to detect without expert testing.
Practically, treat FSCompanion as a documentation and discovery tool rather than a scripting authority. Use it to find references, examples in support articles, and explanations of high-level concepts, but always validate any code through the standard JAWS development workflow: consult official API docs, compile and test in the target JAWS version, and have an experienced scripter review the result. If automated code generation is required, prefer approaches that ground responses in curated code examples (RAG with vetted repositories or models fine-tuned on actual JAWS scripts) and enforce a verification step before any script is used in production.
Best Practices for Using AI in JAWS Script Development
Treat LLM Output as a Starting Point, Not a Solution
When using LLMs for JAWS scripting assistance:
-
Never deploy generated code without review: All LLM-generated code must be thoroughly reviewed by an experienced JAWS scripter before use.
-
Verify syntax carefully: Check that generated code uses actual JSL syntax, not Python, Lua, or pseudocode.
-
Validate all function calls: Ensure that all referenced functions exist in the JAWS API and are called with correct parameters.
-
Test extensively: Test scripts with actual screen reader users in real-world scenarios, not just in isolated test cases.
-
Review against standards: Compare generated code against Freedom Scientific's scripting standards (Chapter [scripting-standards]{reference-type="ref" reference="scripting-standards"}) and coding guidelines (Section [acceptable-guidelines]{reference-type="ref" reference="acceptable-guidelines"}).
-
Verify compilation: Always attempt to compile generated scripts and address any compilation errors before testing.
-
Check file structure: Ensure that supporting files (.jsm, .jsh, .jkm) are properly structured and coordinated.
Use LLMs for Specific Limited Tasks
LLMs may be more reliable for certain limited tasks:
-
Generating boilerplate code structures
-
Providing examples of common patterns (with verification)
-
Suggesting function names or approaches (with validation)
-
Explaining JAWS API documentation
-
Converting between different code formatting styles
-
Generating documentation templates
However, even these uses require expert verification before implementation.
Maintain Deep Understanding
When a model starts hallucinating, it can take more time to fix the generated code than to write it manually. Therefore:
-
Invest in learning JAWS Scripting Language properly
-
Study Freedom Scientific's official documentation
-
Learn from existing, vetted scripts
-
Understand the underlying accessibility principles
-
Develop expertise in debugging JAWS scripts
-
Participate in the JAWS scripting community
The Future of AI-Assisted JAWS Scripting
Potential Improvements
Future developments may improve LLM capabilities for specialized languages:
-
Specialized fine-tuning: Models fine-tuned on specialized datasets can improve performance, though this requires substantial JAWS scripting examples.
-
Retrieval-Augmented Generation (RAG): RAG approaches can help mitigate hallucinations by grounding responses in actual documentation.
-
Improved evaluation methods: Developing standard benchmark datasets and evaluation metrics for LRPLs and DSLs could drive improvements.
-
Domain-specific models: Creating models specifically trained on accessibility scripting languages could improve results.
-
Better validation tools: Integrated compilation checking and API validation could catch errors before deployment.
Realistic Expectations
However, several factors suggest that LLM limitations for JAWS scripting will persist:
-
The JAWS scripting community will likely remain small
-
Proprietary scripts will continue to limit public training data
-
The specialized knowledge required remains difficult to encode
-
Solutions developed for specific language pairs prove ineffective when applied to other language combinations
-
The compilation and file structure complexity adds layers of difficulty
Conclusion
While LLMs and AI have transformed software development for mainstream languages, their application to JAWS Scripting Language faces fundamental challenges. The severe data scarcity, specialized syntax, and unique architectural requirements of low-resource programming languages mean that LLMs cannot fully leverage their capabilities.
For JAWS scripting specifically, LLMs frequently generate code in non-functional pseudocode, borrow inappropriately from other scripting languages (particularly Python from NVDA), fail to mention critical compilation requirements, misunderstand the multi-file architecture, demonstrate poor knowledge of Windows accessibility APIs, generate invalid function calls and event handlers, and produce code that violates established scripting standards. These limitations, combined with serious security concerns around package hallucinations (21.7% for open-source models) and the risks of "vibe coding" (accepting AI suggestions without review), mean that LLM-generated JAWS scripts require extraordinary caution.
The technical architecture of JAWS scripting--compiled language, multi-file coordination, Windows accessibility API integration, event-driven programming model, cursor management requirements, and speech/Braille output considerations--creates a complexity that LLMs cannot reliably navigate without extensive training data that simply does not exist in public repositories.
Developers must possess deep understanding of JAWS Scripting Language and its ecosystem to effectively evaluate, adapt, and integrate any LLM-generated code. The generated code should be treated as a potentially flawed starting point requiring expert review, never as a final solution. This expert review must encompass:
-
Verification of syntactic correctness against JSL grammar
-
Validation that all function calls use actual JAWS API functions with correct signatures
-
Confirmation that event handlers follow proper patterns and update necessary global state
-
Checking that cursor management includes proper save/restore sequences
-
Ensuring proper file structure across .jss, .jsm, .jsh, .jkm, and .jsd files
-
Verifying compliance with Freedom Scientific's scripting standards
-
Testing with actual screen reader users in real-world scenarios
-
Security review to prevent exposure of sensitive information
-
Performance testing to ensure responsiveness
Until substantial improvements occur in LLM training data and specialized fine-tuning for assistive technology scripting languages, human expertise remains irreplaceable in JAWS script development. The stakes--affecting users who depend on assistive technology for computer access--are too high to accept anything less than rigorously validated, professionally developed scripts.
Research on DSLs and LRPLs confirms these concerns with quantitative evidence. Studies show that even with fine-tuning, DSLs with high numbers of custom function names (like JAWS with its hundreds of specialized API functions) experience hallucination rates of 21.7% for open-source models, compilation failures in significant percentages of attempts, and the need for multiple iterations (sometimes 100+ rounds) to produce correct code. The specialized nature of JAWS scripting, combining domain-specific language characteristics with assistive technology requirements and Windows API knowledge, places it among the most challenging environments for LLM code generation.
As LLMs become more reliable and trustworthy over time, they will augment the developer experience, but they will not replace the need for programming expertise. For JAWS scripting, this human expertise is not just desirable but essential. The compilation requirement alone--which LLMs consistently fail to mention--demonstrates the gap between LLM capabilities and the practical knowledge required for JAWS script development. When combined with the specialized knowledge of Windows accessibility APIs (MSAA, IAccessible2, UIA), event-driven programming patterns, cursor management techniques, speech and Braille output considerations, and assistive technology UX principles, the knowledge gap becomes insurmountable for current LLM technology.
The future may bring improvements through specialized fine-tuning, retrieval-augmented generation grounded in JAWS documentation, better evaluation methods, and domain-specific models trained on accessibility scripting languages. However, the fundamental constraint--the small size of the JAWS scripting community and the proprietary nature of professional scripts--suggests that training data limitations will persist indefinitely. Until these challenges are addressed, developers working with JAWS scripting must rely primarily on human expertise, treating LLM assistance as a supplementary tool requiring rigorous validation rather than a primary development method.
More Information
Additional Reading
This chapter draws on extensive research examining the capabilities and limitations of Large Language Models for code generation, particularly in specialized and low-resource programming languages. The following references provide comprehensive background on the technical challenges, security implications, and practical considerations discussed throughout this chapter.
Surveys and Comprehensive Studies on LLMs for Code Generation
{{#cite joel2024survey}}
{{#cite cassano2024knowledge}}
{{#cite cassano2023multiple}}
{{#cite diera2023enhancing}}
{{#cite klimek2023potential}}
{{#cite github2024repository}}
Package Hallucination and Security Vulnerabilities
{{#cite spracklen2024package}}
{{#cite saini2025importing}}
{{#cite lanyado2024package}}
{{#cite haque2025secure}}
{{#cite pradel2024hallucination}}
{{#cite liu2024exploring}}
{{#cite oyesanya2024package}}
{{#cite usenix2025package}}
{{#cite helpnetsecurity2025package}}
{{#cite sciencedaily2025threats}}
{{#cite darkreading2024hallucinations}}
{{#cite infoworld2025hallucinations}}
Vibe Coding: Definitions, Practices, and Implications
{{#cite karpathy2025vibe}}
{{#cite wikipedia2025vibe}}
{{#cite willison2025vibe}}
{{#cite kim2025user}}
{{#cite googlecloud2025vibeoverview}}
{{#cite ibm2025vibe}}
{{#cite codingscape2025tools}}
{{#cite mcnulty2025vibe}}
{{#cite uxplanet2025testing}}
{{#cite arsturn2025rapid}}
{{#cite nocodefinder2025vibe}}
Industry Reports on AI Adoption in Software Development
{{#cite google2024dora}}
{{#cite google2025dora}}
{{#cite github2023survey}}
{{#cite googlecloud2024announcing}}
{{#cite techrepublic2024dora}}
{{#cite register2025dora}}
{{#cite semaphore2025roundup}}
{{#cite opslevel2024takeaways}}
{{#cite devdynamics2024stateofdevops}}
{{#cite thoughtfuldane2024insights}}
Code Generation Quality and LLM Behavior
{{#cite chen2021evaluating}}
{{#cite ouyang2024llm}}
{{#cite orlanski2023measuring}}
{{#cite gong2022distributed}}
Accessibility APIs and JAWS Technical Documentation
{{#cite microsoft2023iaccessible2}}
{{#cite microsoft2023uia}}
{{#cite freedomscientific2024scripting}}
{{#cite freelists:new-era-in-scripting-jaws}}