Skip to content

Commit

Permalink
Merge pull request #2816 from nanshiki/sdl2-ime
Browse files Browse the repository at this point in the history
IME input support in SDL2
  • Loading branch information
joncampbell123 authored Aug 20, 2021
2 parents f4fbae6 + efb21fb commit 228ed51
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 16 deletions.
11 changes: 11 additions & 0 deletions src/dosbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,17 @@ void DOSBOX_RealInit() {
dos.im_enable_flag = false;
SDL_SetIMValues(SDL_IM_ENABLE, 0, NULL);
}
#elif (defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11) && defined(C_SDL2)
if (enableime && !control->opt_silent) {
dos.im_enable_flag = true;
SDL_StartTextInput();
#if defined(LINUX)
SDL_SetHint(SDL_HINT_IME_INTERNAL_EDITING, "1");
#endif
} else if (!control->opt_silent) {
dos.im_enable_flag = false;
SDL_StopTextInput();
}
#endif
#if defined(USE_TTF)
if (IS_PC98_ARCH) ttf.cols = 80; // The number of columns on the screen is apparently fixed to 80 in PC-98 mode at this time
Expand Down
105 changes: 96 additions & 9 deletions src/gui/sdlmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,12 @@ void RebootLanguage(std::string filename, bool confirm=false);
bool CodePageHostToGuestUTF16(char *d/*CROSS_LEN*/,const uint16_t *s/*CROSS_LEN*/);
bool CodePageGuestToHostUTF16(uint16_t *d/*CROSS_LEN*/,const char *s/*CROSS_LEN*/);

#if (defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11) && defined(C_SDL2)
static std::string ime_text = "";
extern bool CodePageHostToGuestUTF8(char *d/*CROSS_LEN*/,const char *s/*CROSS_LEN*/);
extern bool IME_GetEnable();
#endif

#if defined(USE_TTF)
Render_ttf ttf;
bool char512 = true;
Expand Down Expand Up @@ -7341,6 +7347,21 @@ static bool CheckEnableImmOnKey(SDL_KeyboardEvent key)
}
return false;
}
#elif defined(WIN32) && !defined(HX_DOS) && defined(C_SDL2)
static bool CheckEnableImmOnKey(SDL_KeyboardEvent key)
{
if(key.keysym.scancode == 0x29 || (key.keysym.scancode >= 0xe0 && key.keysym.scancode <= 0xe6)) {
// ESC, shift, control, alt
return true;
} else if((key.keysym.mod & 0x03) != 0 && key.keysym.scancode == 0x2c) {
// shift + space
return true;
} else if(key.keysym.mod & 0x40) {
// ctrl+
return true;
}
return false;
}
#endif

bool sdl_wait_on_error() {
Expand Down Expand Up @@ -7419,7 +7440,7 @@ void* GetSetSDLValue(int isget, std::string& target, void* setval) {
return NULL;
}

#if (defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11) && !defined(C_SDL2) && defined(SDL_DOSBOX_X_SPECIAL)
#if (defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11) && (defined(C_SDL2) || defined(SDL_DOSBOX_X_SPECIAL))
static uint8_t im_x, im_y;
static uint32_t last_ticks;
void SetIMPosition() {
Expand All @@ -7444,15 +7465,28 @@ void SetIMPosition() {
#endif
uint8_t height = IS_PC98_ARCH?16:real_readb(BIOSMEM_SEG, BIOSMEM_CHAR_HEIGHT);
uint8_t width = CurMode && DOSV_CheckCJKVideoMode() ? CurMode->cwidth : (height / 2);
SDL_Rect rect;
#if defined(USE_TTF)
if (ttf.inUse)
SDL_SetIMPosition(x * ttf.width, y * ttf.height);
else
if (ttf.inUse) {
rect.x = x * ttf.width;
rect.y = y * ttf.height;
} else {
#endif
rect.x = x * width;
#if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */
SDL_SetIMPosition(x * width, y * height - (IS_DOSV?-1:(DOSV_CheckCJKVideoMode()?2:0)) + mainMenu.menuBarHeightBase);
rect.y = y * height - (IS_DOSV?-1:(DOSV_CheckCJKVideoMode()?2:0)) + mainMenu.menuBarHeight;
#else
SDL_SetIMPosition(x * width, y * height - (IS_DOSV?-1:(DOSV_CheckCJKVideoMode()?2:0)));
rect.y = y * height - (IS_DOSV?-1:(DOSV_CheckCJKVideoMode()?2:0));
#endif
#if defined(USE_TTF)
}
#endif
#if defined(C_SDL2)
rect.w = 0;
rect.h = 0;
SDL_SetTextInputRect(&rect);
#else
SDL_SetIMPosition(rect.x, rect.y);
#endif
}
}
Expand Down Expand Up @@ -7919,6 +7953,37 @@ void GFX_Events() {
}
}
break;
#if defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11
case SDL_TEXTEDITING:
ime_text = event.edit.text;
break;
case SDL_TEXTINPUT:
{
int len = strlen(event.text.text);
if(ime_text == event.text.text || len > 1) {
uint8_t* buff;
if((buff = (uint8_t *)malloc(len * 2)) != NULL) {
if(CodePageHostToGuestUTF8((char *)buff, event.text.text)) {
for(int no = 0 ; buff[no] != 0 ; no++) {
if (IS_PC98_ARCH || isDBCSCP()) {
if(dos.loaded_codepage == 932 && isKanji1(buff[no]) && isKanji2(buff[no + 1])) {
BIOS_AddKeyToBuffer(0xf100 | buff[no++]);
BIOS_AddKeyToBuffer(0xf000 | buff[no]);
} else {
BIOS_AddKeyToBuffer(buff[no]);
}
} else {
BIOS_AddKeyToBuffer(buff[no]);
}
}
}
free(buff);
}
SetIMPosition();
}
}
break;
#endif
case SDL_KEYDOWN:
case SDL_KEYUP:
#if defined (WIN32) || defined(MACOSX) || defined(C_SDL2)
Expand All @@ -7930,6 +7995,27 @@ void GFX_Events() {
if (event.key.keysym.sym==SDLK_RSHIFT) sdl.rshiftstate = event.key.type;
if (event.type == SDL_KEYDOWN && isModifierApplied())
ClipKeySelect(event.key.keysym.sym);
if(dos.im_enable_flag) {
#if defined (WIN32)
if(event.type == SDL_KEYDOWN && IME_GetEnable()) {
// Enter, BS, TAB, <-, ->
if(event.key.keysym.sym == 0x0d || event.key.keysym.sym == 0x08 || event.key.keysym.sym == 0x09 || event.key.keysym.scancode == 0x4f || event.key.keysym.scancode == 0x50) {
if(ime_text.size() != 0) {
break;
}
} else if((event.key.keysym.mod & 0x03) == 0 && event.key.keysym.scancode == 0x2c && ime_text.size() == 0) {
// Zenkaku space
BIOS_AddKeyToBuffer(0xf100 | 0x81);
BIOS_AddKeyToBuffer(0xf000 | 0x40);
break;
} else if(!CheckEnableImmOnKey(event.key)) {
break;
}
}
#endif
// Hankaku/Zenkaku
if(event.key.keysym.scancode == 0x35) break;
}
#endif
#if defined (MACOSX)
/* On macs CMD-Q is the default key to close an application */
Expand Down Expand Up @@ -13496,9 +13582,6 @@ int main(int argc, char* argv[]) SDL_MAIN_NOEXCEPT {
dos.loaded_codepage=cp;
}
}
#if defined(WIN32) && (defined(C_SDL2) || !defined(SDL_DOSBOX_X_SPECIAL))
enableime = false;
#endif
#if defined(WIN32) && !defined(HX_DOS)
if (!enableime) ImmDisableIME((DWORD)(-1));
#endif
Expand Down Expand Up @@ -15162,6 +15245,10 @@ int main(int argc, char* argv[]) SDL_MAIN_NOEXCEPT {
SDL_SetIMValues(SDL_IM_ONOFF, 0, NULL);
SDL_SetIMValues(SDL_IM_ENABLE, 0, NULL);
}
#elif defined(WIN32) && !defined(HX_DOS) && defined(C_SDL2)
if (!control->opt_silent) {
SDL_StopTextInput();
}
#endif

//Force visible mouse to end user. Somehow this sometimes doesn't happen
Expand Down
19 changes: 19 additions & 0 deletions src/ints/bios_keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,11 @@ static bool IsEnhancedKey(uint16_t &key) {
return false;
}

#if defined(WIN32) && !defined(HX_DOS) && defined(C_SDL2)
extern void IME_SetEnable(BOOL state);
extern bool IME_GetEnable();
#endif

extern bool DOS_BreakFlag;
extern bool DOS_BreakConioFlag;

Expand Down Expand Up @@ -1264,6 +1269,20 @@ Bitu INT16_Handler(void) {
}
}
}
#elif defined(WIN32) && !defined(HX_DOS) && defined(C_SDL2)
if(IS_DOSV && IS_DOS_CJK && (DOSV_GetFepCtrl() & DOSV_FEP_CTRL_IAS)) {
if(reg_al == 0x00) {
if(reg_dl & 0x81)
IME_SetEnable(TRUE);
else
IME_SetEnable(FALSE);
} else if(reg_al == 0x01) {
if(IME_GetEnable())
reg_dl = 0x81;
else
reg_dl = 0x00;
}
}
#endif
break;
case 0x14:
Expand Down
8 changes: 7 additions & 1 deletion src/ints/int10_modes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2311,17 +2311,23 @@ static VideoModeBlock *ModeListVtext[] = {
ModeList_DOSV_SXGA_24,
};

#if defined(WIN32) && !defined(HX_DOS) && defined(C_SDL2)
extern void IME_SetFontSize(int size);
#endif

bool INT10_SetDOSVModeVtext(uint16_t mode, enum DOSV_VTEXT_MODE vtext_mode)
{
if(SetCurMode(ModeListVtext[vtext_mode], mode)) {
FinishSetMode(true);
INT10_SetCursorShape(6, 7);
#if defined(WIN32) && !defined(HX_DOS) && !defined(C_SDL2) && defined(SDL_DOSBOX_X_SPECIAL)
int cheight = CurMode->cheight;
if(IS_DOSV && cheight == 19) {
cheight = 16;
}
#if defined(WIN32) && !defined(HX_DOS) && !defined(C_SDL2) && defined(SDL_DOSBOX_X_SPECIAL)
SDL_SetIMValues(SDL_IM_FONT_SIZE, cheight, NULL);
#elif defined(WIN32) && !defined(HX_DOS) && defined(C_SDL2)
IME_SetFontSize(cheight);
#endif
} else {
LOG(LOG_INT10, LOG_ERROR)("DOS/V:Trying to set illegal mode %X", mode);
Expand Down
70 changes: 68 additions & 2 deletions src/ints/int_dosv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,58 @@ bool MakeSbcs24Font() {
return true;
}

#if defined(WIN32) && !defined(HX_DOS) && defined(C_SDL2)
extern HWND GetHWND(void);
bool IME_GetEnable()
{
bool state = false;
HWND wnd = GetHWND();
HIMC imc = ImmGetContext(wnd);
if(ImmGetOpenStatus(imc)) {
state = true;
}
ImmReleaseContext(wnd, imc);
return state;
}

void IME_SetEnable(BOOL state)
{
HWND wnd = GetHWND();
HIMC imc = ImmGetContext(wnd);
ImmSetOpenStatus(imc, state);
ImmReleaseContext(wnd, imc);
}

static wchar_t CompositionFontName[LF_FACESIZE];

void IME_SetCompositionFontName(const char *name)
{
int len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
if(len < LF_FACESIZE) {
MultiByteToWideChar(CP_ACP, 0, name, -1, CompositionFontName, len);
}
}

void IME_SetFontSize(int size)
{
HWND wnd = GetHWND();
HIMC imc = ImmGetContext(wnd);
HDC hc = GetDC(wnd);
HFONT hf = (HFONT)GetCurrentObject(hc, OBJ_FONT);
LOGFONTW lf;
GetObjectW(hf, sizeof(lf), &lf);
ReleaseDC(wnd, hc);
if(CompositionFontName[0]) {
wcscpy(lf.lfFaceName, CompositionFontName);
}
lf.lfHeight = -size;
lf.lfWidth = size / 2;
ImmSetCompositionFontW(imc, &lf);
ImmReleaseContext(wnd, imc);
}

#endif

void JFONT_Init() {
#if defined(LINUX) && C_X11
setlocale(LC_CTYPE,"");
Expand All @@ -865,6 +917,8 @@ void JFONT_Init() {
}
#if (defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11) && !defined(C_SDL2) && defined(SDL_DOSBOX_X_SPECIAL)
SDL_SetCompositionFontName(jfont_name);
#elif defined(WIN32) && !defined(HX_DOS) && defined(C_SDL2)
IME_SetCompositionFontName(jfont_name);
#endif
Section_prop *section = static_cast<Section_prop *>(control->GetSection("dosv"));
getsysfont = section->Get_bool("getsysfont");
Expand Down Expand Up @@ -1103,8 +1157,20 @@ static Bitu mskanji_api(void)
real_writew(param_seg, param_off + 2, 0x0009);
}
}
reg_ax = 0;
#elif defined(WIN32) && !defined(HX_DOS) && defined(C_SDL2)
if(mode & 0x8000) {
if(mode & 0x0001)
IME_SetEnable(FALSE);
else if(mode & 0x0002)
IME_SetEnable(TRUE);
} else {
if(IME_GetEnable() == NULL)
real_writew(param_seg, param_off + 2, 0x000a);
else
real_writew(param_seg, param_off + 2, 0x0009);
}
#endif
reg_ax = 0;
}
return CBRET_NONE;
}
Expand Down Expand Up @@ -1439,7 +1505,7 @@ uint8_t GetKanjiAttr()

void INT8_DOSV()
{
#if (defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11) && !defined(C_SDL2) && defined(SDL_DOSBOX_X_SPECIAL)
#if (defined(WIN32) && !defined(HX_DOS) || defined(LINUX) && C_X11) && (defined(C_SDL2) || defined(SDL_DOSBOX_X_SPECIAL))
SetIMPosition();
#endif
if(!CheckAnotherDisplayDriver() && real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE) != 0x72) {
Expand Down
13 changes: 9 additions & 4 deletions vs2015/sdl2/src/video/windows/SDL_windowskeyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,8 @@ IME_Init(SDL_VideoData *videodata, HWND hwnd)
videodata->ime_available = SDL_TRUE;
IME_UpdateInputLocale(videodata);
IME_SetupAPI(videodata);
videodata->ime_uiless = UILess_SetupSinks(videodata);
// Disabled because the candidate window will not be displayed.
//videodata->ime_uiless = UILess_SetupSinks(videodata);
IME_UpdateInputLocale(videodata);
IME_Disable(videodata, hwnd);
}
Expand Down Expand Up @@ -878,14 +879,18 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD
case WM_INPUTLANGCHANGE:
IME_InputLangChanged(videodata);
break;
case WM_IME_CHAR:
trap = SDL_TRUE;
break;
case WM_IME_SETCONTEXT:
*lParam = 0;
// Disabled because the string being converted will not be displayed.
//*lParam = 0;
break;
case WM_IME_STARTCOMPOSITION:
trap = SDL_TRUE;
//trap = SDL_TRUE;
break;
case WM_IME_COMPOSITION:
trap = SDL_TRUE;
//trap = SDL_TRUE;
himc = ImmGetContext(hwnd);
if (*lParam & GCS_RESULTSTR) {
IME_GetCompositionString(videodata, himc, GCS_RESULTSTR);
Expand Down

0 comments on commit 228ed51

Please sign in to comment.