diff options
Diffstat (limited to 'linden/indra/llwindow/llwindowwin32.cpp')
-rw-r--r-- | linden/indra/llwindow/llwindowwin32.cpp | 172 |
1 files changed, 164 insertions, 8 deletions
diff --git a/linden/indra/llwindow/llwindowwin32.cpp b/linden/indra/llwindow/llwindowwin32.cpp index 2cd1353..0b3cdd4 100644 --- a/linden/indra/llwindow/llwindowwin32.cpp +++ b/linden/indra/llwindow/llwindowwin32.cpp | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <mapi.h> | 37 | #include <mapi.h> |
38 | #include <process.h> // for _spawn | 38 | #include <process.h> // for _spawn |
39 | #include <shellapi.h> | 39 | #include <shellapi.h> |
40 | #include <Imm.h> | ||
40 | 41 | ||
41 | // Require DirectInput version 8 | 42 | // Require DirectInput version 8 |
42 | #define DIRECTINPUT_VERSION 0x0800 | 43 | #define DIRECTINPUT_VERSION 0x0800 |
@@ -84,6 +85,98 @@ void show_window_creation_error(const char* title) | |||
84 | //static | 85 | //static |
85 | BOOL LLWindowWin32::sIsClassRegistered = FALSE; | 86 | BOOL LLWindowWin32::sIsClassRegistered = FALSE; |
86 | 87 | ||
88 | BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE; /* XXX */ | ||
89 | BOOL LLWindowWin32::sWinIMEOpened = FALSE; | ||
90 | HKL LLWindowWin32::sWinInputLocale; | ||
91 | DWORD LLWindowWin32::sWinIMEConversionMode; | ||
92 | DWORD LLWindowWin32::sWinIMESentenceMode; | ||
93 | |||
94 | // The following class LLWinImm delegates Windows IMM APIs. | ||
95 | // We need this because some language versions of Windows, | ||
96 | // e.g., US version of Windows XP, doesn't install IMM32.DLL | ||
97 | // as a default, and we can't link against imm32.lib statically. | ||
98 | // I believe DLL loading of this type is best suited to do | ||
99 | // in a static initialization of a class. What I'm not sure is | ||
100 | // whether it follows the Linden Conding Standard... | ||
101 | // See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members | ||
102 | |||
103 | class LLWinImm | ||
104 | { | ||
105 | public: | ||
106 | static bool isAvailable() { return sTheInstance.mHImmDll != NULL; } | ||
107 | |||
108 | public: | ||
109 | // Wrappers for IMM API. | ||
110 | static BOOL isIME(HKL hkl) { return sTheInstance.mImmIsIME(hkl); } | ||
111 | static HIMC getContext(HWND hwnd) { return sTheInstance.mImmGetContext(hwnd); } | ||
112 | static BOOL releaseContext(HWND hwnd, HIMC himc) { return sTheInstance.mImmReleaseContext(hwnd, himc); } | ||
113 | static BOOL getOpenStatus(HIMC himc) { return sTheInstance.mImmGetOpenStatus(himc); } | ||
114 | static BOOL setOpenStatus(HIMC himc, BOOL status) { return sTheInstance.mImmSetOpenStatus(himc, status); } | ||
115 | static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) { return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); } | ||
116 | static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) { return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); } | ||
117 | |||
118 | private: | ||
119 | LLWinImm(); | ||
120 | ~LLWinImm(); | ||
121 | |||
122 | private: | ||
123 | // Pointers to IMM API. | ||
124 | BOOL (WINAPI *mImmIsIME)(HKL); | ||
125 | HIMC (WINAPI *mImmGetContext)(HWND); | ||
126 | BOOL (WINAPI *mImmReleaseContext)(HWND, HIMC); | ||
127 | BOOL (WINAPI *mImmGetOpenStatus)(HIMC); | ||
128 | BOOL (WINAPI *mImmSetOpenStatus)(HIMC, BOOL); | ||
129 | BOOL (WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD); | ||
130 | BOOL (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD); | ||
131 | |||
132 | private: | ||
133 | HMODULE mHImmDll; | ||
134 | static LLWinImm sTheInstance; | ||
135 | }; | ||
136 | |||
137 | LLWinImm LLWinImm::sTheInstance; | ||
138 | |||
139 | LLWinImm::LLWinImm() | ||
140 | { | ||
141 | mHImmDll = LoadLibraryA("Imm32"); | ||
142 | if (mHImmDll != NULL) | ||
143 | { | ||
144 | mImmIsIME = (BOOL (WINAPI *)(HKL)) GetProcAddress(mHImmDll, "ImmIsIME"); | ||
145 | mImmGetContext = (HIMC (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetContext"); | ||
146 | mImmReleaseContext = (BOOL (WINAPI *)(HWND, HIMC)) GetProcAddress(mHImmDll, "ImmReleaseContext"); | ||
147 | mImmGetOpenStatus = (BOOL (WINAPI *)(HIMC)) GetProcAddress(mHImmDll, "ImmGetOpenStatus"); | ||
148 | mImmSetOpenStatus = (BOOL (WINAPI *)(HIMC, BOOL)) GetProcAddress(mHImmDll, "ImmSetOpenStatus"); | ||
149 | mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus"); | ||
150 | mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmSetConversionStatus"); | ||
151 | if (mImmIsIME == NULL || | ||
152 | mImmGetContext == NULL || | ||
153 | mImmReleaseContext == NULL || | ||
154 | mImmGetOpenStatus == NULL || | ||
155 | mImmSetOpenStatus == NULL || | ||
156 | mImmGetConversionStatus == NULL || | ||
157 | mImmSetConversionStatus == NULL) | ||
158 | { | ||
159 | // If any of the above API entires are not found, we can't use IMM API. | ||
160 | // So, turn off the IMM support. We should log some warning message in | ||
161 | // the case, since it is very unusual; these APIs are available from | ||
162 | // the beginning, and all versions of IMM32.DLL should have them all. | ||
163 | // Unfortunately, this code may be executed before initialization of | ||
164 | // the logging channel (llwarns), and we can't do it here... Yes, this | ||
165 | // is one of disadvantages to use static constraction to DLL loading. | ||
166 | FreeLibrary(mHImmDll); | ||
167 | mHImmDll = NULL; | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | LLWinImm::~LLWinImm() | ||
173 | { | ||
174 | if (mHImmDll != NULL) | ||
175 | { | ||
176 | FreeLibrary(mHImmDll); | ||
177 | mHImmDll = NULL; | ||
178 | } | ||
179 | } | ||
87 | 180 | ||
88 | 181 | ||
89 | LPDIRECTINPUT8 g_pDI = NULL; | 182 | LPDIRECTINPUT8 g_pDI = NULL; |
@@ -111,6 +204,10 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, | |||
111 | // Initialize the keyboard | 204 | // Initialize the keyboard |
112 | gKeyboard = new LLKeyboardWin32(); | 205 | gKeyboard = new LLKeyboardWin32(); |
113 | 206 | ||
207 | // Initialize (boot strap) the Language text input management, | ||
208 | // based on the system's (user's) default settings. | ||
209 | allowLanguageTextInput(FALSE); | ||
210 | |||
114 | GLuint pixel_format; | 211 | GLuint pixel_format; |
115 | WNDCLASS wc; | 212 | WNDCLASS wc; |
116 | DWORD dw_ex_style; | 213 | DWORD dw_ex_style; |
@@ -347,7 +444,6 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, | |||
347 | 444 | ||
348 | if (!mWindowHandle) | 445 | if (!mWindowHandle) |
349 | { | 446 | { |
350 | DestroyWindow(mWindowHandle); | ||
351 | OSMessageBox("Window creation error", "Error", OSMB_OK); | 447 | OSMessageBox("Window creation error", "Error", OSMB_OK); |
352 | return; | 448 | return; |
353 | } | 449 | } |
@@ -1926,6 +2022,15 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ | |||
1926 | case WM_CHAR: | 2022 | case WM_CHAR: |
1927 | // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need | 2023 | // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need |
1928 | // to figure out how that works. - Doug | 2024 | // to figure out how that works. - Doug |
2025 | // | ||
2026 | // ... Well, I don't think so. | ||
2027 | // How it works is explained in Win32 API document, but WM_UNICHAR didn't work | ||
2028 | // as specified at least on Windows XP SP1 Japanese version. I have never used | ||
2029 | // it since then, and I'm not sure whether it has been fixed now, but I don't think | ||
2030 | // it is worth trying. The good old WM_CHAR works just fine even for supplementary | ||
2031 | // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's | ||
2032 | // by ourselves. It is not that tough. -- Alissa Sabre @ SL | ||
2033 | // | ||
1929 | // llinfos << "WM_CHAR: " << w_param << llendl; | 2034 | // llinfos << "WM_CHAR: " << w_param << llendl; |
1930 | if (gDebugWindowProc) | 2035 | if (gDebugWindowProc) |
1931 | { | 2036 | { |
@@ -1933,11 +2038,10 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ | |||
1933 | << " key " << S32(w_param) | 2038 | << " key " << S32(w_param) |
1934 | << llendl; | 2039 | << llendl; |
1935 | } | 2040 | } |
1936 | if (window_imp->mCallbacks->handleUnicodeChar(w_param, gKeyboard->currentMask(FALSE))) | 2041 | // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE, |
1937 | { | 2042 | // we *did* processed the event, so I believe we should not pass it to DefWindowProc... |
1938 | return 0; | 2043 | window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); |
1939 | } | 2044 | return 0; |
1940 | break; | ||
1941 | 2045 | ||
1942 | case WM_LBUTTONDOWN: | 2046 | case WM_LBUTTONDOWN: |
1943 | { | 2047 | { |
@@ -2971,7 +3075,7 @@ void spawn_web_browser(const char* escaped_url ) | |||
2971 | char reg_path_str[256]; /* Flawfinder: ignore */ | 3075 | char reg_path_str[256]; /* Flawfinder: ignore */ |
2972 | snprintf(reg_path_str, sizeof(reg_path_str), "%s\\shell\\open\\command", gURLProtocolWhitelistHandler[i]); /* Flawfinder: ignore */ | 3076 | snprintf(reg_path_str, sizeof(reg_path_str), "%s\\shell\\open\\command", gURLProtocolWhitelistHandler[i]); /* Flawfinder: ignore */ |
2973 | WCHAR reg_path_wstr[256]; | 3077 | WCHAR reg_path_wstr[256]; |
2974 | mbstowcs(reg_path_wstr, reg_path_str, 1024); | 3078 | mbstowcs(reg_path_wstr, reg_path_str, sizeof(reg_path_wstr)/sizeof(reg_path_wstr[0])); |
2975 | 3079 | ||
2976 | HKEY key; | 3080 | HKEY key; |
2977 | WCHAR browser_open_wstr[1024]; | 3081 | WCHAR browser_open_wstr[1024]; |
@@ -3102,6 +3206,58 @@ void LLWindowWin32::bringToFront() | |||
3102 | void LLWindowWin32::focusClient() | 3206 | void LLWindowWin32::focusClient() |
3103 | { | 3207 | { |
3104 | SetFocus ( mWindowHandle ); | 3208 | SetFocus ( mWindowHandle ); |
3105 | }; | 3209 | } |
3210 | |||
3211 | void LLWindowWin32::allowLanguageTextInput(BOOL b) | ||
3212 | { | ||
3213 | if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) | ||
3214 | { | ||
3215 | /* Not actually allowing/disallowing. Do nothing. */ | ||
3216 | return; | ||
3217 | } | ||
3218 | sLanguageTextInputAllowed = b; | ||
3219 | |||
3220 | if (b) | ||
3221 | { | ||
3222 | /* Allowing: Restore the previous IME status, | ||
3223 | so that the user has a feeling that the previous | ||
3224 | text input continues naturally. Be careful, however, | ||
3225 | the IME status is meaningful only during the user keeps | ||
3226 | using same Input Locale (aka Keyboard Layout). */ | ||
3227 | if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale) | ||
3228 | { | ||
3229 | HIMC himc = LLWinImm::getContext(mWindowHandle); | ||
3230 | LLWinImm::setOpenStatus(himc, TRUE); | ||
3231 | LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode); | ||
3232 | LLWinImm::releaseContext(mWindowHandle, himc); | ||
3233 | } | ||
3234 | } | ||
3235 | else | ||
3236 | { | ||
3237 | /* Disallowing: Turn off the IME so that succeeding | ||
3238 | key events bypass IME and come to us directly. | ||
3239 | However, do it after saving the current IME | ||
3240 | status. We need to restore the status when | ||
3241 | allowing language text input again. */ | ||
3242 | sWinInputLocale = GetKeyboardLayout(0); | ||
3243 | sWinIMEOpened = LLWinImm::isIME(sWinInputLocale); | ||
3244 | if (sWinIMEOpened) | ||
3245 | { | ||
3246 | HIMC himc = LLWinImm::getContext(mWindowHandle); | ||
3247 | sWinIMEOpened = LLWinImm::getOpenStatus(himc); | ||
3248 | if (sWinIMEOpened) | ||
3249 | { | ||
3250 | LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode); | ||
3251 | |||
3252 | /* We need both ImmSetConversionStatus and ImmSetOpenStatus here | ||
3253 | to surely disable IME's keyboard hooking, because Some IME reacts | ||
3254 | only on the former and some other on the latter... */ | ||
3255 | LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode); | ||
3256 | LLWinImm::setOpenStatus(himc, FALSE); | ||
3257 | } | ||
3258 | LLWinImm::releaseContext(mWindowHandle, himc); | ||
3259 | } | ||
3260 | } | ||
3261 | } | ||
3106 | 3262 | ||
3107 | #endif // LL_WINDOWS | 3263 | #endif // LL_WINDOWS |