src/video/win32/SDL_win32keyboard.c
author dewyatt
Mon, 12 Jul 2010 14:17:43 -0400
changeset 4753 11b0a6a3eb4d
parent 4752 dc7bdcf06367
child 4759 863ba7d1f029
permissions -rw-r--r--
Changed Start/StopTextInput back to not take any parameters.
We call SDL_GetKeyboardFocus internally now.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_win32video.h"
    25 
    26 #include "../../events/SDL_keyboard_c.h"
    27 #include "../../events/scancodes_win32.h"
    28 
    29 #include <msctf.h>
    30 #include <imm.h>
    31 
    32 #ifndef MAPVK_VK_TO_VSC
    33 #define MAPVK_VK_TO_VSC     0
    34 #endif
    35 #ifndef MAPVK_VSC_TO_VK
    36 #define MAPVK_VSC_TO_VK     1
    37 #endif
    38 #ifndef MAPVK_VK_TO_CHAR
    39 #define MAPVK_VK_TO_CHAR    2
    40 #endif
    41 
    42 /* Alphabetic scancodes for PC keyboards */
    43 BYTE alpha_scancodes[26] = {
    44     30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24,
    45     25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44
    46 };
    47 
    48 BYTE keypad_scancodes[10] = {
    49     82, 79, 80, 81, 75, 76, 77, 71, 72, 73
    50 };
    51 
    52 void IME_Disable(SDL_VideoData *videodata, HWND hwnd);
    53 void IME_Enable(SDL_VideoData *videodata, HWND hwnd);
    54 void IME_Init(SDL_VideoData *videodata, HWND hwnd);
    55 void IME_Quit(SDL_VideoData *videodata);
    56 
    57 void
    58 WIN_InitKeyboard(_THIS)
    59 {
    60     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
    61     int i;
    62 
    63     /* Make sure the alpha scancodes are correct.  T isn't usually remapped */
    64     if (MapVirtualKey('T', MAPVK_VK_TO_VSC) != alpha_scancodes['T' - 'A']) {
    65 #if 0
    66         printf
    67             ("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");
    68 #endif
    69         for (i = 0; i < SDL_arraysize(alpha_scancodes); ++i) {
    70             alpha_scancodes[i] = MapVirtualKey('A' + i, MAPVK_VK_TO_VSC);
    71 #if 0
    72             printf("%d = %d\n", i, alpha_scancodes[i]);
    73 #endif
    74         }
    75     }
    76     if (MapVirtualKey(VK_NUMPAD0, MAPVK_VK_TO_VSC) != keypad_scancodes[0]) {
    77 #if 0
    78         printf
    79             ("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");
    80 #endif
    81         for (i = 0; i < SDL_arraysize(keypad_scancodes); ++i) {
    82             keypad_scancodes[i] =
    83                 MapVirtualKey(VK_NUMPAD0 + i, MAPVK_VK_TO_VSC);
    84 #if 0
    85             printf("%d = %d\n", i, keypad_scancodes[i]);
    86 #endif
    87         }
    88     }
    89 
    90     data->key_layout = win32_scancode_table;
    91 
    92     data->ime_com_initialized = SDL_FALSE;
    93     data->ime_thread_mgr = 0;
    94     data->ime_initialized = SDL_FALSE;
    95     data->ime_enabled = SDL_FALSE;
    96     data->ime_available = SDL_FALSE;
    97     data->ime_hwnd_main = 0;
    98     data->ime_hwnd_current = 0;
    99     data->ime_himc = 0;
   100 
   101     WIN_UpdateKeymap();
   102 
   103     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
   104     SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Windows");
   105     SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Windows");
   106 }
   107 
   108 void
   109 WIN_UpdateKeymap()
   110 {
   111     int i;
   112     SDL_scancode scancode;
   113     SDLKey keymap[SDL_NUM_SCANCODES];
   114 
   115     SDL_GetDefaultKeymap(keymap);
   116 
   117     for (i = 0; i < SDL_arraysize(win32_scancode_table); i++) {
   118 
   119         /* Make sure this scancode is a valid character scancode */
   120         scancode = win32_scancode_table[i];
   121         if (scancode == SDL_SCANCODE_UNKNOWN ||
   122             (keymap[scancode] & SDLK_SCANCODE_MASK)) {
   123             continue;
   124         }
   125 
   126         /* Alphabetic keys are handled specially, since Windows remaps them */
   127         if (i >= 'A' && i <= 'Z') {
   128             BYTE vsc = alpha_scancodes[i - 'A'];
   129             keymap[scancode] = MapVirtualKey(vsc, MAPVK_VSC_TO_VK) + 0x20;
   130         } else {
   131             keymap[scancode] = (MapVirtualKey(i, MAPVK_VK_TO_CHAR) & 0x7FFF);
   132         }
   133     }
   134     SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
   135 }
   136 
   137 void
   138 WIN_QuitKeyboard(_THIS)
   139 {
   140     IME_Quit((SDL_VideoData *)_this->driverdata);
   141 }
   142 
   143 void
   144 WIN_StartTextInput(_THIS)
   145 {
   146     SDL_Window *window = SDL_GetKeyboardFocus();
   147     if (window)
   148     {
   149         HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   150         SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
   151         IME_Init(videodata, hwnd);
   152         IME_Enable(videodata, hwnd);
   153     }
   154 }
   155 
   156 void
   157 WIN_StopTextInput(_THIS)
   158 {
   159     SDL_Window *window = SDL_GetKeyboardFocus();
   160     if (window)
   161     {
   162         HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   163         SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
   164         IME_Init(videodata, hwnd);
   165         IME_Disable(videodata, hwnd);
   166     }
   167 }
   168 
   169 void
   170 WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
   171 {
   172 
   173 }
   174 
   175 void
   176 IME_Disable(SDL_VideoData *videodata, HWND hwnd)
   177 {
   178     if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
   179         return;
   180 
   181     if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
   182         ImmAssociateContext(videodata->ime_hwnd_current, NULL);
   183 
   184     videodata->ime_enabled = SDL_FALSE;
   185 }
   186 
   187 void
   188 IME_Enable(SDL_VideoData *videodata, HWND hwnd)
   189 {
   190     if (!videodata->ime_initialized || !videodata->ime_hwnd_current)
   191         return;
   192 
   193     if (!videodata->ime_available) {
   194         IME_Disable(videodata, hwnd);
   195         return;
   196     }
   197     if (videodata->ime_hwnd_current == videodata->ime_hwnd_main)
   198         ImmAssociateContext(videodata->ime_hwnd_current, videodata->ime_himc);
   199 
   200     videodata->ime_enabled = SDL_TRUE;
   201 }
   202 
   203 void
   204 IME_Init(SDL_VideoData *videodata, HWND hwnd)
   205 {
   206     if (videodata->ime_initialized)
   207         return;
   208 
   209     videodata->ime_hwnd_main = hwnd;
   210     if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) {
   211         videodata->ime_com_initialized = SDL_TRUE;
   212         CoCreateInstance(&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, &videodata->ime_thread_mgr);
   213     }
   214     videodata->ime_initialized = SDL_TRUE;
   215     videodata->ime_hwnd_current = videodata->ime_hwnd_main;
   216     if (videodata->ime_thread_mgr) {
   217         struct ITfDocumentMgr *document_mgr = 0;
   218         if (SUCCEEDED(videodata->ime_thread_mgr->lpVtbl->AssociateFocus(videodata->ime_thread_mgr, hwnd, NULL, &document_mgr))) {
   219             if (document_mgr)
   220                 document_mgr->lpVtbl->Release(document_mgr);
   221         }
   222     }
   223     videodata->ime_himc = ImmGetContext(hwnd);
   224     ImmReleaseContext(hwnd, videodata->ime_himc);
   225     if (!videodata->ime_himc) {
   226         videodata->ime_available = SDL_FALSE;
   227         IME_Disable(videodata, hwnd);
   228         return;
   229     }
   230     videodata->ime_available = SDL_TRUE;
   231     IME_Disable(videodata, hwnd);
   232 }
   233 
   234 void
   235 IME_Quit(SDL_VideoData *videodata)
   236 {
   237     if (!videodata->ime_initialized)
   238         return;
   239 
   240     if (videodata->ime_hwnd_main)
   241         ImmAssociateContext(videodata->ime_hwnd_main, videodata->ime_himc);
   242 
   243     videodata->ime_hwnd_main = 0;
   244     videodata->ime_himc = 0;
   245     if (videodata->ime_thread_mgr)
   246     {
   247         videodata->ime_thread_mgr->lpVtbl->Release(videodata->ime_thread_mgr);
   248         videodata->ime_thread_mgr = 0;
   249     }
   250     if (videodata->ime_com_initialized)
   251     {
   252         CoUninitialize();
   253         videodata->ime_com_initialized = SDL_FALSE;
   254     }
   255     videodata->ime_initialized = SDL_FALSE;
   256 }
   257 
   258 SDL_bool
   259 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
   260 {
   261     SDL_bool trap = SDL_FALSE;
   262     HIMC himc = 0;
   263     WCHAR Buffer[SDL_TEXTINPUTEVENT_TEXT_SIZE / 2];
   264     if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled)
   265         return SDL_FALSE;
   266 
   267     switch (msg)
   268     {
   269     case WM_INPUTLANGCHANGE:
   270         break;
   271     case WM_IME_SETCONTEXT:
   272         *lParam = 0;
   273         break;
   274     case WM_IME_STARTCOMPOSITION:
   275         trap = SDL_TRUE;
   276         break;
   277     case WM_IME_COMPOSITION:
   278         trap = SDL_TRUE;
   279         himc = ImmGetContext(hwnd);
   280         if (*lParam & GCS_RESULTSTR)
   281         {
   282             LONG Length = 0;
   283             char *s = 0;
   284             Length = ImmGetCompositionStringW(himc, GCS_RESULTSTR, Buffer, sizeof(Buffer) * sizeof(Buffer[0]));
   285             Buffer[Length / sizeof(Buffer[0])] = 0;
   286             s = WIN_StringToUTF8(Buffer);
   287             SDL_SendKeyboardText(s);
   288             SDL_free(s);
   289         }
   290         if (*lParam & GCS_COMPSTR)
   291         {
   292             LONG Length = 0;
   293             DWORD Cursor = 0;
   294             char *s = 0;
   295             Length = ImmGetCompositionStringW(himc, GCS_COMPSTR, Buffer, sizeof(Buffer) * sizeof(Buffer[0]));
   296             Buffer[Length / sizeof(Buffer[0])] = 0;
   297             s = WIN_StringToUTF8(Buffer);
   298             Cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
   299             SDL_SendEditingText(s, Cursor, 0);
   300             SDL_free(s);
   301         }
   302         ImmReleaseContext(hwnd, himc);
   303         break;
   304     case WM_IME_ENDCOMPOSITION:
   305         SDL_SendKeyboardText("");
   306         break;
   307     case WM_IME_NOTIFY:
   308         switch (wParam)
   309         {
   310         case IMN_SETCONVERSIONMODE:
   311             break;
   312         case IMN_SETOPENSTATUS:
   313             break;
   314         case IMN_OPENCANDIDATE:
   315         case IMN_CHANGECANDIDATE:
   316             trap = SDL_TRUE;
   317             break;
   318         case IMN_CLOSECANDIDATE:
   319             trap = SDL_TRUE;
   320             break;
   321         case IMN_PRIVATE:
   322             break;
   323         default:
   324             trap = SDL_TRUE;
   325             break;
   326         }
   327         break;
   328     }
   329     return trap;
   330 }
   331 
   332 /* vi: set ts=4 sw=4 expandtab: */