[829] | 1 | unit JAWSImplementation;
|
---|
| 2 |
|
---|
| 3 | interface
|
---|
| 4 | { DONE -oJeremy Merrill -c508 :
|
---|
| 5 | Add something that prevents overwriting of the script files if another
|
---|
| 6 | app is running that's using the JAWS DLL }
|
---|
| 7 | { TODO -oJeremy Merrill -c508 : Add check in here to look at script version in JSS file }
|
---|
| 8 | { DONE -oJeremy Merrill -c508 :
|
---|
| 9 | Replace registry communication with multiple windows - save strings in the window titles
|
---|
| 10 | Use EnumerateChildWindows jaws script function in place of the FindWindow function
|
---|
| 11 | that's being used right now.- EnumerateChildWindows with a window handle of 0
|
---|
| 12 | enumerates all windows on the desktop. Will have to use the first part of the window
|
---|
| 13 | title as an ID, and the last part as the string values. Will need to check for a maximum
|
---|
| 14 | string lenght, probably have to use multiple windows for long text.
|
---|
| 15 | Will also beed to have a global window shared by muiltiple instances of the JAWS.SR DLL. }
|
---|
| 16 | { DONE -oJeremy Merrill -c508 :
|
---|
| 17 | Need to add version checking to TVA508AccessibilityManager component
|
---|
| 18 | and JAWS.DLL. Warning needs to display just like JAWS.DLL and JAWS. }
|
---|
| 19 | uses SysUtils, Windows, Classes, Registry, StrUtils, Forms, Dialogs,
|
---|
| 20 | ExtCtrls, VAUtils, DateUtils, PSApi, IniFiles, ActiveX,
|
---|
| 21 | SHFolder, ShellAPI, VA508AccessibilityConst;
|
---|
| 22 |
|
---|
| 23 | {$I 'VA508ScreenReaderDLLStandard.inc'}
|
---|
| 24 |
|
---|
| 25 | { DONE -oJeremy Merrill -c508 :Figure out why Delphi IDE is loading the DLL when JAWS is running -
|
---|
| 26 | probably has something to do with the VA508 package being installed -
|
---|
| 27 | need to test for csDesigning some place that we're not testing for (maybe?)}
|
---|
| 28 |
|
---|
| 29 | exports Initialize, ShutDown, RegisterCustomBehavior, ComponentData,
|
---|
| 30 | SpeakText, IsRunning, ConfigChangePending;
|
---|
| 31 |
|
---|
| 32 | implementation
|
---|
| 33 |
|
---|
| 34 | uses fVA508HiddenJawsMainWindow, FSAPILib_TLB, ComObj;
|
---|
| 35 |
|
---|
| 36 | const
|
---|
| 37 | // JAWS_REQUIRED_VERSION = '7.10.500'; in VA508AccessibilityConst unit
|
---|
| 38 | JAWS_COM_OBJECT_VERSION = '8.0.2173';
|
---|
| 39 |
|
---|
| 40 | VA508_REG_PARAM_KEY = 'Software\Vista\508\JAWS';
|
---|
| 41 |
|
---|
| 42 | VA508_REG_COMPONENT_CAPTION = 'Caption';
|
---|
| 43 | VA508_REG_COMPONENT_VALUE = 'Value';
|
---|
| 44 | VA508_REG_COMPONENT_CONTROL_TYPE = 'ControlType';
|
---|
| 45 | VA508_REG_COMPONENT_STATE = 'State';
|
---|
| 46 | VA508_REG_COMPONENT_INSTRUCTIONS = 'Instructions';
|
---|
| 47 | VA508_REG_COMPONENT_ITEM_INSTRUCTIONS = 'ItemInstructions';
|
---|
| 48 | VA508_REG_COMPONENT_DATA_STATUS = 'DataStatus';
|
---|
| 49 |
|
---|
| 50 | VA508_ERRORS_SHOWN_STATE = 'ErrorsShown';
|
---|
| 51 |
|
---|
| 52 | RELOAD_CONFIG_SCRIPT = 'VA508Reload';
|
---|
| 53 |
|
---|
| 54 | SLASH = '\';
|
---|
| 55 | { TODO -oJeremy Merrill -c508 :
|
---|
| 56 | Change APP_DATA so that "application data" isn't used - Windows Vista
|
---|
| 57 | doesn't use this value - get data from Windows API call }
|
---|
| 58 | APP_DATA = SLASH + 'application data' + SLASH;
|
---|
| 59 | JAWS_COMMON_SCRIPT_PATH_TEXT = '\freedom scientific\jaws\';
|
---|
| 60 | JAWS_COMMON_SCRIPT_PATH_TEXT_LEN = length(JAWS_COMMON_SCRIPT_PATH_TEXT);
|
---|
| 61 |
|
---|
| 62 | type
|
---|
| 63 | TCompareType = (jcPrior, jcINI, jcLineItems, jcVersion, jcScriptMerge);
|
---|
| 64 |
|
---|
| 65 | TFileInfo = record
|
---|
| 66 | AppFile: boolean;
|
---|
| 67 | Ext: string;
|
---|
| 68 | CompareType: TCompareType;
|
---|
| 69 | Required: boolean;
|
---|
| 70 | Compile: boolean;
|
---|
| 71 | end;
|
---|
| 72 |
|
---|
| 73 | const
|
---|
| 74 | JAWS_SCRIPT_NAME = 'VA508JAWS';
|
---|
| 75 |
|
---|
| 76 | JAWS_SCRIPT_VERSION = 'VA508_Script_Version';
|
---|
| 77 | CompiledScriptFileExtension = '.JSB';
|
---|
| 78 | ScriptFileExtension = '.JSS';
|
---|
| 79 | ScriptDocExtension = '.JSD';
|
---|
| 80 | ConfigFileExtension = '.JCF';
|
---|
| 81 | KeyMapExtension = '.JKM';
|
---|
| 82 | DictionaryFileExtension = '.JDF';
|
---|
| 83 |
|
---|
| 84 | FileInfo: array[1..6] of TFileInfo = (
|
---|
| 85 | (AppFile: FALSE; Ext: ScriptFileExtension; CompareType: jcVersion; Required: TRUE; Compile: TRUE),
|
---|
| 86 | (AppFile: FALSE; Ext: ScriptDocExtension; CompareType: jcPrior; Required: TRUE; Compile: FALSE),
|
---|
| 87 | (AppFile: TRUE; Ext: ScriptFileExtension; CompareType: jcScriptMerge; Required: TRUE; Compile: TRUE),
|
---|
| 88 | (AppFile: TRUE; Ext: ConfigFileExtension; CompareType: jcINI; Required: TRUE; Compile: FALSE),
|
---|
| 89 | (AppFile: TRUE; Ext: DictionaryFileExtension; CompareType: jcLineItems; Required: FALSE; Compile: FALSE),
|
---|
| 90 | (AppFile: TRUE; Ext: KeyMapExtension; CompareType: jcINI; Required: FALSE; Compile: FALSE));
|
---|
| 91 |
|
---|
| 92 | JAWS_VERSION_ERROR = ERROR_INTRO +
|
---|
| 93 | 'The Accessibility Framework can only communicate with JAWS ' + JAWS_REQUIRED_VERSION + CRLF +
|
---|
| 94 | 'or later versions. Please update your version of JAWS to a minimum of' + CRLF +
|
---|
| 95 | JAWS_REQUIRED_VERSION + ', or preferably the most recent release, to allow the Accessibility' + CRLF +
|
---|
| 96 | 'Framework to communicate with JAWS. If you are getting this message' + CRLF +
|
---|
| 97 | 'and you already have a compatible version of JAWS, please contact your' + CRLF +
|
---|
| 98 | 'system administrator, and request that they run, with administrator rights,' + CRLF +
|
---|
| 99 | 'the JAWSUpdate application located in the \Program Files\VistA\' + CRLF +
|
---|
| 100 | 'Common Files directory. JAWSUpdate is not required for JAWS' + CRLF +
|
---|
| 101 | 'versions ' + JAWS_COM_OBJECT_VERSION + ' and above.' + CRLF;
|
---|
| 102 |
|
---|
| 103 | JAWS_FILE_ERROR = ERROR_INTRO +
|
---|
| 104 | 'The JAWS interface with the Accessibility Framework requires the ability' + CRLF +
|
---|
| 105 | 'to write files to the hard disk, but the following error is occurring trying to' + CRLF +
|
---|
| 106 | 'write to the disk:' + CRLF + '%s' + CRLF +
|
---|
| 107 | 'Please contact your system administrator in order to ensure that your ' + CRLF +
|
---|
| 108 | 'security privileges allow you to write files to the hard disk.' + CRLF +
|
---|
| 109 | 'If you are sure you have these privileges, your hard disk may be full. Until' + CRLF +
|
---|
| 110 | 'this problem is resolved, the Accessibility Framework will not be able to' + CRLF +
|
---|
| 111 | 'communicate with JAWS.';
|
---|
| 112 |
|
---|
| 113 | JAWS_USER_MISSMATCH_ERROR = ERROR_INTRO +
|
---|
| 114 | 'An error has been detected in the state of JAWS that will not allow the' + CRLF +
|
---|
| 115 | 'Accessibility Framework to communicate with JAWS until JAWS is shut' + CRLF +
|
---|
| 116 | 'down and restarted. Please restart JAWS at this time.';
|
---|
| 117 |
|
---|
| 118 | DLL_VERSION_ERROR = ERROR_INTRO +
|
---|
| 119 | 'The Accessibility Framework is at version %s, but the required JAWS' + CRLF +
|
---|
| 120 | 'support files are only at version %s. The new support files should have' + CRLF +
|
---|
| 121 | 'been released with the latest version of the software you are currently' + CRLF +
|
---|
| 122 | 'running. The Accessibility Framework will not be able to communicate' + CRLF +
|
---|
| 123 | 'with JAWS until these support files are installed. Please contact your' + CRLF +
|
---|
| 124 | 'system administrator for assistance.';
|
---|
| 125 |
|
---|
| 126 | JAWS_ERROR_VERSION = 1;
|
---|
| 127 | JAWS_ERROR_FILE_IO = 2;
|
---|
| 128 | JAWS_ERROR_USER_PROBLEM = 3;
|
---|
| 129 | DLL_ERROR_VERSION = 4;
|
---|
| 130 |
|
---|
| 131 | JAWS_ERROR_COUNT = 4;
|
---|
| 132 |
|
---|
| 133 | JAWS_RELOAD_DELAY = 500;
|
---|
| 134 |
|
---|
| 135 | var
|
---|
| 136 | JAWSErrorMessage: array[1..JAWS_ERROR_COUNT] of string = (JAWS_VERSION_ERROR, JAWS_FILE_ERROR,
|
---|
| 137 | JAWS_USER_MISSMATCH_ERROR, DLL_VERSION_ERROR);
|
---|
| 138 |
|
---|
| 139 | JAWSErrorsShown: array[1..JAWS_ERROR_COUNT] of boolean = (FALSE, FALSE, FALSE, FALSE);
|
---|
| 140 |
|
---|
| 141 | type
|
---|
| 142 | TJAWSSayString = function(StringToSpeak: PChar; Interrupt: BOOL): BOOL; stdcall;
|
---|
| 143 | TJAWSRunScript = function(ScriptName: PChar): BOOL; stdcall;
|
---|
| 144 |
|
---|
| 145 | TStartupID = record
|
---|
| 146 | Handle: HWND;
|
---|
| 147 | InstanceID: Integer;
|
---|
| 148 | MsgID: Integer;
|
---|
| 149 | end;
|
---|
| 150 |
|
---|
| 151 | TJAWSManager = class
|
---|
| 152 | strict private
|
---|
| 153 | FRequiredFilesFound: boolean;
|
---|
| 154 | FMainForm: TfrmVA508HiddenJawsMainWindow;
|
---|
| 155 | FWasShutdown: boolean;
|
---|
| 156 | FJAWSFileError: string;
|
---|
| 157 | FDictionaryFileName: string;
|
---|
| 158 | FConfigFile: string;
|
---|
| 159 | FKeyMapFile: string;
|
---|
| 160 | FMasterApp: string;
|
---|
| 161 | FRootScriptFileName: string;
|
---|
| 162 | FRootScriptAppFileName: string;
|
---|
| 163 | FDefaultScriptDir: string;
|
---|
| 164 | FUserStriptDir: string;
|
---|
| 165 | FKeyMapINIFile: TINIFile;
|
---|
| 166 | FKeyMapINIFileModified: boolean;
|
---|
| 167 | FAssignedKeys: TStringList;
|
---|
| 168 | FConfigINIFile: TINIFile;
|
---|
| 169 | FConfigINIFileModified: boolean;
|
---|
| 170 | FDictionaryFile: TStringList;
|
---|
| 171 | FDictionaryFileModified: boolean;
|
---|
| 172 | FCompiler: string;
|
---|
| 173 | JAWSAPI: IJawsApi;
|
---|
| 174 | private
|
---|
| 175 | procedure ShutDown;
|
---|
| 176 | procedure MakeFileWritable(FileName: string);
|
---|
| 177 | procedure LaunchMasterApplication;
|
---|
| 178 | procedure KillINIFiles(Sender: TObject);
|
---|
| 179 | procedure ReloadConfiguration;
|
---|
| 180 | public
|
---|
| 181 | constructor Create;
|
---|
| 182 | destructor Destroy; override;
|
---|
| 183 | class procedure ShowError(ErrorNumber: integer); overload;
|
---|
| 184 | class procedure ShowError(ErrorNumber: integer; data: array of const); overload;
|
---|
| 185 | class function GetPathFromJAWS(PathID: integer; DoLowerCase: boolean = TRUE): string;
|
---|
| 186 | class function GetJAWSWindow: HWnd;
|
---|
| 187 | class function IsRunning(HighVersion, LowVersion: Word): BOOL;
|
---|
| 188 | function Initialize(ComponentCallBackProc: TComponentDataRequestProc): BOOL;
|
---|
| 189 | procedure SendComponentData(WindowHandle: HWND; DataStatus: LongInt; Caption, Value, Data,
|
---|
| 190 | ControlType, State, Instructions, ItemInstructions: PChar);
|
---|
| 191 | procedure SpeakText(Text: PChar);
|
---|
| 192 | procedure RegisterCustomBehavior(Before, After: string; Action: integer);
|
---|
| 193 | class function JAWSVersionOK: boolean;
|
---|
| 194 | class function JAWSTalking2CurrentUser: boolean;
|
---|
| 195 | function FileErrorExists: boolean;
|
---|
| 196 | property RequiredFilesFound: boolean read FRequiredFilesFound;
|
---|
| 197 | property MainForm: TfrmVA508HiddenJawsMainWindow read FMainForm;
|
---|
| 198 | end;
|
---|
| 199 |
|
---|
| 200 | var
|
---|
| 201 | JAWSManager: TJAWSManager = nil;
|
---|
| 202 | DLLMessageID: UINT = 0;
|
---|
| 203 |
|
---|
| 204 | procedure EnsureManager;
|
---|
| 205 | begin
|
---|
| 206 | if not assigned(JAWSManager) then
|
---|
| 207 | JAWSManager := TJAWSManager.Create;
|
---|
| 208 | end;
|
---|
| 209 |
|
---|
| 210 | // Checks to see if the screen reader is currently running
|
---|
| 211 | function IsRunning(HighVersion, LowVersion: Word): BOOL; stdcall;
|
---|
| 212 | begin
|
---|
| 213 | Result := TJAWSManager.IsRunning(HighVersion, LowVersion);
|
---|
| 214 | end;
|
---|
| 215 |
|
---|
| 216 | // Executed after IsRunning returns TRUE, when the DLL is accepted as the screen reader of choice
|
---|
| 217 | function Initialize(ComponentCallBackProc: TComponentDataRequestProc): BOOL; stdcall;
|
---|
| 218 | begin
|
---|
| 219 | EnsureManager;
|
---|
| 220 | Result := JAWSManager.Initialize(ComponentCallBackProc);
|
---|
| 221 | end;
|
---|
| 222 |
|
---|
| 223 | // Executed when the DLL is unloaded or screen reader is no longer needed
|
---|
| 224 | procedure ShutDown; stdcall;
|
---|
| 225 | begin
|
---|
| 226 | if assigned(JAWSManager) then
|
---|
| 227 | begin
|
---|
| 228 | JAWSManager.ShutDown;
|
---|
| 229 | FreeAndNil(JAWSManager);
|
---|
| 230 | end;
|
---|
| 231 | end;
|
---|
| 232 |
|
---|
| 233 | function ConfigChangePending: boolean; stdcall;
|
---|
| 234 | begin
|
---|
| 235 | Result := FALSE;
|
---|
| 236 | if assigned(JAWSManager) and assigned(JAWSManager.MainForm) and
|
---|
| 237 | (JAWSManager.MainForm.ConfigChangePending) then
|
---|
| 238 | Result := TRUE;
|
---|
| 239 | end;
|
---|
| 240 |
|
---|
| 241 | // Returns Component Data as requested by the screen reader
|
---|
| 242 | procedure ComponentData(WindowHandle: HWND;
|
---|
| 243 | DataStatus: LongInt = DATA_NONE;
|
---|
| 244 | Caption: PChar = nil;
|
---|
| 245 | Value: PChar = nil;
|
---|
| 246 | Data: PChar = nil;
|
---|
| 247 | ControlType: PChar = nil;
|
---|
| 248 | State: PChar = nil;
|
---|
| 249 | Instructions: PChar = nil;
|
---|
| 250 | ItemInstructions: PChar = nil); stdcall;
|
---|
| 251 | begin
|
---|
| 252 | EnsureManager;
|
---|
| 253 | JAWSManager.SendComponentData(WindowHandle, DataStatus, Caption, Value, Data, ControlType, State,
|
---|
| 254 | Instructions, ItemInstructions);
|
---|
| 255 | end;
|
---|
| 256 |
|
---|
| 257 | // Instructs the Screen Reader to say the specified text
|
---|
| 258 | procedure SpeakText(Text: PChar); stdcall;
|
---|
| 259 | begin
|
---|
| 260 | EnsureManager;
|
---|
| 261 | JAWSManager.SpeakText(Text);
|
---|
| 262 | end;
|
---|
| 263 |
|
---|
| 264 | procedure RegisterCustomBehavior(BehaviorType: integer; Before, After: PChar);
|
---|
| 265 | begin
|
---|
| 266 | EnsureManager;
|
---|
| 267 | JAWSManager.RegisterCustomBehavior(Before, After, BehaviorType);
|
---|
| 268 | end;
|
---|
| 269 |
|
---|
| 270 | { TJAWSManager }
|
---|
| 271 |
|
---|
| 272 | const
|
---|
| 273 | {$WARNINGS OFF} // Don't care about platform specific warning
|
---|
| 274 | NON_WRITABLE_FILE_ATTRIB = faReadOnly or faHidden;
|
---|
| 275 | {$WARNINGS ON}
|
---|
| 276 | WRITABLE_FILE_ATTRIB = faAnyFile and (not NON_WRITABLE_FILE_ATTRIB);
|
---|
| 277 |
|
---|
| 278 | procedure TJAWSManager.MakeFileWritable(FileName: string);
|
---|
| 279 | var
|
---|
| 280 | Attrib: integer;
|
---|
| 281 | begin
|
---|
| 282 | {$WARNINGS OFF} // Don't care about platform specific warning
|
---|
| 283 | Attrib := FileGetAttr(FileName);
|
---|
| 284 | {$WARNINGS ON}
|
---|
| 285 | if (Attrib and NON_WRITABLE_FILE_ATTRIB) <> 0 then
|
---|
| 286 | begin
|
---|
| 287 | Attrib := Attrib and WRITABLE_FILE_ATTRIB;
|
---|
| 288 | {$WARNINGS OFF} // Don't care about platform specific warning
|
---|
| 289 | if FileSetAttr(FileName, Attrib) <> 0 then
|
---|
| 290 | {$WARNINGS ON}
|
---|
| 291 | FJAWSFileError := 'Could not change read-only attribute of file "' + FileName + '"';
|
---|
| 292 | end;
|
---|
| 293 | end;
|
---|
| 294 |
|
---|
| 295 | var
|
---|
| 296 | JAWSMsgID: UINT = 0;
|
---|
| 297 |
|
---|
| 298 | const
|
---|
| 299 | JAWS_MESSAGE_ID = 'JW_GET_FILE_PATH';
|
---|
| 300 | // version is in directory after JAWS \Freedom Scientific\JAWS\*.*\...
|
---|
| 301 | JAWS_PATH_ID_APPLICATION = 0;
|
---|
| 302 | JAWS_PATH_ID_USER_SCRIPT_FILES = 1;
|
---|
| 303 | JAWS_PATH_ID_JAWS_DEFAULT_SCRIPT_FILES = 2;
|
---|
| 304 | // 0 = C:\Program Files\Freedom Scientific\JAWS\8.0\jfw.INI
|
---|
| 305 | // 1 = D:\Documents and Settings\vhaislmerrij\Application Data\Freedom Scientific\JAWS\8.0\USER.INI
|
---|
| 306 | // 2 = D:\Documents and Settings\All Users\Application Data\Freedom Scientific\JAWS\8.0\Settings\enu\DEFAULT.SBL
|
---|
| 307 |
|
---|
| 308 | class function TJAWSManager.GetPathFromJAWS(PathID: integer; DoLowerCase: boolean = TRUE): string;
|
---|
| 309 | var
|
---|
| 310 | atm: ATOM;
|
---|
| 311 | len: integer;
|
---|
| 312 | path: string;
|
---|
| 313 | JAWSWindow: HWnd;
|
---|
| 314 | begin
|
---|
| 315 | JAWSWindow := GetJAWSWindow;
|
---|
| 316 | if JAWSMsgID = 0 then
|
---|
| 317 | JAWSMsgID := RegisterWindowMessage(JAWS_MESSAGE_ID);
|
---|
| 318 | Result := '';
|
---|
| 319 | atm := SendMessage(JAWSWindow, JAWSMsgID, PathID, 0);
|
---|
| 320 | if atm <> 0 then
|
---|
| 321 | begin
|
---|
| 322 | SetLength(path, MAX_PATH * 2);
|
---|
| 323 | len := GlobalGetAtomName(atm, PChar(path), MAX_PATH * 2);
|
---|
| 324 | GlobalDeleteAtom(atm);
|
---|
| 325 | if len > 0 then
|
---|
| 326 | begin
|
---|
| 327 | SetLength(path, len);
|
---|
| 328 | Result := ExtractFilePath(path);
|
---|
| 329 | if DoLowerCase then
|
---|
| 330 | Result := LowerCase(Result);
|
---|
| 331 | end;
|
---|
| 332 | end;
|
---|
| 333 | end;
|
---|
| 334 |
|
---|
| 335 |
|
---|
| 336 | constructor TJAWSManager.Create;
|
---|
| 337 | const
|
---|
| 338 | COMPILER_FILENAME = 'scompile.exe';
|
---|
| 339 | JAWS_APP_NAME = 'VA508APP';
|
---|
| 340 | JAWSMasterApp = 'VA508JAWSDispatcher.exe';
|
---|
| 341 |
|
---|
| 342 | procedure FindCompiler;
|
---|
| 343 | var
|
---|
| 344 | compiler: string;
|
---|
| 345 |
|
---|
| 346 | begin
|
---|
| 347 | compiler := GetPathFromJAWS(JAWS_PATH_ID_APPLICATION);
|
---|
| 348 | compiler := AppendBackSlash(compiler) + COMPILER_FILENAME;
|
---|
| 349 | if FileExists(compiler) then
|
---|
| 350 | FCompiler := compiler;
|
---|
| 351 | end;
|
---|
| 352 |
|
---|
| 353 | procedure FindJAWSRequiredFiles;
|
---|
| 354 | var
|
---|
| 355 | Path: string;
|
---|
| 356 | i: integer;
|
---|
| 357 | FileName: string;
|
---|
| 358 | info: TFileInfo;
|
---|
| 359 |
|
---|
| 360 | begin
|
---|
| 361 | SetLength(Path, MAX_PATH);
|
---|
| 362 | SetLength(Path, GetModuleFileName(HInstance, PChar(Path), Length(Path)));
|
---|
| 363 | Path := ExtractFilePath(Path);
|
---|
| 364 | Path := AppendBackSlash(Path);
|
---|
| 365 | // look for the script files in the same directory as this DLL
|
---|
| 366 | FRootScriptFileName := Path + JAWS_SCRIPT_NAME;
|
---|
| 367 | FRootScriptAppFileName := Path + JAWS_APP_NAME;
|
---|
| 368 | FRequiredFilesFound := TRUE;
|
---|
| 369 | for i := low(FileInfo) to high(FileInfo) do
|
---|
| 370 | begin
|
---|
| 371 | info := FileInfo[i];
|
---|
| 372 | if info.Required then
|
---|
| 373 | begin
|
---|
| 374 | if info.AppFile then
|
---|
| 375 | FileName := FRootScriptAppFileName + info.Ext
|
---|
| 376 | else
|
---|
| 377 | FileName := FRootScriptFileName + info.Ext;
|
---|
| 378 | if not FileExists(FileName) then
|
---|
| 379 | begin
|
---|
| 380 | FRequiredFilesFound := FALSE;
|
---|
| 381 | break;
|
---|
| 382 | end;
|
---|
| 383 | end;
|
---|
| 384 | end;
|
---|
| 385 | if FRequiredFilesFound then
|
---|
| 386 | begin
|
---|
| 387 | FMasterApp := Path + JAWSMasterApp;
|
---|
| 388 | FRequiredFilesFound := FileExists(FMasterApp);
|
---|
| 389 | end;
|
---|
| 390 | if FRequiredFilesFound then
|
---|
| 391 | begin
|
---|
| 392 | FDefaultScriptDir := lowercase(GetPathFromJAWS(JAWS_PATH_ID_JAWS_DEFAULT_SCRIPT_FILES));
|
---|
| 393 | FRequiredFilesFound := (pos(JAWS_COMMON_SCRIPT_PATH_TEXT, FDefaultScriptDir) > 0);
|
---|
| 394 | end;
|
---|
| 395 | if FRequiredFilesFound then
|
---|
| 396 | begin
|
---|
| 397 | FUserStriptDir := lowercase(GetPathFromJAWS(JAWS_PATH_ID_USER_SCRIPT_FILES));
|
---|
| 398 | FRequiredFilesFound := (pos(JAWS_COMMON_SCRIPT_PATH_TEXT, FUserStriptDir) > 0);
|
---|
| 399 | end;
|
---|
| 400 | end;
|
---|
| 401 |
|
---|
| 402 | begin
|
---|
| 403 | FindCompiler;
|
---|
| 404 | if FCompiler <> '' then
|
---|
| 405 | FindJAWSRequiredFiles;
|
---|
| 406 | end;
|
---|
| 407 |
|
---|
| 408 | destructor TJAWSManager.Destroy;
|
---|
| 409 | begin
|
---|
| 410 | ShutDown;
|
---|
| 411 | inherited;
|
---|
| 412 | end;
|
---|
| 413 |
|
---|
| 414 | function TJAWSManager.FileErrorExists: boolean;
|
---|
| 415 | begin
|
---|
| 416 | Result := (FJAWSFileError <> '');
|
---|
| 417 | end;
|
---|
| 418 |
|
---|
| 419 |
|
---|
| 420 | class function TJAWSManager.GetJAWSWindow: HWnd;
|
---|
| 421 | const
|
---|
| 422 | VISIBLE_WINDOW_CLASS: PChar = 'JFWUI2';
|
---|
| 423 | VISIBLE_WINDOW_TITLE: PChar = 'JAWS';
|
---|
| 424 | VISIBLE_WINDOW_TITLE2: PChar = 'Remote JAWS';
|
---|
| 425 |
|
---|
| 426 | begin
|
---|
| 427 | Result := FindWindow(VISIBLE_WINDOW_CLASS, VISIBLE_WINDOW_TITLE);
|
---|
| 428 | if Result = 0 then
|
---|
| 429 | Result := FindWindow(VISIBLE_WINDOW_CLASS, VISIBLE_WINDOW_TITLE2);
|
---|
| 430 | end;
|
---|
| 431 |
|
---|
| 432 | function TJAWSManager.Initialize(ComponentCallBackProc: TComponentDataRequestProc): BOOL;
|
---|
| 433 | var
|
---|
| 434 | DestPath: string;
|
---|
| 435 | ScriptFileChanges: boolean;
|
---|
| 436 | LastFileUpdated: boolean;
|
---|
| 437 | CompileCommands: TStringList;
|
---|
| 438 | AppScriptNeedsFunction: boolean;
|
---|
| 439 | AppNeedsUseLine: boolean;
|
---|
| 440 | AppUseLine: string;
|
---|
| 441 | AppStartFunctionLine: integer;
|
---|
| 442 |
|
---|
| 443 | procedure EnsureWindow;
|
---|
| 444 | begin
|
---|
| 445 | if not assigned(FMainForm) then
|
---|
| 446 | FMainForm := TfrmVA508HiddenJawsMainWindow.Create(nil);
|
---|
| 447 | FMainForm.ComponentDataCallBackProc := ComponentCallBackProc;
|
---|
| 448 | FMainForm.ConfigReloadProc := ReloadConfiguration;
|
---|
| 449 | FMainForm.HandleNeeded;
|
---|
| 450 | Application.ProcessMessages;
|
---|
| 451 | end;
|
---|
| 452 |
|
---|
| 453 |
|
---|
| 454 | function GetVersion(FileName: string): integer;
|
---|
| 455 | var
|
---|
| 456 | list: TStringList;
|
---|
| 457 |
|
---|
| 458 | p,i: integer;
|
---|
| 459 | line: string;
|
---|
| 460 | working: boolean;
|
---|
| 461 | begin
|
---|
| 462 | Result := 0;
|
---|
| 463 | list := TStringList.Create;
|
---|
| 464 | try
|
---|
| 465 | list.LoadFromFile(FileName);
|
---|
| 466 | i := 0;
|
---|
| 467 | working := TRUE;
|
---|
| 468 | while working and (i < list.Count) do
|
---|
| 469 | begin
|
---|
| 470 | line := list[i];
|
---|
| 471 | p := pos('=', line);
|
---|
| 472 | if p > 0 then
|
---|
| 473 | begin
|
---|
| 474 | if trim(copy(line,1,p-1)) = JAWS_SCRIPT_VERSION then
|
---|
| 475 | begin
|
---|
| 476 | line := trim(copy(line,p+1,MaxInt));
|
---|
| 477 | if copy(line,length(line), 1) = ',' then
|
---|
| 478 | delete(line,length(line),1);
|
---|
| 479 | Result := StrToIntDef(line, 0);
|
---|
| 480 | working := FALSE;
|
---|
| 481 | end;
|
---|
| 482 | end;
|
---|
| 483 | inc(i);
|
---|
| 484 | end;
|
---|
| 485 | finally
|
---|
| 486 | list.Free;
|
---|
| 487 | end;
|
---|
| 488 | end;
|
---|
| 489 |
|
---|
| 490 | function VersionDifferent(FromFile, ToFile: string): boolean;
|
---|
| 491 | var
|
---|
| 492 | FromVersion, ToVersion: integer;
|
---|
| 493 | begin
|
---|
| 494 | FromVersion := GetVersion(FromFile);
|
---|
| 495 | ToVersion := GetVersion(ToFile);
|
---|
| 496 | Result := (FromVersion > ToVersion);
|
---|
| 497 | end;
|
---|
| 498 |
|
---|
| 499 | function LineItemUpdateNeeded(FromFile, ToFile: string): boolean;
|
---|
| 500 | var
|
---|
| 501 | fromList, toList: TStringList;
|
---|
| 502 | i, idx: integer;
|
---|
| 503 | line: string;
|
---|
| 504 | begin
|
---|
| 505 | Result := FALSE;
|
---|
| 506 | fromList := TStringList.Create;
|
---|
| 507 | toList := TStringList.Create;
|
---|
| 508 | try
|
---|
| 509 | fromList.LoadFromFile(FromFile);
|
---|
| 510 | toList.LoadFromFile(toFile);
|
---|
| 511 | for i := 0 to fromList.Count - 1 do
|
---|
| 512 | begin
|
---|
| 513 | line := fromList[i];
|
---|
| 514 | if trim(line) <> '' then
|
---|
| 515 | begin
|
---|
| 516 | idx := toList.IndexOf(line);
|
---|
| 517 | if idx < 0 then
|
---|
| 518 | begin
|
---|
| 519 | Result := TRUE;
|
---|
| 520 | break;
|
---|
| 521 | end;
|
---|
| 522 | end;
|
---|
| 523 | end;
|
---|
| 524 | finally
|
---|
| 525 | toList.Free;
|
---|
| 526 | fromList.Free;
|
---|
| 527 | end;
|
---|
| 528 | end;
|
---|
| 529 |
|
---|
| 530 | function INIUpdateNeeded(FromFile, ToFile: string): boolean;
|
---|
| 531 | var
|
---|
| 532 | FromINIFile, ToINIFile: TIniFile;
|
---|
| 533 | Sections, Values: TStringList;
|
---|
| 534 | i, j: integer;
|
---|
| 535 | section, key, val1, val2: string;
|
---|
| 536 | begin
|
---|
| 537 | Result := FALSE;
|
---|
| 538 | Sections := TStringList.Create;
|
---|
| 539 | Values := TStringList.Create;
|
---|
| 540 | try
|
---|
| 541 | FromINIFile := TIniFile.Create(FromFile);
|
---|
| 542 | try
|
---|
| 543 | ToINIFile := TIniFile.Create(ToFile);
|
---|
| 544 | try
|
---|
| 545 | FromINIFile.ReadSections(Sections);
|
---|
| 546 | for i := 0 to Sections.count-1 do
|
---|
| 547 | begin
|
---|
| 548 | section := Sections[i];
|
---|
| 549 | FromINIFile.ReadSectionValues(section, Values);
|
---|
| 550 | for j := 0 to Values.Count - 1 do
|
---|
| 551 | begin
|
---|
| 552 | key := Values.Names[j];
|
---|
| 553 | val1 := Values.ValueFromIndex[j];
|
---|
| 554 | val2 := ToINIFile.ReadString(Section, key, '');
|
---|
| 555 | result := (val1 <> val2);
|
---|
| 556 | if Result then
|
---|
| 557 | break;
|
---|
| 558 | end;
|
---|
| 559 | if Result then
|
---|
| 560 | break;
|
---|
| 561 | end;
|
---|
| 562 | finally
|
---|
| 563 | ToINIFile.Free;
|
---|
| 564 | end;
|
---|
| 565 | finally
|
---|
| 566 | FromINIFile.Free;
|
---|
| 567 | end;
|
---|
| 568 | finally
|
---|
| 569 | Sections.Free;
|
---|
| 570 | Values.Free;
|
---|
| 571 | end;
|
---|
| 572 | end;
|
---|
| 573 |
|
---|
| 574 | function IsUseLine(data: string): boolean;
|
---|
| 575 | var
|
---|
| 576 | p: integer;
|
---|
| 577 | begin
|
---|
| 578 | Result := (copy(data,1,4) = 'use ');
|
---|
| 579 | if Result then
|
---|
| 580 | begin
|
---|
| 581 | Result := FALSE;
|
---|
| 582 | p := pos('"', data);
|
---|
| 583 | if p > 0 then
|
---|
| 584 | begin
|
---|
| 585 | p := posEX('"', data, p+1);
|
---|
| 586 | if p = length(data) then
|
---|
| 587 | Result := TRUE;
|
---|
| 588 | end;
|
---|
| 589 | end;
|
---|
| 590 | end;
|
---|
| 591 |
|
---|
| 592 | function IsFunctionLine(data: string): boolean;
|
---|
| 593 | var
|
---|
| 594 | p1, p2: integer;
|
---|
| 595 | line: string;
|
---|
| 596 | begin
|
---|
| 597 | Result := FALSE;
|
---|
| 598 | line := data;
|
---|
| 599 | p1 := pos(' ', line);
|
---|
| 600 | if (p1 > 0) then
|
---|
| 601 | begin
|
---|
| 602 | if copy(line,1,p1-1) = 'script' then
|
---|
| 603 | Result := true
|
---|
| 604 | else
|
---|
| 605 | begin
|
---|
| 606 | p2 := posEx(' ', line, p1+1);
|
---|
| 607 | if p2 > 0 then
|
---|
| 608 | begin
|
---|
| 609 | line := copy(line, p1+1, p2-p1-1);
|
---|
| 610 | if (line = 'function') then
|
---|
| 611 | Result := TRUE;
|
---|
| 612 | end;
|
---|
| 613 | end;
|
---|
| 614 | end;
|
---|
| 615 | end;
|
---|
| 616 |
|
---|
| 617 | function CheckForUseLineAndFunction(FromFile, ToFile: string): boolean;
|
---|
| 618 | var
|
---|
| 619 | FromData: TStringList;
|
---|
| 620 | ToData: TStringList;
|
---|
| 621 | UseLine: string;
|
---|
| 622 | i: integer;
|
---|
| 623 | line: string;
|
---|
| 624 |
|
---|
| 625 | begin
|
---|
| 626 | Result := FALSE;
|
---|
| 627 | FromData := TStringList.create;
|
---|
| 628 | ToData := TStringList.create;
|
---|
| 629 | try
|
---|
| 630 | UseLine := '';
|
---|
| 631 | AppUseLine := '';
|
---|
| 632 | AppStartFunctionLine := -1;
|
---|
| 633 | FromData.LoadFromFile(FromFile);
|
---|
| 634 | for i := 0 to FromData.Count - 1 do
|
---|
| 635 | begin
|
---|
| 636 | line := lowerCase(trim(FromData[i]));
|
---|
| 637 | if (UseLine = '') and IsUseLine(line) then
|
---|
| 638 | begin
|
---|
| 639 | UseLine := line;
|
---|
| 640 | AppUseLine := FromData[i];
|
---|
| 641 | end
|
---|
| 642 | else
|
---|
| 643 | if (AppStartFunctionLine < 0) and IsFunctionLine(line) then
|
---|
| 644 | AppStartFunctionLine := i;
|
---|
| 645 | if (UseLine <> '') and (AppStartFunctionLine >= 0) then break;
|
---|
| 646 | end;
|
---|
| 647 | if (UseLine = '') or (AppStartFunctionLine < 0) then exit;
|
---|
| 648 |
|
---|
| 649 | AppNeedsUseLine := TRUE;
|
---|
| 650 | AppScriptNeedsFunction := TRUE;
|
---|
| 651 | ToData.LoadFromFile(ToFile);
|
---|
| 652 | for i := 0 to ToData.Count - 1 do
|
---|
| 653 | begin
|
---|
| 654 | line := lowerCase(trim(ToData[i]));
|
---|
| 655 | if AppNeedsUseLine and IsUseLine(line) and (line = UseLine) then
|
---|
| 656 | AppNeedsUseLine := FALSE
|
---|
| 657 | else
|
---|
| 658 | if AppScriptNeedsFunction and IsFunctionLine(line) then
|
---|
| 659 | AppScriptNeedsFunction := FALSE;
|
---|
| 660 | if (not AppNeedsUseLine) and (not AppScriptNeedsFunction) then break;
|
---|
| 661 | end;
|
---|
| 662 | if AppNeedsUseLine or AppScriptNeedsFunction then
|
---|
| 663 | Result := TRUE;
|
---|
| 664 | finally
|
---|
| 665 | FromData.free;
|
---|
| 666 | ToData.free;
|
---|
| 667 | end;
|
---|
| 668 | end;
|
---|
| 669 |
|
---|
| 670 | function UpdateNeeded(FromFile, ToFile: string; CompareType: TCompareType): boolean;
|
---|
| 671 | begin
|
---|
| 672 | Result := TRUE;
|
---|
| 673 | try
|
---|
| 674 | case CompareType of
|
---|
| 675 | jcScriptMerge: Result := CheckForUseLineAndFunction(FromFile, ToFile);
|
---|
| 676 | jcPrior: Result := LastFileUpdated;
|
---|
| 677 | jcVersion: Result := VersionDifferent(FromFile, ToFile);
|
---|
| 678 | jcINI: Result := INIUpdateNeeded(FromFile, ToFile);
|
---|
| 679 | jcLineItems: Result := LineItemUpdateNeeded(FromFile, ToFile);
|
---|
| 680 | end;
|
---|
| 681 | except
|
---|
| 682 | on E: Exception do
|
---|
| 683 | FJAWSFileError := E.Message;
|
---|
| 684 | end;
|
---|
| 685 | end;
|
---|
| 686 |
|
---|
| 687 | procedure INIFileUpdate(FromFile, ToFile: String);
|
---|
| 688 | var
|
---|
| 689 | FromINIFile, ToINIFile: TIniFile;
|
---|
| 690 | Sections, Values: TStringList;
|
---|
| 691 | i, j: integer;
|
---|
| 692 | section, key, val1, val2: string;
|
---|
| 693 | modified: boolean;
|
---|
| 694 | begin
|
---|
| 695 | modified := FALSE;
|
---|
| 696 | Sections := TStringList.Create;
|
---|
| 697 | Values := TStringList.Create;
|
---|
| 698 | try
|
---|
| 699 | FromINIFile := TIniFile.Create(FromFile);
|
---|
| 700 | try
|
---|
| 701 | ToINIFile := TIniFile.Create(ToFile);
|
---|
| 702 | try
|
---|
| 703 | FromINIFile.ReadSections(Sections);
|
---|
| 704 | for i := 0 to Sections.count-1 do
|
---|
| 705 | begin
|
---|
| 706 | section := Sections[i];
|
---|
| 707 | FromINIFile.ReadSectionValues(section, Values);
|
---|
| 708 | for j := 0 to Values.Count - 1 do
|
---|
| 709 | begin
|
---|
| 710 | key := Values.Names[j];
|
---|
| 711 | val1 := Values.ValueFromIndex[j];
|
---|
| 712 | val2 := ToINIFile.ReadString(Section, key, '');
|
---|
| 713 | if (val1 <> val2) then
|
---|
| 714 | begin
|
---|
| 715 | ToINIFile.WriteString(section, key, val1);
|
---|
| 716 | modified := TRUE;
|
---|
| 717 | end;
|
---|
| 718 | end;
|
---|
| 719 | end;
|
---|
| 720 | finally
|
---|
| 721 | if modified then
|
---|
| 722 | ToINIFile.UpdateFile();
|
---|
| 723 | ToINIFile.Free;
|
---|
| 724 | end;
|
---|
| 725 | finally
|
---|
| 726 | FromINIFile.Free;
|
---|
| 727 | end;
|
---|
| 728 | finally
|
---|
| 729 | Sections.Free;
|
---|
| 730 | Values.Free;
|
---|
| 731 | end;
|
---|
| 732 | end;
|
---|
| 733 |
|
---|
| 734 | procedure LineItemFileUpdate(FromFile, ToFile: string);
|
---|
| 735 | var
|
---|
| 736 | fromList, toList: TStringList;
|
---|
| 737 | i, idx: integer;
|
---|
| 738 | line: string;
|
---|
| 739 | modified: boolean;
|
---|
| 740 | begin
|
---|
| 741 | modified := FALSE;
|
---|
| 742 | fromList := TStringList.Create;
|
---|
| 743 | toList := TStringList.Create;
|
---|
| 744 | try
|
---|
| 745 | fromList.LoadFromFile(FromFile);
|
---|
| 746 | toList.LoadFromFile(toFile);
|
---|
| 747 | for i := 0 to fromList.Count - 1 do
|
---|
| 748 | begin
|
---|
| 749 | line := fromList[i];
|
---|
| 750 | if trim(line) <> '' then
|
---|
| 751 | begin
|
---|
| 752 | idx := toList.IndexOf(line);
|
---|
| 753 | if idx < 0 then
|
---|
| 754 | begin
|
---|
| 755 | toList.Add(line);
|
---|
| 756 | modified := TRUE;
|
---|
| 757 | end;
|
---|
| 758 | end;
|
---|
| 759 | end;
|
---|
| 760 | finally
|
---|
| 761 | if Modified then
|
---|
| 762 | toList.SaveToFile(ToFile);
|
---|
| 763 | toList.Free;
|
---|
| 764 | fromList.Free;
|
---|
| 765 | end;
|
---|
| 766 | end;
|
---|
| 767 |
|
---|
| 768 | procedure DeleteCompiledFile(ToFile: string);
|
---|
| 769 | var
|
---|
| 770 | CompiledFile: string;
|
---|
| 771 | begin
|
---|
| 772 | CompiledFile := copy(ToFile, 1, length(ToFile) - length(ExtractFileExt(ToFile)));
|
---|
| 773 | CompiledFile := CompiledFile + CompiledScriptFileExtension;
|
---|
| 774 | if FileExists(CompiledFile) then
|
---|
| 775 | begin
|
---|
| 776 | MakeFileWritable(CompiledFile);
|
---|
| 777 | DeleteFile(PChar(CompiledFile));
|
---|
| 778 | end;
|
---|
| 779 | end;
|
---|
| 780 |
|
---|
| 781 | function DoScriptMerge(FromFile, ToFile: string): boolean;
|
---|
| 782 | var
|
---|
| 783 | BackupFile: string;
|
---|
| 784 | FromData: TStringList;
|
---|
| 785 | ToData: TStringList;
|
---|
| 786 | i, idx: integer;
|
---|
| 787 | ExitCode: integer;
|
---|
| 788 | begin
|
---|
| 789 | Result := TRUE;
|
---|
| 790 | BackupFile := ToFile + '.BACKUP';
|
---|
| 791 | if FileExists(BackupFile) then
|
---|
| 792 | begin
|
---|
| 793 | MakeFileWritable(BackupFile);
|
---|
| 794 | DeleteFile(PChar(BackupFile));
|
---|
| 795 | end;
|
---|
| 796 | DeleteCompiledFile(ToFile);
|
---|
| 797 | CopyFile(PChar(ToFile), PChar(BackupFile), FALSE);
|
---|
| 798 | MakeFileWritable(ToFile);
|
---|
| 799 | FromData := TStringList.create;
|
---|
| 800 | ToData := TStringList.create;
|
---|
| 801 | try
|
---|
| 802 | ToData.LoadFromFile(ToFile);
|
---|
| 803 | if AppNeedsUseLine then
|
---|
| 804 | ToData.Insert(0, AppUseLine);
|
---|
| 805 | if AppScriptNeedsFunction then
|
---|
| 806 | begin
|
---|
| 807 | FromData.LoadFromFile(FromFile);
|
---|
| 808 | ToData.Insert(1,'');
|
---|
| 809 | idx := 2;
|
---|
| 810 | for i := AppStartFunctionLine to FromData.Count - 1 do
|
---|
| 811 | begin
|
---|
| 812 | ToData.Insert(idx, FromData[i]);
|
---|
| 813 | inc(idx);
|
---|
| 814 | end;
|
---|
| 815 | ToData.Insert(idx,'');
|
---|
| 816 | end;
|
---|
| 817 | if not assigned(JAWSAPI) then
|
---|
| 818 | JAWSAPI := CoJawsApi.Create;
|
---|
| 819 | ToData.SaveToFile(ToFile);
|
---|
| 820 | ExitCode := ExecuteAndWait('"' + FCompiler + '"', '"' + ToFile + '"');
|
---|
| 821 | JAWSAPI.StopSpeech;
|
---|
| 822 | if ExitCode = 0 then // compile succeeded!
|
---|
| 823 | ReloadConfiguration
|
---|
| 824 | else
|
---|
| 825 | Result := FALSE; // compile failed - just copy the new one
|
---|
| 826 | finally
|
---|
| 827 | FromData.free;
|
---|
| 828 | ToData.free;
|
---|
| 829 | end;
|
---|
| 830 | end;
|
---|
| 831 |
|
---|
| 832 | procedure UpdateFile(FromFile, ToFile: string; info: TFileInfo);
|
---|
| 833 | var
|
---|
| 834 | DoCopy: boolean;
|
---|
| 835 | error: boolean;
|
---|
| 836 | CheckOverwrite: boolean;
|
---|
| 837 | begin
|
---|
| 838 | DoCopy := FALSE;
|
---|
| 839 | if FileExists(ToFile) then
|
---|
| 840 | begin
|
---|
| 841 | MakeFileWritable(ToFile);
|
---|
| 842 | CheckOverwrite := TRUE;
|
---|
| 843 | try
|
---|
| 844 | case info.CompareType of
|
---|
| 845 | jcScriptMerge: if not DoScriptMerge(FromFile, ToFile) then DoCopy := TRUE;
|
---|
| 846 | jcPrior, jcVersion: DoCopy := TRUE;
|
---|
| 847 | jcINI: INIFileUpdate(FromFile, ToFile);
|
---|
| 848 | jcLineItems: LineItemFileUpdate(FromFile, ToFile);
|
---|
| 849 | end;
|
---|
| 850 | except
|
---|
| 851 | on E: Exception do
|
---|
| 852 | FJAWSFileError := E.Message;
|
---|
| 853 | end;
|
---|
| 854 | end
|
---|
| 855 | else
|
---|
| 856 | begin
|
---|
| 857 | CheckOverwrite := FALSE;
|
---|
| 858 | DoCopy := TRUE;
|
---|
| 859 | end;
|
---|
| 860 | if DoCopy then
|
---|
| 861 | begin
|
---|
| 862 | error := FALSE;
|
---|
| 863 | if not CopyFile(PChar(FromFile), PChar(Tofile), FALSE) then
|
---|
| 864 | error := TRUE;
|
---|
| 865 | if (not error) and (not FileExists(ToFile)) then
|
---|
| 866 | error := TRUE;
|
---|
| 867 | if (not error) and CheckOverwrite and (info.CompareType <> jcPrior) and
|
---|
| 868 | UpdateNeeded(FromFile, ToFile, info.CompareType) then
|
---|
| 869 | error := TRUE;
|
---|
| 870 | if error and (not FileErrorExists) then
|
---|
| 871 | FJAWSFileError := 'Error copying "' + FromFile + '" to' + CRLF + '"' + ToFile + '".';
|
---|
| 872 | if (not error) and (info.Compile) then
|
---|
| 873 | begin
|
---|
| 874 | DeleteCompiledFile(ToFile);
|
---|
| 875 | CompileCommands.Add('"' + ToFile + '"');
|
---|
| 876 | end;
|
---|
| 877 | end;
|
---|
| 878 | end;
|
---|
| 879 |
|
---|
| 880 | procedure EnsureJAWSScriptsAreUpToDate;
|
---|
| 881 | var
|
---|
| 882 | DestFile, FromFile, ToFile, AppName, ext: string;
|
---|
| 883 | idx1, idx2, i: integer;
|
---|
| 884 | DoUpdate: boolean;
|
---|
| 885 | info: TFileInfo;
|
---|
| 886 |
|
---|
| 887 | begin
|
---|
| 888 | AppName := ExtractFileName(ParamStr(0));
|
---|
| 889 | ext := ExtractFileExt(AppName);
|
---|
| 890 | AppName := LeftStr(AppName, length(AppName) - Length(ext));
|
---|
| 891 | DestPath := '';
|
---|
| 892 | idx1 := pos(JAWS_COMMON_SCRIPT_PATH_TEXT, FUserStriptDir);
|
---|
| 893 | idx2 := pos(JAWS_COMMON_SCRIPT_PATH_TEXT, FDefaultScriptDir);
|
---|
| 894 | if (idx1 > 0) and (idx2 > 0) then
|
---|
| 895 | begin
|
---|
| 896 | DestPath := copy(FUserStriptDir,1,idx1-1) + copy(FDefaultScriptDir, idx2, MaxInt);
|
---|
| 897 | DestFile := DestPath + AppName;
|
---|
| 898 | FDictionaryFileName := DestFile + DictionaryFileExtension;
|
---|
| 899 | FConfigFile := DestFile + ConfigFileExtension;
|
---|
| 900 | FKeyMapFile := DestFile + KeyMapExtension;
|
---|
| 901 | LastFileUpdated := FALSE;
|
---|
| 902 | for i := low(FileInfo) to high(FileInfo) do
|
---|
| 903 | begin
|
---|
| 904 | info := FileInfo[i];
|
---|
| 905 | if info.AppFile then
|
---|
| 906 | begin
|
---|
| 907 | FromFile := FRootScriptAppFileName + info.Ext;
|
---|
| 908 | ToFile := DestFile + info.Ext;
|
---|
| 909 | end
|
---|
| 910 | else
|
---|
| 911 | begin
|
---|
| 912 | FromFile := FRootScriptFileName + info.Ext;
|
---|
| 913 | ToFile := DestPath + JAWS_SCRIPT_NAME + info.Ext;
|
---|
| 914 | end;
|
---|
| 915 | if not FileExists(FromFile) then continue;
|
---|
| 916 | if FileExists(ToFile) then
|
---|
| 917 | begin
|
---|
| 918 | DoUpdate := UpdateNeeded(FromFile, ToFile, info.CompareType);
|
---|
| 919 | if DoUpdate then
|
---|
| 920 | MakeFileWritable(ToFile);
|
---|
| 921 | end
|
---|
| 922 | else
|
---|
| 923 | DoUpdate := TRUE;
|
---|
| 924 | LastFileUpdated := DoUpdate;
|
---|
| 925 | if DoUpdate and (not FileErrorExists) then
|
---|
| 926 | begin
|
---|
| 927 | UpdateFile(FromFile, ToFile, info);
|
---|
| 928 | ScriptFileChanges := TRUE;
|
---|
| 929 | end;
|
---|
| 930 | if FileErrorExists then
|
---|
| 931 | break;
|
---|
| 932 | end;
|
---|
| 933 | end
|
---|
| 934 | else
|
---|
| 935 | FJAWSFileError := 'Unknown File Error'; // should never happen - condition checked previously
|
---|
| 936 | end;
|
---|
| 937 |
|
---|
| 938 | procedure DoCompiles;
|
---|
| 939 | var
|
---|
| 940 | i: integer;
|
---|
| 941 | begin
|
---|
| 942 | if not assigned(JAWSAPI) then
|
---|
| 943 | JAWSAPI := CoJawsApi.Create;
|
---|
| 944 | for i := 0 to CompileCommands.Count - 1 do
|
---|
| 945 | begin
|
---|
| 946 | ExecuteAndWait('"' + FCompiler + '"', CompileCommands[i]);
|
---|
| 947 | JAWSAPI.StopSpeech;
|
---|
| 948 | end;
|
---|
| 949 | ReloadConfiguration;
|
---|
| 950 | end;
|
---|
| 951 |
|
---|
| 952 | begin
|
---|
| 953 | Result := FALSE;
|
---|
| 954 | ScriptFileChanges := FALSE;
|
---|
| 955 | if JAWSManager.RequiredFilesFound then
|
---|
| 956 | begin
|
---|
| 957 | FJAWSFileError := '';
|
---|
| 958 | CompileCommands := TStringList.Create;
|
---|
| 959 | try
|
---|
| 960 | EnsureJAWSScriptsAreUpToDate;
|
---|
| 961 | if CompileCommands.Count > 0 then
|
---|
| 962 | DoCompiles;
|
---|
| 963 | finally
|
---|
| 964 | CompileCommands.Free;
|
---|
| 965 | end;
|
---|
| 966 | if FileErrorExists then
|
---|
| 967 | ShowError(JAWS_ERROR_FILE_IO, [FJAWSFileError])
|
---|
| 968 | else if JAWSTalking2CurrentUser then
|
---|
| 969 | begin
|
---|
| 970 | EnsureWindow;
|
---|
| 971 | LaunchMasterApplication;
|
---|
| 972 | if ScriptFileChanges then
|
---|
| 973 | begin
|
---|
| 974 | FMainForm.ConfigReloadNeeded;
|
---|
| 975 | end;
|
---|
| 976 | Result := TRUE;
|
---|
| 977 | end;
|
---|
| 978 | end;
|
---|
| 979 | end;
|
---|
| 980 |
|
---|
| 981 | class function TJAWSManager.IsRunning(HighVersion, LowVersion: Word): BOOL;
|
---|
| 982 |
|
---|
| 983 | function ComponentVersionSupported: boolean;
|
---|
| 984 | var
|
---|
| 985 | SupportedHighVersion, SupportedLowVersion: integer;
|
---|
| 986 | FileName, newVersion, convertedVersion, currentVersion: string;
|
---|
| 987 | addr: pointer;
|
---|
| 988 |
|
---|
| 989 | begin
|
---|
| 990 | addr := @TJAWSManager.IsRunning;
|
---|
| 991 | FileName := GetDLLFileName(addr);
|
---|
| 992 | currentVersion := FileVersionValue(FileName, FILE_VER_FILEVERSION);
|
---|
| 993 | VersionStringSplit(currentVersion, SupportedHighVersion, SupportedLowVersion);
|
---|
| 994 | Result := FALSE;
|
---|
| 995 | if (HighVersion < SupportedHighVersion) then
|
---|
| 996 | Result := TRUE
|
---|
| 997 | else
|
---|
| 998 | if (HighVersion = SupportedHighVersion) and
|
---|
| 999 | (LowVersion <= SupportedLowVersion) then
|
---|
| 1000 | Result := TRUE;
|
---|
| 1001 | if not Result then
|
---|
| 1002 | begin
|
---|
| 1003 | newVersion := IntToStr(HighVersion) + '.' + IntToStr(LowVersion);
|
---|
| 1004 | convertedVersion := IntToStr(SupportedHighVersion) + '.' + IntToStr(SupportedLowVersion);
|
---|
| 1005 | ShowError(DLL_ERROR_VERSION, [newVersion, convertedVersion]);
|
---|
| 1006 | end;
|
---|
| 1007 | end;
|
---|
| 1008 |
|
---|
| 1009 | begin
|
---|
| 1010 | Result := (GetJAWSWindow <> 0);
|
---|
| 1011 | if Result then
|
---|
| 1012 | Result := ComponentVersionSupported;
|
---|
| 1013 | if Result then
|
---|
| 1014 | Result := JAWSVersionOK;
|
---|
| 1015 | if Result then
|
---|
| 1016 | begin
|
---|
| 1017 | EnsureManager;
|
---|
| 1018 | with JAWSManager do
|
---|
| 1019 | Result := RequiredFilesFound;
|
---|
| 1020 | end;
|
---|
| 1021 | end;
|
---|
| 1022 |
|
---|
| 1023 | class function TJAWSManager.JAWSTalking2CurrentUser: boolean;
|
---|
| 1024 | var
|
---|
| 1025 | CurrentUserPath: string;
|
---|
| 1026 | WhatJAWSThinks: string;
|
---|
| 1027 |
|
---|
| 1028 | procedure Fix(var path: string);
|
---|
| 1029 | var
|
---|
| 1030 | idx: integer;
|
---|
| 1031 | begin
|
---|
| 1032 | idx := pos(APP_DATA, lowercase(path));
|
---|
| 1033 | if idx > 0 then
|
---|
| 1034 | path := LeftStr(path,idx-1);
|
---|
| 1035 | idx := length(path);
|
---|
| 1036 | while (idx > 0) and (path[idx] <> '\') do dec(idx);
|
---|
| 1037 | delete(path,1,idx);
|
---|
| 1038 | end;
|
---|
| 1039 |
|
---|
| 1040 | function UserProblemExists: boolean;
|
---|
| 1041 | begin
|
---|
| 1042 | CurrentUserPath := GetSpecialFolderPath(CSIDL_APPDATA);
|
---|
| 1043 | WhatJAWSThinks := GetPathFromJAWS(JAWS_PATH_ID_USER_SCRIPT_FILES, FALSE);
|
---|
| 1044 | fix(CurrentUserPath);
|
---|
| 1045 | fix(WhatJAWSThinks);
|
---|
| 1046 | Result := (lowercase(CurrentUserPath) <> lowercase(WhatJAWSThinks));
|
---|
| 1047 | end;
|
---|
| 1048 |
|
---|
| 1049 | begin
|
---|
| 1050 | if UserProblemExists then
|
---|
| 1051 | begin
|
---|
| 1052 | ShowError(JAWS_ERROR_USER_PROBLEM);
|
---|
| 1053 | Result := FALSE;
|
---|
| 1054 | end
|
---|
| 1055 | else
|
---|
| 1056 | Result := TRUE;
|
---|
| 1057 | end;
|
---|
| 1058 |
|
---|
| 1059 | class function TJAWSManager.JAWSVersionOK: boolean;
|
---|
| 1060 | var
|
---|
| 1061 | JFileVersion: string;
|
---|
| 1062 | JFile: string;
|
---|
| 1063 |
|
---|
| 1064 | function OlderVersionOKIfCOMObjectInstalled: boolean;
|
---|
| 1065 | var
|
---|
| 1066 | api: IJawsApi;
|
---|
| 1067 | begin
|
---|
| 1068 | Result := VersionOK(JAWS_REQUIRED_VERSION, JFileVersion);
|
---|
| 1069 | if Result then
|
---|
| 1070 | begin
|
---|
| 1071 | try
|
---|
| 1072 | try
|
---|
| 1073 | api := CoJawsApi.Create;
|
---|
| 1074 | except
|
---|
| 1075 | Result := FALSE;
|
---|
| 1076 | end;
|
---|
| 1077 | finally
|
---|
| 1078 | api := nil;
|
---|
| 1079 | end;
|
---|
| 1080 | end;
|
---|
| 1081 | end;
|
---|
| 1082 |
|
---|
| 1083 | begin
|
---|
| 1084 | JFile := GetPathFromJAWS(JAWS_PATH_ID_APPLICATION);//JAWS_PATH_ID_USER_SCRIPT_FILES);
|
---|
| 1085 | JFile := AppendBackSlash(JFile) + JAWS_APPLICATION_FILENAME;
|
---|
| 1086 | if FileExists(JFile) then
|
---|
| 1087 | begin
|
---|
| 1088 | JFileVersion := FileVersionValue(JFile, FILE_VER_FILEVERSION);
|
---|
| 1089 | Result := VersionOK(JAWS_COM_OBJECT_VERSION, JFileVersion);
|
---|
| 1090 | if not Result then
|
---|
| 1091 | Result := OlderVersionOKIfCOMObjectInstalled;
|
---|
| 1092 | end
|
---|
| 1093 | else
|
---|
| 1094 | begin
|
---|
| 1095 | // if file not found, then assume a future version where the exe was moved
|
---|
| 1096 | // to a different location
|
---|
| 1097 | Result := TRUE;
|
---|
| 1098 | end;
|
---|
| 1099 | if not Result then
|
---|
| 1100 | ShowError(JAWS_ERROR_VERSION);
|
---|
| 1101 | end;
|
---|
| 1102 |
|
---|
| 1103 | procedure TJAWSManager.KillINIFiles(Sender: TObject);
|
---|
| 1104 | begin
|
---|
| 1105 | if assigned(FDictionaryFile) then
|
---|
| 1106 | begin
|
---|
| 1107 | if FDictionaryFileModified then
|
---|
| 1108 | begin
|
---|
| 1109 | MakeFileWritable(FDictionaryFileName);
|
---|
| 1110 | FDictionaryFile.SaveToFile(FDictionaryFileName);
|
---|
| 1111 | end;
|
---|
| 1112 | FreeAndNil(FDictionaryFile);
|
---|
| 1113 | end;
|
---|
| 1114 |
|
---|
| 1115 | if assigned(FConfigINIFile) then
|
---|
| 1116 | begin
|
---|
| 1117 | if FConfigINIFileModified then
|
---|
| 1118 | begin
|
---|
| 1119 | FConfigINIFile.UpdateFile;
|
---|
| 1120 | end;
|
---|
| 1121 | FreeAndNil(FConfigINIFile);
|
---|
| 1122 | end;
|
---|
| 1123 |
|
---|
| 1124 | if assigned(FKeyMapINIFile) then
|
---|
| 1125 | begin
|
---|
| 1126 | if FKeyMapINIFileModified then
|
---|
| 1127 | begin
|
---|
| 1128 | FKeyMapINIFile.UpdateFile;
|
---|
| 1129 | end;
|
---|
| 1130 | FreeAndNil(FKeyMapINIFile);
|
---|
| 1131 | end;
|
---|
| 1132 |
|
---|
| 1133 | if assigned(FAssignedKeys) then
|
---|
| 1134 | FreeAndNil(FAssignedKeys);
|
---|
| 1135 | end;
|
---|
| 1136 |
|
---|
| 1137 | procedure TJAWSManager.LaunchMasterApplication;
|
---|
| 1138 | begin
|
---|
| 1139 | if FileExists(FMasterApp) then
|
---|
| 1140 | ShellExecute(0, PChar('open'), PChar(FMasterApp), nil,
|
---|
| 1141 | PChar(ExtractFilePath(FMasterApp)), SW_SHOWNA);
|
---|
| 1142 | end;
|
---|
| 1143 |
|
---|
| 1144 |
|
---|
| 1145 | procedure TJAWSManager.RegisterCustomBehavior(Before, After: string;
|
---|
| 1146 | Action: integer);
|
---|
| 1147 |
|
---|
| 1148 | const
|
---|
| 1149 | WindowClassesSection = 'WindowClasses';
|
---|
| 1150 | MSAAClassesSection = 'MSAAClasses';
|
---|
| 1151 | DICT_DELIM: char = Char($2E);
|
---|
| 1152 | CommonKeysSection = 'Common Keys';
|
---|
| 1153 | CustomCommandHelpSection = 'Custom Command Help';
|
---|
| 1154 | KeyCommand = 'VA508SendCustomCommand(';
|
---|
| 1155 | KeyCommandLen = length(KeyCommand);
|
---|
| 1156 |
|
---|
| 1157 | var
|
---|
| 1158 | modified: boolean;
|
---|
| 1159 |
|
---|
| 1160 | procedure Add2INIFile(var INIFile: TINIFile; var FileModified: boolean;
|
---|
| 1161 | FileName, SectionName, Data, Value: string);
|
---|
| 1162 | var
|
---|
| 1163 | oldValue: string;
|
---|
| 1164 |
|
---|
| 1165 | begin
|
---|
| 1166 | if not assigned(INIFile) then
|
---|
| 1167 | begin
|
---|
| 1168 | MakeFileWritable(FileName);
|
---|
| 1169 | INIFile := TINIFile.Create(FileName);
|
---|
| 1170 | FileModified := FALSE;
|
---|
| 1171 | end;
|
---|
| 1172 | OldValue := INIFile.ReadString(SectionName, Data, '');
|
---|
| 1173 | if OldValue <> Value then
|
---|
| 1174 | begin
|
---|
| 1175 | INIFile.WriteString(SectionName, Data, Value);
|
---|
| 1176 | modified := TRUE;
|
---|
| 1177 | FileModified := TRUE;
|
---|
| 1178 | end;
|
---|
| 1179 | end;
|
---|
| 1180 |
|
---|
| 1181 | procedure RemoveFromINIFile(var INIFile: TINIFile; var FileModified: boolean;
|
---|
| 1182 | FileName, SectionName, Data: string);
|
---|
| 1183 | var
|
---|
| 1184 | oldValue: string;
|
---|
| 1185 |
|
---|
| 1186 | begin
|
---|
| 1187 | if not assigned(INIFile) then
|
---|
| 1188 | begin
|
---|
| 1189 | MakeFileWritable(FileName);
|
---|
| 1190 | INIFile := TINIFile.Create(FileName);
|
---|
| 1191 | FileModified := FALSE;
|
---|
| 1192 | end;
|
---|
| 1193 | OldValue := INIFile.ReadString(SectionName, Data, '');
|
---|
| 1194 | if OldValue <> '' then
|
---|
| 1195 | begin
|
---|
| 1196 | INIFile.DeleteKey(SectionName, Data);
|
---|
| 1197 | modified := TRUE;
|
---|
| 1198 | FileModified := TRUE;
|
---|
| 1199 | end;
|
---|
| 1200 | end;
|
---|
| 1201 |
|
---|
| 1202 | procedure RegisterCustomClassChange;
|
---|
| 1203 | begin
|
---|
| 1204 | Add2INIFile(FConfigINIFile, FConfigINIFileModified, FConfigFile,
|
---|
| 1205 | WindowClassesSection, Before, After);
|
---|
| 1206 | end;
|
---|
| 1207 |
|
---|
| 1208 | procedure RegisterMSAAClassChange;
|
---|
| 1209 | begin
|
---|
| 1210 | Add2INIFile(FConfigINIFile, FConfigINIFileModified, FConfigFile,
|
---|
| 1211 | MSAAClassesSection, Before, '1');
|
---|
| 1212 | end;
|
---|
| 1213 |
|
---|
| 1214 | procedure RegisterCustomKeyMapping;
|
---|
| 1215 | begin
|
---|
| 1216 | Add2INIFile(FKeyMapINIFile, FKeyMapINIFileModified, FKeyMapFile,
|
---|
| 1217 | CommonKeysSection, Before, KeyCommand + after + ')');
|
---|
| 1218 | if not assigned(FAssignedKeys) then
|
---|
| 1219 | FAssignedKeys := TStringList.Create;
|
---|
| 1220 | FAssignedKeys.Add(Before);
|
---|
| 1221 | end;
|
---|
| 1222 |
|
---|
| 1223 | procedure RegisterCustomKeyDescription;
|
---|
| 1224 | begin
|
---|
| 1225 | Add2INIFile(FConfigINIFile, FConfigINIFileModified, FConfigFile,
|
---|
| 1226 | CustomCommandHelpSection, Before, After);
|
---|
| 1227 | end;
|
---|
| 1228 |
|
---|
| 1229 | procedure DecodeLine(line: string; var before1, after1: string);
|
---|
| 1230 | var
|
---|
| 1231 | i, j, len: integer;
|
---|
| 1232 | begin
|
---|
| 1233 | before1 := '';
|
---|
| 1234 | after1 := '';
|
---|
| 1235 | len := length(line);
|
---|
| 1236 | if (len < 2) or (line[1] <> DICT_DELIM) then exit;
|
---|
| 1237 | i := 2;
|
---|
| 1238 | while (i < len) and (line[i] <> DICT_DELIM) do inc(i);
|
---|
| 1239 | before1 := copy(line,2,i-2);
|
---|
| 1240 | j := i + 1;
|
---|
| 1241 | while (j <= len) and (line[j] <> DICT_DELIM) do inc(j);
|
---|
| 1242 | after1 := copy(line,i+1,j-i-1);
|
---|
| 1243 | end;
|
---|
| 1244 |
|
---|
| 1245 | procedure RegisterCustomDictionaryChange;
|
---|
| 1246 | var
|
---|
| 1247 | i, idx: integer;
|
---|
| 1248 | line, before1, after1: string;
|
---|
| 1249 | add: boolean;
|
---|
| 1250 | begin
|
---|
| 1251 | if not assigned(FDictionaryFile) then
|
---|
| 1252 | begin
|
---|
| 1253 | FDictionaryFile := TStringList.Create;
|
---|
| 1254 | FDictionaryFileModified := FALSE;
|
---|
| 1255 | if FileExists(FDictionaryFileName) then
|
---|
| 1256 | FDictionaryFile.LoadFromFile(FDictionaryFileName);
|
---|
| 1257 | end;
|
---|
| 1258 |
|
---|
| 1259 | add := TRUE;
|
---|
| 1260 | idx := -1;
|
---|
| 1261 | for I := 0 to FDictionaryFile.Count - 1 do
|
---|
| 1262 | begin
|
---|
| 1263 | line := FDictionaryFile[i];
|
---|
| 1264 | DecodeLine(line, before1, after1);
|
---|
| 1265 | if (before1 = Before) then
|
---|
| 1266 | begin
|
---|
| 1267 | idx := i;
|
---|
| 1268 | if after1 = after then
|
---|
| 1269 | add := false;
|
---|
| 1270 | break;
|
---|
| 1271 | end;
|
---|
| 1272 | end;
|
---|
| 1273 | if add then
|
---|
| 1274 | begin
|
---|
| 1275 | line := DICT_DELIM + Before + DICT_DELIM + after + DICT_DELIM;
|
---|
| 1276 | if idx < 0 then
|
---|
| 1277 | FDictionaryFile.Add(line)
|
---|
| 1278 | else
|
---|
| 1279 | FDictionaryFile[idx] := line;
|
---|
| 1280 | modified := TRUE;
|
---|
| 1281 | FDictionaryFileModified := TRUE;
|
---|
| 1282 | end;
|
---|
| 1283 | end;
|
---|
| 1284 |
|
---|
| 1285 | procedure RemoveComponentClass;
|
---|
| 1286 | begin
|
---|
| 1287 | RemoveFromINIFile(FConfigINIFile, FConfigINIFileModified, FConfigFile,
|
---|
| 1288 | WindowClassesSection, Before);
|
---|
| 1289 | end;
|
---|
| 1290 |
|
---|
| 1291 | procedure RemoveMSAAClass;
|
---|
| 1292 | begin
|
---|
| 1293 | RemoveFromINIFile(FConfigINIFile, FConfigINIFileModified, FConfigFile,
|
---|
| 1294 | MSAAClassesSection, Before);
|
---|
| 1295 | end;
|
---|
| 1296 |
|
---|
| 1297 | procedure PurgeKeyMappings;
|
---|
| 1298 | var
|
---|
| 1299 | i: integer;
|
---|
| 1300 | name, value: string;
|
---|
| 1301 | keys: TStringList;
|
---|
| 1302 | delete: boolean;
|
---|
| 1303 | begin
|
---|
| 1304 | if not assigned(FKeyMapINIFile) then
|
---|
| 1305 | begin
|
---|
| 1306 | MakeFileWritable(FKeyMapFile);
|
---|
| 1307 | FKeyMapINIFile := TINIFile.Create(FKeyMapFile);
|
---|
| 1308 | FKeyMapINIFileModified := FALSE;
|
---|
| 1309 | end;
|
---|
| 1310 | keys := TStringList.Create;
|
---|
| 1311 | try
|
---|
| 1312 | FKeyMapINIFile.ReadSectionValues(CommonKeysSection, keys);
|
---|
| 1313 | for i := keys.Count - 1 downto 0 do
|
---|
| 1314 | begin
|
---|
| 1315 | value := copy(keys.ValueFromIndex[i],1,KeyCommandLen);
|
---|
| 1316 | if value = KeyCommand then
|
---|
| 1317 | begin
|
---|
| 1318 | name := keys.Names[i];
|
---|
| 1319 | delete := (not assigned(FAssignedKeys));
|
---|
| 1320 | if not delete then
|
---|
| 1321 | delete := (FAssignedKeys.IndexOf(name) < 0);
|
---|
| 1322 | if delete then
|
---|
| 1323 | begin
|
---|
| 1324 | FKeyMapINIFile.DeleteKey(CommonKeysSection, name);
|
---|
| 1325 | FKeyMapINIFileModified := TRUE;
|
---|
| 1326 | modified := TRUE;
|
---|
| 1327 | end;
|
---|
| 1328 | end;
|
---|
| 1329 | end;
|
---|
| 1330 | finally
|
---|
| 1331 | keys.Free;
|
---|
| 1332 | end;
|
---|
| 1333 | end;
|
---|
| 1334 |
|
---|
| 1335 | begin
|
---|
| 1336 | { TODO : check file io errors when updating config files }
|
---|
| 1337 | modified := FALSE;
|
---|
| 1338 | case Action of
|
---|
| 1339 | BEHAVIOR_ADD_DICTIONARY_CHANGE: RegisterCustomDictionaryChange;
|
---|
| 1340 | BEHAVIOR_ADD_COMPONENT_CLASS: RegisterCustomClassChange;
|
---|
| 1341 | BEHAVIOR_ADD_COMPONENT_MSAA: RegisterMSAAClassChange;
|
---|
| 1342 | BEHAVIOR_ADD_CUSTOM_KEY_MAPPING: RegisterCustomKeyMapping;
|
---|
| 1343 | BEHAVIOR_ADD_CUSTOM_KEY_DESCRIPTION: RegisterCustomKeyDescription;
|
---|
| 1344 | BEHAVIOR_REMOVE_COMPONENT_CLASS: RemoveComponentClass;
|
---|
| 1345 | BEHAVIOR_REMOVE_COMPONENT_MSAA: RemoveMSAAClass;
|
---|
| 1346 | BEHAVIOR_PURGE_UNREGISTERED_KEY_MAPPINGS: PurgeKeyMappings;
|
---|
| 1347 | end;
|
---|
| 1348 | if modified and assigned(FMainForm) then
|
---|
| 1349 | begin
|
---|
| 1350 | FMainForm.ResetINITimer(KillINIFiles);
|
---|
| 1351 | FMainForm.ConfigReloadNeeded;
|
---|
| 1352 | end;
|
---|
| 1353 | end;
|
---|
| 1354 |
|
---|
| 1355 | procedure TJAWSManager.ReloadConfiguration;
|
---|
| 1356 | begin
|
---|
| 1357 | if not assigned(JAWSAPI) then
|
---|
| 1358 | JAWSAPI := CoJawsApi.Create;
|
---|
| 1359 | JAWSAPI.RunFunction('ReloadAllConfigs');
|
---|
| 1360 | end;
|
---|
| 1361 |
|
---|
| 1362 | procedure TJAWSManager.SendComponentData(WindowHandle: HWND; DataStatus: LongInt; Caption, Value,
|
---|
| 1363 | Data, ControlType, State, Instructions, ItemInstructions: PChar);
|
---|
| 1364 |
|
---|
| 1365 | procedure SendRequestResponse;
|
---|
| 1366 | begin
|
---|
| 1367 | FMainForm.WriteData(VA508_REG_COMPONENT_CAPTION, Caption);
|
---|
| 1368 | FMainForm.WriteData(VA508_REG_COMPONENT_VALUE, Value);
|
---|
| 1369 | FMainForm.WriteData(VA508_REG_COMPONENT_CONTROL_TYPE, ControlType);
|
---|
| 1370 | FMainForm.WriteData(VA508_REG_COMPONENT_STATE, State);
|
---|
| 1371 | FMainForm.WriteData(VA508_REG_COMPONENT_INSTRUCTIONS, Instructions);
|
---|
| 1372 | FMainForm.WriteData(VA508_REG_COMPONENT_ITEM_INSTRUCTIONS, ItemInstructions);
|
---|
| 1373 | FMainForm.WriteData(VA508_REG_COMPONENT_DATA_STATUS, IntToStr(DataStatus));
|
---|
| 1374 | FMainForm.PostData;
|
---|
| 1375 | end;
|
---|
| 1376 |
|
---|
| 1377 | procedure SendChangeEvent;
|
---|
| 1378 | var
|
---|
| 1379 | Event: WideString;
|
---|
| 1380 | begin
|
---|
| 1381 | Event := 'VA508ChangeEvent(' + IntToStr(WindowHandle) + ',' +
|
---|
| 1382 | IntToStr(DataStatus) + ',"' +
|
---|
| 1383 | StrPas(Caption) + '","' +
|
---|
| 1384 | StrPas(Value) + '","' +
|
---|
| 1385 | StrPas(ControlType) + '","' +
|
---|
| 1386 | StrPas(State) + '","' +
|
---|
| 1387 | StrPas(Instructions) + '","' +
|
---|
| 1388 | StrPas(ItemInstructions) + '"';
|
---|
| 1389 | if not assigned(JAWSAPI) then
|
---|
| 1390 | JAWSAPI := CoJawsApi.Create;
|
---|
| 1391 | JAWSAPI.RunFunction(Event)
|
---|
| 1392 | end;
|
---|
| 1393 |
|
---|
| 1394 | begin
|
---|
| 1395 | if (Data <> nil) and (Length(Data) > 0) then
|
---|
| 1396 | begin
|
---|
| 1397 | Value := Data;
|
---|
| 1398 | DataStatus := DataStatus AND DATA_MASK_DATA;
|
---|
| 1399 | DataStatus := DataStatus OR DATA_VALUE;
|
---|
| 1400 | end;
|
---|
| 1401 | if (DataStatus and DATA_CHANGE_EVENT) <> 0 then
|
---|
| 1402 | begin
|
---|
| 1403 | DataStatus := DataStatus AND DATA_MASK_CHANGE_EVENT;
|
---|
| 1404 | SendChangeEvent;
|
---|
| 1405 | end
|
---|
| 1406 | else
|
---|
| 1407 | SendRequestResponse;
|
---|
| 1408 | end;
|
---|
| 1409 |
|
---|
| 1410 | const
|
---|
| 1411 | MAX_REG_CHARS = 125; // When Jaws reads over 126 chars it returns a blank string
|
---|
| 1412 | MORE_STRINGS = '+';
|
---|
| 1413 | LAST_STRING = '-';
|
---|
| 1414 | MAX_COUNT_KEY = 'Max';
|
---|
| 1415 |
|
---|
| 1416 | class procedure TJAWSManager.ShowError(ErrorNumber: integer);
|
---|
| 1417 | begin
|
---|
| 1418 | ShowError(ErrorNumber, []);
|
---|
| 1419 | end;
|
---|
| 1420 |
|
---|
| 1421 | class procedure TJAWSManager.ShowError(ErrorNumber: integer; data: array of const);
|
---|
| 1422 | var
|
---|
| 1423 | error: string;
|
---|
| 1424 |
|
---|
| 1425 | begin
|
---|
| 1426 | if not JAWSErrorsShown[ErrorNumber] then
|
---|
| 1427 | begin
|
---|
| 1428 | error := JAWSErrorMessage[ErrorNumber];
|
---|
| 1429 | if length(data) > 0 then
|
---|
| 1430 | error := Format(error, data);
|
---|
| 1431 | JAWSErrorsShown[ErrorNumber] := TRUE;
|
---|
| 1432 | MessageBox(0, PChar(error), 'JAWS Accessibility Component Error',
|
---|
| 1433 | MB_OK or MB_ICONERROR or MB_TASKMODAL or MB_TOPMOST);
|
---|
| 1434 | end;
|
---|
| 1435 | end;
|
---|
| 1436 |
|
---|
| 1437 | procedure TJAWSManager.ShutDown;
|
---|
| 1438 | begin
|
---|
| 1439 | if FWasShutdown then exit;
|
---|
| 1440 | if assigned(JAWSAPI) then
|
---|
| 1441 | begin
|
---|
| 1442 | try
|
---|
| 1443 | JAWSAPI := nil; // causes access violation
|
---|
| 1444 | except
|
---|
| 1445 | end;
|
---|
| 1446 | end;
|
---|
| 1447 | KillINIFiles(nil);
|
---|
| 1448 | if assigned(FMainForm) then
|
---|
| 1449 | FreeAndNil(FMainForm);
|
---|
| 1450 | FWasShutdown := TRUE;
|
---|
| 1451 | end;
|
---|
| 1452 |
|
---|
| 1453 | procedure TJAWSManager.SpeakText(Text: PChar);
|
---|
| 1454 | begin
|
---|
| 1455 | if not assigned(JAWSAPI) then
|
---|
| 1456 | JAWSAPI := CoJawsApi.Create;
|
---|
| 1457 | JAWSAPI.SayString(Text, FALSE);
|
---|
| 1458 | end;
|
---|
| 1459 |
|
---|
| 1460 |
|
---|
| 1461 | initialization
|
---|
| 1462 | CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
|
---|
| 1463 |
|
---|
| 1464 | finalization
|
---|
| 1465 | ShutDown;
|
---|
| 1466 | CoUninitialize;
|
---|
| 1467 |
|
---|
| 1468 | end.
|
---|