Pierre Ossman | 2f11bd9 | 2014-08-22 14:43:33 +0200 | [diff] [blame^] | 1 | diff -ur fltk-1.3.0r9619.org/configure.in fltk-1.3.0r9619/configure.in |
| 2 | --- fltk-1.3.0r9619.org/configure.in 2012-04-22 04:45:09.000000000 +0200 |
| 3 | +++ fltk-1.3.0r9619/configure.in 2012-06-18 13:47:33.290447462 +0200 |
| 4 | @@ -865,6 +865,8 @@ |
| 5 | Darwin*) |
| 6 | # MacOS X uses Cocoa for graphics. |
| 7 | LIBS="$LIBS -framework Cocoa" |
| 8 | + # And some Carbon for keyboard handling |
| 9 | + LIBS="$LIBS -framework Carbon" |
| 10 | |
| 11 | if test x$have_pthread = xyes; then |
| 12 | AC_DEFINE(HAVE_PTHREAD) |
| 13 | diff -ur fltk-1.3.0r9619.org/src/Fl_cocoa.mm fltk-1.3.0r9619/src/Fl_cocoa.mm |
| 14 | --- fltk-1.3.0r9619.org/src/Fl_cocoa.mm 2012-06-16 10:49:52.000000000 +0200 |
| 15 | +++ fltk-1.3.0r9619/src/Fl_cocoa.mm 2012-06-18 13:47:42.944910782 +0200 |
| 16 | @@ -53,6 +53,7 @@ |
| 17 | #include <math.h> |
| 18 | |
| 19 | #import <Cocoa/Cocoa.h> |
| 20 | +#import <Carbon/Carbon.h> |
| 21 | |
| 22 | #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h |
| 23 | #if defined(__LP64__) && __LP64__ |
| 24 | @@ -114,6 +115,8 @@ |
| 25 | extern Fl_Window* fl_xmousewin; |
| 26 | #endif |
| 27 | |
| 28 | +bool use_simple_keyboard = false; |
| 29 | + |
| 30 | enum { FLTKTimerEvent = 1, FLTKDataReadyEvent }; |
| 31 | |
| 32 | |
| 33 | @@ -130,6 +133,39 @@ |
| 34 | { |
| 35 | } |
| 36 | |
| 37 | +// Undocumented voodoo. Taken from Mozilla. |
| 38 | +#define ENABLE_ROMAN_KYBDS_ONLY -23 |
| 39 | + |
| 40 | +void fl_update_focus(void) |
| 41 | +{ |
| 42 | + Fl_Widget *focus; |
| 43 | + |
| 44 | + focus = Fl::grab(); |
| 45 | + if (!focus) |
| 46 | + focus = Fl::focus(); |
| 47 | + if (!focus) |
| 48 | + return; |
| 49 | + |
| 50 | + if (focus->simple_keyboard()) |
| 51 | + use_simple_keyboard = true; |
| 52 | + else |
| 53 | + use_simple_keyboard = false; |
| 54 | + |
| 55 | + // Force a "Roman" or "ASCII" keyboard, which both the Mozilla and |
| 56 | + // Safari people seem to think implies turning off advanced IME stuff |
| 57 | + // (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput |
| 58 | + // in Safari/Webcore). Should be good enough for us then... |
| 59 | +#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) |
| 60 | + CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); |
| 61 | + TSMSetDocumentProperty(TSMGetActiveDocument(), |
| 62 | + kTSMDocumentEnabledInputSourcesPropertyTag, |
| 63 | + sizeof(CFArrayRef), &inputSources); |
| 64 | + CFRelease(inputSources); |
| 65 | +#else |
| 66 | + KeyScript(use_simple_keyboard ? ENABLE_ROMAN_KYBDS_ONLY : smKeyEnableKybds); |
| 67 | +#endif |
| 68 | +} |
| 69 | + |
| 70 | /* |
| 71 | * Mac keyboard lookup table |
| 72 | */ |
| 73 | @@ -908,6 +944,25 @@ |
| 74 | } |
| 75 | @end |
| 76 | |
| 77 | +static const char* cocoaDead2FLTK(const char *in) |
| 78 | +{ |
| 79 | + if (strcmp(in, "\140") == 0) // GRAVE ACCENT |
| 80 | + return "\314\200"; // COMBINING GRAVE ACCENT |
| 81 | + if (strcmp(in, "\302\264") == 0) // ACUTE ACCENT |
| 82 | + return "\314\201"; // COMBINING ACUTE ACCENT |
| 83 | + if (strcmp(in, "\136") == 0) // CIRCUMFLEX ACCENT |
| 84 | + return "\314\202"; // COMBINING CIRCUMFLEX ACCENT |
| 85 | + if (strcmp(in, "\176") == 0) // TILDE |
| 86 | + return "\314\203"; // COMBINING TILDE |
| 87 | + if (strcmp(in, "\302\250") == 0) // DIAERESIS |
| 88 | + return "\314\210"; // COMBINING DIAERESIS |
| 89 | + // FIXME: OS X dead key behaviour isn't documented and I don't have |
| 90 | + // any more keyboards to test with... |
| 91 | + |
| 92 | + // hope that OS X gave us something proper to begin with |
| 93 | + return in; |
| 94 | +} |
| 95 | + |
| 96 | /* |
| 97 | Handle cocoa keyboard events |
| 98 | Events during a character composition sequence: |
| 99 | @@ -1648,6 +1703,7 @@ |
| 100 | - (void)rightMouseDragged:(NSEvent *)theEvent; |
| 101 | - (void)otherMouseDragged:(NSEvent *)theEvent; |
| 102 | - (void)scrollWheel:(NSEvent *)theEvent; |
| 103 | ++ (NSString *)keyTranslate:(UInt16)keyCode withModifierFlags:(UInt32)modifierFlags; |
| 104 | - (BOOL)handleKeyDown:(NSEvent *)theEvent; |
| 105 | - (void)keyDown:(NSEvent *)theEvent; |
| 106 | - (void)keyUp:(NSEvent *)theEvent; |
| 107 | @@ -1726,6 +1782,130 @@ |
| 108 | - (void)scrollWheel:(NSEvent *)theEvent { |
| 109 | cocoaMouseWheelHandler(theEvent); |
| 110 | } |
| 111 | ++ (NSString *)keyTranslate:(UInt16)keyCode withModifierFlags:(UInt32)modifierFlags { |
| 112 | + const UCKeyboardLayout *layout; |
| 113 | + OSStatus err; |
| 114 | + |
| 115 | + layout = NULL; |
| 116 | + |
| 117 | +#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) |
| 118 | + TISInputSourceRef keyboard; |
| 119 | + CFDataRef uchr; |
| 120 | + |
| 121 | + keyboard = TISCopyCurrentKeyboardInputSource(); |
| 122 | + uchr = (CFDataRef)TISGetInputSourceProperty(keyboard, |
| 123 | + kTISPropertyUnicodeKeyLayoutData); |
| 124 | + if (uchr == NULL) |
| 125 | + return nil; |
| 126 | + |
| 127 | + layout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr); |
| 128 | +#else |
| 129 | + KeyboardLayoutRef old_layout; |
| 130 | + int kind; |
| 131 | + |
| 132 | + err = KLGetCurrentKeyboardLayout(&old_layout); |
| 133 | + if (err != noErr) |
| 134 | + return nil; |
| 135 | + |
| 136 | + err = KLGetKeyboardLayoutProperty(old_layout, kKLKind, |
| 137 | + (const void**)&kind); |
| 138 | + if (err != noErr) |
| 139 | + return nil; |
| 140 | + |
| 141 | + // Old, crufty layout format? |
| 142 | + if (kind == kKLKCHRKind) { |
| 143 | + void *kchr_layout; |
| 144 | + |
| 145 | + UInt32 chars, state; |
| 146 | + char buf[3]; |
| 147 | + |
| 148 | + unichar result[16]; |
| 149 | + ByteCount in_len, out_len; |
| 150 | + |
| 151 | + err = KLGetKeyboardLayoutProperty(old_layout, kKLKCHRData, |
| 152 | + (const void**)&kchr_layout); |
| 153 | + if (err != noErr) |
| 154 | + return nil; |
| 155 | + |
| 156 | + state = 0; |
| 157 | + |
| 158 | + keyCode &= 0x7f; |
| 159 | + modifierFlags &= 0xff00; |
| 160 | + |
| 161 | + chars = KeyTranslate(kchr_layout, keyCode | modifierFlags, &state); |
| 162 | + |
| 163 | + buf[0] = (chars >> 16) & 0xff; |
| 164 | + buf[1] = chars & 0xff; |
| 165 | + buf[2] = '\0'; |
| 166 | + |
| 167 | + if (buf[0] == '\0') { |
| 168 | + buf[0] = buf[1]; |
| 169 | + buf[1] = '\0'; |
| 170 | + } |
| 171 | + |
| 172 | + // The data is now in some layout specific encoding. Need to convert |
| 173 | + // this to unicode. |
| 174 | + |
| 175 | + ScriptCode script; |
| 176 | + TextEncoding encoding; |
| 177 | + TECObjectRef converter; |
| 178 | + |
| 179 | + script = (ScriptCode)GetScriptManagerVariable(smKeyScript); |
| 180 | + |
| 181 | + err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, |
| 182 | + kTextRegionDontCare, NULL, |
| 183 | + &encoding); |
| 184 | + if (err != noErr) |
| 185 | + return nil; |
| 186 | + |
| 187 | + err = TECCreateConverter(&converter, encoding, kTextEncodingUnicodeV4_0); |
| 188 | + if (err != noErr) |
| 189 | + return nil; |
| 190 | + |
| 191 | + in_len = strlen(buf); |
| 192 | + out_len = sizeof(result); |
| 193 | + |
| 194 | + err = TECConvertText(converter, (ConstTextPtr)buf, in_len, &in_len, |
| 195 | + (TextPtr)result, out_len, &out_len); |
| 196 | + |
| 197 | + TECDisposeConverter(converter); |
| 198 | + |
| 199 | + if (err != noErr) |
| 200 | + return nil; |
| 201 | + |
| 202 | + return [NSString stringWithCharacters:result |
| 203 | + length:(out_len / sizeof(unichar))]; |
| 204 | + } |
| 205 | + |
| 206 | + if ((kind != kKLKCHRuchrKind) && (kind != kKLuchrKind)) |
| 207 | + return nil; |
| 208 | + |
| 209 | + err = KLGetKeyboardLayoutProperty(old_layout, kKLuchrData, |
| 210 | + (const void**)&layout); |
| 211 | + if (err != noErr) |
| 212 | + return nil; |
| 213 | +#endif |
| 214 | + |
| 215 | + if (layout == NULL) |
| 216 | + return nil; |
| 217 | + |
| 218 | + UInt32 dead_state; |
| 219 | + UniCharCount max_len, actual_len; |
| 220 | + UniChar string[255]; |
| 221 | + |
| 222 | + dead_state = 0; |
| 223 | + max_len = sizeof(string)/sizeof(*string); |
| 224 | + |
| 225 | + modifierFlags = (modifierFlags >> 8) & 0xff; |
| 226 | + |
| 227 | + err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags, |
| 228 | + LMGetKbdType(), 0, &dead_state, max_len, &actual_len, |
| 229 | + string); |
| 230 | + if (err != noErr) |
| 231 | + return nil; |
| 232 | + |
| 233 | + return [NSString stringWithCharacters:string length:actual_len]; |
| 234 | +} |
| 235 | - (BOOL)handleKeyDown:(NSEvent *)theEvent { |
| 236 | //NSLog(@"handleKeyDown"); |
| 237 | fl_lock_function(); |
| 238 | @@ -1752,14 +1932,47 @@ |
| 239 | break; |
| 240 | } |
| 241 | } |
| 242 | - if (!no_text_key && !(Fl::e_state & FL_META) ) { |
| 243 | - // Don't send cmd-<key> to interpretKeyEvents because it beeps. |
| 244 | + if (!no_text_key) { |
| 245 | + // The simple keyboard model will ignore insertText, so we need to grab |
| 246 | + // the symbol directly from the event. Note that we still use setMarkedText. |
| 247 | + if (use_simple_keyboard) { |
| 248 | + NSString *simple_chars; |
| 249 | + UInt32 modifiers; |
| 250 | + |
| 251 | + // We want a "normal" symbol out of the event, which basically means |
| 252 | + // we only respect the shift and alt/altgr modifiers. Cocoa can help |
| 253 | + // us if we only wanted shift, but as we also want alt/altgr, we'll |
| 254 | + // have to do some lookup ourselves. This matches our behaviour on |
| 255 | + // other platforms. |
| 256 | + |
| 257 | + modifiers = 0; |
| 258 | + if ([theEvent modifierFlags] & NSAlphaShiftKeyMask) |
| 259 | + modifiers |= alphaLock; |
| 260 | + if ([theEvent modifierFlags] & NSShiftKeyMask) |
| 261 | + modifiers |= shiftKey; |
| 262 | + if ([theEvent modifierFlags] & NSAlternateKeyMask) |
| 263 | + modifiers |= optionKey; |
| 264 | + |
| 265 | + simple_chars = [FLView keyTranslate:[theEvent keyCode] |
| 266 | + withModifierFlags:modifiers]; |
| 267 | + if (simple_chars == nil) { |
| 268 | + // Something went wrong. Fall back to what Cocoa gave us... |
| 269 | + simple_chars = [theEvent charactersIgnoringModifiers]; |
| 270 | + } |
| 271 | + |
| 272 | + [FLView prepareEtext:simple_chars]; |
| 273 | + } |
| 274 | + |
| 275 | // Then we can let the OS have a stab at it and see if it thinks it |
| 276 | // should result in some text |
| 277 | - NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; |
| 278 | - in_key_event = true; |
| 279 | - [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; |
| 280 | - in_key_event = false; |
| 281 | + |
| 282 | + // Don't send cmd-<key> to interpretKeyEvents because it beeps. |
| 283 | + if (!(Fl::e_state & FL_META)) { |
| 284 | + NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; |
| 285 | + in_key_event = true; |
| 286 | + [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; |
| 287 | + in_key_event = false; |
| 288 | + } |
| 289 | } |
| 290 | //NSLog(@"to text=%@ l=%d", [NSString stringWithUTF8String:Fl::e_text], Fl::e_length); |
| 291 | int handled = Fl::handle(FL_KEYDOWN, window); |
| 292 | @@ -1937,21 +2150,30 @@ |
| 293 | //NSLog(@"insertText: received=%@",received); |
| 294 | |
| 295 | if (!in_key_event) fl_lock_function(); |
| 296 | + |
| 297 | + // Simple keyboard widgets do not want these side channel inputs. |
| 298 | + if (use_simple_keyboard) |
| 299 | + goto end; |
| 300 | + |
| 301 | [FLView prepareEtext:received]; |
| 302 | + |
| 303 | // We can get called outside of key events (e.g. from the character |
| 304 | - // palette). Transform such actions to FL_PASTE events. |
| 305 | + // palette). We need to fake our own key event at that point. |
| 306 | if (!in_key_event) { |
| 307 | Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; |
| 308 | - Fl::handle(FL_PASTE, target); |
| 309 | + Fl::e_keysym = Fl::e_original_keysym = 0; |
| 310 | + Fl::handle(FL_KEYDOWN, target); |
| 311 | // for some reason, the window does not redraw until the next mouse move or button push |
| 312 | // sending a 'redraw()' or 'awake()' does not solve the issue! |
| 313 | Fl::flush(); |
| 314 | } |
| 315 | + |
| 316 | +end: |
| 317 | if (!in_key_event) fl_unlock_function(); |
| 318 | } |
| 319 | |
| 320 | - (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection { |
| 321 | - NSString *received; |
| 322 | + NSString *received, *current, *aggregate; |
| 323 | if (newSelection.location == 0) { |
| 324 | [self unmarkText]; |
| 325 | return; |
| 326 | @@ -1962,11 +2184,47 @@ |
| 327 | received = (NSString*)aString; |
| 328 | } |
| 329 | //NSLog(@"setMarkedText: %@ %d %d",received,newSelection.location,newSelection.length); |
| 330 | + |
| 331 | + fl_lock_function(); |
| 332 | + |
| 333 | + // Simple keyboard widgets generally do not want these side channel |
| 334 | + // inputs, but we have no other way of getting dead keys so we make |
| 335 | + // an exception in that case. |
| 336 | + if (use_simple_keyboard) { |
| 337 | + if (in_key_event && (Fl::e_length == 0)) { |
| 338 | + [FLView prepareEtext:received]; |
| 339 | + |
| 340 | + Fl::e_text = (char*)cocoaDead2FLTK(Fl::e_text); |
| 341 | + Fl::e_length = strlen(Fl::e_text); |
| 342 | + } |
| 343 | + goto end; |
| 344 | + } |
| 345 | + |
| 346 | // This code creates the OS X behaviour of seeing dead keys as things |
| 347 | // are being composed. |
| 348 | + // |
| 349 | + // Note: The concatenation thing is because of how OS X deals with |
| 350 | + // invalid sequences. At that point it will spit out one call |
| 351 | + // to insertText with the now aborted sequence, and one new |
| 352 | + // call to setMarkedText with the new sequence. Since we want |
| 353 | + // both to be visible, we need to concatenate. |
| 354 | next_compose_length = newSelection.location; |
| 355 | - [FLView prepareEtext:received]; |
| 356 | - //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", received, Fl::e_length, next_compose_length); |
| 357 | + current = [NSString stringWithUTF8String:Fl::e_text]; |
| 358 | + aggregate = [current stringByAppendingString:received]; |
| 359 | + |
| 360 | + [FLView prepareEtext:aggregate]; |
| 361 | + //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", aggregate, Fl::e_length, next_compose_length); |
| 362 | + |
| 363 | + // We can get called outside of key events (e.g. from the character |
| 364 | + // palette). We need to fake our own key event at that point. |
| 365 | + if (!in_key_event) { |
| 366 | + Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; |
| 367 | + Fl::e_keysym = Fl::e_original_keysym = 0; |
| 368 | + Fl::handle(FL_KEYDOWN, target); |
| 369 | + } |
| 370 | + |
| 371 | +end: |
| 372 | + fl_unlock_function(); |
| 373 | } |
| 374 | |
| 375 | - (void)unmarkText { |