Path: blob/master/src/jdk.accessibility/windows/native/jabswitch/jabswitch.cpp
40957 views
/*1* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <stdio.h>26#include <string.h>27#include <stdlib.h>28#include <ctype.h>29#include <Windows.h>30#include <tchar.h>3132// This is the default buffer size used for RegQueryValue values.33#define DEFAULT_ALLOC MAX_PATH34// only allocate a buffer as big as MAX_ALLOC for RegQueryValue values.35#define MAX_ALLOC 2621443637static LPCTSTR ACCESSIBILITY_USER_KEY =38_T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility");39static LPCTSTR ACCESSIBILITY_SYSTEM_KEY =40_T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\Session");41static LPCTSTR ACCESSIBILITY_CONFIG =42_T("Configuration");43static LPCTSTR STR_ACCESSBRIDGE =44_T("oracle_javaaccessbridge");4546// Note: There are senarios where more than one extension can be specified on the47// asssistive_technologies=48// line but this code only deals with the case of49// assistive_technologies=com.sun.java.accessibility.AccessBridge50// assuming that if additional extensions are desired the user knows how edit the file.5152FILE* origFile;53FILE* tempFile;5455bool isXP()56{57static bool isXPFlag = false;58OSVERSIONINFO osvi;5960// Initialize the OSVERSIONINFO structure.61ZeroMemory( &osvi, sizeof( osvi ) );62osvi.dwOSVersionInfoSize = sizeof( osvi );6364GetVersionEx( &osvi );6566if ( osvi.dwMajorVersion == 5 ) // For Windows XP and Windows 200067isXPFlag = true;6869return isXPFlag ;70}7172void enableJAB() {73// Copy lines from orig to temp modifying the line containing74// assistive_technologies=75// There are various scenarios:76// 1) If the line exists exactly as77// #assistive_technologies=com.sun.java.accessibility.AccessBridge78// replace it with79// assistive_technologies=com.sun.java.accessibility.AccessBridge80// 2) else if the line exists exactly as81// assistive_technologies=com.sun.java.accessibility.AccessBridge82// use it as is83// 3) else if a line containing "assistive_technologies" exits84// a) if it's already commented out, us it as is (jab will be enabled in step 4)85// b) else if it's not commented out, comment it out and add a new line with86// assistive_technologies=com.sun.java.accessibility.AccessBridge87// 4) If the line doesn't exist (or case 3a), add88// assistive_technologies=com.sun.java.accessibility.AccessBridge89// Do the same for screen_magnifier_present=90char line[512];91char commentLine[512] = "#";92char jabLine[] = "assistive_technologies=com.sun.java.accessibility.AccessBridge\n";93char magLine[] = "screen_magnifier_present=true\n";94bool foundJabLine = false;95bool foundMagLine = false;96while (!feof(origFile)) {97if (fgets(line, 512, origFile) != NULL) {98if (_stricmp(line, "#assistive_technologies=com.sun.java.accessibility.AccessBridge\n") == 0) {99fputs(jabLine, tempFile);100foundJabLine = true;101} else if (_stricmp(line, jabLine) == 0) {102fputs(line, tempFile);103foundJabLine = true;104} else if (strstr(line, "assistive_technologies") != NULL) {105char* context;106char* firstNonSpaceChar = strtok_s(line, " ", &context);107if (*firstNonSpaceChar == '#') {108fputs(line, tempFile);109} else {110strcat_s(commentLine, line);111fputs(commentLine, tempFile);112fputs(jabLine, tempFile);113foundJabLine = true;114}115} else if (_stricmp(line, "#screen_magnifier_present=true\n") == 0) {116fputs(magLine, tempFile);117foundMagLine = true;118} else if (_stricmp(line, magLine) == 0) {119fputs(line, tempFile);120foundMagLine = true;121} else if (strstr(line, "screen_magnifier_present") != NULL) {122char* context;123char* firstNonSpaceChar = strtok_s(line, " ", &context);124if (*firstNonSpaceChar == '#') {125fputs(line, tempFile);126} else {127strcat_s(commentLine, line);128fputs(commentLine, tempFile);129fputs(magLine, tempFile);130foundMagLine = true;131}132} else {133fputs(line, tempFile);134}135}136}137if (!foundJabLine) {138fputs(jabLine, tempFile);139}140if (!foundMagLine) {141fputs(magLine, tempFile);142}143}144145void disableJAB() {146// Copy lines from orig to temp modifying the line containing147// assistive_technologies=148// There are various scenarios:149// 1) If the uncommented line exists, comment it out150// 2) If the line exists but is preceeded by a #, nothing to do151// 3) If the line doesn't exist, nothing to do152// Do the same for screen_magnifier_present=153char line[512];154char commentLine[512];155while (!feof(origFile)) {156if (fgets(line, 512, origFile) != NULL) {157if (strstr(line, "assistive_technologies") != NULL) {158char* context;159char* firstNonSpaceChar = strtok_s(line, " ", &context);160if (*firstNonSpaceChar != '#') {161strcpy_s(commentLine, "#");162strcat_s(commentLine, line);163fputs(commentLine, tempFile);164} else {165fputs(line, tempFile);166}167} else if (strstr(line, "screen_magnifier_present") != NULL) {168char* context;169char* firstNonSpaceChar = strtok_s(line, " ", &context);170if (*firstNonSpaceChar != '#') {171strcpy_s(commentLine, "#");172strcat_s(commentLine, line);173fputs(commentLine, tempFile);174} else {175fputs(line, tempFile);176}177} else {178fputs(line, tempFile);179}180}181}182}183184int modify(bool enable) {185errno_t error = 0;186char path[_MAX_PATH];187char tempPath[_MAX_PATH];188// Get the path for %USERPROFILE%189char *profilePath;190size_t len;191error = _dupenv_s(&profilePath, &len, "USERPROFILE" );192if (error) {193printf("Error fetching USERPROFILE.\n");194perror("Error");195return error;196}197const char acc_props1[] = "\\.accessibility.properties";198const char acc_props2[] = "\\.acce$$ibility.properties";199// len must be 234 or less (233 characters)200// sizeof(path) is 260 (room for 259 characters)201// sizeof(acc_props1) is 27 (26 characters)202// path will hold 233 path characters plus 26 file characters plus 1 null character)203// if len - 1 > 233 then error204if ( len - 1 > sizeof(path) - sizeof(acc_props1) ||205len - 1 > sizeof(tempPath) - sizeof(acc_props2) ) {206printf("The USERPROFILE environment variable is too long.\n");207printf("It must be no longer than 233 characters.\n");208free(profilePath);209return 123;210}211path[0] = 0;212strcat_s(path, _MAX_PATH, profilePath);213strcat_s(path, acc_props1);214tempPath[0] = 0;215strcat_s(tempPath, _MAX_PATH, profilePath);216strcat_s(tempPath, acc_props2);217free(profilePath);218profilePath = 0;219// Open the original file. If it doesn't exist and this is an enable request then create it.220error = fopen_s(&origFile, path, "r");221if (error) {222if (enable) {223error = fopen_s(&origFile, path, "w");224if (error) {225printf("Couldn't create file: %s\n", path);226perror("Error");227} else {228char str[100] = "assistive_technologies=com.sun.java.accessibility.AccessBridge\n";229strcat_s(str, "screen_magnifier_present=true\n");230fprintf(origFile, str);231fclose(origFile);232}233} else {234// It's OK if the file isn't there for a -disable235error = 0;236}237} else {238// open a temp file239error = fopen_s(&tempFile, tempPath, "w");240if (error) {241printf("Couldn't open temp file: %s\n", tempPath);242perror("Error");243return error;244}245if (enable) {246enableJAB();247} else {248disableJAB();249}250fclose(origFile);251fclose(tempFile);252// delete the orig file and rename the temp file253if (remove(path) != 0) {254printf("Couldn't remove file: %s\n", path);255perror("Error");256return errno;257}258if (rename(tempPath, path) != 0) {259printf("Couldn't rename %s to %s.\n", tempPath, path);260perror("Error");261return errno;262}263}264return error;265}266267void printUsage() {268printf("\njabswitch [/enable | /disable | /version | /?]\n\n");269printf("Description:\n");270printf(" jabswitch enables or disables the Java Access Bridge.\n\n");271printf("Parameters:\n");272printf(" /enable Enable the Java Accessibility Bridge.\n");273printf(" /disable Disable the Java Accessibility Bridge.\n");274printf(" /version Display the version.\n");275printf(" /? Display this usage information.\n");276printf("\nNote:\n");277printf(" The Java Access Bridge can also be enabled with the\n");278printf(" Windows Ease of Access control panel (which can be\n");279printf(" activated by pressing Windows + U). The Ease of Access\n");280printf(" control panel has a Java Access Bridge checkbox. Please\n");281printf(" be aware that unchecking the checkbox has no effect and\n");282printf(" in order to disable the Java Access Bridge you must run\n");283printf(" jabswitch.exe from the command line.\n");284}285286void printVersion() {287TCHAR executableFileName[_MAX_PATH];288if (!GetModuleFileName(0, executableFileName, _MAX_PATH)) {289printf("Unable to get executable file name.\n");290return;291}292DWORD nParam;293DWORD nVersionSize = GetFileVersionInfoSize(executableFileName, &nParam);294if (!nVersionSize) {295printf("Unable to get version info size.\n");296return;297}298char* pVersionData = new char[nVersionSize];299if (!GetFileVersionInfo(executableFileName, 0, nVersionSize, pVersionData)) {300printf("Unable to get version info.\n");301return;302}303LPVOID pVersionInfo;304UINT nSize;305if (!VerQueryValue(pVersionData, _T("\\"), &pVersionInfo, &nSize)) {306printf("Unable to query version value.\n");307return;308}309VS_FIXEDFILEINFO *pVSInfo = (VS_FIXEDFILEINFO *)pVersionInfo;310char versionString[100];311sprintf_s( versionString, "version %i.%i.%i.%i",312pVSInfo->dwProductVersionMS >> 16,313pVSInfo->dwProductVersionMS & 0xFFFF,314pVSInfo->dwProductVersionLS >> 16,315pVSInfo->dwProductVersionLS & 0xFFFF );316char outputString[100];317strcpy_s(outputString, "jabswitch ");318strcat_s(outputString, versionString);319strcat_s(outputString, "\njabswitch enables or disables the Java Access Bridge.\n");320printf(outputString);321}322323int regEnable() {324HKEY hKey;325DWORD retval = -1;326LSTATUS err;327err = RegOpenKeyEx(HKEY_CURRENT_USER, ACCESSIBILITY_USER_KEY, NULL, KEY_READ|KEY_WRITE, &hKey);328if (err == ERROR_SUCCESS) {329DWORD dataType = REG_SZ;330DWORD dataLength = DEFAULT_ALLOC;331TCHAR dataBuffer[DEFAULT_ALLOC];332TCHAR *data = dataBuffer;333bool freeData = false;334err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength);335if (err == ERROR_MORE_DATA) {336if (dataLength > 0 && dataLength < MAX_ALLOC) {337data = new TCHAR[dataLength];338err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength);339}340}341if (err == ERROR_SUCCESS) {342err = _tcslwr_s(dataBuffer, DEFAULT_ALLOC);343if (err) {344return -1;345}346if (_tcsstr(dataBuffer, STR_ACCESSBRIDGE) != NULL) {347return 0; // This is OK, e.g. ran enable twice and the value is there.348} else {349// add oracle_javaaccessbridge to Config key for HKCU350dataLength = dataLength + (_tcslen(STR_ACCESSBRIDGE) + 1) * sizeof(TCHAR);351TCHAR *newStr = new TCHAR[dataLength];352if (newStr != NULL) {353wsprintf(newStr, L"%s,%s", dataBuffer, STR_ACCESSBRIDGE);354RegSetValueEx(hKey, ACCESSIBILITY_CONFIG, 0, REG_SZ, (BYTE *)newStr, dataLength);355}356}357}358RegCloseKey(hKey);359}360return err;361}362363int regDeleteValue(HKEY hFamilyKey, LPCWSTR lpSubKey)364{365HKEY hKey;366DWORD retval = -1;367LSTATUS err;368err = RegOpenKeyEx(hFamilyKey, lpSubKey, NULL, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, &hKey);369if (err != ERROR_SUCCESS)370err = RegOpenKeyEx(hFamilyKey, lpSubKey, NULL, KEY_READ|KEY_WRITE, &hKey);371372if (err == ERROR_SUCCESS) {373DWORD dataType = REG_SZ;374DWORD dataLength = DEFAULT_ALLOC;375TCHAR dataBuffer[DEFAULT_ALLOC];376TCHAR searchBuffer[DEFAULT_ALLOC];377TCHAR *data = dataBuffer;378bool freeData = false;379err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength);380if (err == ERROR_MORE_DATA) {381if (dataLength > 0 && dataLength < MAX_ALLOC) {382data = new TCHAR[dataLength];383err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength);384}385}386if (err == ERROR_SUCCESS) {387err = _tcslwr_s(dataBuffer, DEFAULT_ALLOC);388if (err) {389return -1;390}391if (_tcsstr(dataBuffer, STR_ACCESSBRIDGE) == NULL) {392return 0; // This is OK, e.g. ran disable twice and the value is not there.393} else {394// remove oracle_javaaccessbridge from Config key395TCHAR *newStr = new TCHAR[dataLength];396TCHAR *nextToken;397LPTSTR tok, beg1 = dataBuffer;398bool first = true;399_tcscpy_s(newStr, dataLength, L"");400tok = _tcstok_s(beg1, L",", &nextToken);401while (tok != NULL) {402_tcscpy_s(searchBuffer, DEFAULT_ALLOC, tok);403err = _tcslwr_s(searchBuffer, DEFAULT_ALLOC);404if (err) {405return -1;406}407if (_tcsstr(searchBuffer, STR_ACCESSBRIDGE) == NULL) {408if (!first) {409_tcscat_s(newStr, dataLength, L",");410}411first = false;412_tcscat_s(newStr, dataLength, tok);413}414tok = _tcstok_s(NULL, L",", &nextToken);415}416dataLength = (_tcslen(newStr) + 1) * sizeof(TCHAR);417RegSetValueEx(hKey, ACCESSIBILITY_CONFIG, 0, REG_SZ, (BYTE *)newStr, dataLength);418}419}420RegCloseKey(hKey);421}422return err;423}424425int regDisable()426{427LSTATUS err;428// Update value for HKCU429err=regDeleteValue(HKEY_CURRENT_USER, ACCESSIBILITY_USER_KEY);430// Update value for HKLM for Session431TCHAR dataBuffer[DEFAULT_ALLOC];432DWORD dwSessionId ;433ProcessIdToSessionId(GetCurrentProcessId(),&dwSessionId ) ;434if( dwSessionId >= 0 )435{436wsprintf(dataBuffer, L"%s%d", ACCESSIBILITY_SYSTEM_KEY, dwSessionId);437err=regDeleteValue(HKEY_LOCAL_MACHINE, dataBuffer);438}439return err;440}441442void main(int argc, char* argv[]) {443bool enableWasRequested = false;444bool disableWasRequested = false;445bool badParams = true;446int error = 0;447if (argc == 2) {448if (_stricmp(argv[1], "-?") == 0 || _stricmp(argv[1], "/?") == 0) {449printUsage();450badParams = false;451} else if (_stricmp(argv[1], "-version") == 0 || _stricmp(argv[1], "/version") == 0) {452printVersion();453badParams = false;454} else {455if (_stricmp(argv[1], "-enable") == 0 || _stricmp(argv[1], "/enable") == 0) {456badParams = false;457enableWasRequested = true;458error = modify(true);459if (error == 0) {460if( !isXP() )461regEnable();462}463} else if (_stricmp(argv[1], "-disable") == 0 || _stricmp(argv[1], "/disable") == 0) {464badParams = false;465disableWasRequested = true;466error = modify(false);467if (error == 0) {468if( !isXP() )469regDisable();470}471}472}473}474if (badParams) {475printUsage();476} else if (enableWasRequested || disableWasRequested) {477if (error != 0) {478printf("There was an error.\n\n");479}480printf("The Java Access Bridge has ");481if (error != 0) {482printf("not ");483}484printf("been ");485if (enableWasRequested) {486printf("enabled.\n");487} else {488printf("disabled.\n");489}490// Use exit so test case can sense for error.491if (error != 0) {492exit(error);493}494}495}496497498