Mercurial > sdl-ios-xcode
comparison src/video/win32/SDL_win32keyboard.c @ 4913:6b89d83b0b5a
Windows candidate list support.
Candidate list should now be drawn and function normally.
Tested in XP and 7.
author | Daniel Wyatt <Daniel.Wyatt@gmail.com> |
---|---|
date | Tue, 23 Nov 2010 17:46:47 -0500 |
parents | ac19d74e2a47 |
children | cc7ac6aaac5d |
comparison
equal
deleted
inserted
replaced
4912:37576cdf6751 | 4913:6b89d83b0b5a |
---|---|
98 data->ime_hwnd_current = 0; | 98 data->ime_hwnd_current = 0; |
99 data->ime_himc = 0; | 99 data->ime_himc = 0; |
100 data->ime_composition[0] = 0; | 100 data->ime_composition[0] = 0; |
101 data->ime_readingstring[0] = 0; | 101 data->ime_readingstring[0] = 0; |
102 data->ime_cursor = 0; | 102 data->ime_cursor = 0; |
103 | |
104 data->ime_candlist = SDL_FALSE; | |
105 SDL_memset(data->ime_candidates, 0, sizeof(data->ime_candidates)); | |
106 data->ime_candcount = 0; | |
107 data->ime_candref = 0; | |
108 data->ime_candsel = 0; | |
109 data->ime_candpgsize = 0; | |
110 data->ime_candlistindexbase = 0; | |
111 data->ime_candvertical = SDL_TRUE; | |
112 | |
113 data->ime_candtex = NULL; | |
114 data->ime_dirty = SDL_FALSE; | |
115 SDL_memset(&data->ime_rect, 0, sizeof(data->ime_rect)); | |
116 SDL_memset(&data->ime_candlistrect, 0, sizeof(data->ime_candlistrect)); | |
117 data->ime_winwidth = 0; | |
118 data->ime_winheight = 0; | |
119 | |
103 data->ime_hkl = 0; | 120 data->ime_hkl = 0; |
104 data->ime_himm32 = 0; | 121 data->ime_himm32 = 0; |
105 data->GetReadingString = 0; | 122 data->GetReadingString = 0; |
106 data->ShowReadingWindow = 0; | 123 data->ShowReadingWindow = 0; |
107 data->ImmLockIMC = 0; | 124 data->ImmLockIMC = 0; |
163 { | 180 { |
164 SDL_Window *window = SDL_GetKeyboardFocus(); | 181 SDL_Window *window = SDL_GetKeyboardFocus(); |
165 if (window) { | 182 if (window) { |
166 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; | 183 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; |
167 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; | 184 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; |
185 SDL_GetWindowSize(window, &videodata->ime_winwidth, &videodata->ime_winheight); | |
168 IME_Init(videodata, hwnd); | 186 IME_Init(videodata, hwnd); |
169 IME_Enable(videodata, hwnd); | 187 IME_Enable(videodata, hwnd); |
170 } | 188 } |
171 } | 189 } |
172 | 190 |
183 } | 201 } |
184 | 202 |
185 void | 203 void |
186 WIN_SetTextInputRect(_THIS, SDL_Rect *rect) | 204 WIN_SetTextInputRect(_THIS, SDL_Rect *rect) |
187 { | 205 { |
188 | 206 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; |
207 videodata->ime_rect = *rect; | |
189 } | 208 } |
190 | 209 |
191 #ifdef __GNUC__ | 210 #ifdef __GNUC__ |
192 #undef DEFINE_GUID | 211 #undef DEFINE_GUID |
193 #define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const GUID n = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} | 212 #define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const GUID n = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} |
194 DEFINE_GUID(IID_ITfInputProcessorProfileActivationSink, 0x71C6E74E,0x0F28,0x11D8,0xA8,0x2A,0x00,0x06,0x5B,0x84,0x43,0x5C); | 213 DEFINE_GUID(IID_ITfInputProcessorProfileActivationSink, 0x71C6E74E,0x0F28,0x11D8,0xA8,0x2A,0x00,0x06,0x5B,0x84,0x43,0x5C); |
195 DEFINE_GUID(IID_ITfUIElementSink, 0xEA1EA136,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C); | 214 DEFINE_GUID(IID_ITfUIElementSink, 0xEA1EA136,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C); |
196 DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD, 0x34745C63,0xB2F0,0x4784,0x8B,0x67,0x5E,0x12,0xC8,0x70,0x1A,0x31); | 215 DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD, 0x34745C63,0xB2F0,0x4784,0x8B,0x67,0x5E,0x12,0xC8,0x70,0x1A,0x31); |
197 DEFINE_GUID(IID_ITfSource, 0x4EA48A35,0x60AE,0x446F,0x8F,0xD6,0xE6,0xA8,0xD8,0x24,0x59,0xF7); | 216 DEFINE_GUID(IID_ITfSource, 0x4EA48A35,0x60AE,0x446F,0x8F,0xD6,0xE6,0xA8,0xD8,0x24,0x59,0xF7); |
198 DEFINE_GUID(IID_ITfUIElementMgr, 0xEA1EA135,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C); | 217 DEFINE_GUID(IID_ITfUIElementMgr, 0xEA1EA135,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C); |
218 DEFINE_GUID(IID_ITfCandidateListUIElement, 0xEA1EA138,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C); | |
199 DEFINE_GUID(IID_ITfReadingInformationUIElement, 0xEA1EA139,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C); | 219 DEFINE_GUID(IID_ITfReadingInformationUIElement, 0xEA1EA139,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C); |
200 DEFINE_GUID(IID_ITfThreadMgr, 0xAA80E801,0x2021,0x11D2,0x93,0xE0,0x00,0x60,0xB0,0x67,0xB8,0x6E); | 220 DEFINE_GUID(IID_ITfThreadMgr, 0xAA80E801,0x2021,0x11D2,0x93,0xE0,0x00,0x60,0xB0,0x67,0xB8,0x6E); |
201 DEFINE_GUID(CLSID_TF_ThreadMgr, 0x529A9E6B,0x6587,0x4F23,0xAB,0x9E,0x9C,0x7D,0x68,0x3E,0x3C,0x50); | 221 DEFINE_GUID(CLSID_TF_ThreadMgr, 0x529A9E6B,0x6587,0x4F23,0xAB,0x9E,0x9C,0x7D,0x68,0x3E,0x3C,0x50); |
202 DEFINE_GUID(IID_ITfThreadMgrEx, 0x3E90ADE3,0x7594,0x4CB0,0xBB,0x58,0x69,0x62,0x8F,0x5F,0x45,0x8C); | 222 DEFINE_GUID(IID_ITfThreadMgrEx, 0x3E90ADE3,0x7594,0x4CB0,0xBB,0x58,0x69,0x62,0x8F,0x5F,0x45,0x8C); |
203 #endif | 223 #endif |
241 static void IME_ClearComposition(SDL_VideoData *videodata); | 261 static void IME_ClearComposition(SDL_VideoData *videodata); |
242 static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd); | 262 static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd); |
243 static void IME_SetupAPI(SDL_VideoData *videodata); | 263 static void IME_SetupAPI(SDL_VideoData *videodata); |
244 static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex); | 264 static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex); |
245 static void IME_SendEditingEvent(SDL_VideoData *videodata); | 265 static void IME_SendEditingEvent(SDL_VideoData *videodata); |
266 static void IME_DestroyTextures(SDL_VideoData *videodata); | |
267 | |
246 #define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2) | 268 #define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2) |
247 #define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID))) | 269 #define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID))) |
248 | 270 |
249 static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata); | 271 static SDL_bool UILess_SetupSinks(SDL_VideoData *videodata); |
250 static void UILess_ReleaseSinks(SDL_VideoData *videodata); | 272 static void UILess_ReleaseSinks(SDL_VideoData *videodata); |
343 } | 365 } |
344 if (videodata->ime_com_initialized) { | 366 if (videodata->ime_com_initialized) { |
345 CoUninitialize(); | 367 CoUninitialize(); |
346 videodata->ime_com_initialized = SDL_FALSE; | 368 videodata->ime_com_initialized = SDL_FALSE; |
347 } | 369 } |
370 IME_DestroyTextures(videodata); | |
348 videodata->ime_initialized = SDL_FALSE; | 371 videodata->ime_initialized = SDL_FALSE; |
349 } | 372 } |
350 | 373 |
351 static void | 374 static void |
352 IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd) | 375 IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd) |
451 | 474 |
452 static void | 475 static void |
453 IME_InputLangChanged(SDL_VideoData *videodata) | 476 IME_InputLangChanged(SDL_VideoData *videodata) |
454 { | 477 { |
455 UINT lang = PRIMLANG(); | 478 UINT lang = PRIMLANG(); |
456 HWND hwndime = 0; | |
457 IME_UpdateInputLocale(videodata); | 479 IME_UpdateInputLocale(videodata); |
480 if (!videodata->ime_uiless) | |
481 videodata->ime_candlistindexbase = (videodata->ime_hkl == CHT_HKL_DAYI) ? 0 : 1; | |
482 | |
458 IME_SetupAPI(videodata); | 483 IME_SetupAPI(videodata); |
459 if (lang != PRIMLANG()) { | 484 if (lang != PRIMLANG()) { |
460 IME_ClearComposition(videodata); | 485 IME_ClearComposition(videodata); |
461 } | |
462 hwndime = ImmGetDefaultIMEWnd(videodata->ime_hwnd_current); | |
463 if (hwndime) { | |
464 SendMessageA(hwndime, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0); | |
465 SendMessageA(hwndime, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0); | |
466 } | 486 } |
467 } | 487 } |
468 | 488 |
469 static DWORD | 489 static DWORD |
470 IME_GetId(SDL_VideoData *videodata, UINT uIndex) | 490 IME_GetId(SDL_VideoData *videodata, UINT uIndex) |
608 videodata->ime_hkl = GetKeyboardLayout(0); | 628 videodata->ime_hkl = GetKeyboardLayout(0); |
609 if (hklprev == videodata->ime_hkl) | 629 if (hklprev == videodata->ime_hkl) |
610 return; | 630 return; |
611 | 631 |
612 hklprev = videodata->ime_hkl; | 632 hklprev = videodata->ime_hkl; |
633 switch (PRIMLANG()) | |
634 { | |
635 case LANG_CHINESE: | |
636 videodata->ime_candvertical = SDL_TRUE; | |
637 if (SUBLANG() == SUBLANG_CHINESE_SIMPLIFIED) | |
638 videodata->ime_candvertical = SDL_FALSE; | |
639 | |
640 break; | |
641 case LANG_JAPANESE: | |
642 videodata->ime_candvertical = SDL_TRUE; | |
643 break; | |
644 case LANG_KOREAN: | |
645 videodata->ime_candvertical = SDL_FALSE; | |
646 break; | |
647 } | |
613 } | 648 } |
614 | 649 |
615 static void | 650 static void |
616 IME_ClearComposition(SDL_VideoData *videodata) | 651 IME_ClearComposition(SDL_VideoData *videodata) |
617 { | 652 { |
628 ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR)); | 663 ImmSetCompositionString(himc, SCS_SETSTR, TEXT(""), sizeof(TCHAR), TEXT(""), sizeof(TCHAR)); |
629 | 664 |
630 ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0); | 665 ImmNotifyIME(himc, NI_CLOSECANDIDATE, 0, 0); |
631 ImmReleaseContext(videodata->ime_hwnd_current, himc); | 666 ImmReleaseContext(videodata->ime_hwnd_current, himc); |
632 SDL_SendEditingText("", 0, 0); | 667 SDL_SendEditingText("", 0, 0); |
633 } | |
634 | |
635 static void | |
636 IME_ClearEditing(SDL_VideoData *videodata) | |
637 { | |
638 | |
639 } | 668 } |
640 | 669 |
641 static void | 670 static void |
642 IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string) | 671 IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string) |
643 { | 672 { |
688 s = WIN_StringToUTF8(buffer); | 717 s = WIN_StringToUTF8(buffer); |
689 SDL_SendEditingText(s, videodata->ime_cursor + SDL_wcslen(videodata->ime_readingstring), 0); | 718 SDL_SendEditingText(s, videodata->ime_cursor + SDL_wcslen(videodata->ime_readingstring), 0); |
690 SDL_free(s); | 719 SDL_free(s); |
691 } | 720 } |
692 | 721 |
722 static void | |
723 IME_AddCandidate(SDL_VideoData *videodata, UINT i, LPCWSTR candidate) | |
724 { | |
725 LPWSTR dst = videodata->ime_candidates[i]; | |
726 *dst++ = (WCHAR)(TEXT('0') + ((i + videodata->ime_candlistindexbase) % 10)); | |
727 if (videodata->ime_candvertical) | |
728 *dst++ = TEXT(' '); | |
729 | |
730 while (*candidate && (SDL_arraysize(videodata->ime_candidates[i]) > (dst - videodata->ime_candidates[i]))) | |
731 *dst++ = *candidate++; | |
732 | |
733 *dst = (WCHAR)'\0'; | |
734 } | |
735 | |
736 static void | |
737 IME_GetCandidateList(HIMC himc, SDL_VideoData *videodata) | |
738 { | |
739 LPCANDIDATELIST cand_list = 0; | |
740 DWORD size = ImmGetCandidateListW(himc, 0, 0, 0); | |
741 if (size) | |
742 { | |
743 cand_list = (LPCANDIDATELIST)SDL_malloc(size); | |
744 if (cand_list) | |
745 { | |
746 size = ImmGetCandidateListW(himc, 0, cand_list, size); | |
747 if (size) | |
748 { | |
749 int i = 0; | |
750 int j = 0; | |
751 int page_start = 0; | |
752 videodata->ime_candsel = cand_list->dwSelection; | |
753 videodata->ime_candcount = cand_list->dwCount; | |
754 | |
755 if (LANG() == LANG_CHS && IME_GetId(videodata, 0)) | |
756 { | |
757 const UINT maxcandchar = 18; | |
758 UINT i = 0; | |
759 UINT cchars = 0; | |
760 | |
761 for (; i < videodata->ime_candcount; ++i) | |
762 { | |
763 UINT len = SDL_wcslen((LPWSTR)((DWORD)cand_list + cand_list->dwOffset[i])) + 1; | |
764 if (len + cchars > maxcandchar) | |
765 { | |
766 if (i > cand_list->dwSelection) | |
767 break; | |
768 | |
769 page_start = i; | |
770 cchars = len; | |
771 } | |
772 else | |
773 { | |
774 cchars += len; | |
775 } | |
776 } | |
777 videodata->ime_candpgsize = i - page_start; | |
778 } | |
779 else | |
780 { | |
781 videodata->ime_candpgsize = SDL_min(cand_list->dwPageSize, MAX_CANDLIST); | |
782 page_start = (cand_list->dwSelection / videodata->ime_candpgsize) * videodata->ime_candpgsize; | |
783 } | |
784 SDL_memset(&videodata->ime_candidates, 0, sizeof(videodata->ime_candidates)); | |
785 for (i = page_start, j = 0; (DWORD)i < cand_list->dwCount && j < (int)videodata->ime_candpgsize; i++, j++) | |
786 { | |
787 LPCWSTR candidate = (LPCWSTR)((DWORD)cand_list + cand_list->dwOffset[i]); | |
788 IME_AddCandidate(videodata, j, candidate); | |
789 } | |
790 if (PRIMLANG() == LANG_KOREAN || (PRIMLANG() == LANG_CHT && !IME_GetId(videodata, 0))) | |
791 videodata->ime_candsel = -1; | |
792 | |
793 } | |
794 SDL_free(cand_list); | |
795 } | |
796 } | |
797 } | |
798 | |
799 static void | |
800 IME_ShowCandidateList(SDL_VideoData *videodata) | |
801 { | |
802 videodata->ime_dirty = SDL_TRUE; | |
803 videodata->ime_candlist = SDL_TRUE; | |
804 IME_DestroyTextures(videodata); | |
805 IME_SendEditingEvent(videodata); | |
806 } | |
807 | |
808 static void | |
809 IME_HideCandidateList(SDL_VideoData *videodata) | |
810 { | |
811 videodata->ime_dirty = SDL_FALSE; | |
812 videodata->ime_candlist = SDL_FALSE; | |
813 IME_DestroyTextures(videodata); | |
814 IME_SendEditingEvent(videodata); | |
815 } | |
816 | |
693 SDL_bool | 817 SDL_bool |
694 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) | 818 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) |
695 { | 819 { |
696 SDL_bool trap = SDL_FALSE; | 820 SDL_bool trap = SDL_FALSE; |
697 HIMC himc = 0; | 821 HIMC himc = 0; |
699 return SDL_FALSE; | 823 return SDL_FALSE; |
700 | 824 |
701 switch (msg) | 825 switch (msg) |
702 { | 826 { |
703 case WM_INPUTLANGCHANGE: | 827 case WM_INPUTLANGCHANGE: |
704 //IME_InputLangChanged(videodata); | 828 IME_InputLangChanged(videodata); |
705 break; | 829 break; |
706 case WM_IME_SETCONTEXT: | 830 case WM_IME_SETCONTEXT: |
707 *lParam = 0; | 831 *lParam = 0; |
708 break; | 832 break; |
709 case WM_IME_STARTCOMPOSITION: | 833 case WM_IME_STARTCOMPOSITION: |
738 case IMN_SETOPENSTATUS: | 862 case IMN_SETOPENSTATUS: |
739 IME_UpdateInputLocale(videodata); | 863 IME_UpdateInputLocale(videodata); |
740 break; | 864 break; |
741 case IMN_OPENCANDIDATE: | 865 case IMN_OPENCANDIDATE: |
742 case IMN_CHANGECANDIDATE: | 866 case IMN_CHANGECANDIDATE: |
867 if (videodata->ime_uiless) | |
868 break; | |
869 | |
743 trap = SDL_TRUE; | 870 trap = SDL_TRUE; |
871 IME_ShowCandidateList(videodata); | |
872 himc = ImmGetContext(hwnd); | |
873 if (!himc) | |
874 break; | |
875 | |
876 IME_GetCandidateList(himc, videodata); | |
877 ImmReleaseContext(hwnd, himc); | |
744 break; | 878 break; |
745 case IMN_CLOSECANDIDATE: | 879 case IMN_CLOSECANDIDATE: |
746 trap = SDL_TRUE; | 880 trap = SDL_TRUE; |
881 IME_HideCandidateList(videodata); | |
747 break; | 882 break; |
748 case IMN_PRIVATE: | 883 case IMN_PRIVATE: |
749 { | 884 { |
750 DWORD dwId = IME_GetId(videodata, 0); | 885 DWORD dwId = IME_GetId(videodata, 0); |
751 IME_GetReadingString(videodata, hwnd); | 886 IME_GetReadingString(videodata, hwnd); |
782 break; | 917 break; |
783 } | 918 } |
784 return trap; | 919 return trap; |
785 } | 920 } |
786 | 921 |
922 static void | |
923 IME_CloseCandidateList(SDL_VideoData *videodata) | |
924 { | |
925 IME_HideCandidateList(videodata); | |
926 videodata->ime_candcount = 0; | |
927 SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates)); | |
928 } | |
929 | |
930 static void | |
931 UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pcandlist) | |
932 { | |
933 UINT selection = 0; | |
934 UINT count = 0; | |
935 UINT page = 0; | |
936 UINT pgcount = 0; | |
937 DWORD pgstart = 0; | |
938 DWORD pgsize = 0; | |
939 UINT i, j; | |
940 pcandlist->lpVtbl->GetSelection(pcandlist, &selection); | |
941 pcandlist->lpVtbl->GetCount(pcandlist, &count); | |
942 pcandlist->lpVtbl->GetCurrentPage(pcandlist, &page); | |
943 | |
944 videodata->ime_candsel = selection; | |
945 videodata->ime_candcount = count; | |
946 IME_ShowCandidateList(videodata); | |
947 | |
948 pcandlist->lpVtbl->GetPageIndex(pcandlist, 0, 0, &pgcount); | |
949 if (pgcount > 0) | |
950 { | |
951 UINT *idxlist = SDL_malloc(sizeof(UINT) * pgcount); | |
952 if (idxlist) | |
953 { | |
954 pcandlist->lpVtbl->GetPageIndex(pcandlist, idxlist, pgcount, &pgcount); | |
955 pgstart = idxlist[page]; | |
956 if (page < pgcount - 1) | |
957 pgsize = SDL_min(count, idxlist[page + 1]) - pgstart; | |
958 else | |
959 pgsize = count - pgstart; | |
960 | |
961 SDL_free(idxlist); | |
962 } | |
963 } | |
964 videodata->ime_candpgsize = SDL_min(pgsize, MAX_CANDLIST); | |
965 videodata->ime_candsel = videodata->ime_candsel - pgstart; | |
966 | |
967 SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates)); | |
968 for (i = pgstart, j = 0; (DWORD)i < count && j < videodata->ime_candpgsize; i++, j++) | |
969 { | |
970 BSTR bstr; | |
971 if (SUCCEEDED(pcandlist->lpVtbl->GetString(pcandlist, i, &bstr))) | |
972 { | |
973 if (bstr) | |
974 { | |
975 IME_AddCandidate(videodata, j, bstr); | |
976 SysFreeString(bstr); | |
977 } | |
978 } | |
979 } | |
980 if (PRIMLANG() == LANG_KOREAN) | |
981 videodata->ime_candsel = -1; | |
982 } | |
983 | |
787 STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink) | 984 STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink) |
788 { | 985 { |
789 return ++sink->refcount; | 986 return ++sink->refcount; |
790 } | 987 } |
791 | 988 |
833 | 1030 |
834 STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow) | 1031 STDMETHODIMP UIElementSink_BeginUIElement(TSFSink *sink, DWORD dwUIElementId, BOOL *pbShow) |
835 { | 1032 { |
836 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); | 1033 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); |
837 ITfReadingInformationUIElement *preading = 0; | 1034 ITfReadingInformationUIElement *preading = 0; |
1035 ITfCandidateListUIElement *pcandlist = 0; | |
838 SDL_VideoData *videodata = (SDL_VideoData *)sink->data; | 1036 SDL_VideoData *videodata = (SDL_VideoData *)sink->data; |
839 if (!element) | 1037 if (!element) |
840 return E_INVALIDARG; | 1038 return E_INVALIDARG; |
841 | 1039 |
842 *pbShow = FALSE; | 1040 *pbShow = FALSE; |
846 WCHAR *s = (WCHAR *)bstr; | 1044 WCHAR *s = (WCHAR *)bstr; |
847 SysFreeString(bstr); | 1045 SysFreeString(bstr); |
848 } | 1046 } |
849 preading->lpVtbl->Release(preading); | 1047 preading->lpVtbl->Release(preading); |
850 } | 1048 } |
1049 else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) { | |
1050 videodata->ime_candref++; | |
1051 UILess_GetCandidateList(videodata, pcandlist); | |
1052 pcandlist->lpVtbl->Release(pcandlist); | |
1053 } | |
851 return S_OK; | 1054 return S_OK; |
852 } | 1055 } |
853 | 1056 |
854 STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId) | 1057 STDMETHODIMP UIElementSink_UpdateUIElement(TSFSink *sink, DWORD dwUIElementId) |
855 { | 1058 { |
856 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); | 1059 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); |
857 ITfReadingInformationUIElement *preading = 0; | 1060 ITfReadingInformationUIElement *preading = 0; |
1061 ITfCandidateListUIElement *pcandlist = 0; | |
858 SDL_VideoData *videodata = (SDL_VideoData *)sink->data; | 1062 SDL_VideoData *videodata = (SDL_VideoData *)sink->data; |
859 if (!element) | 1063 if (!element) |
860 return E_INVALIDARG; | 1064 return E_INVALIDARG; |
861 | 1065 |
862 if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { | 1066 if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { |
867 IME_SendEditingEvent(videodata); | 1071 IME_SendEditingEvent(videodata); |
868 SysFreeString(bstr); | 1072 SysFreeString(bstr); |
869 } | 1073 } |
870 preading->lpVtbl->Release(preading); | 1074 preading->lpVtbl->Release(preading); |
871 } | 1075 } |
1076 else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) { | |
1077 UILess_GetCandidateList(videodata, pcandlist); | |
1078 pcandlist->lpVtbl->Release(pcandlist); | |
1079 } | |
872 return S_OK; | 1080 return S_OK; |
873 } | 1081 } |
874 | 1082 |
875 STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId) | 1083 STDMETHODIMP UIElementSink_EndUIElement(TSFSink *sink, DWORD dwUIElementId) |
876 { | 1084 { |
877 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); | 1085 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId); |
878 ITfReadingInformationUIElement *preading = 0; | 1086 ITfReadingInformationUIElement *preading = 0; |
1087 ITfCandidateListUIElement *pcandlist = 0; | |
879 SDL_VideoData *videodata = (SDL_VideoData *)sink->data; | 1088 SDL_VideoData *videodata = (SDL_VideoData *)sink->data; |
880 if (!element) | 1089 if (!element) |
881 return E_INVALIDARG; | 1090 return E_INVALIDARG; |
882 | 1091 |
883 if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { | 1092 if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfReadingInformationUIElement, (LPVOID *)&preading))) { |
884 videodata->ime_readingstring[0] = 0; | 1093 videodata->ime_readingstring[0] = 0; |
885 IME_SendEditingEvent(videodata); | 1094 IME_SendEditingEvent(videodata); |
886 preading->lpVtbl->Release(preading); | 1095 preading->lpVtbl->Release(preading); |
1096 } | |
1097 if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) { | |
1098 videodata->ime_candref--; | |
1099 if (videodata->ime_candref == 0) | |
1100 IME_CloseCandidateList(videodata); | |
1101 | |
1102 pcandlist->lpVtbl->Release(pcandlist); | |
887 } | 1103 } |
888 return S_OK; | 1104 return S_OK; |
889 } | 1105 } |
890 | 1106 |
891 STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv) | 1107 STDMETHODIMP IPPASink_QueryInterface(TSFSink *sink, REFIID riid, PVOID *ppv) |
906 return E_NOINTERFACE; | 1122 return E_NOINTERFACE; |
907 } | 1123 } |
908 | 1124 |
909 STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags) | 1125 STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags) |
910 { | 1126 { |
1127 static GUID TF_PROFILE_DAYI = {0x037B2C25, 0x480C, 0x4D7F, 0xB0, 0x27, 0xD6, 0xCA, 0x6B, 0x69, 0x78, 0x8A}; | |
1128 SDL_VideoData *videodata = (SDL_VideoData *)sink->data; | |
1129 videodata->ime_candlistindexbase = SDL_IsEqualGUID(&TF_PROFILE_DAYI, guidProfile) ? 0 : 1; | |
911 if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE)) | 1130 if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE)) |
912 IME_InputLangChanged((SDL_VideoData *)sink->data); | 1131 IME_InputLangChanged((SDL_VideoData *)sink->data); |
913 | 1132 |
1133 IME_HideCandidateList(videodata); | |
914 return S_OK; | 1134 return S_OK; |
915 } | 1135 } |
916 | 1136 |
917 static void *vtUIElementSink[] = { | 1137 static void *vtUIElementSink[] = { |
918 (void *)(UIElementSink_QueryInterface), | 1138 (void *)(UIElementSink_QueryInterface), |
1014 TSFSink_Release(videodata->ime_ippasink); | 1234 TSFSink_Release(videodata->ime_ippasink); |
1015 videodata->ime_ippasink = 0; | 1235 videodata->ime_ippasink = 0; |
1016 } | 1236 } |
1017 } | 1237 } |
1018 | 1238 |
1239 static void * | |
1240 StartDrawToBitmap(HDC hdc, HBITMAP *hhbm, int width, int height) | |
1241 { | |
1242 BITMAPINFO info = {0}; | |
1243 BITMAPINFOHEADER *infoHeader = &info.bmiHeader; | |
1244 BYTE *bits = NULL; | |
1245 if (hhbm) | |
1246 { | |
1247 infoHeader->biSize = sizeof(BITMAPINFOHEADER); | |
1248 infoHeader->biWidth = width; | |
1249 infoHeader->biHeight = -1 * SDL_abs(height); | |
1250 infoHeader->biPlanes = 1; | |
1251 infoHeader->biBitCount = 32; | |
1252 infoHeader->biCompression = BI_RGB; | |
1253 *hhbm = CreateDIBSection(hdc, &info, DIB_RGB_COLORS, (void **)&bits, 0, 0); | |
1254 if (*hhbm) | |
1255 SelectObject(hdc, *hhbm); | |
1256 } | |
1257 return bits; | |
1258 } | |
1259 | |
1260 static void | |
1261 StopDrawToBitmap(HDC hdc, HBITMAP *hhbm) | |
1262 { | |
1263 if (hhbm && *hhbm) | |
1264 { | |
1265 DeleteObject(*hhbm); | |
1266 *hhbm = NULL; | |
1267 } | |
1268 } | |
1269 | |
1270 static void | |
1271 BitmapToTexture(HBITMAP hbm, BYTE *bits, int width, int height, SDL_Texture **texture) | |
1272 { | |
1273 SDL_Surface *surface = NULL; | |
1274 BITMAP bm = {0}; | |
1275 | |
1276 if (GetObject(hbm, sizeof(bm), &bm) == 0) | |
1277 return; | |
1278 | |
1279 if (bits && texture) | |
1280 { | |
1281 /* | |
1282 For transparency: | |
1283 | |
1284 const Uint8 alpha = 130; | |
1285 unsigned long *p = (unsigned long *)bits; | |
1286 unsigned long *end = (unsigned long *)(bits + (bm.bmWidthBytes * bm.bmHeight)); | |
1287 while (p < end) | |
1288 { | |
1289 *p = RGB(GetRValue(*p), GetGValue(*p), GetBValue(*p)) | (alpha << 24); | |
1290 ++p; | |
1291 } | |
1292 surface = SDL_CreateRGBSurfaceFrom(bits, width, height, bm.bmBitsPixel, bm.bmWidthBytes, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); | |
1293 */ | |
1294 surface = SDL_CreateRGBSurfaceFrom(bits, width, height, bm.bmBitsPixel, bm.bmWidthBytes, 0x00ff0000, 0x0000ff00, 0x000000ff, 0); | |
1295 if (surface) | |
1296 { | |
1297 *texture = SDL_CreateTextureFromSurface(0, surface); | |
1298 SDL_FreeSurface(surface); | |
1299 } | |
1300 } | |
1301 } | |
1302 | |
1303 /* This draws only within the specified area and fills the entire region. */ | |
1304 static void | |
1305 DrawRect(HDC hdc, int left, int top, int right, int bottom, int pensize) | |
1306 { | |
1307 /* The case of no pen (PenSize = 0) is automatically taken care of. */ | |
1308 const int penadjust = (int)SDL_floor(pensize / 2.0f - 0.5f); | |
1309 left += pensize / 2; | |
1310 top += pensize / 2; | |
1311 right -= penadjust; | |
1312 bottom -= penadjust; | |
1313 Rectangle(hdc, left, top, right, bottom); | |
1314 } | |
1315 | |
1316 static void | |
1317 DestroyTexture(SDL_Texture **texture) | |
1318 { | |
1319 if (texture && *texture) | |
1320 { | |
1321 SDL_DestroyTexture(*texture); | |
1322 *texture = NULL; | |
1323 } | |
1324 } | |
1325 | |
1326 static void | |
1327 IME_DestroyTextures(SDL_VideoData *videodata) | |
1328 { | |
1329 DestroyTexture(&videodata->ime_candtex); | |
1330 } | |
1331 | |
1332 #define SDL_swap(a,b) { \ | |
1333 int c = (a); \ | |
1334 (a) = (b); \ | |
1335 (b) = c; \ | |
1336 } | |
1337 | |
1338 static void | |
1339 IME_PositionCandidateList(SDL_VideoData *videodata, SIZE size) | |
1340 { | |
1341 int left, top, right, bottom; | |
1342 SDL_bool ok = SDL_FALSE; | |
1343 int winw = videodata->ime_winwidth; | |
1344 int winh = videodata->ime_winheight; | |
1345 | |
1346 /* Bottom */ | |
1347 left = videodata->ime_rect.x; | |
1348 top = videodata->ime_rect.y + videodata->ime_rect.h; | |
1349 right = left + size.cx; | |
1350 bottom = top + size.cy; | |
1351 if (right >= winw) | |
1352 { | |
1353 left -= right - winw; | |
1354 right = winw; | |
1355 } | |
1356 if (bottom < winh) | |
1357 ok = SDL_TRUE; | |
1358 | |
1359 /* Top */ | |
1360 if (!ok) | |
1361 { | |
1362 left = videodata->ime_rect.x; | |
1363 top = videodata->ime_rect.y - size.cy; | |
1364 right = left + size.cx; | |
1365 bottom = videodata->ime_rect.y; | |
1366 if (right >= winw) | |
1367 { | |
1368 left -= right - winw; | |
1369 right = winw; | |
1370 } | |
1371 if (top >= 0) | |
1372 ok = SDL_TRUE; | |
1373 } | |
1374 | |
1375 /* Right */ | |
1376 if (!ok) | |
1377 { | |
1378 left = videodata->ime_rect.x + size.cx; | |
1379 top = 0; | |
1380 right = left + size.cx; | |
1381 bottom = size.cy; | |
1382 if (right < winw) | |
1383 ok = SDL_TRUE; | |
1384 } | |
1385 | |
1386 /* Left */ | |
1387 if (!ok) | |
1388 { | |
1389 left = videodata->ime_rect.x - size.cx; | |
1390 top = 0; | |
1391 right = videodata->ime_rect.x; | |
1392 bottom = size.cy; | |
1393 if (right >= 0) | |
1394 ok = SDL_TRUE; | |
1395 } | |
1396 | |
1397 /* Window too small, show at (0,0) */ | |
1398 if (!ok) | |
1399 { | |
1400 left = 0; | |
1401 top = 0; | |
1402 right = size.cx; | |
1403 bottom = size.cy; | |
1404 } | |
1405 | |
1406 videodata->ime_candlistrect.x = left; | |
1407 videodata->ime_candlistrect.y = top; | |
1408 videodata->ime_candlistrect.w = right - left; | |
1409 videodata->ime_candlistrect.h = bottom - top; | |
1410 } | |
1411 | |
1412 static void | |
1413 IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc) | |
1414 { | |
1415 int i = 0; | |
1416 SIZE size = {0}; | |
1417 SIZE maxcandsize = {0}; | |
1418 HBITMAP hbm = NULL; | |
1419 BYTE *bits = NULL; | |
1420 const int candcount = SDL_min(SDL_min(MAX_CANDLIST, videodata->ime_candcount), videodata->ime_candpgsize); | |
1421 SDL_bool vertical = videodata->ime_candvertical; | |
1422 | |
1423 const int listborder = 1; | |
1424 const int listpadding = 0; | |
1425 const int listbordercolor = RGB(0xB4, 0xC7, 0xAA); | |
1426 const int listfillcolor = RGB(255, 255, 255); | |
1427 | |
1428 const int candborder = 1; | |
1429 const int candpadding = 0; | |
1430 const int candmargin = 1; | |
1431 const COLORREF candbordercolor = RGB(255, 255, 255); | |
1432 const COLORREF candfillcolor = RGB(255, 255, 255); | |
1433 const COLORREF candtextcolor = RGB(0, 0, 0); | |
1434 const COLORREF selbordercolor = RGB(0x84, 0xAC, 0xDD); | |
1435 const COLORREF selfillcolor = RGB(0xD2, 0xE6, 0xFF); | |
1436 const COLORREF seltextcolor = RGB(0, 0, 0); | |
1437 | |
1438 HPEN listpen = listborder != 0 ? CreatePen(PS_SOLID, listborder, listbordercolor) : (HPEN)GetStockObject(NULL_PEN); | |
1439 HBRUSH listbrush = CreateSolidBrush(listfillcolor); | |
1440 HPEN candpen = candborder != 0 ? CreatePen(PS_SOLID, candborder, candbordercolor) : (HPEN)GetStockObject(NULL_PEN); | |
1441 HBRUSH candbrush = CreateSolidBrush(candfillcolor); | |
1442 HPEN selpen = candborder != 0 ? CreatePen(PS_DOT, candborder, selbordercolor) : (HPEN)GetStockObject(NULL_PEN); | |
1443 HBRUSH selbrush = CreateSolidBrush(selfillcolor); | |
1444 HFONT font = CreateFont((int)(1 + videodata->ime_rect.h * 0.75f), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | FF_SWISS, TEXT("Microsoft Sans Serif")); | |
1445 | |
1446 SetBkMode(hdc, TRANSPARENT); | |
1447 SelectObject(hdc, font); | |
1448 | |
1449 for (i = 0; i < candcount; ++i) | |
1450 { | |
1451 const WCHAR *s = videodata->ime_candidates[i]; | |
1452 if (!*s) | |
1453 break; | |
1454 | |
1455 GetTextExtentPoint32W(hdc, s, SDL_wcslen(s), &size); | |
1456 maxcandsize.cx = SDL_max(maxcandsize.cx, size.cx); | |
1457 maxcandsize.cy = SDL_max(maxcandsize.cy, size.cy); | |
1458 | |
1459 } | |
1460 if (!vertical) | |
1461 SDL_swap(maxcandsize.cx, maxcandsize.cy); | |
1462 | |
1463 size.cx = | |
1464 (listborder * 2) + | |
1465 (listpadding * 2) + | |
1466 (candmargin * 2) + | |
1467 (candborder * 2) + | |
1468 (candpadding * 2) + | |
1469 (maxcandsize.cx) | |
1470 ; | |
1471 size.cy = | |
1472 (listborder * 2) + | |
1473 (listpadding * 2) + | |
1474 ((candcount + 1) * candmargin) + | |
1475 (candcount * candborder * 2) + | |
1476 (candcount * candpadding * 2) + | |
1477 (candcount * maxcandsize.cy) | |
1478 ; | |
1479 if (!vertical) | |
1480 SDL_swap(size.cx, size.cy); | |
1481 | |
1482 bits = StartDrawToBitmap(hdc, &hbm, size.cx, size.cy); | |
1483 | |
1484 SelectObject(hdc, listpen); | |
1485 SelectObject(hdc, listbrush); | |
1486 DrawRect(hdc, 0, 0, size.cx, size.cy, listborder); | |
1487 | |
1488 SelectObject(hdc, candpen); | |
1489 SelectObject(hdc, candbrush); | |
1490 SetTextColor(hdc, candtextcolor); | |
1491 SetBkMode(hdc, TRANSPARENT); | |
1492 | |
1493 for (i = 0; i < candcount; ++i) | |
1494 { | |
1495 const WCHAR *s = videodata->ime_candidates[i]; | |
1496 int left, top, right, bottom; | |
1497 if (!*s) | |
1498 break; | |
1499 | |
1500 left = listborder + listpadding + candmargin; | |
1501 top = listborder + listpadding + (i * candborder * 2) + (i * candpadding * 2) + ((i + 1) * candmargin) + (i * maxcandsize.cy); | |
1502 if (!vertical) | |
1503 SDL_swap(size.cx, size.cy); | |
1504 | |
1505 right = size.cx - listborder - listpadding - candmargin; | |
1506 if (!vertical) | |
1507 SDL_swap(size.cx, size.cy); | |
1508 | |
1509 bottom = top + maxcandsize.cy + (candpadding * 2) + (candborder * 2); | |
1510 if (!vertical) | |
1511 { | |
1512 SDL_swap(left, top); | |
1513 SDL_swap(right, bottom); | |
1514 } | |
1515 | |
1516 if (i == videodata->ime_candsel) | |
1517 { | |
1518 SelectObject(hdc, selpen); | |
1519 SelectObject(hdc, selbrush); | |
1520 SetTextColor(hdc, seltextcolor); | |
1521 } | |
1522 else | |
1523 { | |
1524 SelectObject(hdc, candpen); | |
1525 SelectObject(hdc, candbrush); | |
1526 SetTextColor(hdc, candtextcolor); | |
1527 } | |
1528 | |
1529 DrawRect(hdc, left, top, right, bottom, candborder); | |
1530 ExtTextOutW(hdc, left + candborder + candpadding, top + candborder + candpadding, 0, NULL, s, SDL_wcslen(s), NULL); | |
1531 } | |
1532 BitmapToTexture(hbm, bits, size.cx, size.cy, &videodata->ime_candtex); | |
1533 StopDrawToBitmap(hdc, &hbm); | |
1534 | |
1535 DeleteObject(listpen); | |
1536 DeleteObject(listbrush); | |
1537 DeleteObject(candpen); | |
1538 DeleteObject(candbrush); | |
1539 DeleteObject(selpen); | |
1540 DeleteObject(selbrush); | |
1541 DeleteObject(font); | |
1542 | |
1543 IME_PositionCandidateList(videodata, size); | |
1544 } | |
1545 | |
1546 static void | |
1547 IME_Render(SDL_VideoData *videodata) | |
1548 { | |
1549 HDC hdc = CreateCompatibleDC(NULL); | |
1550 | |
1551 if (videodata->ime_candlist) | |
1552 IME_RenderCandidateList(videodata, hdc); | |
1553 | |
1554 DeleteDC(hdc); | |
1555 | |
1556 videodata->ime_dirty = SDL_FALSE; | |
1557 } | |
1558 | |
1559 void IME_Present(SDL_VideoData *videodata) | |
1560 { | |
1561 if (videodata->ime_dirty) | |
1562 IME_Render(videodata); | |
1563 | |
1564 SDL_RenderCopy(videodata->ime_candtex, NULL, &videodata->ime_candlistrect); | |
1565 } | |
1566 | |
1019 /* vi: set ts=4 sw=4 expandtab: */ | 1567 /* vi: set ts=4 sw=4 expandtab: */ |