1 /* 2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import "JavaTextAccessibility.h" 27 #import "JavaAccessibilityAction.h" 28 #import "JavaAccessibilityUtilities.h" 29 #import "ThreadUtilities.h" 30 #import "JNIUtilities.h" 31 32 static jclass sjc_CAccessibility = NULL; 33 #define GET_CACCESSIBLITY_CLASS() \ 34 GET_CLASS(sjc_CAccessibility, "sun/lwawt/macosx/CAccessibility"); 35 #define GET_CACCESSIBLITY_CLASS_RETURN(ret) \ 36 GET_CLASS_RETURN(sjc_CAccessibility, "sun/lwawt/macosx/CAccessibility", ret); 37 38 static jmethodID sjm_getAccessibleText = NULL; 39 #define GET_ACCESSIBLETEXT_METHOD_RETURN(ret) \ 40 GET_CACCESSIBLITY_CLASS_RETURN(ret); \ 41 GET_STATIC_METHOD_RETURN(sjm_getAccessibleText, sjc_CAccessibility, "getAccessibleText", \ 42 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleText;", ret); 43 44 static jclass sjc_CAccessibleText = NULL; 45 #define GET_CACCESSIBLETEXT_CLASS() \ 46 GET_CLASS(sjc_CAccessibleText, "sun/lwawt/macosx/CAccessibleText"); 47 #define GET_CACCESSIBLETEXT_CLASS_RETURN(ret) \ 48 GET_CLASS_RETURN(sjc_CAccessibleText, "sun/lwawt/macosx/CAccessibleText", ret); 49 50 static jmethodID sjm_getAccessibleEditableText = NULL; 51 #define GET_ACCESSIBLEEDITABLETEXT_METHOD_RETURN(ret) \ 52 GET_CACCESSIBLETEXT_CLASS_RETURN(ret); \ 53 GET_STATIC_METHOD_RETURN(sjm_getAccessibleEditableText, sjc_CAccessibleText, "getAccessibleEditableText", \ 54 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleEditableText;", ret); 55 56 57 /* 58 * Converts an int array to an NSRange wrapped inside an NSValue 59 * takes [start, end] values and returns [start, end - start] 60 */ 61 NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) { 62 jint *values = (*env)->GetIntArrayElements(env, array, 0); 63 if (values == NULL) { 64 // Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck. 65 NSLog(@"%s failed calling GetIntArrayElements", __FUNCTION__); 66 return nil; 67 }; 68 NSValue *value = [NSValue valueWithRange:NSMakeRange(values[0], values[1] - values[0])]; 69 (*env)->ReleaseIntArrayElements(env, array, values, 0); 70 return value; 71 } 72 73 @implementation JavaTextAccessibility 74 75 // based strongly upon NSTextViewAccessibility:accessibilityAttributeNames 76 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env 77 { 78 static NSArray *attributes = nil; 79 80 if (attributes == nil) { 81 //APPKIT_LOCK; 82 if (attributes == nil) { 83 NSMutableArray *temp = [[super initializeAttributeNamesWithEnv:env] mutableCopy]; 84 //[temp removeObject:NSAccessibilityTitleAttribute]; // title may have been set in the superclass implementation - some static text reports from java that it has a name 85 [temp addObjectsFromArray:[NSArray arrayWithObjects: 86 NSAccessibilityValueAttribute, 87 NSAccessibilitySelectedTextAttribute, 88 NSAccessibilitySelectedTextRangeAttribute, 89 NSAccessibilityNumberOfCharactersAttribute, 90 NSAccessibilityVisibleCharacterRangeAttribute, 91 NSAccessibilityInsertionPointLineNumberAttribute, 92 // NSAccessibilitySharedTextUIElementsAttribute, // cmcnote: investigate what these two are for. currently unimplemented 93 // NSAccessibilitySharedCharacterRangeAttribute, 94 nil]]; 95 attributes = [[NSArray alloc] initWithArray:temp]; 96 [temp release]; 97 } 98 //APPKIT_UNLOCK; 99 } 100 return attributes; 101 } 102 103 // copied from NSTextViewAccessibility. 104 - (NSArray *)accessibilityParameterizedAttributeNames 105 { 106 static NSArray *attributes = nil; 107 108 if (attributes == nil) { 109 //APPKIT_LOCK; 110 if (attributes == nil) { 111 attributes = [[NSArray alloc] initWithObjects: 112 NSAccessibilityLineForIndexParameterizedAttribute, 113 NSAccessibilityRangeForLineParameterizedAttribute, 114 NSAccessibilityStringForRangeParameterizedAttribute, 115 NSAccessibilityRangeForPositionParameterizedAttribute, 116 NSAccessibilityRangeForIndexParameterizedAttribute, 117 NSAccessibilityBoundsForRangeParameterizedAttribute, 118 //NSAccessibilityRTFForRangeParameterizedAttribute, // cmcnote: not sure when/how these three are used. Investigate. radr://3960026 119 //NSAccessibilityStyleRangeForIndexParameterizedAttribute, 120 //NSAccessibilityAttributedStringForRangeParameterizedAttribute, 121 nil]; 122 } 123 //APPKIT_UNLOCK; 124 } 125 return attributes; 126 } 127 128 - (NSString *)accessibilityValueAttribute 129 { 130 JNIEnv *env = [ThreadUtilities getJNIEnv]; 131 GET_CACCESSIBLITY_CLASS_RETURN(nil); 132 DECLARE_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", 133 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil); 134 if ([[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityStaticTextRole]) { 135 // if it's static text, the AppKit AXValue is the java accessibleName 136 jobject axName = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, 137 sjm_getAccessibleName, fAccessible, fComponent); 138 CHECK_EXCEPTION(); 139 if (axName != NULL) { 140 NSString* str = JavaStringToNSString(env, axName); 141 (*env)->DeleteLocalRef(env, axName); 142 return str; 143 } 144 // value is still nil if no accessibleName for static text. Below, try to get the accessibleText. 145 } 146 147 // cmcnote: inefficient to make three distinct JNI calls. Coalesce. radr://3951923 148 GET_ACCESSIBLETEXT_METHOD_RETURN(@""); 149 jobject axText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, 150 sjm_getAccessibleText, fAccessible, fComponent); 151 CHECK_EXCEPTION(); 152 if (axText == NULL) return nil; 153 (*env)->DeleteLocalRef(env, axText); 154 155 GET_ACCESSIBLEEDITABLETEXT_METHOD_RETURN(nil); 156 jobject axEditableText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, 157 sjm_getAccessibleEditableText, fAccessible, fComponent); 158 CHECK_EXCEPTION(); 159 if (axEditableText == NULL) return nil; 160 161 DECLARE_STATIC_METHOD_RETURN(jm_getTextRange, sjc_CAccessibleText, "getTextRange", 162 "(Ljavax/accessibility/AccessibleEditableText;IILjava/awt/Component;)Ljava/lang/String;", nil); 163 jobject jrange = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getTextRange, 164 axEditableText, 0, getAxTextCharCount(env, axEditableText, fComponent), fComponent); 165 CHECK_EXCEPTION(); 166 NSString *string = JavaStringToNSString(env, jrange); 167 168 (*env)->DeleteLocalRef(env, jrange); 169 (*env)->DeleteLocalRef(env, axEditableText); 170 171 if (string == nil) string = @""; 172 return string; 173 } 174 175 - (BOOL)accessibilityIsValueAttributeSettable 176 { 177 // if text is enabled and editable, it's settable (according to NSCellTextAttributesAccessibility) 178 BOOL isEnabled = [(NSNumber *)[self accessibilityEnabledAttribute] boolValue]; 179 if (!isEnabled) return NO; 180 181 JNIEnv* env = [ThreadUtilities getJNIEnv]; 182 GET_ACCESSIBLEEDITABLETEXT_METHOD_RETURN(NO); 183 jobject axEditableText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, 184 sjm_getAccessibleEditableText, fAccessible, fComponent); 185 CHECK_EXCEPTION(); 186 if (axEditableText == NULL) return NO; 187 (*env)->DeleteLocalRef(env, axEditableText); 188 return YES; 189 } 190 191 - (void)accessibilitySetValueAttribute:(id)value 192 { 193 // cmcnote: should set the accessibleEditableText to the stringValue of value - AccessibleEditableText.setTextContents(String s) 194 #ifdef JAVA_AX_DEBUG 195 NSLog(@"Not yet implemented: %s\n", __FUNCTION__); // radr://3954018 196 #endif 197 } 198 199 // Currently selected text (NSString) 200 - (NSString *)accessibilitySelectedTextAttribute 201 { 202 JNIEnv* env = [ThreadUtilities getJNIEnv]; 203 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 204 DECLARE_STATIC_METHOD_RETURN(jm_getSelectedText, sjc_CAccessibleText, "getSelectedText", 205 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", nil); 206 jobject axText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getSelectedText, 207 fAccessible, fComponent); 208 CHECK_EXCEPTION(); 209 if (axText == NULL) return @""; 210 NSString* str = JavaStringToNSString(env, axText); 211 (*env)->DeleteLocalRef(env, axText); 212 return str; 213 } 214 215 - (BOOL)accessibilityIsSelectedTextAttributeSettable 216 { 217 return YES; //cmcnote: for AXTextField that's selectable, it's settable. Investigate further. 218 } 219 220 - (void)accessibilitySetSelectedTextAttribute:(id)value 221 { 222 #ifdef JAVA_AX_DEBUG_PARMS 223 if (![value isKindOfClass:[NSString class]]) { 224 JavaAccessibilityRaiseSetAttributeToIllegalTypeException(__FUNCTION__, self, NSAccessibilitySelectedTextAttribute, value); 225 return; 226 } 227 #endif 228 229 JNIEnv *env = [ThreadUtilities getJNIEnv]; 230 jstring jstringValue = NSStringToJavaString(env, (NSString *)value); 231 GET_CACCESSIBLETEXT_CLASS(); 232 DECLARE_STATIC_METHOD(jm_setSelectedText, sjc_CAccessibleText, "setSelectedText", 233 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;Ljava/lang/String;)V"); 234 (*env)->CallStaticVoidMethod(env, sjc_CAccessibleText, jm_setSelectedText, 235 fAccessible, fComponent, jstringValue); 236 CHECK_EXCEPTION(); 237 } 238 239 // Range of selected text (NSValue) 240 - (NSValue *)accessibilitySelectedTextRangeAttribute 241 { 242 JNIEnv *env = [ThreadUtilities getJNIEnv]; 243 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 244 DECLARE_STATIC_METHOD_RETURN(jm_getSelectedTextRange, sjc_CAccessibleText, "getSelectedTextRange", 245 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[I", nil); 246 jintArray axTextRange = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, 247 jm_getSelectedTextRange, fAccessible, fComponent); 248 CHECK_EXCEPTION(); 249 if (axTextRange == NULL) return nil; 250 251 return javaIntArrayToNSRangeValue(env, axTextRange); 252 } 253 254 - (BOOL)accessibilityIsSelectedTextRangeAttributeSettable 255 { 256 return [(NSNumber *)[self accessibilityEnabledAttribute] boolValue]; // cmcnote: also may want to find out if isSelectable. Investigate. 257 } 258 259 - (void)accessibilitySetSelectedTextRangeAttribute:(id)value 260 { 261 #ifdef JAVA_AX_DEBUG_PARMS 262 if (!([value isKindOfClass:[NSValue class]] && strcmp([(NSValue *)value objCType], @encode(NSRange)) == 0)) { 263 JavaAccessibilityRaiseSetAttributeToIllegalTypeException(__FUNCTION__, self, NSAccessibilitySelectedTextRangeAttribute, value); 264 return; 265 } 266 #endif 267 268 NSRange range = [(NSValue *)value rangeValue]; 269 jint startIndex = range.location; 270 jint endIndex = startIndex + range.length; 271 272 JNIEnv *env = [ThreadUtilities getJNIEnv]; 273 GET_CACCESSIBLETEXT_CLASS(); 274 DECLARE_STATIC_METHOD(jm_setSelectedTextRange, sjc_CAccessibleText, "setSelectedTextRange", 275 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)V"); 276 (*env)->CallStaticVoidMethod(env, sjc_CAccessibleText, jm_setSelectedTextRange, 277 fAccessible, fComponent, startIndex, endIndex); 278 CHECK_EXCEPTION(); 279 } 280 281 - (NSNumber *)accessibilityNumberOfCharactersAttribute 282 { 283 // cmcnote: should coalesce these two calls - radr://3951923 284 // also, static text doesn't always have accessibleText. if axText is null, should get the charcount of the accessibleName instead 285 JNIEnv *env = [ThreadUtilities getJNIEnv]; 286 GET_ACCESSIBLETEXT_METHOD_RETURN(nil); 287 jobject axText = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, 288 sjm_getAccessibleText, fAccessible, fComponent); 289 CHECK_EXCEPTION(); 290 NSNumber* num = [NSNumber numberWithInt:getAxTextCharCount(env, axText, fComponent)]; 291 (*env)->DeleteLocalRef(env, axText); 292 return num; 293 } 294 295 - (BOOL)accessibilityIsNumberOfCharactersAttributeSettable 296 { 297 return NO; // according to NSTextViewAccessibility.m and NSCellTextAttributesAccessibility.m 298 } 299 300 - (NSValue *)accessibilityVisibleCharacterRangeAttribute 301 { 302 JNIEnv *env = [ThreadUtilities getJNIEnv]; 303 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 304 DECLARE_STATIC_METHOD_RETURN(jm_getVisibleCharacterRange, sjc_CAccessibleText, "getVisibleCharacterRange", 305 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[I", nil); 306 jintArray axTextRange = (*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, 307 jm_getVisibleCharacterRange, fAccessible, fComponent); 308 CHECK_EXCEPTION(); 309 if (axTextRange == NULL) return nil; 310 311 return javaIntArrayToNSRangeValue(env, axTextRange); 312 } 313 314 - (BOOL)accessibilityIsVisibleCharacterRangeAttributeSettable 315 { 316 #ifdef JAVA_AX_DEBUG 317 NSLog(@"Not yet implemented: %s\n", __FUNCTION__); 318 #endif 319 return NO; 320 } 321 322 - (NSValue *)accessibilityInsertionPointLineNumberAttribute 323 { 324 JNIEnv *env = [ThreadUtilities getJNIEnv]; 325 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 326 DECLARE_STATIC_METHOD_RETURN(jm_getLineNumberForInsertionPoint, sjc_CAccessibleText, 327 "getLineNumberForInsertionPoint", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)I", nil); 328 jint row = (*env)->CallStaticIntMethod(env, sjc_CAccessibleText, 329 jm_getLineNumberForInsertionPoint, fAccessible, fComponent); 330 CHECK_EXCEPTION(); 331 if (row < 0) return nil; 332 return [NSNumber numberWithInt:row]; 333 } 334 335 - (BOOL)accessibilityIsInsertionPointLineNumberAttributeSettable 336 { 337 #ifdef JAVA_AX_DEBUG 338 NSLog(@"Not yet implemented: %s\n", __FUNCTION__); 339 #endif 340 return NO; 341 } 342 343 // parameterized attributes 344 345 // 346 // Usage of accessibilityBoundsForRangeAttributeForParameter: 347 // --- 348 // called by VoiceOver when interacting with text via ctrl-option-shift-downArrow. 349 // Need to know bounding box for the character / word / line of interest in 350 // order to draw VoiceOver cursor 351 // 352 - (NSValue *)accessibilityBoundsForRangeAttributeForParameter:(id)parameter 353 { 354 #ifdef JAVA_AX_DEBUG_PARMS 355 if (!([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue *)parameter objCType], @encode(NSRange)) == 0)) { 356 JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityBoundsForRangeParameterizedAttribute, parameter); 357 return nil; 358 } 359 #endif 360 361 NSRange range = [(NSValue *)parameter rangeValue]; 362 363 JNIEnv *env = [ThreadUtilities getJNIEnv]; 364 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 365 DECLARE_STATIC_METHOD_RETURN(jm_getBoundsForRange, sjc_CAccessibleText, "getBoundsForRange", 366 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)[D", nil); 367 jdoubleArray axBounds = (jdoubleArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getBoundsForRange, 368 fAccessible, fComponent, range.location, range.length); 369 CHECK_EXCEPTION(); 370 if (axBounds == NULL) return nil; 371 372 // We cheat because we know that the array is 4 elements long (x, y, width, height) 373 jdouble *values = (*env)->GetDoubleArrayElements(env, axBounds, 0); 374 CHECK_EXCEPTION(); 375 if (values == NULL) { 376 // Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck. 377 NSLog(@"%s failed calling GetDoubleArrayElements", __FUNCTION__); 378 return nil; 379 }; 380 NSRect bounds; 381 bounds.origin.x = values[0]; 382 bounds.origin.y = [[[[self view] window] screen] frame].size.height - values[1] - values[3]; //values[1] is y-coord from top-left of screen. Flip. Account for the height (values[3]) when flipping 383 bounds.size.width = values[2]; 384 bounds.size.height = values[3]; 385 NSValue *result = [NSValue valueWithRect:bounds]; 386 (*env)->ReleaseDoubleArrayElements(env, axBounds, values, 0); 387 return result; 388 } 389 390 - (NSNumber *)accessibilityLineForIndexAttributeForParameter:(id)parameter 391 { 392 NSNumber *line = (NSNumber *) parameter; 393 if (line == nil) return nil; 394 395 JNIEnv *env = [ThreadUtilities getJNIEnv]; 396 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 397 DECLARE_STATIC_METHOD_RETURN(jm_getLineNumberForIndex, sjc_CAccessibleText, "getLineNumberForIndex", 398 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)I", nil); 399 jint row = (*env)->CallStaticIntMethod(env, sjc_CAccessibleText, jm_getLineNumberForIndex, 400 fAccessible, fComponent, [line intValue]); 401 CHECK_EXCEPTION(); 402 if (row < 0) return nil; 403 return [NSNumber numberWithInt:row]; 404 } 405 406 - (NSValue *)accessibilityRangeForLineAttributeForParameter:(id)parameter 407 { 408 NSNumber *line = (NSNumber *) parameter; 409 if (line == nil) return nil; 410 411 JNIEnv *env = [ThreadUtilities getJNIEnv]; 412 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 413 DECLARE_STATIC_METHOD_RETURN(jm_getRangeForLine, sjc_CAccessibleText, "getRangeForLine", 414 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I", nil); 415 jintArray axTextRange = (jintArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, 416 jm_getRangeForLine, fAccessible, fComponent, [line intValue]); 417 CHECK_EXCEPTION(); 418 if (axTextRange == NULL) return nil; 419 420 return javaIntArrayToNSRangeValue(env,axTextRange); 421 } 422 423 // 424 // Usage of accessibilityStringForRangeAttributeForParameter: 425 // --- 426 // called by VoiceOver when interacting with text via ctrl-option-shift-downArrow. 427 // VO needs to know the particular string its currently dealing with so it can 428 // speak the string 429 // 430 - (NSString *)accessibilityStringForRangeAttributeForParameter:(id)parameter 431 { 432 #ifdef JAVA_AX_DEBUG_PARMS 433 if (!([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue *)parameter objCType], @encode(NSRange)) == 0)) { 434 JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityBoundsForRangeParameterizedAttribute, parameter); 435 return nil; 436 } 437 #endif 438 439 NSRange range = [(NSValue *)parameter rangeValue]; 440 441 JNIEnv *env = [ThreadUtilities getJNIEnv]; 442 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 443 DECLARE_STATIC_METHOD_RETURN(jm_getStringForRange, sjc_CAccessibleText, "getStringForRange", 444 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)Ljava/lang/String;", nil); 445 jstring jstringForRange = (jstring)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getStringForRange, 446 fAccessible, fComponent, range.location, range.length); 447 CHECK_EXCEPTION(); 448 if (jstringForRange == NULL) return @""; 449 NSString* str = JavaStringToNSString(env, jstringForRange); 450 (*env)->DeleteLocalRef(env, jstringForRange); 451 return str; 452 } 453 454 // 455 // Usage of accessibilityRangeForPositionAttributeForParameter: 456 // --- 457 // cmcnote: I'm not sure when this is called / how it's used. Investigate. 458 // probably could be used in a special text-only accessibilityHitTest to 459 // find the index of the string under the mouse? 460 // 461 - (NSValue *)accessibilityRangeForPositionAttributeForParameter:(id)parameter 462 { 463 #ifdef JAVA_AX_DEBUG_PARMS 464 if (!([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue *)parameter objCType], @encode(NSPoint)) == 0)) { 465 JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityRangeForPositionParameterizedAttribute, parameter); 466 return nil; 467 } 468 #endif 469 470 NSPoint point = [(NSValue *)parameter pointValue]; // point is in screen coords 471 point.y = [[[[self view] window] screen] frame].size.height - point.y; // flip into java screen coords (0 is at upper-left corner of screen) 472 473 JNIEnv *env = [ThreadUtilities getJNIEnv]; 474 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 475 DECLARE_STATIC_METHOD_RETURN(jm_getCharacterIndexAtPosition, sjc_CAccessibleText, "getCharacterIndexAtPosition", 476 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)I", nil); 477 jint charIndex = (*env)->CallStaticIntMethod(env, sjc_CAccessibleText, jm_getCharacterIndexAtPosition, 478 fAccessible, fComponent, point.x, point.y); 479 CHECK_EXCEPTION(); 480 if (charIndex == -1) return nil; 481 482 // AccessibleText.getIndexAtPoint returns -1 for an invalid point 483 NSRange range = NSMakeRange(charIndex, 1); //range's length is 1 - one-character range 484 return [NSValue valueWithRange:range]; 485 } 486 487 // 488 // Usage of accessibilityRangeForIndexAttributeForParameter: 489 // --- 490 // cmcnote: I'm not sure when this is called / how it's used. Investigate. 491 // AppKit version calls: [string rangeOfComposedCharacterSequenceAtIndex:index] 492 // We call: CAccessibility.getRangeForIndex, which calls AccessibleText.getAtIndex(AccessibleText.WORD, index) 493 // to determine the word closest to the given index. Then we find the length/location of this string. 494 // 495 - (NSValue *)accessibilityRangeForIndexAttributeForParameter:(id)parameter 496 { 497 #ifdef JAVA_AX_DEBUG_PARMS 498 if (![parameter isKindOfClass:[NSNumber class]]) { 499 JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityRangeForIndexParameterizedAttribute, parameter); 500 return nil; 501 } 502 #endif 503 504 NSUInteger index = [(NSNumber *)parameter unsignedIntegerValue]; 505 506 JNIEnv *env = [ThreadUtilities getJNIEnv]; 507 GET_CACCESSIBLETEXT_CLASS_RETURN(nil); 508 DECLARE_STATIC_METHOD_RETURN(jm_getRangeForIndex, sjc_CAccessibleText, "getRangeForIndex", 509 "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I", nil); 510 jintArray axTextRange = (jintArray)(*env)->CallStaticObjectMethod(env, sjc_CAccessibleText, jm_getRangeForIndex, 511 fAccessible, fComponent, index); 512 CHECK_EXCEPTION(); 513 if (axTextRange == NULL) return nil; 514 515 return javaIntArrayToNSRangeValue(env, axTextRange); 516 } 517 518 /* 519 * - (NSDictionary *)getActions:(JNIEnv *)env { ... } 520 * 521 * In the future, possibly add support: Editable text has AXShowMenu. 522 * Textfields have AXConfirm. 523 * 524 * Note: JLabels (static text) in JLists have a press/click selection action 525 * which is currently handled in superclass JavaComponentAccessibility. 526 * If function is added here be sure to use [super getActions:env] for JLabels. 527 */ 528 529 @end