Created
January 28, 2013 15:14
-
-
Save lifthrasiir/4656254 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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