System IME support in Linux SDL1 builds (imported and tested to work by nanshiki)

This commit is contained in:
Wengier
2021-07-21 23:47:29 -04:00
parent 4aa2948e06
commit e05357c0a1
11 changed files with 961 additions and 15 deletions

View File

@@ -66,6 +66,7 @@
#if defined(linux) || defined(__linux) || defined(__linux__)
#undef __LINUX__
#define __LINUX__ 1
#define ENABLE_IM_EVENT 1
#endif
#if defined(__APPLE__)
#undef __MACOSX__

View File

@@ -58,6 +58,14 @@ static SDLKey ODD_keymap[256];
static SDLKey MISC_keymap[256];
SDLKey X11_TranslateKeycode(Display *display, KeyCode kc);
#ifdef ENABLE_IM_EVENT
void xim_lookup_key(_THIS, XKeyPressedEvent *event);
/* Buffer size required by xim_lookup_key */
#define BASE_BUFSIZE 50
#endif /* ENABLE_IM_EVENT */
/*
Pending resize target for ConfigureNotify (so outdated events don't
cause inappropriate resize events)
@@ -402,6 +410,14 @@ static int X11_DispatchEvent(_THIS)
SDL_memset(&xevent, '\0', sizeof (XEvent)); /* valgrind fix. --ryan. */
XNextEvent(SDL_Display, &xevent);
#ifdef ENABLE_IM_EVENT
if (IM_Context.im_enable && IM_Context.ic_focus) {
if (XFilterEvent(&xevent, None)) {
return 0;
}
}
#endif
/* Discard KeyRelease and KeyPress events generated by auto-repeat.
We need to do it before passing event to XFilterEvent. Otherwise,
KeyRelease aware IMs are confused... */
@@ -482,6 +498,13 @@ printf("FocusIn!\n");
/* Queue entry into fullscreen mode */
switch_waiting = 0x01 | SDL_FULLSCREEN;
switch_time = SDL_GetTicks() + 1500;
#ifdef ENABLE_IM_EVENT
if (IM_Context.SDL_XIC && IM_Context.im_enable) {
XSetICFocus(IM_Context.SDL_XIC);
IM_Context.ic_focus = 1;
}
#endif
}
}
break;
@@ -506,6 +529,13 @@ printf("FocusOut!\n");
/* Queue leaving fullscreen mode */
switch_waiting = 0x01;
switch_time = SDL_GetTicks() + 200;
#ifdef ENABLE_IM_EVENT
if (IM_Context.SDL_XIC && IM_Context.im_enable) {
XUnsetICFocus(IM_Context.SDL_XIC);
IM_Context.ic_focus = 0;
}
#endif
}
}
break;
@@ -575,6 +605,12 @@ printf("KeymapNotify!\n");
#ifdef DEBUG_XEVENTS
printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
#endif
#ifdef ENABLE_IM_EVENT
if (IM_Context.im_enable && IM_Context.ic_focus) {
xim_lookup_key(this, (XKeyPressedEvent *)&xevent);
}
#endif
/* If we're not doing translation, we're done! */
if ( !SDL_TranslateUNICODE ) {
@@ -1460,3 +1496,358 @@ void X11_InitOSKeymap(_THIS)
X11_InitKeymap();
}
#ifdef ENABLE_IM_EVENT
extern int SDL_TranslateUNICODE;
void xim_lookup_key(_THIS, XKeyPressedEvent *event)
{
KeySym keysym;
Status status;
int i;
if (IM_Context.SDL_XIC) {
if (!IM_Context.string.im_wide_char_buffer) {
IM_Context.im_buffer_len = BASE_BUFSIZE;
IM_Context.string.im_wide_char_buffer = (wchar_t*)malloc(IM_Context.im_buffer_len*sizeof(wchar_t));
}
//memset(IM_Context.string.im_wide_char_buffer, 0, IM_Context.im_buffer_len*sizeof(wchar_t));
IM_Context.string.im_wide_char_buffer[0] = '\0';
//if (SDL_TranslateUNICODE)
IM_Context.im_compose_len = XwcLookupString(IM_Context.SDL_XIC, event, IM_Context.string.im_wide_char_buffer, IM_Context.im_buffer_len, &keysym, &status);
//else
// IM_Context.im_compose_len = XmbLookupString(IM_Context.SDL_XIC, event, IM_Context.string.im_multi_byte_buffer, IM_Context.im_buffer_len*sizeof(wchar_t), &keysym, &status);
if ((status == XBufferOverflow)) {
IM_Context.im_buffer_len = IM_Context.im_compose_len + 1;
IM_Context.string.im_wide_char_buffer = (wchar_t*)realloc(IM_Context.string.im_wide_char_buffer, IM_Context.im_buffer_len*sizeof(wchar_t));
//memset(IM_Context.string.im_wide_char_buffer, 0, IM_Context.im_buffer_len*sizeof(wchar_t));
//if (SDL_TranslateUNICODE)
IM_Context.im_compose_len = XwcLookupString(IM_Context.SDL_XIC, event, IM_Context.string.im_wide_char_buffer, IM_Context.im_buffer_len, &keysym, &status);
//else
// IM_Context.im_compose_len = XmbLookupString(IM_Context.SDL_XIC, event, IM_Context.string.im_multi_byte_buffer, IM_Context.im_buffer_len*sizeof(wchar_t), &keysym, &status);
}
if (status != XLookupChars) {
IM_Context.im_compose_len = 0;
}
else {
//if (SDL_TranslateUNICODE)
IM_Context.string.im_wide_char_buffer[IM_Context.im_compose_len] = '\0';
//else
// IM_Context.string.im_multi_byte_buffer[IM_Context.im_compose_len] = '\0';
}
for (i = 0; i < IM_Context.im_compose_len ; i++) {
SDL_keysym sdlkeysym;
sdlkeysym.scancode = 0;
sdlkeysym.sym = SDLK_UNKNOWN;
sdlkeysym.mod = KMOD_NONE;
sdlkeysym.unicode = IM_Context.string.im_wide_char_buffer[i];
SDL_PrivateKeyboard(SDL_PRESSED, &sdlkeysym);
}
}
else {
IM_Context.im_compose_len = 0;
SDL_SetError("SDL_XIC is NULL.");
}
}
int X11_SetIMPosition(_THIS, int x, int y)
{
XPoint spot;
XVaNestedList preedit_attr;
if (!IM_Context.SDL_XIC) {
SDL_SetError("SDL_XIC is NULL.");
return 0;
}
spot.x = x;
spot.y = y;
preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
XSetICValues(IM_Context.SDL_XIC, XNPreeditAttributes, preedit_attr, NULL);
XFree(preedit_attr);
return 1;
}
char *X11_SetIMValues(_THIS, SDL_imvalue value, int alt)
{
if (IM_Context.SDL_XIC) {
switch (value) {
case SDL_IM_ENABLE:
if (alt) {
if (!IM_Context.im_enable) {
XSetICFocus(IM_Context.SDL_XIC);
IM_Context.ic_focus = 1;
IM_Context.im_enable = 1;
}
return NULL;
}
else {
if (IM_Context.im_enable) {
XUnsetICFocus(IM_Context.SDL_XIC);
IM_Context.im_enable = 0;
IM_Context.ic_focus = 0;
}
return NULL;
}
case SDL_IM_FLIP:
/* backup original attributes */
if (IM_Context.im_style_orig == 0) {
XGetICValues(IM_Context.SDL_XIC,
XNInputStyle,
&IM_Context.im_style_orig, NULL);
if (IM_Context.im_style_orig == 0) {
IM_Context.im_style_orig = IM_Context.im_style_now;
}
}
if (IM_Context.preedit_attr_orig == NULL) {
XGetICValues(IM_Context.SDL_XIC,
XNPreeditAttributes,
&IM_Context.preedit_attr_orig, NULL);
if (IM_Context.preedit_attr_orig == NULL) {
IM_Context.preedit_attr_orig = IM_Context.preedit_attr_now;
}
}
if (IM_Context.status_attr_orig == NULL) {
XGetICValues(IM_Context.SDL_XIC,
XNStatusAttributes,
&IM_Context.status_attr_orig, NULL);
if (IM_Context.status_attr_orig == NULL) {
IM_Context.status_attr_orig = IM_Context.status_attr_now;
}
}
if (alt) {
/* Back to prev style mode, exclude OnTheSpot mode. */
/* If the now style is OnTheSpot */
XGetICValues(IM_Context.SDL_XIC, XNInputStyle,
&IM_Context.im_style_now, NULL);
if (IM_Context.im_style_now &
(XIMPreeditCallbacks | XIMStatusCallbacks)) {
/* If prev style is OnTheSpot */
if (IM_Context.im_style_orig &
(XIMPreeditCallbacks | XIMStatusCallbacks)) {
if (IM_Context.bEnable_OverTheSpot) {
IM_Context.im_style_now =
(XIMPreeditPosition | XIMStatusNothing);
} else if (IM_Context.bEnable_Root) {
IM_Context.im_style_now =
(XIMPreeditNothing | XIMStatusNothing);
} else {
SDL_SetError(
"Cannot support OverTheSpot or Root style mode XIC.");
return "SDL_IM_FLIP";
}
IM_Context.preedit_attr_now = NULL;
IM_Context.status_attr_now = NULL;
}
else {
/* prev style is not OnTheSpot */
IM_Context.im_style_now = IM_Context.im_style_orig;
IM_Context.preedit_attr_now = IM_Context.preedit_attr_orig;
IM_Context.status_attr_now = IM_Context.status_attr_orig;
}
if (IM_Context.SDL_XIC) {
XDestroyIC(IM_Context.SDL_XIC);
IM_Context.SDL_XIC = XCreateIC(IM_Context.SDL_XIM,
XNInputStyle, IM_Context.im_style_now,
XNClientWindow, WMwindow,
XNFocusWindow, WMwindow,
IM_Context.preedit_attr_now ? XNPreeditAttributes : NULL,
IM_Context.preedit_attr_now,
IM_Context.status_attr_now ? XNStatusAttributes : NULL,
IM_Context.status_attr_now,
NULL);
if (IM_Context.SDL_XIC == NULL) {
SDL_SetError(
"Cannot create original style mode XIC.");
return "SDL_IM_FLIP";
}
} else {
SDL_SetError("Missing XIC");
return "SDL_IM_FLIP";
}
}
return NULL;
}
else {
/* Back to prev style mode, and just OnTheSpot mode. */
/* if the prev style is not OnTheSpot */
/* turn into OnTheSpot Mode */
/* If the now style is not OnTheSpot */
XGetICValues(IM_Context.SDL_XIC, XNInputStyle, &IM_Context.im_style_now, NULL);
if (IM_Context.im_style_now & (XIMPreeditCallbacks | XIMStatusCallbacks))
;
else {
/* if the orig style is OnTheSpot */
if (IM_Context.im_style_orig &
(XIMPreeditCallbacks|XIMStatusCallbacks)) {
IM_Context.im_style_now = IM_Context.im_style_orig;
IM_Context.preedit_attr_now = IM_Context.preedit_attr_orig;
IM_Context.status_attr_now = IM_Context.status_attr_orig;
}
else {
IM_Context.im_style_now =
(XIMPreeditCallbacks | XIMStatusCallbacks);
IM_Context.preedit_attr_now = NULL;
IM_Context.status_attr_now = NULL;
}
if (IM_Context.SDL_XIC && IM_Context.bEnable_OnTheSpot) {
XDestroyIC(IM_Context.SDL_XIC);
IM_Context.SDL_XIC = XCreateIC(IM_Context.SDL_XIM,
XNInputStyle, IM_Context.im_style_now,
XNClientWindow, WMwindow,
XNFocusWindow, WMwindow,
IM_Context.preedit_attr_now ? XNPreeditAttributes : NULL,
IM_Context.preedit_attr_now,
IM_Context.status_attr_now ? XNStatusAttributes : NULL,
IM_Context.status_attr_now,
NULL);
if (IM_Context.SDL_XIC == NULL) {
SDL_SetError("Cannot create OnTheSpot mode XIC.");
return "SDL_IM_FLIP";
}
} else {
SDL_SetError("Missing XIC or Unsupport OnTheSopt mode.");
return "SDL_IM_FLIP";
}
}
return NULL;
}
case SDL_IM_ONOFF:
if(alt) {
XVaNestedList list;
list = XVaCreateNestedList(0, XNPreeditState, XIMPreeditEnable, NULL);
if(XSetICValues(IM_Context.SDL_XIC, XNPreeditAttributes, list, NULL) != NULL) {
SDL_SetError("XSetICValues() failed. (XNPreeditState not supported.)");
}
XFree(list);
} else {
XVaNestedList list;
list = XVaCreateNestedList(0, XNPreeditState, XIMPreeditDisable, NULL);
if(XSetICValues(IM_Context.SDL_XIC, XNPreeditAttributes, list, NULL) != NULL) {
SDL_SetError("XSetICValues() failed. (XNPreeditState not supported.)");
}
XFree(list);
}
return NULL;
default:
SDL_SetError("X11_SetIMValues: unknown enum type: %d", value);
return "Unknown enum type";
}
}
else {
SDL_SetError("SDL_XIC is NULL");
return "SDL_XIC is NULL";
}
}
char *X11_GetIMValues(_THIS, SDL_imvalue value, int *alt)
{
char *rec;
rec = 0;
if (IM_Context.SDL_XIC) {
switch (value) {
case SDL_IM_ENABLE:
if (IM_Context.ic_focus) {
*alt = 1;
return NULL;
} else {
*alt = 0;
return NULL;
}
case SDL_IM_FLIP:
rec = XGetICValues(IM_Context.SDL_XIC, XNInputStyle, &IM_Context.im_style_now, NULL);
if (rec) {
SDL_SetError("Can not get IC values");
return rec;
}
if (IM_Context.im_style_now != (XIMPreeditCallbacks | XIMStatusCallbacks) &&
IM_Context.im_style_now != (XIMPreeditArea | XIMStatusArea)) {
*alt = 1;
return NULL;
}
else {
*alt = 0;
return NULL;
}
case SDL_IM_ONOFF:
{
XIMPreeditState state;
if(XGetICValues(IM_Context.SDL_XIC, XNPreeditState, &state, NULL) != NULL) {
if(state == XIMPreeditEnable) {
*alt = 1;
} else {
*alt = 0;
}
return NULL;
}
}
default:
SDL_SetError("X11_GetIMValues: unknown enum type: %d", value);
return "Unknown enum type";
}
}
else {
SDL_SetError("SDL_XIC is NULL.");
return "SDL_XIC is NULL";
}
}
int X11_FlushIMString(_THIS, void *buffer)
{
int result;
if (buffer && IM_Context.im_compose_len) {
if (SDL_TranslateUNICODE) {
int i = 0;
Uint16* b = (Uint16*)buffer;
while (i < IM_Context.im_compose_len) {
b[i] = IM_Context.string.im_wide_char_buffer[i];
++i;
}
}
else
memcpy(buffer, IM_Context.string.im_multi_byte_buffer, IM_Context.im_compose_len);
result = IM_Context.im_compose_len;
IM_Context.im_compose_len = 0;
}
else
result = IM_Context.im_compose_len;
return result;
}
#else /* ! ENABLE_IM_EVENT */
/* Fill with null implementation */
int X11_SetIMPosition(_THIS, int x, int y)
{
return 0;
}
char *X11_SetIMValues(_THIS, SDL_imvalue value, int alt)
{
return NULL;
}
char *X11_GetIMValues(_THIS, SDL_imvalue value, int *alt)
{
return NULL;
}
int X11_FlushIMString(_THIS, void *buffer)
{
return 0;
}
#endif

View File

@@ -32,3 +32,7 @@ extern void X11_SetKeyboardState(Display *display, const char *key_vec);
extern int X11_PendingConfigureNotifyWidth;
extern int X11_PendingConfigureNotifyHeight;
extern int X11_SetIMPosition(_THIS, int x, int y);
extern char *X11_SetIMValues(_THIS, SDL_imvalue value, int alt);
extern char *X11_GetIMValues(_THIS, SDL_imvalue value, int *alt);
extern int X11_FlushIMString(_THIS, void *buffer);

View File

@@ -68,6 +68,41 @@ static int X11_SetColors(_THIS, int firstcolor, int ncolors,
static int X11_SetGammaRamp(_THIS, Uint16 *ramp);
static void X11_VideoQuit(_THIS);
#ifdef ENABLE_IM_EVENT
#include <ctype.h>
/* When this flag is enabled, force to use the default visual.
Some Input Methods fails to create preedit window in other visuals.
kinput2 fails. skkinput is OK. */
#define FORCE_USE_DEFAULT_VISUAL
/* XIM initialization function */
static int xim_init(_THIS);
static void xim_free(_THIS);
/* IM CallBack Function */
static int ef_height=0, ef_width=0, ef_ascent=0;
typedef struct {
XIMStyle style;
char *description;
} im_style_t;
/* Enumeration of XIM input style */
static im_style_t im_styles[] = {
{ XIMPreeditNothing | XIMStatusNothing, "Root" },
{ XIMPreeditPosition | XIMStatusNothing, "OverTheSpot" },
{ XIMPreeditArea | XIMStatusArea, "OffTheSpot" },
{ XIMPreeditCallbacks| XIMStatusCallbacks, "OnTheSpot" },
{ (XIMStyle)0, NULL }};
#include <locale.h>
#include <X11/Xlocale.h>
/* Locale-specific data taken by locale_init and xim_init */
static char *im_name;
static char *lc_ctype;
#endif /* ENABLE_IM_EVENT */
/* X11 driver bootstrap functions */
@@ -173,6 +208,12 @@ static SDL_VideoDevice *X11_CreateDevice(int devindex)
device->InitOSKeymap = X11_InitOSKeymap;
device->PumpEvents = X11_PumpEvents;
device->SetIMPosition = X11_SetIMPosition;
device->SetIMValues = X11_SetIMValues;
device->GetIMValues = X11_GetIMValues;
device->FlushIMString = X11_FlushIMString;
device->GetIMInfo = X11_GetIMInfo;
device->free = X11_DeleteDevice;
}
@@ -412,6 +453,12 @@ static void create_aux_windows(_THIS, const unsigned int force)
XFree(hints);
X11_SetCaptionNoLock(this, this->wm_title, this->wm_icon);
#ifdef ENABLE_IM_EVENT
if(!xim_init(this)) {
SDL_SetError("Error: Can not initialize XIM.");
}
#endif
app_event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
| PropertyChangeMask | StructureNotifyMask | KeymapStateMask;
XSelectInput(SDL_Display, WMwindow, app_event_mask);
@@ -1632,3 +1679,418 @@ void X11_VideoQuit(_THIS)
#endif
}
#ifdef ENABLE_IM_EVENT
//#define DEBUG_XEVENTS
void destroy_callback_func(XIM current_ic, XPointer client_data, XPointer call_data)
{
SDL_VideoDevice *this = current_video;
xim_free(this);
}
void im_callback(XIM xim, XPointer client_data, XPointer call_data)
{
XIMStyle input_style;
XIMStyles *xim_styles = NULL;
XIMCallback destroy;
int j;
XPoint spot;
char *env_sdlim_style;
SDL_VideoDevice *this = current_video;
XVaNestedList preedit_attr = NULL;
/*
* Open connection to IM server.
*/
{
char *env_xmodifiers = getenv("XMODIFIERS");
if (env_xmodifiers != NULL)
im_name = XSetLocaleModifiers(env_xmodifiers);
else
fprintf(stderr, "Warning: XMODIFIERS is unspecified\n");
}
if (! (IM_Context.SDL_XIM = XOpenIM(SDL_Display, NULL, NULL, NULL))) {
SDL_SetError("Cannot open the connection to XIM server.");
#ifdef DEBUG_XEVENTS
printf("Cannot open the connection to XIM server.\n");
#endif
return;
}
destroy.callback = (XIMProc)destroy_callback_func;
destroy.client_data = NULL;
XSetIMValues(IM_Context.SDL_XIM, XNDestroyCallback, &destroy, NULL);
/*
* Detect the input style supported by XIM server.
*/
if (XGetIMValues(IM_Context.SDL_XIM, XNQueryInputStyle, &xim_styles, NULL) || !xim_styles) {
#ifdef DEBUG_XEVENTS
printf("input method doesn't support any style.");
#endif
SDL_SetError("input method doesn't support any style.");
XCloseIM(IM_Context.SDL_XIM);
return;
}
#ifdef DEBUG_XEVENTS
else {
int i;
for (i=0; i<xim_styles->count_styles; i++) {
for (j=0; im_styles[j].description!=NULL; j++) {
if (im_styles[j].style == xim_styles->supported_styles[i]) {
printf("XIM server support input_style = %s\n", im_styles[j].description);
break;
}
}
if (im_styles[j].description==NULL)
printf("XIM server support unknown input_style = %x\n", (unsigned)(xim_styles->supported_styles[i]));
}
}
#endif
/*
* Setting the XIM style.
*/
/* OverTheSpot input_style as the default */
input_style = 0;
for (j = 0; im_styles[j].description != NULL; j++) {
if (! strcmp(im_styles[j].description, "OverTheSpot")) {
input_style = im_styles[j].style;
IM_Context.bEnable_OverTheSpot = 1;
#ifdef DEBUG_XEVENTS
printf("OverTheSpot mode supported.\n");
#endif
}
if (! strcmp(im_styles[j].description, "OnTheSpot")) {
IM_Context.bEnable_OnTheSpot = 1;
#ifdef DEBUG_XEVENTS
printf("OnTheSpot mode supported.\n");
#endif
}
if (! strcmp(im_styles[j].description, "Root")) {
IM_Context.bEnable_Root = 1;
#ifdef DEBUG_XEVENTS
printf("Root mode supported.\n");
#endif
}
}
/* If not support OverTheSpot mode, use Root mode. */
if (input_style != (XIMPreeditPosition | XIMStatusNothing)) {
SDL_SetError("The XIM doesn't support OverTheSpot mode.");
for (j=0; im_styles[j].description!=NULL; j++) {
if (! strcmp(im_styles[j].description, "Root")) {
#ifdef DEBUG_XEVENTS
printf("Root\n");
#endif
input_style = im_styles[j].style;
}
}
/* If not support Root mode, use OnTheSpot mode.*/
if (input_style != (XIMPreeditNothing | XIMStatusNothing)) {
SDL_SetError("The XIM doesn't support OverTheSpot and Root mode.");
for (j = 0; im_styles[j].description != NULL; j++) {
if (! strcmp(im_styles[j].description, "OnTheSpot")) {
#ifdef DEBUG_XEVENTS
printf("OnTheSpot\n");
#endif
input_style = im_styles[j].style;
}
}
if (input_style != (XIMPreeditCallbacks | XIMStatusCallbacks)) {
SDL_SetError("The XIM doesn't support OverTheSpot, Root, and OnTheSpot mode.");
}
}
}
XFree(xim_styles);
/* If the environmet variable SDLIM_STYLE is set,
override the style setting.
In current SDL-IM implementation, this is required
since some Input Methods don't work in OverTheSpot style
despite they tell they support OverTheSpot style. */
env_sdlim_style = getenv("SDLIM_STYLE");
if (env_sdlim_style != NULL) {
#ifdef DEBUG_XEVENTS
printf("SDLIM_STYLE=%s\n", env_sdlim_style);
#endif
if (strcmp(env_sdlim_style, "Root") == 0) {
input_style = (XIMPreeditNothing | XIMStatusNothing);
} else if (strcmp(env_sdlim_style, "OverTheSpot") == 0) {
input_style = (XIMPreeditPosition | XIMStatusNothing);
} else if (strcmp(env_sdlim_style, "OnTheSpot") == 0) {
input_style = (XIMPreeditCallbacks | XIMStatusCallbacks);
}
}
#ifdef DEBUG_XEVENTS
else
printf("SDLIM_STYLE= \n");
#endif
#ifdef DEBUG_XEVENTS
/* print which mode used. */
switch(input_style)
{
case (XIMPreeditNothing | XIMStatusNothing):
printf("use Root mode.\n");
break;
case (XIMPreeditPosition | XIMStatusNothing):
printf("use OverTheSpot mode.\n");
break;
case (XIMPreeditCallbacks | XIMStatusCallbacks):
printf("use OnTheSpot mode.\n");
break;
case (XIMPreeditArea|XIMStatusArea):
printf("use OffTheSpot mode.\n");
break;
default:
printf("use Unknown mode.\n");
break;
}
#endif
/* for XIMPreeditPosition(OverTheSpot) */
preedit_attr = 0;
spot.x = 0;
spot.y = 2*ef_height + 3*(ef_ascent+5);
preedit_attr = XVaCreateNestedList(0,
XNSpotLocation, &spot,
(IM_Context.fontset) ? XNFontSet : NULL,
IM_Context.fontset,
NULL);
/*
* Create IC.
*/
IM_Context.SDL_XIC = XCreateIC(IM_Context.SDL_XIM,
XNInputStyle, input_style,
XNClientWindow, WMwindow,
XNFocusWindow, WMwindow,
(input_style & (XIMPreeditPosition | XIMStatusNothing) &&
preedit_attr) ?
XNPreeditAttributes : NULL, preedit_attr,
NULL);
if(IM_Context.SDL_XIC == NULL) {
// try Root mode
#ifdef DEBUG_XEVENTS
printf("Cannot create XIC. Try Root mode.\n");
#endif
input_style = (XIMPreeditNothing | XIMStatusNothing);
IM_Context.SDL_XIC = XCreateIC(IM_Context.SDL_XIM,
XNInputStyle, input_style,
XNClientWindow, WMwindow,
XNFocusWindow, WMwindow,
NULL);
if (IM_Context.SDL_XIC == NULL) {
#ifdef DEBUG_XEVENTS
printf("Cannot create XIC. ");
#endif
SDL_SetError("Cannot create XIC.");
return;
}
}
IM_Context.preedit_attr_now = preedit_attr;
IM_Context.im_style_now = input_style;
XSetICFocus(IM_Context.SDL_XIC);
XUnsetICFocus(IM_Context.SDL_XIC);
return;
}
int create_fontset(void)
{
int i, fsize, charset_count, fontset_count = 1;
char *s1, *s2;
char **charset_list, *def_string;
XFontStruct **font_structs;
char *fontset_name = NULL;
SDL_VideoDevice *this = current_video;
fontset_name = getenv("SDLIM_FONTSET");
if (fontset_name == NULL || !isprint(*fontset_name)) {
#ifdef DEBUG_XEVENTS
printf("Please set environment variable: SDLIM_FONTSET\nbash ex.\n\texport SDLIM_FONTSET=*-ISO8859-1,*-BIG5-0\n");
#endif
//SDL_SetError("Please set environment variable: SDLIM_FONTSET\nbash ex.\n\texport SDLIM_FONTSET=*-ISO8859-1,*-BIG5-0");
//fontset_name = "*-ISO8859-1";
fontset_name = "-*-fixed-medium-r-normal--16-*-*-*";
}
#ifdef DEBUG_XEVENTS
printf("IM fontset: %s\n", fontset_name);
#endif
/*
* Calculate the number of fonts.
*/
s1 = fontset_name;
while ((s2=strchr(s1, ',')) != NULL) {
s2 ++;
while (isspace((int)(*s2)))
s2++;
if (*s2 && *s2 != ',') {
fontset_count++;
s1 = s2;
}
else {
break;
*s1 = '\0';
}
}
/*
* Create fontset and extract font information.
*/
IM_Context.fontset = XCreateFontSet(SDL_Display, fontset_name, &charset_list, &charset_count, &def_string);
if (charset_count || !IM_Context.fontset) {
SDL_SetError("Error: cannot create fontset.");
#ifdef DEBUG_XEVENTS
printf("Error: cannot create fontset. %d %d %s\n", charset_count, IM_Context.fontset, def_string);
#endif
return 0;
}
if (fontset_count != XFontsOfFontSet(IM_Context.fontset, &font_structs, &charset_list)) {
SDL_SetError("Warning: fonts not consistant to fontset.");
#ifdef DEBUG_XEVENTS
printf("Warning: fonts not consistant to fontset.\n");
#endif
fontset_count = XFontsOfFontSet(IM_Context.fontset, &font_structs, &charset_list);
}
for (i = 0; i < fontset_count; i++) {
fsize = font_structs[i]->max_bounds.width / 2;
if (fsize > ef_width)
ef_width = fsize;
fsize = font_structs[i]->ascent + font_structs[i]->descent;
if (fsize > ef_height) {
ef_height = fsize;
ef_ascent = font_structs[i]->ascent;
}
}
if (charset_list)
XFreeStringList(charset_list);
return 0;
}
int locale_init(void)
{
char buf[1024];
if ((lc_ctype = setlocale(LC_CTYPE, "")) == NULL) {
SDL_SetError("setlocale LC_CTYPE false.");
#ifdef DEBUG_XEVENTS
printf("setlocale LC_CTYPE false.\n");
#endif
return 0;
}
if (XSupportsLocale() != True) {
SDL_SetError("XSupportsLocale false.");
#ifdef DEBUG_XEVENTS
printf("XSupportsLocale false.\n");
#endif
return 0;
}
if (im_name){
sprintf(buf, "@im=%s", im_name);
}
else {
/* clean up buf if environment variable wasn't specified. */
memset(buf, 0, 1024);
}
if (XSetLocaleModifiers(buf) == NULL) {
SDL_SetError("XSetLocaleModifiers false.");
#ifdef DEBUG_XEVENTS
SDL_SetError("XSetLocaleModifiers false.\n");
#endif
return 0;
}
create_fontset();
return 1;
}
int xim_init(_THIS)
{
IM_Context.SDL_XIM = NULL;
IM_Context.SDL_XIC = NULL;
IM_Context.string.im_wide_char_buffer = '\0';
IM_Context.im_buffer_len = 0;
IM_Context.im_compose_len = 0;
IM_Context.ic_focus = 0;
IM_Context.im_enable = 0;
IM_Context.bEnable_OverTheSpot = 0;
IM_Context.bEnable_OnTheSpot = 0;
IM_Context.bEnable_Root = 0;
IM_Context.preedit_attr_orig = NULL;
IM_Context.status_attr_orig = NULL;
IM_Context.im_style_orig = 0;
IM_Context.preedit_attr_now = NULL;
IM_Context.status_attr_now = NULL;
IM_Context.im_style_now = 0;
IM_Context.fontset = NULL;
if (!locale_init()) {
return 0;
}
if (XRegisterIMInstantiateCallback(SDL_Display, NULL, NULL, NULL, (XIMProc)im_callback, NULL) != True) {
SDL_SetError("XRegisterIMInstantiateCallback false.");
#ifdef DEBUG_XEVENTS
printf("XRegisterIMInstantiateCallback false.\n");
#endif
return 0;
}
return 1;
}
static void xim_free(_THIS)
{
if (IM_Context.SDL_XIM) {
XCloseIM(IM_Context.SDL_XIM);
}
if (IM_Context.SDL_XIC) {
XDestroyIC(IM_Context.SDL_XIC);
}
IM_Context.SDL_XIC = NULL;
IM_Context.SDL_XIM = NULL;
IM_Context.ic_focus = 0;
IM_Context.im_compose_len = 0;
IM_Context.im_buffer_len = 0;
if (IM_Context.string.im_wide_char_buffer) {
free(IM_Context.string.im_wide_char_buffer);
}
/*IM_Context.string.im_wide_char_buffer = '\0';*/
IM_Context.bEnable_OverTheSpot = 0;
IM_Context.bEnable_OnTheSpot = 0;
IM_Context.bEnable_Root = 0;
if (IM_Context.preedit_attr_orig) {
XFree(IM_Context.preedit_attr_orig);
}
if ((IM_Context.preedit_attr_now != IM_Context.preedit_attr_orig) && IM_Context.preedit_attr_now) {
XFree(IM_Context.preedit_attr_now);
}
IM_Context.preedit_attr_now = NULL;
IM_Context.preedit_attr_orig = NULL;
if (IM_Context.fontset) {
XFreeFontSet(SDL_Display, IM_Context.fontset);
}
IM_Context.fontset = NULL;
}
#endif /* ENABLE_IM_EVENT */

View File

@@ -154,6 +154,37 @@ struct SDL_PrivateVideoData {
/* Screensaver settings */
int allow_screensaver;
/* IM context */
struct {
XIM SDL_XIM;
XIC SDL_XIC;
union {
char *im_multi_byte_buffer;
wchar_t *im_wide_char_buffer;
} string;
int im_buffer_len;
int im_compose_len;
/* Switch of XIM InputContext */
char ic_focus;
char im_enable;
/* Decide if OverTheSpot, OnTheSpot, and Root input style is enabled. */
char bEnable_OverTheSpot;
char bEnable_OnTheSpot;
char bEnable_Root;
XVaNestedList preedit_attr_orig;
XVaNestedList status_attr_orig;
XIMStyle im_style_orig;
XVaNestedList preedit_attr_now;
XVaNestedList status_attr_now;
XIMStyle im_style_now;
XFontSet fontset;
} IM_Context;
};
/* Old variable names */
@@ -206,6 +237,8 @@ struct SDL_PrivateVideoData {
#define SDL_iconcolors (this->hidden->iconcolors)
#define allow_screensaver (this->hidden->allow_screensaver)
#define IM_Context (this->hidden->IM_Context)
/* Some versions of XFree86 have bugs - detect if this is one of them */
#define BUGGY_XFREE86(condition, buggy_version) \
((SDL_strcmp(ServerVendor(SDL_Display), "The XFree86 Project, Inc") == 0) && \

View File

@@ -435,3 +435,27 @@ int X11_GetWMInfo(_THIS, SDL_SysWMinfo *info)
return(-1);
}
}
int X11_GetIMInfo(_THIS, SDL_SysIMinfo *info)
{
if ( info->version.major <= SDL_MAJOR_VERSION ) {
if ( SDL_VERSIONNUM(info->version.major,
info->version.minor,
info->version.patch) >=
SDL_VERSIONNUM(1, 2, 8) ) {
#ifdef ENABLE_IM_EVENT
info->xim = IM_Context.SDL_XIM;
info->xic = &IM_Context.SDL_XIC;
#else
info->xim = NULL;
info->xic = NULL;
#endif
}
return(1);
} else {
SDL_SetError("Application not compiled with SDL %d.%d\n",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
return(-1);
}
}

View File

@@ -32,3 +32,6 @@ extern SDL_GrabMode X11_GrabInputNoLock(_THIS, SDL_GrabMode mode);
extern SDL_GrabMode X11_GrabInput(_THIS, SDL_GrabMode mode);
extern int X11_GetWMInfo(_THIS, SDL_SysWMinfo *info);
/* Functions to IM */
extern int X11_GetIMInfo(_THIS, SDL_SysIMinfo *info);