mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-10-14 02:17:36 +08:00
System IME support in Linux SDL1 builds (imported and tested to work by nanshiki)
This commit is contained in:
@@ -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__
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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 */
|
||||
|
@@ -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) && \
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user