正しい IME の殺し方

正直、どうやったらええのんかなあと。

Windows だと WINNLSEnableIME だかなんだかいう(旧式の)API 一発でとりあえず切り離せたのですが、OS/2 の PM にも似たような API がありまして…

/* 
    PMNLSSSC.15 -> ULONG APIENTRY WinDBCSModeControl(HAB, HWND, ULONG, ULONG, PULONG);
    PMNLSSSC.16 -> ULONG APIENTRY WinDBCSIMEControl(HAB, HWND, ULONG, PIMEMODE);
*/
static HMODULE hmIMDll = NULLHANDLE;
typedef struct my_IMEMODE {
    ULONG lenIMEMODE;
    ULONG fIMEMode;
    ULONG hIME;
    ULONG hModIME;
} myIMEMODE;
static ULONG (APIENTRY *myWinDBCSModeControl)(HAB, HWND, ULONG, ULONG, PULONG);
static ULONG (APIENTRY *myWinDBCSIMEControl)(HAB, HWND, ULONG, myIMEMODE *);

BOOL myDBCSEnableIME(HAB hab, HWND hFrame, BOOL bActive)
{
    ULONG imeEnable = 1;  /* DBE_IMCTL_IMEENABLE */
    ULONG imeDisable = 2; /* DBE_IMCTL_IMEDISABLE */
    ULONG imemodemask = ~(imeEnable | imeDisable);
    BOOL prevmode;
    myIMEMODE imm;

    if (myWinDBCSIMEControl == 0) return FALSE;
    memset(&imm, 0 ,sizeof(imm));
    imm.lenIMEMODE = sizeof(imm);
    (*myWinDBCSIMEControl)(hab, hFrame, 1 /* DBE_IMCTL_QUERY */, &imm);
    prevmode = (imm.fIMEMode & imemodemask) == imeEnable;
    imm.fIMEMode &= imemodemask;
    imm.fIMEMode |= bActive ? imeEnable : imeDisable;
    (*myWinDBCSIMEControl)(hab, hFrame, 2 /* DBE_IMCTL_SET */, &imm);
    return prevmode;
}
ULONG loadIMDll()
{
    ULONG rc;
    PSZ dllname = (PSZ)"PMNLSSSC.DLL";
    HMODULE hm = NULLHANDLE;
    char errpn[_MAX_PATH];
    
    if (hmIMDll) return 0;
    rc = DosLoadModule(errpn, sizeof(errpn), dllname, &hm);
    if (rc != 0) return rc;
    hmIMDll = hm;
    myWinDBCSIMEControl = 0;
    rc = DosQueryProcAddr(hm, 16L, NULL, (PFN *)&myWinDBCSIMEControl);
    if (rc != 0) return rc;
    myWinDBCSModeControl = 0;
    rc = DosQueryProcAddr(hm, 15L, NULL, (PFN *)&myWinDBCSModeControl);
    return rc;
}

OS/2 だと、こういうしょーもない関数ほど Windows に比べて行数多めになるのは何故だろう…いや、API にポインタ引数が多いからですが……)

これで一応 Alt-漢字 を押しても変換モードにはならなくなる…のですが、かな漢以外の日本語入力機能は依然として有効だったりする。つまり全角/半角、ひらがな/カタカナ、英数あたりが利いてしまう。単に各キーに一対一で対応する仮想キーコード(がなければスキャンコードでも可)が欲しいだけのときはまだダメなのでした。WndProc のメッセージを捕まえて NLS 方面の特殊キーコードをどうにかしないとダメなのか(実はこのへん、Windows も似たり寄ったりだけど)。あと Warp V4 以上向けの IM32 API(Win9x で実装された IME 方面の API とほぼ同等、というかクリソツ)でこのへん楽になるとも思えないしなあ。

なんかメンドくさくなってきたので、もっと適当にやっつけることにした。メッセージキューのコードページを非 DBCS 圏に切りかえちゃえば IME とあっさりおさらばできるのですよな、実は。

int SwitchToSBCSCp(HMQ hmq)
{
    int rc = 1;
    ULONG cp;
    
    cp = WinQueryCp(hmq);
    switch(cp) {
      case 932: case 942: /* Japan */
      case 934: case 944: /* Korea */
      case 936: case 946: /* PRC */
      case 938: case 948: /* Taiwan */
        if ((rc = WinSetCp(hmq, 850)) == 0) rc = WinSetCp(hmq, 437);
      default:
        break;
    }
    return rc;
}

しかしウィンドウ内で日本語なんか使わねえ、とか開き直っていないとできないソリューション。

ちなみにメッセージキューと OS/2 システム側のコードページはそれぞれ個別に設定可能で、日本語 OS/2 だとシステムコードページは基本的に 932 と 437 しか選べませんが、メッセージキューのコードページはかなり無節操に選択可能なようです。というか設定可能なコードページのリストを API (WinQueryCpList) で調べたら 108 エントリあったヨ…。