2000-02-21 13:30:00 +03:00
|
|
|
//
|
2005-02-25 00:55:12 +03:00
|
|
|
// "$Id$"
|
2000-02-21 13:30:00 +03:00
|
|
|
//
|
|
|
|
// Character compose processing for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2009-01-02 00:28:26 +03:00
|
|
|
// Copyright 1998-2009 by Bill Spitzak and others.
|
2000-02-21 13:30:00 +03:00
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Library General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Library General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Library General Public
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
|
|
// USA.
|
|
|
|
//
|
2005-04-16 04:13:17 +04:00
|
|
|
// Please report all bugs and problems on the following page:
|
|
|
|
//
|
|
|
|
// http://www.fltk.org/str.php
|
2000-02-21 13:30:00 +03:00
|
|
|
//
|
|
|
|
|
|
|
|
#include <FL/Fl.H>
|
2009-12-07 01:21:55 +03:00
|
|
|
#include <FL/x.H>
|
2000-02-21 13:30:00 +03:00
|
|
|
|
2002-11-08 19:05:33 +03:00
|
|
|
//
|
|
|
|
// MRS: Uncomment the following define to get the original (pre-1.1.2)
|
|
|
|
// dead key support code. The original code apparently did not
|
|
|
|
// work on Belgian keyboards.
|
|
|
|
//
|
|
|
|
|
|
|
|
//#define OLD_DEAD_KEY_CODE
|
|
|
|
|
|
|
|
|
2006-04-19 07:00:26 +04:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
2009-12-07 01:21:55 +03:00
|
|
|
#ifdef __APPLE_COCOA__
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2000-02-21 13:30:00 +03:00
|
|
|
static const char* const compose_pairs =
|
2006-04-19 07:00:26 +04:00
|
|
|
":A*A,C'E~N:O:U'a`a^a:a~a*a,c'e`e"
|
|
|
|
"^e:e'i`i^i:i~n'o`o^o:o~o'u`u^u:u"
|
|
|
|
"+ o /c# SS* P|ssrOcOTM' : !=AE/O"
|
|
|
|
"oo+-<=>=Y=mudtSgPipiS a dgOmaeo/"
|
|
|
|
"? ! !!v-f ~~Dt<<>>.. `A~A~OOEoe"
|
|
|
|
"- --''``\"'\"`:-^V:y:Y//E=< > fifl"
|
|
|
|
"++..,,_\"%%^A^E'A:E`E'I^I:I`I'O^O"
|
2006-05-05 18:09:50 +04:00
|
|
|
"mc`O'U^U`U||^ ~^_ u . * , ~-; v ";
|
2006-04-19 07:00:26 +04:00
|
|
|
|
2009-12-07 01:21:55 +03:00
|
|
|
#endif
|
|
|
|
|
2006-04-19 07:00:26 +04:00
|
|
|
#else
|
|
|
|
|
2006-04-19 17:57:46 +04:00
|
|
|
static const char* const compose_pairs =
|
2006-04-18 17:07:42 +04:00
|
|
|
"=E _'f _\"..+ ++^ %%^S< OE ^Z ^''^^\"\"^-*- --~ TM^s> oe ^z:Y"
|
2000-02-21 13:30:00 +03:00
|
|
|
" ! % # $ y=| & : c a <<~ - r _ * +-2 3 ' u p . , 1 o >>141234? "
|
|
|
|
"`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"
|
|
|
|
"`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";
|
|
|
|
|
2006-04-19 07:00:26 +04:00
|
|
|
#endif
|
|
|
|
|
2002-11-08 19:05:33 +03:00
|
|
|
#if !defined(WIN32) && defined(OLD_DEAD_KEY_CODE) // X only
|
2000-02-21 13:30:00 +03:00
|
|
|
// X dead-key lookup table. This turns a dead-key keysym into the
|
|
|
|
// first of two characters for one of the compose sequences. These
|
|
|
|
// keysyms start at 0xFE50.
|
2002-11-08 19:05:33 +03:00
|
|
|
// Win32 handles the dead keys before FLTK can see them. This is
|
2000-02-21 13:30:00 +03:00
|
|
|
// unfortunate, because you don't get the preview effect.
|
|
|
|
static char dead_keys[] = {
|
|
|
|
'`', // XK_dead_grave
|
|
|
|
'\'', // XK_dead_acute
|
|
|
|
'^', // XK_dead_circumflex
|
|
|
|
'~', // XK_dead_tilde
|
|
|
|
'_', // XK_dead_macron
|
|
|
|
0, // XK_dead_breve
|
|
|
|
'.', // XK_dead_abovedot
|
|
|
|
':', // XK_dead_diaeresis
|
|
|
|
'*', // XK_dead_abovering
|
|
|
|
0, // XK_dead_doubleacute
|
|
|
|
'v', // XK_dead_caron
|
|
|
|
',' // XK_dead_cedilla
|
|
|
|
// 0, // XK_dead_ogonek
|
|
|
|
// 0, // XK_dead_iota
|
|
|
|
// 0, // XK_dead_voiced_sound
|
|
|
|
// 0, // XK_dead_semivoiced_sound
|
|
|
|
// 0 // XK_dead_belowdot
|
|
|
|
};
|
2002-11-08 19:05:33 +03:00
|
|
|
#endif // !WIN32 && OLD_DEAD_KEY_CODE
|
2000-02-21 13:30:00 +03:00
|
|
|
|
2008-09-18 23:09:34 +04:00
|
|
|
#ifndef FL_DOXYGEN
|
2002-11-08 19:05:33 +03:00
|
|
|
int Fl::compose_state = 0;
|
2008-09-18 23:09:34 +04:00
|
|
|
#endif
|
2000-02-21 13:30:00 +03:00
|
|
|
|
2008-09-14 02:33:03 +04:00
|
|
|
/** Any text editing widget should call this for each FL_KEYBOARD event.
|
|
|
|
Use of this function is very simple.
|
|
|
|
|
|
|
|
<p>If <i>true</i> is returned, then it has modified the
|
|
|
|
Fl::event_text() and Fl::event_length() to a set of <i>bytes</i> to
|
|
|
|
insert (it may be of zero length!). In will also set the "del"
|
|
|
|
parameter to the number of <i>bytes</i> to the left of the cursor to
|
|
|
|
delete, this is used to delete the results of the previous call to
|
|
|
|
Fl::compose().
|
|
|
|
|
|
|
|
<p>If <i>false</i> is returned, the keys should be treated as function
|
|
|
|
keys, and del is set to zero. You could insert the text anyways, if
|
|
|
|
you don't know what else to do.
|
|
|
|
|
|
|
|
<p>Though the current implementation returns immediately, future
|
|
|
|
versions may take quite awhile, as they may pop up a window or do
|
|
|
|
other user-interface things to allow characters to be selected.
|
|
|
|
*/
|
2000-02-21 13:30:00 +03:00
|
|
|
int Fl::compose(int& del) {
|
|
|
|
|
|
|
|
del = 0;
|
2002-11-08 19:05:33 +03:00
|
|
|
unsigned char ascii = (unsigned)e_text[0];
|
2000-02-21 13:30:00 +03:00
|
|
|
|
|
|
|
// Alt+letters are reserved for shortcuts. But alt+foreign letters
|
|
|
|
// has to be allowed, because some key layouts require alt to be held
|
|
|
|
// down in order to type them...
|
2003-05-20 19:29:42 +04:00
|
|
|
//
|
|
|
|
// 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__
|
2000-02-21 13:30:00 +03:00
|
|
|
|
|
|
|
if (compose_state == 1) { // after the compose key
|
2006-06-19 11:43:39 +04:00
|
|
|
if ( // do not get distracted by any modifier keys
|
|
|
|
e_keysym==FL_Shift_L||
|
|
|
|
e_keysym==FL_Shift_R ||
|
|
|
|
e_keysym==FL_Alt_L ||
|
|
|
|
e_keysym==FL_Alt_R ||
|
|
|
|
e_keysym==FL_Meta_L ||
|
|
|
|
e_keysym==FL_Meta_R ||
|
|
|
|
e_keysym==FL_Control_R ||
|
|
|
|
e_keysym==FL_Control_L ||
|
|
|
|
e_keysym==FL_Menu
|
|
|
|
) return 0;
|
2000-02-21 13:30:00 +03:00
|
|
|
|
|
|
|
if (ascii == ' ') { // space turns into nbsp
|
2006-04-18 17:07:42 +04:00
|
|
|
#ifdef __APPLE__
|
2008-09-11 03:56:49 +04:00
|
|
|
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;
|
2006-04-18 17:07:42 +04:00
|
|
|
#endif
|
2000-02-21 13:30:00 +03:00
|
|
|
compose_state = 0;
|
|
|
|
return 1;
|
2004-02-26 06:06:41 +03:00
|
|
|
} else if (ascii < ' ' || ascii == 127) {
|
|
|
|
compose_state = 0;
|
|
|
|
return 0;
|
2000-02-21 13:30:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// see if it is either character of any pair:
|
2008-09-11 03:56:49 +04:00
|
|
|
for (const char *p = compose_pairs; *p; p += 2)
|
2000-02-21 13:30:00 +03:00
|
|
|
if (p[0] == ascii || p[1] == ascii) {
|
2008-09-11 03:56:49 +04:00
|
|
|
if (p[1] == ' ') {
|
|
|
|
int len = fl_utf8encode((p-compose_pairs)/2+0xA0, e_text);
|
|
|
|
e_text[len] = '\0';
|
|
|
|
e_length = len;
|
|
|
|
}
|
|
|
|
|
2000-02-21 13:30:00 +03:00
|
|
|
compose_state = ascii;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e_length) { // compose key also "quotes" control characters
|
|
|
|
compose_state = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (compose_state) { // second character of compose
|
|
|
|
|
|
|
|
char c1 = char(compose_state); // retrieve first character
|
2006-04-19 07:00:26 +04:00
|
|
|
#ifdef __APPLE__
|
|
|
|
if ( (c1==0x60 && ascii==0xab) || (c1==0x27 && ascii==0x60)) {
|
|
|
|
del = 1;
|
|
|
|
compose_state = '^';
|
|
|
|
e_text[0] = 0xf6;
|
|
|
|
return 1;
|
|
|
|
}
|
2006-05-05 18:09:50 +04:00
|
|
|
if (ascii==' ') {
|
|
|
|
del = 0;
|
|
|
|
compose_state = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2006-04-19 07:00:26 +04:00
|
|
|
#endif
|
2000-02-21 13:30:00 +03:00
|
|
|
// 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) {
|
2008-09-11 03:56:49 +04:00
|
|
|
int len = fl_utf8encode((p-compose_pairs)/2+0xA0, e_text);
|
|
|
|
e_text[len] = '\0';
|
|
|
|
e_length = len;
|
2000-02-21 13:30:00 +03:00
|
|
|
del = 1; // delete the old character and insert new one
|
|
|
|
compose_state = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int i = e_keysym;
|
|
|
|
|
|
|
|
// See if they type the compose prefix key:
|
|
|
|
if (i == FL_Control_R || i == 0xff20/* Multi-Key */) {
|
|
|
|
compose_state = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-04-18 17:07:42 +04:00
|
|
|
#ifdef WIN32
|
2006-04-19 07:00:26 +04:00
|
|
|
#elif (defined __APPLE__)
|
|
|
|
if (e_state & 0x40000000) {
|
|
|
|
if (ascii<0x80)
|
|
|
|
compose_state = ascii;
|
|
|
|
else
|
|
|
|
compose_state = compose_pairs[(ascii-0x80)*2];
|
|
|
|
return 1;
|
|
|
|
}
|
2006-04-18 17:07:42 +04:00
|
|
|
#else
|
2000-02-21 13:30:00 +03:00
|
|
|
// See if they typed a dead key. This gets it into the same state as
|
|
|
|
// typing prefix+accent:
|
|
|
|
if (i >= 0xfe50 && i <= 0xfe5b) {
|
2002-11-08 19:05:33 +03:00
|
|
|
# ifdef OLD_DEAD_KEY_CODE
|
2000-02-21 13:30:00 +03:00
|
|
|
ascii = dead_keys[i-0xfe50];
|
|
|
|
for (const char *p = compose_pairs; *p; p += 2)
|
|
|
|
if (p[0] == ascii) {
|
2002-11-08 19:05:33 +03:00
|
|
|
compose_state = ascii;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
# else
|
|
|
|
ascii = e_text[0];
|
|
|
|
for (const char *p = compose_pairs; *p; p += 2)
|
|
|
|
if (p[0] == ascii ||
|
2008-09-11 03:56:49 +04:00
|
|
|
(p[1] == ' ' && (p - compose_pairs) / 2 + 0xA0 == ascii)) {
|
2002-11-08 19:05:33 +03:00
|
|
|
compose_state = p[0];
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
# endif // OLD_DEAD_KEY_CODE
|
2000-02-21 13:30:00 +03:00
|
|
|
compose_state = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Only insert non-control characters:
|
2000-03-05 09:51:07 +03:00
|
|
|
if (e_length && (ascii & ~31 && ascii!=127)) {compose_state = 0; return 1;}
|
2000-02-21 13:30:00 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-04-19 07:00:26 +04:00
|
|
|
|
|
|
|
|