Mercurial > sdl-ios-xcode
view src/video/win32/SDL_win32keyboard.c @ 5080:6d94060d16a9
Fixed bug #1011
Daniel Ellis 2010-06-25 15:20:31 PDT
SDL based applications sometimes display the wrong application name in the
Sound Preferences dialog when using pulseaudio.
I can see from the code that the SDL pulse module is initiating a new pulse
audio context and passing an application name using the function
get_progname().
The get_progname() function returns the name of the current process. However,
the process name is often not a suitable name to use. For example, the OpenShot
video editor is a python application, and so "python" is displayed in the Sound
Preferences window (see Bug #596504), when it should be displaying "OpenShot".
PulseAudio allows applications to specify the application name, either at the
time the context is created (as SDL does currently), or by special environment
variables (see http://www.pulseaudio.org/wiki/ApplicationProperties). If no
name is specified, then pulseaudio will determine the name based on the
process.
If you specify the application name when initiating the pulseaudio context,
then that will override any application name specified using an environment
variable.
As libsdl is a library, I believe the solution is for libsdl to not specify any
application name when initiating a pulseaudio context, which will enable
applications to specify the application name using environment variables. In
the case that the applications do not specify anything, pulseaudio will fall
back to using the process name anyway.
The attached patch removes the get_progname() function and passes NULL as the
application name when creating the pulseaudio context, which fixes the issue.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 23 Jan 2011 21:55:04 -0800 |
parents | 27c458e4ae31 |
children |
line wrap: on
line source
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2010 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include "SDL_config.h" #include "SDL_win32video.h" #include "../../events/SDL_keyboard_c.h" #include "../../events/scancodes_win32.h" #include <imm.h> #include <oleauto.h> #include <winver.h> static void IME_Init(SDL_VideoData *videodata, HWND hwnd); static void IME_Enable(SDL_VideoData *videodata, HWND hwnd); static void IME_Disable(SDL_VideoData *videodata, HWND hwnd); static void IME_Quit(SDL_VideoData *videodata); #ifndef MAPVK_VK_TO_VSC #define MAPVK_VK_TO_VSC 0 #endif #ifndef MAPVK_VSC_TO_VK #define MAPVK_VSC_TO_VK 1 #endif #ifndef MAPVK_VK_TO_CHAR #define MAPVK_VK_TO_CHAR 2 #endif /* Alphabetic scancodes for PC keyboards */ BYTE alpha_scancodes[26] = { 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44 }; BYTE keypad_scancodes[10] = { 82, 79, 80, 81, 75, 76, 77, 71, 72, 73 }; void WIN_InitKeyboard(_THIS) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; int i; /* Make sure the alpha scancodes are correct. T isn't usually remapped */ if (MapVirtualKey('T', MAPVK_VK_TO_VSC) != alpha_scancodes['T' - 'A']) { #if 0 printf ("Fixing alpha scancode map, assuming US QWERTY layout!\nPlease send the following 26 lines of output to the SDL mailing list <sdl@libsdl.org>, including a description of your keyboard hardware.\n"); #endif for (i = 0; i < SDL_arraysize(alpha_scancodes); ++i) { alpha_scancodes[i] = MapVirtualKey('A' + i, MAPVK_VK_TO_VSC); #if 0 printf("%d = %d\n", i, alpha_scancodes[i]); #endif } } if (MapVirtualKey(VK_NUMPAD0, MAPVK_VK_TO_VSC) != keypad_scancodes[0]) { #if 0 printf ("Fixing keypad scancode map!\nPlease send the following 10 lines of output to the SDL mailing list <sdl@libsdl.org>, including a description of your keyboard hardware.\n"); #endif for (i = 0; i < SDL_arraysize(keypad_scancodes); ++i) { keypad_scancodes[i] = MapVirtualKey(VK_NUMPAD0 + i, MAPVK_VK_TO_VSC); #if 0 printf("%d = %d\n", i, keypad_scancodes[i]); #endif } } data->key_layout = win32_scancode_table; data->ime_com_initialized = SDL_FALSE; data->ime_threadmgr = 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; data->ime_composition[0] = 0; data->ime_readingstring[0] = 0; data->ime_cursor = 0; data->ime_hkl = 0; data->ime_himm32 = 0; data->GetReadingString = 0; data->ShowReadingWindow = 0; data->ImmLockIMC = 0; data->ImmUnlockIMC = 0; data->ImmLockIMCC = 0; data->ImmUnlockIMCC = 0; data->ime_uiless = SDL_FALSE; data->ime_threadmgrex = 0; data->ime_uielemsinkcookie = TF_INVALID_COOKIE; data->ime_alpnsinkcookie = TF_INVALID_COOKIE; data->ime_openmodesinkcookie = TF_INVALID_COOKIE; data->ime_convmodesinkcookie = TF_INVALID_COOKIE; data->ime_uielemsink = 0; data->ime_ippasink = 0; WIN_UpdateKeymap(); SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu"); SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Windows"); SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Windows"); } void WIN_UpdateKeymap() { int i; SDL_scancode scancode; SDLKey keymap[SDL_NUM_SCANCODES]; SDL_GetDefaultKeymap(keymap); for (i = 0; i < SDL_arraysize(win32_scancode_table); i++) { /* Make sure this scancode is a valid character scancode */ scancode = win32_scancode_table[i]; if (scancode == SDL_SCANCODE_UNKNOWN || keymap[scancode] >= 127) { continue; } /* Alphabetic keys are handled specially, since Windows remaps them */ if (i >= 'A' && i <= 'Z') { BYTE vsc = alpha_scancodes[i - 'A']; keymap[scancode] = MapVirtualKey(vsc, MAPVK_VSC_TO_VK) + 0x20; } else { keymap[scancode] = (MapVirtualKey(i, MAPVK_VK_TO_CHAR) & 0x7FFF); } } SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES); } void WIN_QuitKeyboard(_THIS) { IME_Quit((SDL_VideoData *)_this->driverdata); } void WIN_StartTextInput(_THIS) { SDL_Window *window = SDL_GetKeyboardFocus(); if (window) { HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; IME_Init(videodata, hwnd); IME_Enable(videodata, hwnd); } } void WIN_StopTextInput(_THIS) { SDL_Window *window = SDL_GetKeyboardFocus(); if (window) { HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; IME_Init(videodata, hwnd); IME_Disable(videodata, hwnd); } } void WIN_SetTextInputRect(_THIS, SDL_Rect *rect) { } #define LANG_CHT MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL) #define LANG_CHS MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED) #define MAKEIMEVERSION(major,minor) ((DWORD) (((BYTE)(major) << 24) | ((BYTE)(minor) << 16) )) #define IMEID_VER(id) ((id) & 0xffff0000) #define IMEID_LANG(id) ((id) & 0x0000ffff) #define CHT_HKL_DAYI ((HKL)0xE0060404) #define CHT_HKL_NEW_PHONETIC ((HKL)0xE0080404) #define CHT_HKL_NEW_CHANG_JIE ((HKL)0xE0090404) #define CHT_HKL_NEW_QUICK ((HKL)0xE00A0404) #define CHT_HKL_HK_CANTONESE ((HKL)0xE00B0404) #define CHT_IMEFILENAME1 "TINTLGNT.IME" #define CHT_IMEFILENAME2 "CINTLGNT.IME" #define CHT_IMEFILENAME3 "MSTCIPHA.IME" #define IMEID_CHT_VER42 (LANG_CHT | MAKEIMEVERSION(4, 2)) #define IMEID_CHT_VER43 (LANG_CHT | MAKEIMEVERSION(4, 3)) #define IMEID_CHT_VER44 (LANG_CHT | MAKEIMEVERSION(4, 4)) #define IMEID_CHT_VER50 (LANG_CHT | MAKEIMEVERSION(5, 0)) #define IMEID_CHT_VER51 (LANG_CHT | MAKEIMEVERSION(5, 1)) #define IMEID_CHT_VER52 (LANG_CHT | MAKEIMEVERSION(5, 2)) #define IMEID_CHT_VER60 (LANG_CHT | MAKEIMEVERSION(6, 0)) #define IMEID_CHT_VER_VISTA (LANG_CHT | MAKEIMEVERSION(7, 0)) #define CHS_HKL ((HKL)0xE00E0804) #define CHS_IMEFILENAME1 "PINTLGNT.IME" #define CHS_IMEFILENAME2 "MSSCIPYA.IME" #define IMEID_CHS_VER41 (LANG_CHS | MAKEIMEVERSION(4, 1)) #define IMEID_CHS_VER42 (LANG_CHS | MAKEIMEVERSION(4, 2)) #define IMEID_CHS_VER53 (LANG_CHS | MAKEIMEVERSION(5, 3)) #define LANG() LOWORD((videodata->ime_hkl)) #define PRIMLANG() ((WORD)PRIMARYLANGID(LANG())) #define SUBLANG() SUBLANGID(LANG()) static void IME_UpdateInputLocale(SDL_VideoData *videodata); static void IME_ClearComposition(SDL_VideoData *videodata); static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd); static void IME_SetupAPI(SDL_VideoData *videodata); static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex); static void IME_SendEditingEvent(SDL_VideoData *videodata); #define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2) #define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID))) static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata); static void UILess_ReleaseSinks(SDL_VideoData *videodata); static void UILess_EnableUIUpdates(SDL_VideoData *videodata); static void UILess_DisableUIUpdates(SDL_VideoData *videodata); static 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, (LPVOID *)&videodata->ime_threadmgr); } videodata->ime_initialized = SDL_TRUE; videodata->ime_himm32 = LoadLibraryA("imm32.dll"); if (!videodata->ime_himm32) { videodata->ime_available = SDL_FALSE; return; } videodata->ImmLockIMC = (LPINPUTCONTEXT2 (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmLockIMC"); videodata->ImmUnlockIMC = (BOOL (WINAPI *)(HIMC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMC"); videodata->ImmLockIMCC = (LPVOID (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmLockIMCC"); videodata->ImmUnlockIMCC = (BOOL (WINAPI *)(HIMCC))GetProcAddress(videodata->ime_himm32, "ImmUnlockIMCC"); IME_SetWindow(videodata, hwnd); #ifdef _WIN32_WCE videodata->ime_himc = ImmGetContext(hwnd); ImmReleaseContext(hwnd, videodata->ime_himc); #endif if (!videodata->ime_himc) { videodata->ime_available = SDL_FALSE; IME_Disable(videodata, hwnd); return; } videodata->ime_available = SDL_TRUE; IME_UpdateInputLocale(videodata); IME_SetupAPI(videodata); videodata->ime_uiless = UILess_SetupSinks(videodata); IME_UpdateInputLocale(videodata); IME_Disable(videodata, hwnd); } static 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; } #ifdef _WIN32_WCE if (videodata->ime_hwnd_current == videodata->ime_hwnd_main) ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc); #endif videodata->ime_enabled = SDL_TRUE; IME_UpdateInputLocale(videodata); UILess_EnableUIUpdates(videodata); } static void IME_Disable(SDL_VideoData *videodata, HWND hwnd) { if (!videodata->ime_initialized || !videodata->ime_hwnd_current) return; IME_ClearComposition(videodata); #ifdef _WIN32_WCE if (videodata->ime_hwnd_current == videodata->ime_hwnd_main) ImmAssociateContext(videodata->ime_hwnd_current, NULL); #endif videodata->ime_enabled = SDL_FALSE; UILess_DisableUIUpdates(videodata); } static void IME_Quit(SDL_VideoData *videodata) { if (!videodata->ime_initialized) return; UILess_ReleaseSinks(videodata); #ifdef _WIN32_WCE if (videodata->ime_hwnd_main) ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc); #endif videodata->ime_hwnd_main = 0; videodata->ime_himc = 0; if (videodata->ime_himm32) { FreeLibrary(videodata->ime_himm32); videodata->ime_himm32 = 0; } if (videodata->ime_threadmgr) { videodata->ime_threadmgr->lpVtbl->Release(videodata->ime_threadmgr); videodata->ime_threadmgr = 0; } if (videodata->ime_com_initialized) { CoUninitialize(); videodata->ime_com_initialized = SDL_FALSE; } videodata->ime_initialized = SDL_FALSE; } static void IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd) { DWORD id = 0; HIMC himc = 0; WCHAR buffer[16]; WCHAR *s = buffer; DWORD len = 0; DWORD err = 0; BOOL vertical = FALSE; UINT maxuilen = 0; static OSVERSIONINFOA osversion = {0}; if (videodata->ime_uiless) return; videodata->ime_readingstring[0] = 0; if (!osversion.dwOSVersionInfoSize) { osversion.dwOSVersionInfoSize = sizeof(osversion); GetVersionExA(&osversion); } id = IME_GetId(videodata, 0); if (!id) return; #ifdef _WIN32_WCE himc = ImmGetContext(hwnd); if (!himc) return; #endif if (videodata->GetReadingString) { len = videodata->GetReadingString(himc, 0, 0, &err, &vertical, &maxuilen); if (len) { if (len > SDL_arraysize(buffer)) len = SDL_arraysize(buffer); len = videodata->GetReadingString(himc, len, s, &err, &vertical, &maxuilen); } SDL_wcslcpy(videodata->ime_readingstring, s, len); } else { LPINPUTCONTEXT2 lpimc = videodata->ImmLockIMC(himc); LPBYTE p = 0; s = 0; switch (id) { case IMEID_CHT_VER42: case IMEID_CHT_VER43: case IMEID_CHT_VER44: p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 24); if (!p) break; len = *(DWORD *)(p + 7*4 + 32*4); s = (WCHAR *)(p + 56); break; case IMEID_CHT_VER51: case IMEID_CHT_VER52: case IMEID_CHS_VER53: p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 4); if (!p) break; p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4); if (!p) break; len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2); s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4); break; case IMEID_CHS_VER41: { int offset = (IME_GetId(videodata, 1) >= 0x00000002) ? 8 : 7; p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + offset * 4); if (!p) break; len = *(DWORD *)(p + 7*4 + 16*2*4); s = (WCHAR *)(p + 6*4 + 16*2*1); } break; case IMEID_CHS_VER42: if (osversion.dwPlatformId != VER_PLATFORM_WIN32_NT) break; p = *(LPBYTE *)((LPBYTE)videodata->ImmLockIMCC(lpimc->hPrivate) + 1*4 + 1*4 + 6*4); if (!p) break; len = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16*2); s = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4); break; } if (s) SDL_wcslcpy(videodata->ime_readingstring, s, len + 1); videodata->ImmUnlockIMCC(lpimc->hPrivate); videodata->ImmUnlockIMC(himc); } #ifdef _WIN32_WCE ImmReleaseContext(hwnd, himc); #endif IME_SendEditingEvent(videodata); } static void IME_InputLangChanged(SDL_VideoData *videodata) { UINT lang = PRIMLANG(); HWND hwndime = 0; IME_UpdateInputLocale(videodata); IME_SetupAPI(videodata); if (lang != PRIMLANG()) { IME_ClearComposition(videodata); } #ifdef _WIN32_WCE hwndime = ImmGetDefaultIMEWnd(videodata->ime_hwnd_current); if (hwndime) { SendMessageA(hwndime, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0); SendMessageA(hwndime, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0); } #endif } static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex) { static HKL hklprev = 0; static DWORD dwRet[2] = {0}; DWORD dwVerSize = 0; DWORD dwVerHandle = 0; LPVOID lpVerBuffer = 0; LPVOID lpVerData = 0; UINT cbVerData = 0; char szTemp[256]; HKL hkl = 0; DWORD dwLang = 0; if (uIndex >= sizeof(dwRet) / sizeof(dwRet[0])) return 0; hkl = videodata->ime_hkl; if (hklprev == hkl) return dwRet[uIndex]; hklprev = hkl; dwLang = ((DWORD)hkl & 0xffff); if (videodata->ime_uiless && LANG() == LANG_CHT) { dwRet[0] = IMEID_CHT_VER_VISTA; dwRet[1] = 0; return dwRet[0]; } if (hkl != CHT_HKL_NEW_PHONETIC && hkl != CHT_HKL_NEW_CHANG_JIE && hkl != CHT_HKL_NEW_QUICK && hkl != CHT_HKL_HK_CANTONESE && hkl != CHS_HKL) { dwRet[0] = dwRet[1] = 0; return dwRet[uIndex]; } #ifdef _WIN32_WCE if (ImmGetIMEFileNameA(hkl, szTemp, sizeof(szTemp) - 1) <= 0) { dwRet[0] = dwRet[1] = 0; return dwRet[uIndex]; } #endif if (!videodata->GetReadingString) { #define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) if (CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME1, -1) != 2 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME2, -1) != 2 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHT_IMEFILENAME3, -1) != 2 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME1, -1) != 2 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME2, -1) != 2) { dwRet[0] = dwRet[1] = 0; return dwRet[uIndex]; } #undef LCID_INVARIANT dwVerSize = GetFileVersionInfoSizeA(szTemp, &dwVerHandle); if (dwVerSize) { lpVerBuffer = SDL_malloc(dwVerSize); if (lpVerBuffer) { if (GetFileVersionInfoA(szTemp, dwVerHandle, dwVerSize, lpVerBuffer)) { if (VerQueryValueA(lpVerBuffer, "\\", &lpVerData, &cbVerData)) { #define pVerFixedInfo ((VS_FIXEDFILEINFO FAR*)lpVerData) DWORD dwVer = pVerFixedInfo->dwFileVersionMS; dwVer = (dwVer & 0x00ff0000) << 8 | (dwVer & 0x000000ff) << 16; if (videodata->GetReadingString || dwLang == LANG_CHT && ( dwVer == MAKEIMEVERSION(4, 2) || dwVer == MAKEIMEVERSION(4, 3) || dwVer == MAKEIMEVERSION(4, 4) || dwVer == MAKEIMEVERSION(5, 0) || dwVer == MAKEIMEVERSION(5, 1) || dwVer == MAKEIMEVERSION(5, 2) || dwVer == MAKEIMEVERSION(6, 0)) || dwLang == LANG_CHS && ( dwVer == MAKEIMEVERSION(4, 1) || dwVer == MAKEIMEVERSION(4, 2) || dwVer == MAKEIMEVERSION(5, 3))) { dwRet[0] = dwVer | dwLang; dwRet[1] = pVerFixedInfo->dwFileVersionLS; SDL_free(lpVerBuffer); return dwRet[0]; } #undef pVerFixedInfo } } } SDL_free(lpVerBuffer); } } dwRet[0] = dwRet[1] = 0; return dwRet[uIndex]; } static void IME_SetupAPI(SDL_VideoData *videodata) { char ime_file[MAX_PATH + 1]; HMODULE hime = 0; HKL hkl = 0; videodata->GetReadingString = 0; videodata->ShowReadingWindow = 0; if (videodata->ime_uiless) return; hkl = videodata->ime_hkl; #ifdef _WIN32_WCE if (ImmGetIMEFileNameA(hkl, ime_file, sizeof(ime_file) - 1) <= 0) return; #endif hime = LoadLibraryA(ime_file); if (!hime) return; videodata->GetReadingString = (UINT (WINAPI *)(HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT)) GetProcAddress(hime, "GetReadingString"); videodata->ShowReadingWindow = (BOOL (WINAPI *)(HIMC, BOOL)) GetProcAddress(hime, "ShowReadingWindow"); #ifdef _WIN32_WCE if (videodata->ShowReadingWindow) { HIMC himc = ImmGetContext(videodata->ime_hwnd_current); if (himc) { videodata->ShowReadingWindow(himc, FALSE); ImmReleaseContext(videodata->ime_hwnd_current, himc); } } #endif } static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd) { videodata->ime_hwnd_current = hwnd; if (videodata->ime_threadmgr) { struct ITfDocumentMgr *document_mgr = 0; if (SUCCEEDED(videodata->ime_threadmgr->lpVtbl->AssociateFocus(videodata->ime_threadmgr, hwnd, NULL, &document_mgr))) { if (document_mgr) document_mgr->lpVtbl->Release(document_mgr); } } } static void IME_UpdateInputLocale(SDL_VideoData *videodata) { static HKL hklprev = 0; videodata->ime_hkl = GetKeyboardLayout(0); if (hklprev == videodata->ime_hkl) return; hklprev = videodata->ime_hkl; } static void IME_ClearComposition(SDL_VideoData *videodata) { HIMC himc = 0; if (!videodata->ime_initialized) return; #ifdef _WIN32_WCE himc = ImmGetContext(videodata->ime_hwnd_current); if (!himc) return; ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); if (videodata->ime_uiless) ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR)); ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0); ImmReleaseContext(videodata->ime_hwnd_current, himc); #endif SDL_SendEditingText("", 0, 0); } static void IME_ClearEditing(SDL_VideoData *videodata) { } static void IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string) { LONG length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition)); if (length < 0) length = 0; length /= sizeof(videodata->ime_composition[0]); videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0)); if (videodata->ime_composition[videodata->ime_cursor] == 0x3000) { int i; for (i = videodata->ime_cursor + 1; i < length; ++i) videodata->ime_composition[i - 1] = videodata->ime_composition[i]; --length; } videodata->ime_composition[length] = 0; } static void IME_SendInputEvent(SDL_VideoData *videodata) { char *s = 0; s = WIN_StringToUTF8(videodata->ime_composition); SDL_SendKeyboardText(s); SDL_free(s); videodata->ime_composition[0] = 0; videodata->ime_readingstring[0] = 0; videodata->ime_cursor = 0; } static void IME_SendEditingEvent(SDL_VideoData *videodata) { char *s = 0; WCHAR buffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; buffer[0] = 0; if (videodata->ime_readingstring[0]) { size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor); SDL_wcslcpy(buffer, videodata->ime_composition, len + 1); SDL_wcslcat(buffer, videodata->ime_readingstring, sizeof(buffer)); SDL_wcslcat(buffer, &videodata->ime_composition[len], sizeof(buffer) - len); } else { SDL_wcslcpy(buffer, videodata->ime_composition, sizeof(videodata->ime_composition)); } s = WIN_StringToUTF8(buffer); SDL_SendEditingText(s, videodata->ime_cursor + SDL_wcslen(videodata->ime_readingstring), 0); SDL_free(s); } SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) { SDL_bool trap = SDL_FALSE; HIMC himc = 0; if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled) return SDL_FALSE; switch (msg) { case WM_INPUTLANGCHANGE: //IME_InputLangChanged(videodata); break; case WM_IME_SETCONTEXT: *lParam = 0; break; case WM_IME_STARTCOMPOSITION: trap = SDL_TRUE; break; case WM_IME_COMPOSITION: trap = SDL_TRUE; #ifdef _WIN32_WCE himc = ImmGetContext(hwnd); if (*lParam & GCS_RESULTSTR) { IME_GetCompositionString(videodata, himc, GCS_RESULTSTR); IME_SendInputEvent(videodata); } if (*lParam & GCS_COMPSTR) { if (!videodata->ime_uiless) videodata->ime_readingstring[0] = 0; IME_GetCompositionString(videodata, himc, GCS_COMPSTR); IME_SendEditingEvent(videodata); } ImmReleaseContext(hwnd, himc); #endif break; case WM_IME_ENDCOMPOSITION: videodata->ime_composition[0] = 0; videodata->ime_readingstring[0] = 0; videodata->ime_cursor = 0; SDL_SendEditingText("", 0, 0); break; case WM_IME_NOTIFY: switch (wParam) { case IMN_SETCONVERSIONMODE: case IMN_SETOPENSTATUS: IME_UpdateInputLocale(videodata); break; case IMN_OPENCANDIDATE: case IMN_CHANGECANDIDATE: trap = SDL_TRUE; break; case IMN_CLOSECANDIDATE: trap = SDL_TRUE; break; case IMN_PRIVATE: { DWORD dwId = IME_GetId(videodata, 0); IME_GetReadingString(videodata, hwnd); switch (dwId) { case IMEID_CHT_VER42: case IMEID_CHT_VER43: case IMEID_CHT_VER44: case IMEID_CHS_VER41: case IMEID_CHS_VER42: if (*lParam == 1 || *lParam == 2) trap = SDL_TRUE; break; case IMEID_CHT_VER50: case IMEID_CHT_VER51: case IMEID_CHT_VER52: case IMEID_CHT_VER60: case IMEID_CHS_VER53: if (*lParam == 16 || *lParam == 17 || *lParam == 26 || *lParam == 27 || *lParam == 28) trap = SDL_TRUE; break; } } break; default: trap = SDL_TRUE; break; } break; } return trap; } STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink) { return ++sink->refcount; } STDMETHODIMP_(ULONG)TSFSink_Release(TSFSink *sink) { --sink->refcount; if (sink->refcount == 0) { SDL_free(sink); return 0; } return sink->refcount; } STDMETHODIMP UIElementSink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv) { if (!ppv) return E_INVALIDARG; *ppv = 0; if (SDL_IsEqualIID(riid, &IID_IUnknown)) *ppv = (IUnknown *)sink; else if (SDL_IsEqualIID(riid, &IID_ITfUIElementSink)) *ppv = (ITfUIElementSink *)sink; if (*ppv) { TSFSink_AddRef(sink); return S_OK; } return E_NOINTERFACE; } ITfUIElement *UILess_GetUIElement(SDL_VideoData *videodata, DWORD dwUIElementId) { ITfUIElementMgr *puiem = 0; ITfUIElement *pelem = 0; ITfThreadMgrEx *threadmgrex = videodata->ime_threadmgrex; if (SUCCEEDED(threadmgrex->lpVtbl->QueryInterface(threadmgrex, &IID_ITfUIElementMgr, (LPVOID *)&puiem))) { puiem->lpVtbl->GetUIElement(puiem, dwUIElementId, &pelem); puiem->lpVtbl->Release(puiem); } return pelem; } STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow) { ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); ITfReadingInformationUIElement *preading = 0; SDL_VideoData *videodata = (SDL_VideoData *)sink->data; if (!element) return E_INVALIDARG; *pbShow = FALSE; if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { BSTR bstr; if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) { WCHAR *s = (WCHAR *)bstr; SysFreeString(bstr); } preading->lpVtbl->Release(preading); } return S_OK; } STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId) { ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); ITfReadingInformationUIElement *preading = 0; SDL_VideoData *videodata = (SDL_VideoData *)sink->data; if (!element) return E_INVALIDARG; if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { BSTR bstr; if (SUCCEEDED(preading->lpVtbl->GetString(preading, &bstr)) && bstr) { WCHAR *s = (WCHAR *)bstr; SDL_wcslcpy(videodata->ime_readingstring, s, sizeof(videodata->ime_readingstring)); IME_SendEditingEvent(videodata); SysFreeString(bstr); } preading->lpVtbl->Release(preading); } return S_OK; } STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId) { ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); ITfReadingInformationUIElement *preading = 0; SDL_VideoData *videodata = (SDL_VideoData *)sink->data; if (!element) return E_INVALIDARG; if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { videodata->ime_readingstring[0] = 0; IME_SendEditingEvent(videodata); preading->lpVtbl->Release(preading); } return S_OK; } STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv) { if (!ppv) return E_INVALIDARG; *ppv = 0; if (SDL_IsEqualIID(riid, &IID_IUnknown)) *ppv = (IUnknown *)sink; else if (SDL_IsEqualIID(riid, &IID_ITfInputProcessorProfileActivationSink)) *ppv = (ITfInputProcessorProfileActivationSink *)sink; if (*ppv) { TSFSink_AddRef(sink); return S_OK; } return E_NOINTERFACE; } STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags) { if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE)) IME_InputLangChanged((SDL_VideoData *)sink->data); return S_OK; } static void *vtUIElementSink[] = { (void *)(UIElementSink_QueryInterface), (void *)(TSFSink_AddRef), (void *)(TSFSink_Release), (void *)(UIElementSink_BeginUIElement), (void *)(UIElementSink_UpdateUIElement), (void *)(UIElementSink_EndUIElement) }; static void *vtIPPASink[] = { (void *)(IPPASink_QueryInterface), (void *)(TSFSink_AddRef), (void *)(TSFSink_Release), (void *)(IPPASink_OnActivated) }; static void UILess_EnableUIUpdates(SDL_VideoData *videodata) { ITfSource *source = 0; if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie != TF_INVALID_COOKIE) return; if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie); source->lpVtbl->Release(source); } } static void UILess_DisableUIUpdates(SDL_VideoData *videodata) { ITfSource *source = 0; if (!videodata->ime_threadmgrex || videodata->ime_uielemsinkcookie == TF_INVALID_COOKIE) return; if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie); videodata->ime_uielemsinkcookie = TF_INVALID_COOKIE; source->lpVtbl->Release(source); } } static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata) { TfClientId clientid = 0; SDL_bool result = SDL_FALSE; ITfSource *source = 0; if (FAILED(CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgrEx, &videodata->ime_threadmgrex))) return SDL_FALSE; if (FAILED(videodata->ime_threadmgrex->lpVtbl->ActivateEx(videodata->ime_threadmgrex, &clientid, TF_TMAE_UIELEMENTENABLEDONLY))) return SDL_FALSE; videodata->ime_uielemsink = SDL_malloc(sizeof(TSFSink)); videodata->ime_ippasink = SDL_malloc(sizeof(TSFSink)); videodata->ime_uielemsink->lpVtbl = vtUIElementSink; videodata->ime_uielemsink->refcount = 1; videodata->ime_uielemsink->data = videodata; videodata->ime_ippasink->lpVtbl = vtIPPASink; videodata->ime_ippasink->refcount = 1; videodata->ime_ippasink->data = videodata; if (SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, (LPVOID *)&source))) { if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfUIElementSink, (IUnknown *)videodata->ime_uielemsink, &videodata->ime_uielemsinkcookie))) { if (SUCCEEDED(source->lpVtbl->AdviseSink(source, &IID_ITfInputProcessorProfileActivationSink, (IUnknown *)videodata->ime_ippasink, &videodata->ime_alpnsinkcookie))) { result = SDL_TRUE; } } source->lpVtbl->Release(source); } return result; } #define SAFE_RELEASE(p) \ { \ if (p) { \ (p)->lpVtbl->Release((p)); \ (p) = 0; \ } \ } static void UILess_ReleaseSinks(SDL_VideoData *videodata) { ITfSource *source = 0; if (videodata->ime_threadmgrex && SUCCEEDED(videodata->ime_threadmgrex->lpVtbl->QueryInterface(videodata->ime_threadmgrex, &IID_ITfSource, &source))) { source->lpVtbl->UnadviseSink(source, videodata->ime_uielemsinkcookie); source->lpVtbl->UnadviseSink(source, videodata->ime_alpnsinkcookie); SAFE_RELEASE(source); videodata->ime_threadmgrex->lpVtbl->Deactivate(videodata->ime_threadmgrex); SAFE_RELEASE(videodata->ime_threadmgrex); TSFSink_Release(videodata->ime_uielemsink); videodata->ime_uielemsink = 0; TSFSink_Release(videodata->ime_ippasink); videodata->ime_ippasink = 0; } } /* vi: set ts=4 sw=4 expandtab: */