Skip to content

Instantly share code, notes, and snippets.

@lifthrasiir
Created January 28, 2013 15:14
Show Gist options
  • Save lifthrasiir/4656254 to your computer and use it in GitHub Desktop.
Save lifthrasiir/4656254 to your computer and use it in GitHub Desktop.
/* MineCJK 0.1 */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include "MineCJK.h"
static JavaVM *jvm;
static int ime_codepage;
typedef struct {
jclass WindowsDisplay; /* of org.lwjgl.opengl */
jclass WindowsImplementation; /* of org.mearie.minecjk */
} userdata_t;
static void minecjk_set_ime_codepage(HKL kbdlayout)
{
char buf[20];
GetLocaleInfo(LOWORD(kbdlayout), LOCALE_IDEFAULTANSICODEPAGE,
buf, sizeof buf);
ime_codepage = atoi(buf);
}
static wchar_t minecjk_ime_codepage_to_unicode(WPARAM wParam)
{
char buf[2];
wchar_t wbuf[1];
int buflen;
if (wParam & 0xff00) {
buf[0] = (unsigned char)(wParam >> 8);
buf[1] = (unsigned char)wParam;
buflen = 2;
} else {
buf[0] = (unsigned char)wParam;
buflen = 1;
}
if (!MultiByteToWideChar(ime_codepage,
MB_COMPOSITE|MB_ERR_INVALID_CHARS,
buf, buflen, wbuf, 1)) {
return (wchar_t)0xfffd;
} else {
return wbuf[0];
}
}
static LRESULT CALLBACK minecjk_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
JNIEnv *env;
userdata_t *ud;
LONG msgtime;
jmethodID handler;
if ((*jvm)->GetEnv(jvm, (void *)&env, JNI_VERSION_1_4)) goto fallback;
if (env == NULL || (*env)->ExceptionOccurred(env)) goto fallback;
ud = (userdata_t*)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (ud == NULL) goto fallback;
switch (msg) {
case WM_INPUTLANGCHANGE:
minecjk_set_ime_codepage((HKL)lParam);
return 0;
case WM_IME_STARTCOMPOSITION: {
HIMC imc = ImmGetContext(hwnd);
COMPOSITIONFORM cf;
RECT workarea;
/* move the composition window out of screen */
SystemParametersInfo(SPI_GETWORKAREA, 0, (void*)&workarea, 0);
cf.dwStyle = CFS_POINT;
cf.ptCurrentPos.x = 0;
cf.ptCurrentPos.y = workarea.bottom + 64;
ImmSetCompositionWindow(imc, &cf);
ImmReleaseContext(hwnd, imc);
handler = (*env)->GetStaticMethodID(env,
ud->WindowsImplementation, "startComposition", "()V");
if (handler == NULL) goto fallback;
(*env)->CallStaticVoidMethod(env, ud->WindowsImplementation, handler);
return 0;
}
case WM_IME_ENDCOMPOSITION:
handler = (*env)->GetStaticMethodID(env,
ud->WindowsImplementation, "endComposition", "()V");
if (handler == NULL) goto fallback;
(*env)->CallStaticVoidMethod(env, ud->WindowsImplementation, handler);
return 0;
case WM_IME_COMPOSITION: {
if (lParam & GCS_COMPSTR) {
HIMC imc = ImmGetContext(hwnd);
int n = ImmGetCompositionStringW(imc, GCS_COMPSTR, NULL, 0);
if (n <= 0) {
ImmReleaseContext(hwnd, imc);
goto fallback;
}
wchar_t buf[(n - 1) / sizeof(wchar_t) + 1];
jstring str;
ImmGetCompositionStringW(imc, GCS_COMPSTR, buf, n);
n = (n - 1) / sizeof(wchar_t) + 1;
handler = (*env)->GetStaticMethodID(env,
ud->WindowsImplementation, "updateComposingString",
"(Ljava/lang/String;)V");
if (handler == NULL) {
ImmReleaseContext(hwnd, imc);
goto fallback;
}
str = (*env)->NewString(env, (jchar*)buf, n);
if (str == NULL) {
ImmReleaseContext(hwnd, imc);
goto fallback;
}
(*env)->CallStaticVoidMethod(env, ud->WindowsImplementation,
handler, str);
ImmReleaseContext(hwnd, imc);
return 0;
}
break;
}
case WM_IME_CHAR:
msgtime = GetMessageTime();
wParam = (WPARAM)minecjk_ime_codepage_to_unicode(wParam);
/* we are going to be more hairy. lwjgl lacks the proper Unicode
* support until very recently (svn r3616), so we cannot directly
* use its own message handler. */
handler = (*env)->GetStaticMethodID(env,
ud->WindowsImplementation, "handleChar", "(JJJ)I");
if (handler == NULL) goto fallback;
return (*env)->CallStaticIntMethod(env,
ud->WindowsImplementation, handler,
(jlong)wParam, (jlong)lParam, (jlong)msgtime);
default:
msgtime = GetMessageTime();
handler = (*env)->GetStaticMethodID(env, ud->WindowsDisplay,
"handleMessage", "(JIJJJ)I");
if (handler == NULL) goto fallback;
return (*env)->CallStaticIntMethod(env, ud->WindowsDisplay,
handler, (jlong)(intptr_t)hwnd, (jint)msg,
(jlong)wParam, (jlong)lParam, (jlong)msgtime);
}
fallback:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
(void)reserved;
jvm = vm;
minecjk_set_ime_codepage(GetKeyboardLayout(0));
return JNI_VERSION_1_4;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
{
(void)vm;
(void)reserved;
}
JNIEXPORT jboolean JNICALL Java_org_mearie_minecjk_WindowsImplementation_replaceWindowProc(JNIEnv *env, jclass unused)
{
jclass dispcls, implcls, winimplcls;
jobject impl;
jmethodID getimpl, gethwnd;
HWND hwnd;
userdata_t *ud;
(void)unused;
/* yes, we are cheating a lot. */
dispcls = (*env)->FindClass(env, "org/lwjgl/opengl/Display");
if (dispcls == NULL) return JNI_FALSE;
getimpl = (*env)->GetStaticMethodID(env, dispcls, "getImplementation",
"()Lorg/lwjgl/opengl/DisplayImplementation;");
if (getimpl == NULL) return JNI_FALSE;
impl = (*env)->CallStaticObjectMethod(env, dispcls, getimpl);
if (impl == NULL) return JNI_FALSE;
implcls = (*env)->FindClass(env, "org/lwjgl/opengl/WindowsDisplay");
if (implcls == NULL) return JNI_FALSE;
gethwnd = (*env)->GetMethodID(env, implcls, "getHwnd", "()J");
if (gethwnd == NULL) return JNI_FALSE;
hwnd = (HWND)(*env)->CallLongMethod(env, impl, gethwnd);
winimplcls = (*env)->FindClass(env, "org/mearie/minecjk/WindowsImplementation");
if (winimplcls == NULL) return JNI_FALSE;
winimplcls = (*env)->NewGlobalRef(env, winimplcls);
if (winimplcls == NULL) return JNI_FALSE;
ud = malloc(sizeof(userdata_t));
if (ud == NULL) return JNI_FALSE;
/* unlike lwjglWindowProc, this function is called long after the initial
* message (that is, WM_CREATE). so we are certain that the jclass pointed
* by GWLP_USERDATA is initialized. */
ud->WindowsDisplay = (jclass)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_USERDATA);
ud->WindowsImplementation = winimplcls;
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)&minecjk_wndproc);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)ud);
return JNI_TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment