Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IME input support in SDL2 #2816

Merged
merged 1 commit into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -2314,17 +2314,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