summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManolo Gouy <Manolo>2010-10-26 21:01:17 +0000
committerManolo Gouy <Manolo>2010-10-26 21:01:17 +0000
commit901bc31ec35c79ea245a2895ff7a80657d01cf8b (patch)
tree488b52e672804a207ac229f912b55c6cae6f74c4
parentcac2ff33395798abaf2fa8a3041dea3819e4a36e (diff)
Use Mac OS-defined character composition method. It allows to handle composed characters of many more languages than before (e.g., Polish, Greek).
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7759 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
-rw-r--r--FL/Fl_Input.H13
-rw-r--r--src/Fl_cocoa.mm271
-rw-r--r--src/Fl_compose.cxx67
3 files changed, 83 insertions, 268 deletions
diff --git a/FL/Fl_Input.H b/FL/Fl_Input.H
index 08f212526..05b870237 100644
--- a/FL/Fl_Input.H
+++ b/FL/Fl_Input.H
@@ -37,10 +37,10 @@
This is the FLTK text input widget. It displays a single line
of text and lets the user edit it. Normally it is drawn with an
inset box and a white background. The text may contain any
- characters (even 0), and will correctly display anything, using
- ^X notation for unprintable control characters and \\nnn notation
- for unprintable characters with the high bit set. It assumes the
- font can draw any characters in the ISO-8859-1 character set.</P>
+ characters (even 0), and will correctly display any UTF text, using
+ ^X notation for unprintable control characters. It assumes the
+ font can draw any characters of the used scripts, which is true
+ for standard fonts under MSWindows and Mac OS X.</P>
<CENTER><TABLE border=1 WIDTH=90% summary="Fl_Input keyboard and mouse bindings.">
@@ -114,7 +114,10 @@
also be able to type "dead key" prefix characters. On X you will
actually be able to see what dead key you typed, and if you then move
the cursor without completing the sequence the accent will remain
- inserted.</TD></TR>
+ inserted.
+
+ <p>Under Mac OS X, character composition is done as for any Mac application
+ using Mac OS-defined keystroke series.</TD></TR>
</TABLE></CENTER>
<!-- NEW PAGE -->
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm
index ec4513150..e74b1a4db 100644
--- a/src/Fl_cocoa.mm
+++ b/src/Fl_cocoa.mm
@@ -875,141 +875,33 @@ static void cocoaMouseHandler(NSEvent *theEvent)
}
-/*
- * keycode_function for post-10.5 systems, allows more sophisticated decoding of keys
- */
-/*
- static int keycodeToUnicode(
- char * uniChars, int maxChars,
- EventKind eKind,
- UInt32 keycode, UInt32 modifiers,
- UInt32 * deadKeyStatePtr,
- unsigned char, // not used in this function
- unsigned short) // not used in this function
- {
- // first get the keyboard mapping in a post 10.2 way
-
- Ptr resource;
- TextEncoding encoding;
- static TextEncoding lastEncoding = kTextEncodingMacRoman;
- int len = 0;
- KeyboardLayoutRef currentLayout = NULL;
- static KeyboardLayoutRef lastLayout = NULL;
- SInt32 currentLayoutId = 0;
- static SInt32 lastLayoutId;
- int hasLayoutChanged = false;
- static Ptr uchr = NULL;
- static Ptr KCHR = NULL;
- // ScriptCode currentKeyScript;
-
- KLGetCurrentKeyboardLayout(&currentLayout);
- if (currentLayout) {
- KLGetKeyboardLayoutProperty(currentLayout, kKLIdentifier, (const void**)&currentLayoutId);
- if ( (lastLayout != currentLayout) || (lastLayoutId != currentLayoutId) ) {
- lastLayout = currentLayout;
- lastLayoutId = currentLayoutId;
- uchr = NULL;
- KCHR = NULL;
- if ((KLGetKeyboardLayoutProperty(currentLayout, kKLuchrData, (const void**)&uchr) == noErr) && (uchr != NULL)) {
- // done
- } else if ((KLGetKeyboardLayoutProperty(currentLayout, kKLKCHRData, (const void**)&KCHR) == noErr) && (KCHR != NULL)) {
- // done
- }
- // FIXME No Layout property found. Now we have a problem.
- }
- }
- if (hasLayoutChanged) {
- // deadKeyStateUp = deadKeyStateDown = 0;
- if (KCHR != NULL) {
- // FIXME this must not happen
- } else if (uchr == NULL) {
- KCHR = (Ptr) GetScriptManagerVariable(smKCHRCache);
- }
- }
- if (uchr != NULL) {
- // this is what I expect
- resource = uchr;
- } else {
- resource = KCHR;
- encoding = lastEncoding;
- // this is actually not supported by the following code and will likely crash
- }
-
- // now apply that keyboard mapping to our keycode
-
- int action;
- //OptionBits options = 0;
- // not used yet: OptionBits options = kUCKeyTranslateNoDeadKeysMask;
- unsigned long keyboardType;
- keycode &= 0xFF;
- modifiers = (modifiers >> 8) & 0xFF;
- keyboardType = LMGetKbdType();
- OSStatus status;
- UniCharCount actuallength;
- UniChar utext[10];
-
- switch(eKind) {
- case kEventRawKeyDown: action = kUCKeyActionDown; break;
- case kEventRawKeyUp: action = kUCKeyActionUp; break;
- case kEventRawKeyRepeat: action = kUCKeyActionAutoKey; break;
- default: return 0;
- }
-
- UInt32 deadKeyState = *deadKeyStatePtr;
- if ((action==kUCKeyActionUp)&&(*deadKeyStatePtr)) {
- deadKeyStatePtr = &deadKeyState;
- }
-
- status = UCKeyTranslate((const UCKeyboardLayout *) uchr,
- keycode, action, modifiers, keyboardType,
- 0, deadKeyStatePtr,
- 10, &actuallength, utext);
-
- if (noErr != status) {
- fprintf(stderr,"UCKeyTranslate failed: %d\n", (int) status);
- actuallength = 0;
- }
-
- // convert the list of unicode chars into utf8
- // FIXME no bounds check (see maxchars)
- unsigned i;
- for (i=0; i<actuallength; ++i) {
- len += fl_utf8encode(utext[i], uniChars+len);
- }
- uniChars[len] = 0;
- return len;
- }
- */
-
-/*
- * keycode_function for pre-10.5 systems, this is the "historic" fltk Mac key handling
- */
-static int keycode_wrap_old(char * buffer,
- int, EventKind, UInt32, // not used in this function
- UInt32, UInt32 *, // not used in this function
- unsigned char key,
- unsigned short sym)
-{
- if ( (sym >= FL_KP && sym <= FL_KP_Last) || !(sym & 0xff00) ||
- sym == FL_Tab || sym == FL_Enter) {
- buffer[0] = key;
- return 1;
- } else {
+static void calc_e_text(CFStringRef s, char *buffer, size_t len, unsigned sym)
+{
+ int i, no_text_key = false;
+ static unsigned notext[] = { // keys that don't emit text
+ FL_BackSpace, FL_Print, FL_Scroll_Lock, FL_Pause,
+ FL_Insert, FL_Home, FL_Page_Up, FL_Delete, FL_End, FL_Page_Down,
+ FL_Left, FL_Up, FL_Right, FL_Down,
+ FL_Menu, FL_Num_Lock, FL_Help
+ };
+ int count = sizeof(notext)/sizeof(int);
+
+ if (sym > FL_F && sym <= FL_F_Last) no_text_key = true;
+ else for (i=0; i < count; i++) {
+ if(notext[i] == sym) {
+ no_text_key = true;
+ break;
+ }
+ }
+
+ if ( no_text_key) {
buffer[0] = 0;
- return 0;
+ } else {
+ CFStringGetCString(s, buffer, len, kCFStringEncodingUTF8);
}
-} /* keycode_wrap_old */
-
-/*
- * Stub pointer to select appropriate keycode_function per operating system version. This function pointer
- * is initialised in fl_open_display, based on the runtime identification of the host OS version. This is
- * intended to allow us to utilise 10.5 services dynamically to improve Unicode handling, whilst still
- * allowing code to run satisfactorily on older systems.
- */
-static int (*keycode_function)(char*, int, EventKind, UInt32, UInt32, UInt32*, unsigned char, unsigned short) = keycode_wrap_old;
+}
-// EXPERIMENTAL!
// this gets called by CJK character palette input
OSStatus carbonTextHandler( EventHandlerCallRef nextHandler, EventRef event, void *unused )
{
@@ -1047,44 +939,6 @@ OSStatus carbonTextHandler( EventHandlerCallRef nextHandler, EventRef event, voi
return noErr;
}
-static void processCompositionSequence(CFStringRef s, Fl_Window *window)
-// composed character sequences are sent here
-// they contain 2 unichars, the first comes from the deadkey and can be non ascii (e.g., diaeresis),
-// the second is the character to be modified (e.g., e to be accented)
-{
- // unicodes: non-ascii unicode chars produced by deadkeys
- // asciis: corresponding ascii chars expected by Fl::compose()
- // diaeresis acute-accent circumflex tilde ring-above
- static UniChar unicodes[] = {0xA8, 0xB4, 0x2C6, 0x2DC, 0x2DA };
- static char asciis[] = { ':', '\'', '^', '~', '*' };
- if (CFStringGetLength(s) == 0) return;
- char text[10];
- char buffer[10];
- UniChar unis[2];
- CFStringGetCharacters(s, CFRangeMake(0, 2), unis);
- for(unsigned int i = 0; i < sizeof(asciis)/sizeof(char); i++) {
- if (unis[0] == unicodes[i]) {
- // replace the non-ascii unicode by the corresponding ascii value
- unis[0] = (UniChar)asciis[i];
- break;
- }
- }
- CFStringRef smod = CFStringCreateWithCharacters(kCFAllocatorDefault, unis, 2);
- CFStringGetCString(smod, buffer, sizeof(buffer), kCFStringEncodingUTF8);
- CFRelease(smod);
- Fl::e_keysym = 0;
- Fl::e_state = 0;
- Fl::e_length = 1;
- Fl::e_text = text;
- Fl::e_text[0] = buffer[0];
- Fl::handle(FL_KEYBOARD, window);
- Fl::e_keysym = 0;
- Fl::e_state = 0;
- Fl::e_length = 1;
- Fl::e_text[0] = buffer[1];
- Fl::handle(FL_KEYBOARD, window);
-}
-
/*
* handle cocoa keyboard events
@@ -1106,36 +960,41 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
// get the key code only for key events
UInt32 keyCode = 0, maskedKeyCode = 0;
- unichar key = 0;
- unsigned char keychar = 0;
unsigned short sym = 0;
keyCode = [theEvent keyCode];
NSString *s = [theEvent characters];
static BOOL compose = NO;
static NSText *edit;
static int countevents;
- static CFMutableStringRef sequence; // will contain the two characters of the composition sequence
if ( (mods & NSShiftKeyMask) && (mods & NSCommandKeyMask) ) {
s = [s uppercaseString]; // US keyboards return lowercase letter in s if cmd-shift-key is hit
}
if (compose) { // we are in a composition sequence
- // the only benefit of sending events to the NSText object edit is that the deadkey becomes visible
- // at its keyUp event; without this, the deadkey remains invisible
if ([s length] == 0) { // occurs if 2 deadkeys are typed successively by error
compose = NO;
[edit setString:@""];
- CFRelease(sequence);
fl_unlock_function();
return noErr;
}
- [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+ mods_to_e_state( mods ); // process modifier keys
+ Fl::e_keysym = Fl::e_original_keysym = macKeyLookUp[keyCode];
+ if([theEvent type] == NSKeyDown) { // keydown of the 2nd key of the compose sequence
+ [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+ }
+ else { // keyup of the dead key: there's text in s: display it temporarily
+ CFStringGetCString((CFStringRef)s, buffer, sizeof(buffer), kCFStringEncodingUTF8);
+ Fl::e_length = strlen(buffer);
+ Fl::e_text = buffer;
+ Fl::handle(FL_KEYBOARD, window);
+ }
countevents++;
- UniChar deadkey;
- CFStringGetCharacters((CFStringRef)s, CFRangeMake(0, 1), &deadkey);
- CFStringAppendCharacters(sequence, &deadkey, 1);// done for keyUp of deadkey and keyDown of next key
if (countevents >= 3) { // end of composition sequence
- processCompositionSequence( sequence, window );
- CFRelease(sequence);
+ // the composed char is now in s, handle it
+ CFStringGetCString((CFStringRef)s, buffer, sizeof(buffer), kCFStringEncodingUTF8);
+ Fl::e_length = strlen(buffer);
+ Fl::e_text = buffer;
+ Fl::compose_state = 1; // signals the end of a composition sequence
+ Fl::handle(FL_KEYBOARD, window);
[edit setString:@""]; // clear the content of the edit object
compose=NO; // character composition is now complete
}
@@ -1144,23 +1003,13 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
}
if ([s length] == 0) { // this is a dead key that must be combined with the next key to be pressed
while (window->parent()) window = window->window();
- Fl::e_keysym = FL_Control_R; // first simulate pressing of the compose key (FL_Control_R)
- Fl::e_text = (char*)"";
- Fl::e_length = 0;
- Fl::handle(FL_KEYBOARD, window);
compose=YES;
- // then send remaining events to an object of type NSText that helps handle character composition sequences
+ // send remaining keydown events to an object of type NSText that handles character composition sequences
edit = [[theEvent window] fieldEditor:YES forObject:nil];
- [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+ [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
countevents = 1;
- sequence = CFStringCreateMutable(NULL, 2);
fl_unlock_function();
return noErr;
- } else {
- char buff[10];
- CFStringGetCString((CFStringRef)s, buff, sizeof(buff), kCFStringEncodingUnicode);
- key = *(unichar*)buff;
- keychar = buff[0];
}
// extended keyboards can also send sequences on key-up to generate Kanji etc. codes.
// Some observed prefixes are 0x81 to 0x83, followed by an 8 bit keycode.
@@ -1187,15 +1036,10 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
sendEvent = FL_KEYUP;
Fl::e_state &= 0xbfffffff; // clear the deadkey flag
}
- mods_to_e_state( mods ); // we process modifier keys at the same time
- // if the user pressed alt/option, event_key should have the keycap,
- // but event_text should generate the international symbol
+ mods_to_e_state( mods ); // process modifier keys
sym = macKeyLookUp[maskedKeyCode];
- if ( isalpha(key) )
- sym = tolower(key);
- else if ( Fl::e_state&FL_CTRL && key<32 && sym<0xff00)
- sym = key+96;
- else if ( Fl::e_state&FL_ALT && sym<0xff00) { // find the keycap of this key
+ if (sym < 0xff00) { // a "simple" key
+ // find the result of this key without modifier
NSString *sim = [theEvent charactersIgnoringModifiers];
UniChar one;
CFStringGetCharacters((CFStringRef)sim, CFRangeMake(0, 1), &one);
@@ -1206,16 +1050,11 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
Fl::e_keysym = Fl::e_original_keysym = sym;
// Handle FL_KP_Enter on regular keyboards and on Powerbooks
- if ( maskedKeyCode==0x4c || maskedKeyCode==0x34) key=0x0d;
- static UInt32 deadKeyState = 0; // must be cleared when losing focus
- int l = (*keycode_function)(buffer, 31, kind, keyCode, mods, &deadKeyState, keychar, sym);
- if (l > 0) {
- CFStringGetCString((CFStringRef)s, buffer, sizeof(buffer), kCFStringEncodingUTF8);
- }
+ if ( maskedKeyCode==0x4c || maskedKeyCode==0x34) s = @"\r";
+ calc_e_text((CFStringRef)s, buffer, sizeof(buffer), sym);
Fl::e_length = strlen(buffer);
Fl::e_text = buffer;
- buffer[Fl::e_length] = 0; // just in case...
- }
+ }
break;
default:
fl_unlock_function();
@@ -1232,7 +1071,6 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
}
-
/*
* Open callback function to call...
*/
@@ -1557,18 +1395,7 @@ void fl_open_display() {
CFRelease(execUrl);
}
-
- keycode_function = keycode_wrap_old; // under Cocoa we always use this one
- /* // imm: keycode handler stub setting - use Gestalt to determine the running system version,
- * // then set the keycode_function pointer accordingly
- * if (MACsystemVersion >= 0x1050) { // 10.5.0 or later
- * keycode_function = keycodeToUnicode;
- * }
- * else {
- * keycode_function = keycode_wrap_old; // pre-10.5 mechanism
- * }
- */
-
+
if ( !bundle )
{
// Earlier versions of this code tried to use weak linking, however it
diff --git a/src/Fl_compose.cxx b/src/Fl_compose.cxx
index 3f2ff0bae..1601c74dd 100644
--- a/src/Fl_compose.cxx
+++ b/src/Fl_compose.cxx
@@ -37,14 +37,7 @@
//#define OLD_DEAD_KEY_CODE
-#ifdef __APPLE__
-
-static const char* const compose_pairs =
-" ! % # $ y=| & : c a <<~ - r _ * +-2 3 ' u p . , 1 o >>141234? "//00A0 ...
-"`A'A^A~A:A*AAE,C`E'E^E:E`I'I^I:I-D~N`O'O^O~O:Ox O/`U'U^U:U'YTHss" //00C0 ...
-"`a'a^a~a:a*aae,c`e'e^e:e`i'i^i:i-d~n`o'o^o~o:o-:o/`u'u^u:u'yth:y";//00E0 ...
-
-#else
+#ifndef __APPLE__
static const char* const compose_pairs =
"=E _'f _\"..+ ++^ %%^S< OE ^Z ^''^^\"\"^-*- --~ TM^s> oe ^z:Y"
@@ -85,6 +78,26 @@ static char dead_keys[] = {
int Fl::compose_state = 0;
#endif
+#ifdef __APPLE__
+// under Mac OS X character composition is handled by the OS
+int Fl::compose(int& del) {
+ if(Fl::e_length == 0 || Fl::e_keysym == FL_Enter || Fl::e_keysym == FL_KP_Enter ||
+ Fl::e_keysym == FL_Tab || Fl::e_keysym == FL_Escape || Fl::e_state&FL_META || Fl::e_state&FL_CTRL) {
+ del = 0;
+ return 0;
+ }
+ if(Fl::compose_state) {
+ del = 1;
+ Fl::compose_state = 0;
+ }
+ else {
+ del = 0;
+ }
+ return 1;
+}
+
+#else
+
/** Any text editing widget should call this for each FL_KEYBOARD event.
Use of this function is very simple.
@@ -114,11 +127,7 @@ int Fl::compose(int& del) {
//
// OSX users sometimes need to hold down ALT for keys, so we only check
// for META on OSX...
-#ifdef __APPLE__
- if ((e_state & FL_META) && !(ascii & 128)) return 0;
-#else
if ((e_state & (FL_ALT|FL_META)) && !(ascii & 128)) return 0;
-#endif // __APPLE__
if (compose_state == 1) { // after the compose key
if ( // do not get distracted by any modifier keys
@@ -134,15 +143,9 @@ int Fl::compose(int& del) {
) return 0;
if (ascii == ' ') { // space turns into nbsp
-#ifdef __APPLE__
- int len = fl_utf8encode(0xCA, e_text);
- e_text[len] = '\0';
- e_length = len;
- #else
int len = fl_utf8encode(0xA0, e_text);
e_text[len] = '\0';
e_length = len;
-#endif
compose_state = 0;
return 1;
} else if (ascii < ' ' || ascii == 127) {
@@ -171,19 +174,6 @@ int Fl::compose(int& del) {
} else if (compose_state) { // second character of compose
char c1 = char(compose_state); // retrieve first character
-#ifdef __APPLE__
- if ( (c1==0x60 && ascii==0xab) || (c1==0x27 && ascii==0x60)) {
- del = 1;
- compose_state = '^';
- e_text[0] = 0xf6;
- return 1;
- }
- if (ascii==' ') {
- del = 0;
- compose_state = 0;
- return 0;
- }
-#endif
// now search for the pair in either order:
for (const char *p = compose_pairs; *p; p += 2) {
if (p[0] == ascii && p[1] == c1 || p[1] == ascii && p[0] == c1) {
@@ -206,16 +196,7 @@ int Fl::compose(int& del) {
return 1;
}
-#ifdef WIN32
-#elif (defined __APPLE__)
- if (e_state & 0x40000000) {
- if (ascii<0x80)
- compose_state = ascii;
- else
- compose_state = compose_pairs[(ascii-0x80)*2];
- return 1;
- }
-#else
+#ifndef WIN32
// See if they typed a dead key. This gets it into the same state as
// typing prefix+accent:
if (i >= 0xfe50 && i <= 0xfe5b) {
@@ -246,5 +227,9 @@ int Fl::compose(int& del) {
return 0;
}
+#endif // __APPLE__
+//
+// End of "$Id$"
+//