Initial IMM implementation.
IME input should now work fairly well.
This commit is contained in:
parent
2f1a5c4653
commit
3d5a6d8597
4 changed files with 197 additions and 3 deletions
|
@ -131,6 +131,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
|
||||||
|
return 0;
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
#include "../../events/SDL_keyboard_c.h"
|
#include "../../events/SDL_keyboard_c.h"
|
||||||
#include "../../events/scancodes_win32.h"
|
#include "../../events/scancodes_win32.h"
|
||||||
|
|
||||||
|
#include <msctf.h>
|
||||||
|
#include <imm.h>
|
||||||
|
|
||||||
#ifndef MAPVK_VK_TO_VSC
|
#ifndef MAPVK_VK_TO_VSC
|
||||||
#define MAPVK_VK_TO_VSC 0
|
#define MAPVK_VK_TO_VSC 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -46,6 +49,11 @@ BYTE keypad_scancodes[10] = {
|
||||||
82, 79, 80, 81, 75, 76, 77, 71, 72, 73
|
82, 79, 80, 81, 75, 76, 77, 71, 72, 73
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
|
||||||
|
void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
|
||||||
|
void IME_Init(SDL_VideoData *videodata, HWND hwnd);
|
||||||
|
void IME_Quit(SDL_VideoData *videodata);
|
||||||
|
|
||||||
void
|
void
|
||||||
WIN_InitKeyboard(_THIS)
|
WIN_InitKeyboard(_THIS)
|
||||||
{
|
{
|
||||||
|
@ -81,6 +89,15 @@ WIN_InitKeyboard(_THIS)
|
||||||
|
|
||||||
data->key_layout = win32_scancode_table;
|
data->key_layout = win32_scancode_table;
|
||||||
|
|
||||||
|
data->ime_com_initialized = SDL_FALSE;
|
||||||
|
data->ime_thread_mgr = 0;
|
||||||
|
data->ime_initialized = SDL_FALSE;
|
||||||
|
data->ime_enabled = SDL_FALSE;
|
||||||
|
data->ime_available = SDL_FALSE;
|
||||||
|
data->ime_hwnd_main = 0;
|
||||||
|
data->ime_hwnd_current = 0;
|
||||||
|
data->ime_himc = 0;
|
||||||
|
|
||||||
WIN_UpdateKeymap();
|
WIN_UpdateKeymap();
|
||||||
|
|
||||||
SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
|
SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
|
||||||
|
@ -120,19 +137,25 @@ WIN_UpdateKeymap()
|
||||||
void
|
void
|
||||||
WIN_QuitKeyboard(_THIS)
|
WIN_QuitKeyboard(_THIS)
|
||||||
{
|
{
|
||||||
|
IME_Quit((SDL_VideoData *)_this->driverdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WIN_StartTextInput(_THIS, SDL_Window *window)
|
WIN_StartTextInput(_THIS, SDL_Window *window)
|
||||||
{
|
{
|
||||||
HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
|
HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
|
||||||
|
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
|
||||||
|
IME_Init(videodata, hwnd);
|
||||||
|
IME_Enable(videodata, hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WIN_StopTextInput(_THIS, SDL_Window *window)
|
WIN_StopTextInput(_THIS, SDL_Window *window)
|
||||||
{
|
{
|
||||||
|
HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
|
||||||
|
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
|
||||||
|
IME_Init(videodata, hwnd);
|
||||||
|
IME_Disable(videodata, hwnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -141,4 +164,161 @@ WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IME_Disable(SDL_VideoData *videodata, HWND hwnd)
|
||||||
|
{
|
||||||
|
if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
|
||||||
|
ImmAssociateContext(videodata->ime_hwnd_current, NULL);
|
||||||
|
|
||||||
|
videodata->ime_enabled = SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IME_Enable(SDL_VideoData *videodata, HWND hwnd)
|
||||||
|
{
|
||||||
|
if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!videodata->ime_available) {
|
||||||
|
IME_Disable(videodata, hwnd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
|
||||||
|
ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc);
|
||||||
|
|
||||||
|
videodata->ime_enabled = SDL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IME_Init(SDL_VideoData *videodata, HWND hwnd)
|
||||||
|
{
|
||||||
|
if (videodata->ime_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
videodata->ime_hwnd_main = hwnd;
|
||||||
|
if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
|
||||||
|
videodata->ime_com_initialized = SDL_TRUE;
|
||||||
|
CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, &videodata->ime_thread_mgr);
|
||||||
|
}
|
||||||
|
videodata->ime_initialized = SDL_TRUE;
|
||||||
|
videodata->ime_hwnd_current = videodata->ime_hwnd_main;
|
||||||
|
if (videodata->ime_thread_mgr) {
|
||||||
|
struct ITfDocumentMgr *document_mgr = 0;
|
||||||
|
if (SUCCEEDED(videodata->ime_thread_mgr->lpVtbl->AssociateFocus(videodata->ime_thread_mgr, hwnd, NULL, &document_mgr))) {
|
||||||
|
if (document_mgr)
|
||||||
|
document_mgr->lpVtbl->Release(document_mgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
videodata->ime_himc = ImmGetContext(hwnd);
|
||||||
|
ImmReleaseContext(hwnd, videodata->ime_himc);
|
||||||
|
if (!videodata->ime_himc) {
|
||||||
|
videodata->ime_available = SDL_FALSE;
|
||||||
|
IME_Disable(videodata, hwnd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
videodata->ime_available = SDL_TRUE;
|
||||||
|
IME_Disable(videodata, hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IME_Quit(SDL_VideoData *videodata)
|
||||||
|
{
|
||||||
|
if (!videodata->ime_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (videodata->ime_hwnd_main)
|
||||||
|
ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc);
|
||||||
|
|
||||||
|
videodata->ime_hwnd_main = 0;
|
||||||
|
videodata->ime_himc = 0;
|
||||||
|
if (videodata->ime_thread_mgr)
|
||||||
|
{
|
||||||
|
videodata->ime_thread_mgr->lpVtbl->Release(videodata->ime_thread_mgr);
|
||||||
|
videodata->ime_thread_mgr = 0;
|
||||||
|
}
|
||||||
|
if (videodata->ime_com_initialized)
|
||||||
|
{
|
||||||
|
CoUninitialize();
|
||||||
|
videodata->ime_com_initialized = SDL_FALSE;
|
||||||
|
}
|
||||||
|
videodata->ime_initialized = SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_bool
|
||||||
|
IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
|
||||||
|
{
|
||||||
|
SDL_bool trap = SDL_FALSE;
|
||||||
|
HIMC himc = 0;
|
||||||
|
WCHAR Buffer[SDL_TEXTINPUTEVENT_TEXT_SIZE / 2];
|
||||||
|
if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled)
|
||||||
|
return SDL_FALSE;
|
||||||
|
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case WM_INPUTLANGCHANGE:
|
||||||
|
break;
|
||||||
|
case WM_IME_SETCONTEXT:
|
||||||
|
*lParam = 0;
|
||||||
|
break;
|
||||||
|
case WM_IME_STARTCOMPOSITION:
|
||||||
|
trap = SDL_TRUE;
|
||||||
|
break;
|
||||||
|
case WM_IME_COMPOSITION:
|
||||||
|
trap = SDL_TRUE;
|
||||||
|
himc = ImmGetContext(hwnd);
|
||||||
|
if (*lParam & GCS_RESULTSTR)
|
||||||
|
{
|
||||||
|
LONG Length = 0;
|
||||||
|
char *s = 0;
|
||||||
|
Length = ImmGetCompositionStringW(himc, GCS_RESULTSTR, Buffer, sizeof(Buffer) * sizeof(Buffer[0]));
|
||||||
|
Buffer[Length / sizeof(Buffer[0])] = 0;
|
||||||
|
s = WIN_StringToUTF8(Buffer);
|
||||||
|
SDL_SendKeyboardText(s);
|
||||||
|
SDL_free(s);
|
||||||
|
}
|
||||||
|
if (*lParam & GCS_COMPSTR)
|
||||||
|
{
|
||||||
|
LONG Length = 0;
|
||||||
|
DWORD Cursor = 0;
|
||||||
|
char *s = 0;
|
||||||
|
Length = ImmGetCompositionStringW(himc, GCS_COMPSTR, Buffer, sizeof(Buffer) * sizeof(Buffer[0]));
|
||||||
|
Buffer[Length / sizeof(Buffer[0])] = 0;
|
||||||
|
s = WIN_StringToUTF8(Buffer);
|
||||||
|
Cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
|
||||||
|
SDL_SendEditingText(s, Cursor, 0);
|
||||||
|
SDL_free(s);
|
||||||
|
}
|
||||||
|
ImmReleaseContext(hwnd, himc);
|
||||||
|
break;
|
||||||
|
case WM_IME_ENDCOMPOSITION:
|
||||||
|
SDL_SendKeyboardText("");
|
||||||
|
break;
|
||||||
|
case WM_IME_NOTIFY:
|
||||||
|
switch (wParam)
|
||||||
|
{
|
||||||
|
case IMN_SETCONVERSIONMODE:
|
||||||
|
break;
|
||||||
|
case IMN_SETOPENSTATUS:
|
||||||
|
break;
|
||||||
|
case IMN_OPENCANDIDATE:
|
||||||
|
case IMN_CHANGECANDIDATE:
|
||||||
|
trap = SDL_TRUE;
|
||||||
|
break;
|
||||||
|
case IMN_CLOSECANDIDATE:
|
||||||
|
trap = SDL_TRUE;
|
||||||
|
break;
|
||||||
|
case IMN_PRIVATE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
trap = SDL_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return trap;
|
||||||
|
}
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -35,6 +35,8 @@ extern void WIN_StartTextInput(_THIS, SDL_Window *window);
|
||||||
extern void WIN_StopTextInput(_THIS, SDL_Window *window);
|
extern void WIN_StopTextInput(_THIS, SDL_Window *window);
|
||||||
extern void WIN_SetTextInputRect(_THIS, SDL_Rect *rect);
|
extern void WIN_SetTextInputRect(_THIS, SDL_Rect *rect);
|
||||||
|
|
||||||
|
extern SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata);
|
||||||
|
|
||||||
#endif /* _SDL_win32keyboard_h */
|
#endif /* _SDL_win32keyboard_h */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -75,6 +75,16 @@ typedef struct SDL_VideoData
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const SDL_scancode *key_layout;
|
const SDL_scancode *key_layout;
|
||||||
|
|
||||||
|
SDL_bool ime_com_initialized;
|
||||||
|
struct ITfThreadMgr *ime_thread_mgr;
|
||||||
|
SDL_bool ime_initialized;
|
||||||
|
SDL_bool ime_enabled;
|
||||||
|
SDL_bool ime_available;
|
||||||
|
HWND ime_hwnd_main;
|
||||||
|
HWND ime_hwnd_current;
|
||||||
|
HIMC ime_himc;
|
||||||
|
|
||||||
} SDL_VideoData;
|
} SDL_VideoData;
|
||||||
|
|
||||||
#endif /* _SDL_win32video_h */
|
#endif /* _SDL_win32video_h */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue