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 31 32 static JNF_CLASS_CACHE(sjc_CAccessibleText, "sun/lwawt/macosx/CAccessibleText"); 33 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleText, sjc_CAccessibility, "getAccessibleText", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleText;"); 34 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleEditableText, sjc_CAccessibleText, "getAccessibleEditableText", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleEditableText;"); 35 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;"); 36 37 /* 38 * Converts an int array to an NSRange wrapped inside an NSValue 39 * takes [start, end] values and returns [start, end - start] 40 */ 41 NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) { 42 jint *values = (*env)->GetIntArrayElements(env, array, 0); 43 if (values == NULL) { 44 // Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck. 45 NSLog(@"%s failed calling GetIntArrayElements", __FUNCTION__); 46 return nil; 47 }; 48 NSValue *value = [NSValue valueWithRange:NSMakeRange(values[0], values[1] - values[0])]; 49 (*env)->ReleaseIntArrayElements(env, array, values, 0); 50 return value; 51 } 52 53 @implementation JavaTextAccessibility 54 55 // based strongly upon NSTextViewAccessibility:accessibilityAttributeNames 56 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env 57 { 58 static NSArray *attributes = nil; 59 60 if (attributes == nil) { 61 //APPKIT_LOCK; 62 if (attributes == nil) { 63 NSMutableArray *temp = [[super initializeAttributeNamesWithEnv:env] mutableCopy]; 64 //[temp removeObject:NSAccessibilityTitleAttribute]; // title may have been set in the superclass implementation - some static text reports from java that it has a name 65 [temp addObjectsFromArray:[NSArray arrayWithObjects: 66 NSAccessibilityValueAttribute, 67 NSAccessibilitySelectedTextAttribute, 68 NSAccessibilitySelectedTextRangeAttribute, 69 NSAccessibilityNumberOfCharactersAttribute, 70 NSAccessibilityVisibleCharacterRangeAttribute, 71 NSAccessibilityInsertionPointLineNumberAttribute, 72 // NSAccessibilitySharedTextUIElementsAttribute, // cmcnote: investigate what these two are for. currently unimplemented 73 // NSAccessibilitySharedCharacterRangeAttribute, 74 nil]]; 75 attributes = [[NSArray alloc] initWithArray:temp]; 76 [temp release]; 77 } 78 //APPKIT_UNLOCK; 79 } 80 return attributes; 81 } 82 83 // copied from NSTextViewAccessibility. 84 - (NSArray *)accessibilityParameterizedAttributeNames 85 { 86 static NSArray *attributes = nil; 87 88 if (attributes == nil) { 89 //APPKIT_LOCK; 90 if (attributes == nil) { 91 attributes = [[NSArray alloc] initWithObjects: 92 NSAccessibilityLineForIndexParameterizedAttribute, 93 NSAccessibilityRangeForLineParameterizedAttribute, 94 NSAccessibilityStringForRangeParameterizedAttribute, 95 NSAccessibilityRangeForPositionParameterizedAttribute, 96 NSAccessibilityRangeForIndexParameterizedAttribute, 97 NSAccessibilityBoundsForRangeParameterizedAttribute, 98 //NSAccessibilityRTFForRangeParameterizedAttribute, // cmcnote: not sure when/how these three are used. Investigate. radr://3960026 99 //NSAccessibilityStyleRangeForIndexParameterizedAttribute, 100 //NSAccessibilityAttributedStringForRangeParameterizedAttribute, 101 nil]; 102 } 103 //APPKIT_UNLOCK; 104 } 105 return attributes; 106 } 107 108 - (NSString *)accessibilityValueAttribute 109 { 110 JNIEnv *env = [ThreadUtilities getJNIEnv]; 111 if ([[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityStaticTextRole]) { 112 // if it's static text, the AppKit AXValue is the java accessibleName 113 jobject axName = JNFCallStaticObjectMethod(env, sjm_getAccessibleName, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop) 114 if (axName != NULL) { 115 NSString* str = JNFJavaToNSString(env, axName); 116 (*env)->DeleteLocalRef(env, axName); 117 return str; 118 } 119 // value is still nil if no accessibleName for static text. Below, try to get the accessibleText. 120 } 121 122 // cmcnote: inefficient to make three distinct JNI calls. Coalesce. radr://3951923 123 jobject axText = JNFCallStaticObjectMethod(env, sjm_getAccessibleText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop) 124 if (axText == NULL) return nil; 125 (*env)->DeleteLocalRef(env, axText); 126 127 jobject axEditableText = JNFCallStaticObjectMethod(env, sjm_getAccessibleEditableText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop) 128 if (axEditableText == NULL) return nil; 129 130 static JNF_STATIC_MEMBER_CACHE(jm_getTextRange, sjc_CAccessibleText, "getTextRange", "(Ljavax/accessibility/AccessibleEditableText;IILjava/awt/Component;)Ljava/lang/String;"); 131 jobject jrange = JNFCallStaticObjectMethod(env, jm_getTextRange, axEditableText, 0, getAxTextCharCount(env, axEditableText, fComponent), fComponent); 132 NSString *string = JNFJavaToNSString(env, jrange); // AWT_THREADING Safe (AWTRunLoop) 133 134 (*env)->DeleteLocalRef(env, jrange); 135 (*env)->DeleteLocalRef(env, axEditableText); 136 137 if (string == nil) string = @""; 138 return string; 139 } 140 141 - (BOOL)accessibilityIsValueAttributeSettable 142 { 143 // if text is enabled and editable, it's settable (according to NSCellTextAttributesAccessibility) 144 BOOL isEnabled = [(NSNumber *)[self accessibilityEnabledAttribute] boolValue]; 145 if (!isEnabled) return NO; 146 147 JNIEnv* env = [ThreadUtilities getJNIEnv]; 148 jobject axEditableText = JNFCallStaticObjectMethod(env, sjm_getAccessibleEditableText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop) 149 if (axEditableText == NULL) return NO; 150 (*env)->DeleteLocalRef(env, axEditableText); 151 return YES; 152 } 153 154 - (void)accessibilitySetValueAttribute:(id)value 155 { 156 // cmcnote: should set the accessibleEditableText to the stringValue of value - AccessibleEditableText.setTextContents(String s) 157 #ifdef JAVA_AX_DEBUG 158 NSLog(@"Not yet implemented: %s\n", __FUNCTION__); // radr://3954018 159 #endif 160 } 161 162 // Currently selected text (NSString) 163 - (NSString *)accessibilitySelectedTextAttribute 164 { 165 JNIEnv* env = [ThreadUtilities getJNIEnv]; 166 static JNF_STATIC_MEMBER_CACHE(jm_getSelectedText, sjc_CAccessibleText, "getSelectedText", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;"); 167 jobject axText = JNFCallStaticObjectMethod(env, jm_getSelectedText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop) 168 if (axText == NULL) return @""; 169 NSString* str = JNFJavaToNSString(env, axText); 170 (*env)->DeleteLocalRef(env, axText); 171 return str; 172 } 173 174 - (BOOL)accessibilityIsSelectedTextAttributeSettable 175 { 176 return YES; //cmcnote: for AXTextField that's selectable, it's settable. Investigate further. 177 } 178 179 - (void)accessibilitySetSelectedTextAttribute:(id)value 180 { 181 #ifdef JAVA_AX_DEBUG_PARMS 182 if (![value isKindOfClass:[NSString class]]) { 183 JavaAccessibilityRaiseSetAttributeToIllegalTypeException(__FUNCTION__, self, NSAccessibilitySelectedTextAttribute, value); 184 return; 185 } 186 #endif 187 188 JNIEnv *env = [ThreadUtilities getJNIEnv]; 189 jstring jstringValue = JNFNSToJavaString(env, (NSString *)value); 190 static JNF_STATIC_MEMBER_CACHE(jm_setSelectedText, sjc_CAccessibleText, "setSelectedText", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;Ljava/lang/String;)V"); 191 JNFCallStaticVoidMethod(env, jm_setSelectedText, fAccessible, fComponent, jstringValue); // AWT_THREADING Safe (AWTRunLoop) 192 } 193 194 // Range of selected text (NSValue) 195 - (NSValue *)accessibilitySelectedTextRangeAttribute 196 { 197 JNIEnv *env = [ThreadUtilities getJNIEnv]; 198 static JNF_STATIC_MEMBER_CACHE(jm_getSelectedTextRange, sjc_CAccessibleText, "getSelectedTextRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[I"); 199 jintArray axTextRange = JNFCallStaticObjectMethod(env, jm_getSelectedTextRange, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop) 200 if (axTextRange == NULL) return nil; 201 202 return javaIntArrayToNSRangeValue(env, axTextRange); 203 } 204 205 - (BOOL)accessibilityIsSelectedTextRangeAttributeSettable 206 { 207 return [(NSNumber *)[self accessibilityEnabledAttribute] boolValue]; // cmcnote: also may want to find out if isSelectable. Investigate. 208 } 209 210 - (void)accessibilitySetSelectedTextRangeAttribute:(id)value 211 { 212 #ifdef JAVA_AX_DEBUG_PARMS 213 if (!([value isKindOfClass:[NSValue class]] && strcmp([(NSValue *)value objCType], @encode(NSRange)) == 0)) { 214 JavaAccessibilityRaiseSetAttributeToIllegalTypeException(__FUNCTION__, self, NSAccessibilitySelectedTextRangeAttribute, value); 215 return; 216 } 217 #endif 218 219 NSRange range = [(NSValue *)value rangeValue]; 220 jint startIndex = range.location; 221 jint endIndex = startIndex + range.length; 222 223 JNIEnv *env = [ThreadUtilities getJNIEnv]; 224 static JNF_STATIC_MEMBER_CACHE(jm_setSelectedTextRange, sjc_CAccessibleText, "setSelectedTextRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)V"); 225 JNFCallStaticVoidMethod(env, jm_setSelectedTextRange, fAccessible, fComponent, startIndex, endIndex); // AWT_THREADING Safe (AWTRunLoop) 226 } 227 228 - (NSNumber *)accessibilityNumberOfCharactersAttribute 229 { 230 // cmcnote: should coalesce these two calls - radr://3951923 231 // also, static text doesn't always have accessibleText. if axText is null, should get the charcount of the accessibleName instead 232 JNIEnv *env = [ThreadUtilities getJNIEnv]; 233 jobject axText = JNFCallStaticObjectMethod(env, sjm_getAccessibleText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop) 234 NSNumber* num = [NSNumber numberWithInt:getAxTextCharCount(env, axText, fComponent)]; 235 (*env)->DeleteLocalRef(env, axText); 236 return num; 237 } 238 239 - (BOOL)accessibilityIsNumberOfCharactersAttributeSettable 240 { 241 return NO; // according to NSTextViewAccessibility.m and NSCellTextAttributesAccessibility.m 242 } 243 244 - (NSValue *)accessibilityVisibleCharacterRangeAttribute 245 { 246 JNIEnv *env = [ThreadUtilities getJNIEnv]; 247 static JNF_STATIC_MEMBER_CACHE(jm_getVisibleCharacterRange, sjc_CAccessibleText, "getVisibleCharacterRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[I"); 248 jintArray axTextRange = JNFCallStaticObjectMethod(env, jm_getVisibleCharacterRange, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop) 249 if (axTextRange == NULL) return nil; 250 251 return javaIntArrayToNSRangeValue(env, axTextRange); 252 } 253 254 - (BOOL)accessibilityIsVisibleCharacterRangeAttributeSettable 255 { 256 #ifdef JAVA_AX_DEBUG 257 NSLog(@"Not yet implemented: %s\n", __FUNCTION__); 258 #endif 259 return NO; 260 } 261 262 - (NSValue *)accessibilityInsertionPointLineNumberAttribute 263 { 264 JNIEnv *env = [ThreadUtilities getJNIEnv]; 265 static JNF_STATIC_MEMBER_CACHE(jm_getLineNumberForInsertionPoint, sjc_CAccessibleText, "getLineNumberForInsertionPoint", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)I"); 266 jint row = JNFCallStaticIntMethod(env, jm_getLineNumberForInsertionPoint, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop) 267 if (row < 0) return nil; 268 return [NSNumber numberWithInt:row]; 269 } 270 271 - (BOOL)accessibilityIsInsertionPointLineNumberAttributeSettable 272 { 273 #ifdef JAVA_AX_DEBUG 274 NSLog(@"Not yet implemented: %s\n", __FUNCTION__); 275 #endif 276 return NO; 277 } 278 279 // parameterized attributes 280 281 // 282 // Usage of accessibilityBoundsForRangeAttributeForParameter: 283 // --- 284 // called by VoiceOver when interacting with text via ctrl-option-shift-downArrow. 285 // Need to know bounding box for the character / word / line of interest in 286 // order to draw VoiceOver cursor 287 // 288 - (NSValue *)accessibilityBoundsForRangeAttributeForParameter:(id)parameter 289 { 290 #ifdef JAVA_AX_DEBUG_PARMS 291 if (!([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue *)parameter objCType], @encode(NSRange)) == 0)) { 292 JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityBoundsForRangeParameterizedAttribute, parameter); 293 return nil; 294 } 295 #endif 296 297 NSRange range = [(NSValue *)parameter rangeValue]; 298 299 JNIEnv *env = [ThreadUtilities getJNIEnv]; 300 static JNF_STATIC_MEMBER_CACHE(jm_getBoundsForRange, sjc_CAccessibleText, "getBoundsForRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)[D"); 301 jdoubleArray axBounds = (jdoubleArray)JNFCallStaticObjectMethod(env, jm_getBoundsForRange, fAccessible, fComponent, range.location, range.length); // AWT_THREADING Safe (AWTRunLoop) 302 if (axBounds == NULL) return nil; 303 304 // We cheat because we know that the array is 4 elements long (x, y, width, height) 305 jdouble *values = (*env)->GetDoubleArrayElements(env, axBounds, 0); 306 if (values == NULL) { 307 // Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck. 308 NSLog(@"%s failed calling GetDoubleArrayElements", __FUNCTION__); 309 return nil; 310 }; 311 NSRect bounds; 312 bounds.origin.x = values[0]; 313 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 314 bounds.size.width = values[2]; 315 bounds.size.height = values[3]; 316 NSValue *result = [NSValue valueWithRect:bounds]; 317 (*env)->ReleaseDoubleArrayElements(env, axBounds, values, 0); 318 return result; 319 } 320 321 - (NSNumber *)accessibilityLineForIndexAttributeForParameter:(id)parameter 322 { 323 NSNumber *line = (NSNumber *) parameter; 324 if (line == nil) return nil; 325 326 JNIEnv *env = [ThreadUtilities getJNIEnv]; 327 static JNF_STATIC_MEMBER_CACHE(jm_getLineNumberForIndex, sjc_CAccessibleText, "getLineNumberForIndex", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)I"); 328 jint row = JNFCallStaticIntMethod(env, jm_getLineNumberForIndex, fAccessible, fComponent, [line intValue]); // AWT_THREADING Safe (AWTRunLoop) 329 if (row < 0) return nil; 330 return [NSNumber numberWithInt:row]; 331 } 332 333 - (NSValue *)accessibilityRangeForLineAttributeForParameter:(id)parameter 334 { 335 NSNumber *line = (NSNumber *) parameter; 336 if (line == nil) return nil; 337 338 JNIEnv *env = [ThreadUtilities getJNIEnv]; 339 static JNF_STATIC_MEMBER_CACHE(jm_getRangeForLine, sjc_CAccessibleText, "getRangeForLine", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I"); 340 jintArray axTextRange = (jintArray)JNFCallStaticObjectMethod(env, jm_getRangeForLine, fAccessible, fComponent, [line intValue]); // AWT_THREADING Safe (AWTRunLoop) 341 if (axTextRange == NULL) return nil; 342 343 return javaIntArrayToNSRangeValue(env,axTextRange); 344 } 345 346 // 347 // Usage of accessibilityStringForRangeAttributeForParameter: 348 // --- 349 // called by VoiceOver when interacting with text via ctrl-option-shift-downArrow. 350 // VO needs to know the particular string its currently dealing with so it can 351 // speak the string 352 // 353 - (NSString *)accessibilityStringForRangeAttributeForParameter:(id)parameter 354 { 355 #ifdef JAVA_AX_DEBUG_PARMS 356 if (!([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue *)parameter objCType], @encode(NSRange)) == 0)) { 357 JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityBoundsForRangeParameterizedAttribute, parameter); 358 return nil; 359 } 360 #endif 361 362 NSRange range = [(NSValue *)parameter rangeValue]; 363 364 JNIEnv *env = [ThreadUtilities getJNIEnv]; 365 static JNF_STATIC_MEMBER_CACHE(jm_getStringForRange, sjc_CAccessibleText, "getStringForRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)Ljava/lang/String;"); 366 jstring jstringForRange = (jstring)JNFCallStaticObjectMethod(env, jm_getStringForRange, fAccessible, fComponent, range.location, range.length); // AWT_THREADING Safe (AWTRunLoop) 367 368 if (jstringForRange == NULL) return @""; 369 NSString* str = JNFJavaToNSString(env, jstringForRange); 370 (*env)->DeleteLocalRef(env, jstringForRange); 371 return str; 372 } 373 374 // 375 // Usage of accessibilityRangeForPositionAttributeForParameter: 376 // --- 377 // cmcnote: I'm not sure when this is called / how it's used. Investigate. 378 // probably could be used in a special text-only accessibilityHitTest to 379 // find the index of the string under the mouse? 380 // 381 - (NSValue *)accessibilityRangeForPositionAttributeForParameter:(id)parameter 382 { 383 #ifdef JAVA_AX_DEBUG_PARMS 384 if (!([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue *)parameter objCType], @encode(NSPoint)) == 0)) { 385 JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityRangeForPositionParameterizedAttribute, parameter); 386 return nil; 387 } 388 #endif 389 390 NSPoint point = [(NSValue *)parameter pointValue]; // point is in screen coords 391 point.y = [[[[self view] window] screen] frame].size.height - point.y; // flip into java screen coords (0 is at upper-left corner of screen) 392 393 JNIEnv *env = [ThreadUtilities getJNIEnv]; 394 static JNF_STATIC_MEMBER_CACHE(jm_getCharacterIndexAtPosition, sjc_CAccessibleText, "getCharacterIndexAtPosition", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)I"); 395 jint charIndex = JNFCallStaticIntMethod(env, jm_getCharacterIndexAtPosition, fAccessible, fComponent, point.x, point.y); // AWT_THREADING Safe (AWTRunLoop) 396 if (charIndex == -1) return nil; 397 398 // AccessibleText.getIndexAtPoint returns -1 for an invalid point 399 NSRange range = NSMakeRange(charIndex, 1); //range's length is 1 - one-character range 400 return [NSValue valueWithRange:range]; 401 } 402 403 // 404 // Usage of accessibilityRangeForIndexAttributeForParameter: 405 // --- 406 // cmcnote: I'm not sure when this is called / how it's used. Investigate. 407 // AppKit version calls: [string rangeOfComposedCharacterSequenceAtIndex:index] 408 // We call: CAccessibility.getRangeForIndex, which calls AccessibleText.getAtIndex(AccessibleText.WORD, index) 409 // to determine the word closest to the given index. Then we find the length/location of this string. 410 // 411 - (NSValue *)accessibilityRangeForIndexAttributeForParameter:(id)parameter 412 { 413 #ifdef JAVA_AX_DEBUG_PARMS 414 if (![parameter isKindOfClass:[NSNumber class]]) { 415 JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityRangeForIndexParameterizedAttribute, parameter); 416 return nil; 417 } 418 #endif 419 420 NSUInteger index = [(NSNumber *)parameter unsignedIntegerValue]; 421 422 JNIEnv *env = [ThreadUtilities getJNIEnv]; 423 static JNF_STATIC_MEMBER_CACHE(jm_getRangeForIndex, sjc_CAccessibleText, "getRangeForIndex", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I"); 424 jintArray axTextRange = (jintArray)JNFCallStaticObjectMethod(env, jm_getRangeForIndex, fAccessible, fComponent, index); // AWT_THREADING Safe (AWTRunLoop) 425 if (axTextRange == NULL) return nil; 426 427 return javaIntArrayToNSRangeValue(env, axTextRange); 428 } 429 430 /* 431 * - (NSDictionary *)getActions:(JNIEnv *)env { ... } 432 * 433 * In the future, possibly add support: Editable text has AXShowMenu. 434 * Textfields have AXConfirm. 435 * 436 * Note: JLabels (static text) in JLists have a press/click selection action 437 * which is currently handled in superclass JavaComponentAccessibility. 438 * If function is added here be sure to use [super getActions:env] for JLabels. 439 */ 440 441 @end