Skip to content

Instantly share code, notes, and snippets.

@ponkore
Last active August 13, 2020 12:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ponkore/cff76d28023b648ef728070d1c721c71 to your computer and use it in GitHub Desktop.
Save ponkore/cff76d28023b648ef728070d1c721c71 to your computer and use it in GitHub Desktop.
Windows IME Patch for Emacs27.1 on Windows (derived from https://gist.github.com/rzl24ozi/b4f4b4d729035d3c439b )
diff --git a/lisp/loadup.el b/lisp/loadup.el
index 97525b2..634e6a0 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -311,7 +311,9 @@
(load "w32-vars")
(load "term/w32-win")
(load "disp-table")
+ (load "international/w32-ime")
(when (eq system-type 'windows-nt)
+ (load "image")
(load "w32-fns")
(load "ls-lisp")
(load "dos-w32"))))
diff --git a/lisp/startup.el b/lisp/startup.el
index bff1000..91bde4e 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -643,6 +643,8 @@ normal-top-level
;; `user-full-name' is now known; reset its standard-value here.
(put 'user-full-name 'standard-value
(list (default-value 'user-full-name)))
+ ;; Set language environment for using "Japanese".
+ (set-language-environment "Japanese")
;; If the PWD environment variable isn't accurate, delete it.
(let ((pwd (getenv "PWD")))
(and (stringp pwd)
diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el
index 3e932c7..86fb993 100644
--- a/lisp/term/w32-win.el
+++ b/lisp/term/w32-win.el
@@ -281,6 +281,10 @@ libgnutls-version
'(glib "libglib-2.0-0.dll")
'(gio "libgio-2.0-0.dll")
'(gobject "libgobject-2.0-0.dll")
+ '(magickwand "libMagickWand-6.Q16HDRI-5.dll" "libMagickWand-6.Q16-5.dll"
+ "libMagickWand-6.Q16HDRI-2.dll" "libMagickWand-6.Q16-2.dll")
+ '(magickcore "libMagickCore-6.Q16HDRI-5.dll" "libMagickCore-6.Q16-5.dll"
+ "libMagickCore-6.Q16HDRI-2.dll" "libMagickCore-6.Q16-2.dll")
(if (>= libgnutls-version 30400)
'(gnutls "libgnutls-30.dll")
'(gnutls "libgnutls-28.dll" "libgnutls-26.dll"))
diff --git a/src/frame.c b/src/frame.c
index 4dd8bb1..7001109 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -3776,6 +3776,9 @@ DEFUN ("set-frame-window-state-change", Fset_frame_window_state_change,
{"ns-appearance", SYMBOL_INDEX (Qns_appearance)},
{"ns-transparent-titlebar", SYMBOL_INDEX (Qns_transparent_titlebar)},
#endif
+#ifdef USE_W32_IME
+ {"ime-font", SYMBOL_INDEX (Qime_font)},
+#endif /* USE_W32_IME */
};
#ifdef HAVE_WINDOW_SYSTEM
@@ -6024,6 +6027,9 @@ syms_of_frame (void)
DEFSYM (Qtop_only, "top-only");
DEFSYM (Qiconify_top_level, "iconify-top-level");
DEFSYM (Qmake_invisible, "make-invisible");
+#ifdef USE_W32_IME
+ DEFSYM (Qime_font, "ime-font");
+#endif /* USE_W32_IME */
{
int i;
diff --git a/src/image.c b/src/image.c
index 56878bc..63420e0 100644
--- a/src/image.c
+++ b/src/image.c
@@ -8618,6 +8618,231 @@ imagemagick_initialize (void)
}
}
+#ifdef WINDOWSNT
+DEF_DLL_FN (MagickWand *, CloneMagickWand, (const MagickWand *));
+DEF_DLL_FN (MagickWand *, DestroyMagickWand, (MagickWand *));
+DEF_DLL_FN (MagickWand *, DestroyPixelIterator, (PixelIterator *));
+DEF_DLL_FN (PixelWand *, DestroyPixelWand, (PixelWand *));
+#ifdef HAVE_MAGICKAUTOORIENTIMAGE
+DEF_DLL_FN (MagickBooleanType, MagickAutoOrientImage, (MagickWand *));
+#endif
+DEF_DLL_FN (MagickBooleanType, MagickCropImage, (MagickWand *, const size_t, const size_t, const ssize_t, const ssize_t));
+#ifdef HAVE_MAGICKEXPORTIMAGEPIXELS
+DEF_DLL_FN (MagickBooleanType, MagickExportImagePixels, (MagickWand *, const ssize_t, const ssize_t, const size_t, const size_t, const char *, const StorageType, void *));
+#endif
+DEF_DLL_FN (char *, MagickGetException, (const MagickWand *, ExceptionType *));
+DEF_DLL_FN (MagickWand *, MagickGetImage, (MagickWand *));
+DEF_DLL_FN (DisposeType, MagickGetImageDelay, (MagickWand *));
+DEF_DLL_FN (DisposeType, MagickGetImageDispose, (MagickWand *));
+DEF_DLL_FN (size_t, MagickGetImageHeight, (MagickWand *));
+DEF_DLL_FN (MagickBooleanType, MagickGetImagePage, (MagickWand *, size_t *, size_t *, ssize_t *, ssize_t *));
+DEF_DLL_FN (char *, MagickGetImageSignature, (MagickWand *));
+DEF_DLL_FN (size_t, MagickGetImageWidth, (MagickWand *));
+DEF_DLL_FN (size_t, MagickGetNumberImages, (MagickWand *));
+#ifdef HAVE_MAGICKMERGEIMAGELAYERS
+DEF_DLL_FN (MagickWand *, MagickMergeImageLayers, (MagickWand *, const ImageLayerMethod));
+#else
+DEF_DLL_FN (MagickWand *, MagickFlattenImages, (MagickWand *));
+#endif
+DEF_DLL_FN (MagickBooleanType, MagickReadImage, (MagickWand *, const char *));
+DEF_DLL_FN (MagickBooleanType, MagickReadImageBlob, (MagickWand *, const void *, const size_t));
+DEF_DLL_FN (void *, MagickRelinquishMemory, (void *));
+DEF_DLL_FN (MagickBooleanType, MagickRotateImage, (MagickWand *, const PixelWand *, const double));
+DEF_DLL_FN (MagickBooleanType, MagickScaleImage, (MagickWand *, const size_t, const size_t));
+DEF_DLL_FN (MagickBooleanType, MagickSetDepth, (MagickWand *, const size_t));
+DEF_DLL_FN (MagickBooleanType, MagickSetFilename, (MagickWand *, const char *));
+DEF_DLL_FN (MagickBooleanType, MagickSetImageBackgroundColor, (MagickWand *, const PixelWand *));
+DEF_DLL_FN (MagickBooleanType, MagickSetIteratorIndex, (MagickWand *, const ssize_t));
+DEF_DLL_FN (MagickBooleanType, MagickSetSize, (MagickWand *, const size_t, const size_t));
+DEF_DLL_FN (void, MagickWandGenesis, (void));
+DEF_DLL_FN (void, MagickWandTerminus, (void));
+DEF_DLL_FN (MagickWand *, NewMagickWand, (void));
+DEF_DLL_FN (PixelIterator *, NewPixelIterator, (MagickWand *));
+DEF_DLL_FN (PixelWand *, NewPixelWand, (void));
+DEF_DLL_FN (double, PixelGetAlpha, (const PixelWand *));
+DEF_DLL_FN (void, PixelGetMagickColor, (const PixelWand *, MagickPixelPacket *));
+DEF_DLL_FN (PixelWand **, PixelGetNextIteratorRow, (PixelIterator *, size_t *));
+DEF_DLL_FN (MagickBooleanType, PixelSetIteratorRow, (PixelIterator *, const ssize_t));
+DEF_DLL_FN (void, PixelSetMagickColor, (PixelWand *, const MagickPixelPacket *));
+DEF_DLL_FN (void, PixelSetRed, (PixelWand *, const double));
+DEF_DLL_FN (void, PixelSetGreen, (PixelWand *, const double));
+DEF_DLL_FN (void, PixelSetBlue, (PixelWand *, const double));
+DEF_DLL_FN (MagickBooleanType, PixelSyncIterator, (PixelIterator *));
+
+DEF_DLL_FN (ExceptionInfo *, AcquireExceptionInfo, (void));
+DEF_DLL_FN (ExceptionInfo *, DestroyExceptionInfo, (ExceptionInfo *));
+DEF_DLL_FN (char *, DestroyString, (char *));
+DEF_DLL_FN (char **, GetMagickList, (const char *, size_t *, ExceptionInfo *));
+
+static bool
+init_imagemagick_functions (void)
+{
+ HMODULE magickwand, magickcore;
+
+ if (!(magickcore = w32_delayed_load (Qmagickcore))
+ || !(magickwand = w32_delayed_load (Qmagickwand)))
+ return 0;
+
+ LOAD_DLL_FN (magickwand, CloneMagickWand);
+ LOAD_DLL_FN (magickwand, DestroyMagickWand);
+ LOAD_DLL_FN (magickwand, DestroyPixelIterator);
+ LOAD_DLL_FN (magickwand, DestroyPixelWand);
+#ifdef HAVE_MAGICKAUTOORIENTIMAGE
+ LOAD_DLL_FN (magickwand, MagickAutoOrientImage);
+#endif
+ LOAD_DLL_FN (magickwand, MagickCropImage);
+#ifdef HAVE_MAGICKEXPORTIMAGEPIXELS
+ LOAD_DLL_FN (magickwand, MagickExportImagePixels);
+#endif
+ LOAD_DLL_FN (magickwand, MagickGetException);
+ LOAD_DLL_FN (magickwand, MagickGetImage);
+ LOAD_DLL_FN (magickwand, MagickGetImageDelay);
+ LOAD_DLL_FN (magickwand, MagickGetImageDispose);
+ LOAD_DLL_FN (magickwand, MagickGetImageHeight);
+ LOAD_DLL_FN (magickwand, MagickGetImagePage);
+ LOAD_DLL_FN (magickwand, MagickGetImageSignature);
+ LOAD_DLL_FN (magickwand, MagickGetImageWidth);
+ LOAD_DLL_FN (magickwand, MagickGetNumberImages);
+#ifdef HAVE_MAGICKMERGEIMAGELAYERS
+ LOAD_DLL_FN (magickwand, MagickMergeImageLayers);
+#else
+ LOAD_DLL_FN (magickwand, MagickFlattenImages);
+#endif
+ LOAD_DLL_FN (magickwand, MagickReadImage);
+ LOAD_DLL_FN (magickwand, MagickReadImageBlob);
+ LOAD_DLL_FN (magickwand, MagickRelinquishMemory);
+ LOAD_DLL_FN (magickwand, MagickRotateImage);
+ LOAD_DLL_FN (magickwand, MagickScaleImage);
+ LOAD_DLL_FN (magickwand, MagickSetDepth);
+ LOAD_DLL_FN (magickwand, MagickSetFilename);
+ LOAD_DLL_FN (magickwand, MagickSetImageBackgroundColor);
+ LOAD_DLL_FN (magickwand, MagickSetIteratorIndex);
+ LOAD_DLL_FN (magickwand, MagickSetSize);
+ LOAD_DLL_FN (magickwand, MagickWandGenesis);
+ LOAD_DLL_FN (magickwand, MagickWandTerminus);
+ LOAD_DLL_FN (magickwand, NewMagickWand);
+ LOAD_DLL_FN (magickwand, NewPixelIterator);
+ LOAD_DLL_FN (magickwand, NewPixelWand);
+ LOAD_DLL_FN (magickwand, PixelGetAlpha);
+ LOAD_DLL_FN (magickwand, PixelGetMagickColor);
+ LOAD_DLL_FN (magickwand, PixelGetNextIteratorRow);
+ LOAD_DLL_FN (magickwand, PixelSetIteratorRow);
+ LOAD_DLL_FN (magickwand, PixelSetMagickColor);
+ LOAD_DLL_FN (magickwand, PixelSetRed);
+ LOAD_DLL_FN (magickwand, PixelSetGreen);
+ LOAD_DLL_FN (magickwand, PixelSetBlue);
+ LOAD_DLL_FN (magickwand, PixelSyncIterator);
+
+ LOAD_DLL_FN (magickcore, AcquireExceptionInfo);
+ LOAD_DLL_FN (magickcore, DestroyExceptionInfo);
+ LOAD_DLL_FN (magickcore, DestroyString);
+ LOAD_DLL_FN (magickcore, GetMagickList);
+
+ return 1;
+}
+
+#undef CloneMagickWand
+#undef DestroyMagickWand
+#undef DestroyPixelIterator
+#undef DestroyPixelWand
+#undef MagickAutoOrientImage
+#undef MagickCropImage
+#undef MagickExportImagePixels
+#undef MagickGetException
+#undef MagickGetImage
+#undef MagickGetImageDelay
+#undef MagickGetImageDispose
+#undef MagickGetImageHeight
+#undef MagickGetImagePage
+#undef MagickGetImageSignature
+#undef MagickGetImageWidth
+#undef MagickGetNumberImages
+#ifdef HAVE_MAGICKMERGEIMAGELAYERS
+#undef MagickMergeImageLayers
+#else
+#undef MagickFlattenImages
+#endif
+#undef MagickReadImage
+#undef MagickReadImageBlob
+#undef MagickRelinquishMemory
+#undef MagickRotateImage
+#undef MagickScaleImage
+#undef MagickSetDepth
+#undef MagickSetFilename
+#undef MagickSetImageBackgroundColor
+#undef MagickSetIteratorIndex
+#undef MagickSetSize
+#undef MagickWandGenesis
+#undef MagickWandTerminus
+#undef NewMagickWand
+#undef NewPixelIterator
+#undef NewPixelWand
+#undef PixelGetAlpha
+#undef PixelGetMagickColor
+#undef PixelGetNextIteratorRow
+#undef PixelSetIteratorRow
+#undef PixelSetMagickColor
+#undef PixelSetRed
+#undef PixelSetGreen
+#undef PixelSetBlue
+#undef PixelSyncIterator
+#undef AcquireExceptionInfo
+#undef DestroyExceptionInfo
+#undef DestroyString
+#undef GetMagickList
+
+#define CloneMagickWand fn_CloneMagickWand
+#define DestroyMagickWand fn_DestroyMagickWand
+#define DestroyPixelIterator fn_DestroyPixelIterator
+#define DestroyPixelWand fn_DestroyPixelWand
+#define MagickAutoOrientImage fn_MagickAutoOrientImage
+#define MagickCropImage fn_MagickCropImage
+#define MagickExportImagePixels fn_MagickExportImagePixels
+#define MagickGetException fn_MagickGetException
+#define MagickGetImage fn_MagickGetImage
+#define MagickGetImageDelay fn_MagickGetImageDelay
+#define MagickGetImageDispose fn_MagickGetImageDispose
+#define MagickGetImageHeight fn_MagickGetImageHeight
+#define MagickGetImagePage fn_MagickGetImagePage
+#define MagickGetImageSignature fn_MagickGetImageSignature
+#define MagickGetImageWidth fn_MagickGetImageWidth
+#define MagickGetNumberImages fn_MagickGetNumberImages
+#ifdef HAVE_MAGICKMERGEIMAGELAYERS
+#define MagickMergeImageLayers fn_MagickMergeImageLayers
+#else
+#define MagickFlattenImages fn_MagickFlattenImages
+#endif
+#define MagickReadImage fn_MagickReadImage
+#define MagickReadImageBlob fn_MagickReadImageBlob
+#define MagickRelinquishMemory fn_MagickRelinquishMemory
+#define MagickRotateImage fn_MagickRotateImage
+#define MagickScaleImage fn_MagickScaleImage
+#define MagickSetDepth fn_MagickSetDepth
+#define MagickSetFilename fn_MagickSetFilename
+#define MagickSetImageBackgroundColor fn_MagickSetImageBackgroundColor
+#define MagickSetIteratorIndex fn_MagickSetIteratorIndex
+#define MagickSetSize fn_MagickSetSize
+#define MagickWandGenesis fn_MagickWandGenesis
+#define MagickWandTerminus fn_MagickWandTerminus
+#define NewMagickWand fn_NewMagickWand
+#define NewPixelIterator fn_NewPixelIterator
+#define NewPixelWand fn_NewPixelWand
+#define PixelGetAlpha fn_PixelGetAlpha
+#define PixelGetMagickColor fn_PixelGetMagickColor
+#define PixelGetNextIteratorRow fn_PixelGetNextIteratorRow
+#define PixelSetIteratorRow fn_PixelSetIteratorRow
+#define PixelSetMagickColor fn_PixelSetMagickColor
+#define PixelSetRed fn_PixelSetRed
+#define PixelSetGreen fn_PixelSetGreen
+#define PixelSetBlue fn_PixelSetBlue
+#define PixelSyncIterator fn_PixelSyncIterator
+#define AcquireExceptionInfo fn_AcquireExceptionInfo
+#define DestroyExceptionInfo fn_DestroyExceptionInfo
+#define DestroyString fn_DestroyString
+#define GetMagickList fn_GetMagickList
+
+#endif /* !WINDOWSNT */
+
/* Log ImageMagick error message.
Useful when an ImageMagick function returns the status `MagickFalse'. */
@@ -9299,6 +9524,11 @@ DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
size_t i;
imagemagick_initialize ();
+#if WINDOWSNT
+ if (!init_imagemagick_functions ())
+ return Qnil;
+#endif
+
ex = AcquireExceptionInfo ();
imtypes = GetMagickList ("*", &numf, ex);
DestroyExceptionInfo (ex);
@@ -10338,6 +10568,10 @@ syms_of_image (void)
#if defined (HAVE_IMAGEMAGICK)
DEFSYM (Qimagemagick, "imagemagick");
add_image_type (Qimagemagick);
+#if defined HAVE_NTGUI && !defined CYGWIN
+ DEFSYM (Qmagickwand, "magickwand");
+ DEFSYM (Qmagickcore, "magickcore");
+#endif /* HAVE_NTGUI */
#endif
#if defined (HAVE_RSVG)
diff --git a/src/keyboard.c b/src/keyboard.c
index 5f136f0..576d699 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4594,7 +4594,11 @@ #define FUNCTION_KEY_OFFSET 0x0
"junja", /* VK_JUNJA 0x17 */
"final", /* VK_FINAL 0x18 */
"kanji", /* VK_KANJI/VK_HANJA 0x19 */
+#ifdef USE_W32_IME
+ "compend", /* VK_COMPEND 0x1A */
+#else
0, /* 0x1A */
+#endif /* USE_W32_IME */
"escape", /* VK_ESCAPE 0x1B */
"convert", /* VK_CONVERT 0x1C */
"non-convert", /* VK_NONCONVERT 0x1D */
@@ -9305,6 +9309,12 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
{
ptrdiff_t count = SPECPDL_INDEX ();
+ /* To control IME */
+#ifdef USE_W32_IME
+ Lisp_Object VIME_command_off_flag = Qnil;
+ Lisp_Object IME_command_loop_flag = Qnil;
+#endif /* USE_W32_IME */
+
/* How many keys there are in the current key sequence. */
int t;
@@ -9426,6 +9436,12 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
keybuf[0..mock_input] holds the sequence we should reread. */
replay_sequence:
+#ifdef USE_W32_IME
+/* If key sequences are to replay, IME_loop_flag should not be set.
+ Because event has never been occured. */
+ IME_command_loop_flag = Qnil;
+#endif /* USE_W32_IME */
+
starting_buffer = current_buffer;
first_unbound = READ_KEY_ELTS + 1;
Lisp_Object first_event = mock_input > 0 ? keybuf[0] : Qnil;
@@ -9508,6 +9524,16 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
goto replay_sequence;
}
+#ifdef USE_W32_IME
+ if (!NILP (IME_command_loop_flag) && NILP (VIME_command_off_flag))
+ {
+ VIME_command_off_flag = Fime_get_mode ();
+ if (!NILP (VIME_command_off_flag))
+ Fime_force_off (Qnil);
+ }
+ IME_command_loop_flag = Qt;
+#endif /* USE_W32_IME */
+
if (t >= READ_KEY_ELTS)
error ("Key sequence too long");
@@ -10192,6 +10218,12 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
? Fcommand_remapping (read_key_sequence_cmd, Qnil, Qnil)
: Qnil;
+ /* to control IME */
+#ifdef USE_W32_IME
+ if (!NILP (VIME_command_off_flag))
+ Fime_force_on (Qnil);
+#endif /* USE_W32_IME */
+
unread_switch_frame = delayed_switch_frame;
unbind_to (count, Qnil);
diff --git a/src/w32fns.c b/src/w32fns.c
index 2f01fb5..8256e27 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -59,6 +59,11 @@ #define _WIN32_WINNT 0x0600
#include "pdumper.h"
+#ifdef USE_W32_IME
+#include "fontset.h"
+#include "w32font.h"
+#endif
+
#include <basetyps.h>
#include <unknwn.h>
#include <commctrl.h>
@@ -86,6 +91,44 @@ #define FOF_NO_CONNECTED_ELEMENTS 0x2000
#define IDC_HAND MAKEINTRESOURCE(32649)
#endif
+#ifdef USE_W32_IME
+#ifdef RECONVERSION
+#define CHRSZ sizeof(short)
+#define RECONV_LENG 100
+#define DOCFEED_LENG 100
+static LRESULT w32_get_ime_reconversion_string (HWND, RECONVERTSTRING*);
+static BOOL w32_perform_reconversion (HWND, RECONVERTSTRING*);
+#ifdef DOCUMENTFEED
+#define DOCFEED_CSTR_LENG 64
+static LRESULT w32_get_ime_documentfeed_string (HWND, RECONVERTSTRING*);
+#endif
+#endif
+static int set_ime_font = 0;
+static LOGFONT ime_logfont = {0};
+static int IME_event_off_count;
+const char * const ImmGetOpenStatus_Name = "ImmGetOpenStatus";
+const char * const ImmSetOpenStatus_Name = "ImmSetOpenStatus";
+const char * const ImmSetCompositionWindow_Name = "ImmSetCompositionWindow";
+const char * const ImmGetContext_Name = "ImmGetContext";
+const char * const ImmGetConversionStatus_Name = "ImmGetConversionStatus";
+const char * const ImmSetConversionStatus_Name = "ImmSetConversionStatus";
+const char * const ImmNotifyIME_Name = "ImmNotifyIME";
+
+const char * const ImmReleaseContext_Name = "ImmReleaseContext";
+const char * const ImmCreateContext_Name = "ImmCreateContext";
+const char * const ImmDestroyContext_Name = "ImmDestroyContext";
+const char * const ImmAssociateContext_Name = "ImmAssociateContext";
+const char * const ImmGetHotKey_Name = "ImmGetHotKey";
+const char * const ImmGetProperty_Name = "ImmGetProperty";
+const char * const ImmGetCompositionString_Name = "ImmGetCompositionStringW";
+const char * const ImmSetCompositionString_Name = "ImmSetCompositionStringW";
+const char * const ImmSetCompositionFont_Name = "ImmSetCompositionFontA"; /* LOGFONTA */
+const char * const ImmGetConversionList_Name = "ImmGetConversionListW";
+const char * const ImmConfigureIME_Name = "ImmConfigureIMEW";
+const char * const ImmGetCandidateList_Name = "ImmGetCandidateListW";
+const char * const ImmGetCandidateListCount_Name = "ImmGetCandidateListCountW";
+#endif
+
/* Prefix for system colors. */
#define SYSTEM_COLOR_PREFIX "System"
#define SYSTEM_COLOR_PREFIX_LEN (sizeof (SYSTEM_COLOR_PREFIX) - 1)
@@ -160,12 +203,14 @@ DECLARE_HANDLE(HMONITOR);
typedef BOOL (WINAPI * TrackMouseEvent_Proc)
(IN OUT LPTRACKMOUSEEVENT lpEventTrack);
+#ifndef USE_W32_IME
typedef LONG (WINAPI * ImmGetCompositionString_Proc)
(IN HIMC context, IN DWORD index, OUT LPVOID buffer, IN DWORD bufLen);
typedef HIMC (WINAPI * ImmGetContext_Proc) (IN HWND window);
typedef BOOL (WINAPI * ImmReleaseContext_Proc) (IN HWND wnd, IN HIMC context);
typedef BOOL (WINAPI * ImmSetCompositionWindow_Proc) (IN HIMC context,
IN COMPOSITIONFORM *form);
+#endif /* !USE_W32_IME */
typedef HMONITOR (WINAPI * MonitorFromPoint_Proc) (IN POINT pt, IN DWORD flags);
typedef BOOL (WINAPI * GetMonitorInfo_Proc)
(IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
@@ -183,10 +228,12 @@ DECLARE_HANDLE(HMONITOR);
(HANDLE hThread, PCWSTR lpThreadDescription);
TrackMouseEvent_Proc track_mouse_event_fn = NULL;
+#ifndef USE_W32_IME
ImmGetCompositionString_Proc get_composition_string_fn = NULL;
ImmGetContext_Proc get_ime_context_fn = NULL;
ImmReleaseContext_Proc release_ime_context_fn = NULL;
ImmSetCompositionWindow_Proc set_ime_composition_window_fn = NULL;
+#endif /* !USE_W32_IME */
MonitorFromPoint_Proc monitor_from_point_fn = NULL;
GetMonitorInfo_Proc get_monitor_info_fn = NULL;
MonitorFromWindow_Proc monitor_from_window_fn = NULL;
@@ -197,8 +244,13 @@ DECLARE_HANDLE(HMONITOR);
extern AppendMenuW_Proc unicode_append_menu;
+#ifdef USE_W32_IME
+/* Flag for indicating in conversion in IME. */
+int ime_in_conversion = 0;
+#else
/* Flag to selectively ignore WM_IME_CHAR messages. */
static int ignore_ime_char = 0;
+#endif
/* W95 mousewheel handler */
unsigned int msh_mousewheel = 0;
@@ -803,6 +855,15 @@ w32_color_map_lookup (const char *colorname)
return ret;
}
+#ifdef USE_W32_IME
+static void w32_set_ime_conv_window (HWND, struct frame *);
+static void w32_set_ime_status (HWND, int);
+static int w32_get_ime_status (HWND);
+static int w32_set_ime_mode (HWND, int, int);
+static void w32_set_ime_font (HWND);
+static BOOL w32_get_ime_composition_string (HWND);
+static LRESULT CALLBACK conversion_agent_wndproc (HWND, UINT, WPARAM, LPARAM);
+#endif /* USE_W32_IME */
static void
add_system_logical_colors_to_map (Lisp_Object *system_colors)
@@ -2492,6 +2553,8 @@ w32_createwindow (struct frame *f, int *coords)
if (hwnd)
{
+ static int initialized = 0;
+
if (FRAME_SKIP_TASKBAR (f))
SetWindowLong (hwnd, GWL_EXSTYLE,
GetWindowLong (hwnd, GWL_EXSTYLE) | WS_EX_NOACTIVATE);
@@ -2503,6 +2566,12 @@ w32_createwindow (struct frame *f, int *coords)
SetWindowLong (hwnd, WND_HSCROLLBAR_INDEX, FRAME_SCROLL_BAR_AREA_HEIGHT (f));
SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
+ if (!initialized && (w32_major_version > 6 || (w32_major_version == 6 && w32_minor_version >= 2)))
+ {
+ ShowWindow (hwnd, SW_MINIMIZE); ShowWindow (hwnd, SW_RESTORE);
+ initialized = 1;
+ }
+
/* Enable drag-n-drop. */
DragAcceptFiles (hwnd, TRUE);
@@ -4521,6 +4590,24 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
TranslateMessage (&windows_msg);
goto dflt;
}
+#ifdef USE_W32_IME
+ else
+ {
+ MSG ime_undo_test_msg;
+
+ if (wParam == VK_BACK
+ && ctrl_modifier == w32_get_key_modifiers (wParam, lParam)
+ && w32_get_ime_status (hwnd) != 0
+ && PeekMessage (&ime_undo_test_msg, hwnd, WM_KEYDOWN, WM_KEYDOWN, PM_NOYIELD | PM_NOREMOVE) != 0
+ && ime_undo_test_msg.wParam == VK_BACK
+ && ime_undo_test_msg.lParam == 0x40000001
+ )
+ {
+ post_character_message (hwnd, msg, wParam, lParam, 0);
+ break;
+ }
+ }
+#endif
/* Fall through */
FALLTHROUGH;
@@ -4540,6 +4627,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
w32_get_key_modifiers (wParam, lParam));
break;
+#ifndef USE_W32_IME
case WM_UNICHAR:
/* WM_UNICHAR looks promising from the docs, but the exact
circumstances in which TranslateMessage sends it is one of those
@@ -4664,6 +4752,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_IME_ENDCOMPOSITION:
ignore_ime_char = 0;
goto dflt;
+#endif /* USE_W32_IME */
/* Simulate middle mouse button events when left and right buttons
are used together, but only if user has two button mouse. */
@@ -5487,8 +5576,89 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_EMACS_FILENOTIFY:
my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
return 1;
+#ifdef USE_W32_IME
+ case WM_IME_NOTIFY:
+ if (wParam == IMN_SETOPENSTATUS)
+ {
+ if (w32_get_ime_status(hwnd)){
+ struct frame *f = w32_window_to_frame (dpyinfo, hwnd);
+ if (f) {
+ set_ime_font = 0;
+ w32_set_ime_conv_window (hwnd, f);
+ }
+ }
+ if (!IME_event_off_count)
+ my_post_msg (&wmsg, hwnd, WM_MULE_IME_STATUS, 0, 0);
+ else
+ IME_event_off_count--;
+ }
+ goto dflt;
+
+ case WM_IME_STARTCOMPOSITION:
+ {
+ struct frame *f = w32_window_to_frame (dpyinfo, hwnd);
+ if (f && !set_ime_font)
+ {
+ my_post_msg (&wmsg, hwnd, WM_MULE_IME_SET_FONT, (WPARAM) f, 0);
+ set_ime_font = 1;
+ }
+ }
+ ime_in_conversion = 1;
+ goto dflt;
+
+ case WM_IME_ENDCOMPOSITION:
+ ime_in_conversion = 0;
+ goto dflt;
+
+ case WM_IME_SETCONTEXT:
+ set_ime_font = 0;
+ goto dflt;
+
+ case WM_IME_COMPOSITION:
+ if (lParam & GCS_RESULTSTR)
+ {
+ if (w32_get_ime_composition_string (hwnd))
+ return 0;
+ else
+ break;
+ }
+ goto dflt;
+
+#ifdef RECONVERSION
+ case WM_IME_REQUEST:
+ if (wParam == IMR_RECONVERTSTRING)
+ {
+ if (!ime_enable_reconversion || !w32_get_ime_status (hwnd))
+ return 0;
+ if (lParam)
+ return w32_get_ime_reconversion_string (hwnd,
+ (RECONVERTSTRING*) lParam);
+ else
+ return sizeof (RECONVERTSTRING) + (RECONV_LENG * 2 + 1) * CHRSZ;
+ }
+#ifdef DOCUMENTFEED
+ else if (wParam == IMR_DOCUMENTFEED)
+ {
+ if (!ime_enable_document_feed)
+ return 0;
+ if (lParam)
+ return w32_get_ime_documentfeed_string (hwnd,
+ (RECONVERTSTRING*) lParam);
+ else
+ return sizeof (RECONVERTSTRING) + (DOCFEED_LENG * 2 + DOCFEED_CSTR_LENG + 1) * CHRSZ;
+ }
+#endif
+ goto dflt;
+#endif
+#endif /* USE_W32_IME */
default:
+
+#ifdef USE_W32_IME
+ if (MESSAGE_IMM_COM_P(msg))
+ return conversion_agent_wndproc (hwnd, msg, wParam, lParam);
+#endif /* USE_W32_IME */
+
/* Check for messages registered at runtime. */
if (msg == msh_mousewheel)
{
@@ -8145,6 +8315,992 @@ DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
#endif /* WINDOWSNT */
+
+/***********************************************************************
+ Input Method Editor
+ ***********************************************************************/
+#ifdef USE_W32_IME
+BOOL fIME = FALSE;
+
+typedef BOOL (WINAPI *IMMGETOPENSTATUSPROC)(HIMC);
+IMMGETOPENSTATUSPROC ImmGetOpenStatusProc;
+
+typedef BOOL (WINAPI *IMMSETOPENSTATUSPROC)(HIMC, BOOL);
+IMMSETOPENSTATUSPROC ImmSetOpenStatusProc;
+
+typedef BOOL (WINAPI *IMMSETCOMPOSITIONWINDOWPROC)(HIMC, LPCOMPOSITIONFORM);
+IMMSETCOMPOSITIONWINDOWPROC ImmSetCompositionWindowProc;
+
+typedef LONG (WINAPI *IMMGETCOMPOSITIONSTRINGPROC)
+ (HIMC, DWORD, LPVOID, DWORD);
+IMMGETCOMPOSITIONSTRINGPROC ImmGetCompositionStringProc;
+
+typedef LONG (WINAPI *IMMSETCOMPOSITIONSTRINGPROC)
+ (HIMC, DWORD, LPCVOID, DWORD, LPCVOID, DWORD);
+IMMSETCOMPOSITIONSTRINGPROC ImmSetCompositionStringProc;
+
+typedef BOOL (WINAPI *IMMSETCOMPOSITIONFONTPROC) (HIMC, LPLOGFONTA);
+IMMSETCOMPOSITIONFONTPROC ImmSetCompositionFontProc;
+
+typedef HIMC (WINAPI *IMMGETCONTEXTPROC)(HWND);
+IMMGETCONTEXTPROC ImmGetContextProc;
+
+typedef BOOL (WINAPI *IMMGETCONVERSIONSTATUSPROC)(HIMC, LPDWORD, LPDWORD);
+IMMGETCONVERSIONSTATUSPROC ImmGetConversionStatusProc;
+
+typedef BOOL (WINAPI *IMMSETCONVERSIONSTATUSPROC)(HIMC, DWORD, DWORD);
+IMMSETCONVERSIONSTATUSPROC ImmSetConversionStatusProc;
+
+typedef BOOL (WINAPI *IMMGETCONVERSIONLISTPROC)
+ (HKL, HIMC, LPCTSTR, LPCANDIDATELIST, DWORD, UINT);
+IMMGETCONVERSIONLISTPROC ImmGetConversionListProc;
+
+typedef BOOL (WINAPI *IMMCONFIGUREIMEPROC)(HKL, HWND, DWORD, LPVOID);
+IMMCONFIGUREIMEPROC ImmConfigureIMEProc;
+
+typedef BOOL (WINAPI *IMMNOTIFYIMEPROC)(HIMC, DWORD, DWORD, DWORD);
+IMMNOTIFYIMEPROC ImmNotifyIMEProc;
+
+typedef BOOL (WINAPI *IMMRELEASECONTEXTPROC)(HWND, HIMC);
+IMMRELEASECONTEXTPROC ImmReleaseContextProc;
+
+typedef HIMC (WINAPI *IMMCREATECONTEXTPROC)(void);
+IMMCREATECONTEXTPROC ImmCreateContextProc;
+
+typedef BOOL (WINAPI *IMMDESTROYCONTEXTPROC)(HIMC);
+IMMDESTROYCONTEXTPROC ImmDestroyContextProc;
+
+typedef HIMC (WINAPI *IMMASSOCIATECONTEXTPROC) (HWND, HIMC);
+IMMASSOCIATECONTEXTPROC ImmAssociateContextProc;
+
+typedef BOOL (WINAPI *IMMGETCANDIDATELISTPROC)
+ (HIMC, DWORD, LPCANDIDATELIST, DWORD);
+IMMGETCANDIDATELISTPROC ImmGetCandidateListProc;
+
+typedef BOOL (WINAPI *IMMGETCANDIDATELISTCOUNTPROC) (HIMC, LPDWORD);
+IMMGETCANDIDATELISTCOUNTPROC ImmGetCandidateListCountProc;
+
+typedef BOOL (WINAPI *IMMGETHOTKEYPROC)(DWORD, LPUINT, LPUINT, LPHKL);
+IMMGETHOTKEYPROC ImmGetHotKeyProc;
+
+typedef BOOL (WINAPI *IMMGETPROPERTYPROC)(HKL, DWORD);
+IMMGETPROPERTYPROC ImmGetPropertyProc;
+
+// Lisp_Object Vime_control;
+
+static void
+w32_set_ime_conv_window (HWND hwnd, struct frame *f)
+{
+ if (fIME && !NILP (Vime_control))
+ {
+ HIMC himc;
+ COMPOSITIONFORM compform;
+ struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+
+ /* If Vw32_ime_composition_window is set, try it. */
+ if (!NILP (Vw32_ime_composition_window)
+ && WINDOWP (Vw32_ime_composition_window)
+ && EQ (WINDOW_FRAME (XWINDOW (Vw32_ime_composition_window)),
+ WINDOW_FRAME (w)))
+ w = XWINDOW (Vw32_ime_composition_window);
+
+ himc = (ImmGetContextProc) (hwnd);
+ compform.dwStyle = CFS_RECT;
+
+ compform.ptCurrentPos.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+
+ compform.ptCurrentPos.y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y);
+#if 0
+ if (FRAME_FONT (f)->vertical_centering == 1)
+ compform.ptCurrentPos.y += FRAME_FONT (f)->baseline_offset;
+#endif
+
+ compform.rcArea.left = (WINDOW_BOX_LEFT_EDGE_X (w)
+ + WINDOW_LEFT_MARGIN_WIDTH (w)
+ + WINDOW_LEFT_FRINGE_WIDTH (w));
+
+ compform.rcArea.top = (WINDOW_TOP_EDGE_Y (w)
+ + WINDOW_HEADER_LINE_HEIGHT (w));
+
+ compform.rcArea.right = (WINDOW_BOX_RIGHT_EDGE_X (w)
+ - WINDOW_RIGHT_MARGIN_WIDTH (w)
+ - WINDOW_RIGHT_FRINGE_WIDTH (w)) + 1;
+
+ compform.rcArea.bottom = (WINDOW_BOTTOM_EDGE_Y (w)
+ - WINDOW_MODE_LINE_HEIGHT (w));
+
+ (ImmSetCompositionWindowProc) (himc, &compform);
+ (ImmReleaseContextProc) (hwnd, himc);
+ }
+}
+
+static void
+w32_set_ime_status (HWND hwnd, int openp)
+{
+ HIMC himc;
+
+ himc = (ImmGetContextProc) (hwnd);
+ (ImmSetOpenStatusProc) (himc, openp);
+ (ImmReleaseContextProc) (hwnd, himc);
+}
+
+static int
+w32_get_ime_status (HWND hwnd)
+{
+ HIMC himc;
+ int ret;
+
+ himc = (ImmGetContextProc) (hwnd);
+ ret = (ImmGetOpenStatusProc) (himc);
+ (ImmReleaseContextProc) (hwnd, himc);
+
+ return ret;
+}
+
+static int
+w32_set_ime_mode (HWND hwnd, int mode, int mask)
+{
+ HIMC himc;
+ DWORD cmode, smode;
+
+ himc = (ImmGetContextProc) (hwnd);
+ if (!(ImmGetConversionStatusProc) (himc, &cmode, &smode))
+ return 0;
+
+ cmode = (cmode & (~mask)) | (mode & mask);
+
+ (ImmSetConversionStatusProc) (himc, cmode, smode);
+ (ImmReleaseContextProc) (hwnd, himc);
+
+ return 1;
+}
+
+static BOOL
+w32_get_ime_composition_string (HWND hwnd)
+{
+ HIMC hIMC;
+ int size;
+ HANDLE himestr;
+
+ struct frame *f;
+
+ hIMC = (ImmGetContextProc) (hwnd);
+ if (!hIMC)
+ return FALSE;
+
+ size = (ImmGetCompositionStringProc) (hIMC, GCS_RESULTSTR, NULL, 0);
+ size += sizeof (WCHAR);
+ himestr = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, size);
+ if (!himestr)
+ abort ();
+
+ (ImmGetCompositionStringProc) (hIMC, GCS_RESULTSTR, himestr, size);
+ (ImmReleaseContextProc) (hwnd, hIMC);
+ {
+ W32Msg wmsg;
+ f = SELECTED_FRAME ();
+ my_post_msg (&wmsg, hwnd, WM_MULE_IME_REPORT,
+ (WPARAM) himestr, (LPARAM) f);
+ }
+ return TRUE;
+}
+
+#ifdef RECONVERSION
+
+static EMACS_INT compstr_beginning_pos(int max_char)
+{
+ EMACS_INT bol, point = PT, pt;
+ for (bol = XFIXNAT(Fline_beginning_position(Qnil)), pt = PT;
+ PT >= bol && PT > point - max_char; ) {
+ pt = PT;
+ if (NILP(Fforward_word (make_fixnum (-1))))
+ break;
+ }
+ Fgoto_char (make_fixnum(point));
+ return pt;
+}
+
+static EMACS_INT compstr_end_pos(int max_char)
+{
+ EMACS_INT eol, point = PT, pt;
+
+ for (eol = XFIXNAT(Fline_end_position(Qnil)), pt = PT;
+ PT <= eol && PT < point + max_char;) {
+ pt = PT;
+ if (NILP(Fforward_word (make_fixnum (1))))
+ break;
+ }
+ Fgoto_char (make_fixnum(point));
+ return pt;
+}
+
+static LRESULT
+get_reconversion_string (HWND hwnd,
+ RECONVERTSTRING *reconv,
+ unsigned short *compstr)
+{
+ EMACS_INT pt, pt_byte, start, end, len, t_start, t_end, compstr_len;
+ W32Msg wmsg;
+
+ if (!NILP (BVAR (current_buffer, read_only)))
+ return 0;
+
+ pt = PT;
+ pt_byte = PT_BYTE;
+
+ if (compstr)
+ {
+ t_start = t_end = PT;
+ start = compstr_beginning_pos (DOCFEED_LENG);
+ end = compstr_end_pos (DOCFEED_LENG);
+ }
+ else if (!NILP (BVAR (current_buffer, mark_active))
+ && !NILP (Vtransient_mark_mode))
+ {
+ if (marker_position (BVAR (current_buffer, mark)) < PT)
+ {
+ t_start = marker_position (BVAR (current_buffer, mark));
+ t_end = PT;
+ }
+ else
+ {
+ t_start = PT;
+ t_end = marker_position (BVAR (current_buffer, mark));
+ }
+ Fgoto_char (make_fixnum (t_end));
+ while (!NILP (Fbolp ()) && t_start < PT)
+ Fforward_char (make_fixnum (-1));
+ if (t_start >= PT)
+ return 0;
+ t_end = PT;
+ }
+ else
+ {
+ if (NILP (Feobp ()))
+ Fforward_char (make_fixnum (1));
+ if (!NILP (Fforward_word (make_fixnum (-1))))
+ t_start = PT;
+ else
+ {
+ SET_PT_BOTH (pt, pt_byte);
+ return 0;
+ }
+ Fforward_word (make_fixnum (1));
+ t_end = PT;
+ SET_PT_BOTH (pt, pt_byte);
+ if (t_end < PT)
+ return 0;
+ }
+
+ if (!compstr)
+ {
+ if (t_start == t_end)
+ return 0;
+
+ Fgoto_char (make_fixnum (t_start));
+ start = compstr_beginning_pos (RECONV_LENG);
+ Fgoto_char (make_fixnum (t_end));
+ end = compstr_end_pos (RECONV_LENG);
+ }
+
+ len = end - start;
+ if (reconv)
+ {
+ int pos;
+ WCHAR *s;
+
+ s = (WCHAR *) (reconv + 1);
+
+ for (pos = start; pos < t_start; pos++)
+ *s++ = (WCHAR) FETCH_CHAR (CHAR_TO_BYTE (pos));
+
+ if (compstr)
+ {
+ for (compstr_len = 0; compstr[compstr_len]; compstr_len++)
+ *s++ = compstr[compstr_len];
+
+ len += compstr_len;
+ }
+ else
+ compstr_len = t_end - t_start;
+
+ for (; pos < end; pos++)
+ *s++ = (WCHAR) FETCH_CHAR (CHAR_TO_BYTE (pos));
+
+ *s = 0;
+ }
+ else
+ {
+ SET_PT_BOTH (pt, pt_byte);
+ if (compstr)
+ {
+ for (compstr_len = 0; compstr[compstr_len]; compstr_len++)
+ ;
+
+ len += compstr_len;
+ }
+ return (sizeof (RECONVERTSTRING) + (len + 1) * CHRSZ);
+ }
+
+ reconv->dwStrOffset = sizeof (RECONVERTSTRING);
+ reconv->dwStrLen = len;
+ reconv->dwCompStrOffset =
+ reconv->dwTargetStrOffset = (t_start - start) * CHRSZ;
+ reconv->dwCompStrLen =
+ reconv->dwTargetStrLen = compstr_len;
+
+ if (!compstr)
+ my_post_msg (&wmsg, hwnd, WM_MULE_IME_DEL_RANGE, (WPARAM) t_start, (LPARAM) t_end);
+
+ return (reconv->dwSize = sizeof (RECONVERTSTRING) + (len + 1) * CHRSZ);
+}
+
+static LRESULT
+w32_get_ime_reconversion_string (HWND hwnd,
+ RECONVERTSTRING *reconv)
+{
+ return get_reconversion_string (hwnd, reconv, NULL);
+}
+#endif /* RECONVERSION */
+
+#if defined(DOCUMENTFEED)
+static LRESULT
+w32_get_ime_documentfeed_string (HWND hwnd,
+ RECONVERTSTRING *reconv)
+{
+ unsigned short ime_compstr[DOCFEED_CSTR_LENG];
+ HIMC hIMC;
+ LONG l;
+
+ if ((hIMC = (ImmGetContextProc) (hwnd)))
+ {
+ if ((ImmGetCompositionStringProc) (hIMC, GCS_COMPSTR, NULL, 0)
+ >= DOCFEED_CSTR_LENG * CHRSZ)
+ {
+ (ImmReleaseContextProc) (hwnd, hIMC);
+ return 0;
+ }
+
+ switch (l = (ImmGetCompositionStringProc)
+ (hIMC, GCS_COMPSTR, ime_compstr,
+ (DOCFEED_CSTR_LENG - 1) * CHRSZ))
+ {
+ case IMM_ERROR_NODATA:
+ case IMM_ERROR_GENERAL:
+ ime_compstr[0] = 0;
+ break;
+ default:
+ ime_compstr[l / CHRSZ] = 0;
+ break;
+ }
+ (ImmReleaseContextProc) (hwnd, hIMC);
+
+ return get_reconversion_string (hwnd, reconv, ime_compstr);
+ }
+
+ return 0;
+}
+#endif /* DOCUMENTFEED */
+
+void
+w32_ime_control_init (void)
+{
+ HMODULE hImm32;
+
+ hImm32 = GetModuleHandle ("IMM32.DLL");
+ if (!hImm32)
+ hImm32 = LoadLibrary ("IMM32.DLL");
+
+ fIME = FALSE;
+ Vime_control = Qnil;
+ IME_event_off_count = 0;
+
+ if (hImm32)
+ {
+ ImmGetOpenStatusProc =
+ (IMMGETOPENSTATUSPROC)
+ GetProcAddress (hImm32,
+ ImmGetOpenStatus_Name);
+ ImmSetOpenStatusProc =
+ (IMMSETOPENSTATUSPROC)
+ GetProcAddress (hImm32,
+ ImmSetOpenStatus_Name);
+ ImmSetCompositionWindowProc =
+ (IMMSETCOMPOSITIONWINDOWPROC)
+ GetProcAddress (hImm32,
+ ImmSetCompositionWindow_Name);
+ ImmGetContextProc =
+ (IMMGETCONTEXTPROC)
+ GetProcAddress (hImm32,
+ ImmGetContext_Name);
+ ImmGetConversionStatusProc =
+ (IMMGETCONVERSIONSTATUSPROC)
+ GetProcAddress (hImm32,
+ ImmGetConversionStatus_Name);
+ ImmSetConversionStatusProc =
+ (IMMSETCONVERSIONSTATUSPROC)
+ GetProcAddress (hImm32,
+ ImmSetConversionStatus_Name);
+ ImmNotifyIMEProc =
+ (IMMNOTIFYIMEPROC)
+ GetProcAddress (hImm32,
+ ImmNotifyIME_Name);
+ ImmReleaseContextProc =
+ (IMMRELEASECONTEXTPROC)
+ GetProcAddress (hImm32,
+ ImmReleaseContext_Name);
+ ImmCreateContextProc =
+ (IMMCREATECONTEXTPROC)
+ GetProcAddress (hImm32,
+ ImmCreateContext_Name);
+ ImmDestroyContextProc =
+ (IMMDESTROYCONTEXTPROC)
+ GetProcAddress (hImm32,
+ ImmDestroyContext_Name);
+ ImmAssociateContextProc =
+ (IMMASSOCIATECONTEXTPROC)
+ GetProcAddress (hImm32,
+ ImmAssociateContext_Name);
+ ImmGetHotKeyProc =
+ (IMMGETHOTKEYPROC)
+ GetProcAddress (hImm32,
+ ImmGetHotKey_Name);
+ ImmGetPropertyProc =
+ (IMMGETPROPERTYPROC)
+ GetProcAddress (hImm32, ImmGetProperty_Name);
+ ImmGetCompositionStringProc =
+ (IMMGETCOMPOSITIONSTRINGPROC)
+ GetProcAddress (hImm32, ImmGetCompositionString_Name);
+ ImmSetCompositionStringProc =
+ (IMMSETCOMPOSITIONSTRINGPROC)
+ GetProcAddress (hImm32, ImmSetCompositionString_Name);
+ ImmSetCompositionFontProc =
+ (IMMSETCOMPOSITIONFONTPROC)
+ GetProcAddress (hImm32, ImmSetCompositionFont_Name);
+ ImmGetConversionListProc =
+ (IMMGETCONVERSIONLISTPROC)
+ GetProcAddress (hImm32,
+ ImmGetConversionList_Name);
+ ImmConfigureIMEProc =
+ (IMMCONFIGUREIMEPROC)
+ GetProcAddress (hImm32,
+ ImmConfigureIME_Name);
+ ImmGetCandidateListProc =
+ (IMMGETCANDIDATELISTPROC)
+ GetProcAddress (hImm32,
+ ImmGetCandidateList_Name);
+ ImmGetCandidateListCountProc =
+ (IMMGETCANDIDATELISTCOUNTPROC)
+ GetProcAddress (hImm32,
+ ImmGetCandidateListCount_Name);
+
+ if (ImmGetOpenStatusProc &&
+ ImmSetOpenStatusProc &&
+ ImmSetCompositionWindowProc &&
+ ImmGetCompositionStringProc &&
+ ImmSetCompositionStringProc &&
+ ImmSetCompositionFontProc &&
+ ImmGetPropertyProc &&
+ ImmGetContextProc &&
+ ImmGetConversionStatusProc &&
+ ImmSetConversionStatusProc &&
+ ImmGetConversionListProc &&
+ ImmConfigureIMEProc &&
+ ImmNotifyIMEProc &&
+ ImmReleaseContextProc &&
+ ImmCreateContextProc &&
+ ImmDestroyContextProc &&
+ ImmAssociateContextProc &&
+ ImmGetCandidateListProc &&
+ ImmGetCandidateListCountProc &&
+ ImmGetHotKeyProc)
+ {
+ fIME = TRUE;
+ Vime_control = Qt;
+ }
+ }
+}
+
+#ifdef HAVE_NTGUI
+static int
+need_set_ime_font (PLOGFONT p)
+{
+ if (!p ||
+ (p->lfHeight == ime_logfont.lfHeight
+ && p->lfWidth == ime_logfont.lfWidth
+ && p->lfEscapement == ime_logfont.lfEscapement
+ && p->lfOrientation == ime_logfont.lfOrientation
+ && p->lfWeight == ime_logfont.lfWeight
+ && p->lfItalic == ime_logfont.lfItalic
+ && p->lfUnderline == ime_logfont.lfUnderline
+ && p->lfStrikeOut == ime_logfont.lfStrikeOut
+ && p->lfCharSet == ime_logfont.lfCharSet
+ && p->lfOutPrecision == ime_logfont.lfOutPrecision
+ && p->lfClipPrecision == ime_logfont.lfClipPrecision
+ && p->lfQuality == ime_logfont.lfQuality
+ && p->lfPitchAndFamily == ime_logfont.lfPitchAndFamily
+ && strncmp (p->lfFaceName, ime_logfont.lfFaceName, LF_FACESIZE) == 0))
+ return 0;
+ else
+ return 1;
+}
+void
+w32_set_ime_logfont (HWND hwnd, struct frame *f)
+{
+ Lisp_Object ime_font = Qnil, temp = Qnil, font = Qnil, family;
+ int fsid = -1;
+ LOGFONT logfont = {0};
+
+ if (!IsWindow (hwnd))
+ return;
+
+ if (!fIME || NILP(Vime_control))
+ return;
+
+ if ((STRINGP(ime_font = get_frame_param (f, Qime_font))
+ /* fontset */
+ && (((fsid = fs_query_fontset(ime_font, 0)) >= 0
+ && !NILP(font = fontset_ascii(fsid))
+ && !NILP(font = font_spec_from_name(font))
+ && !NILP(temp = Ffontset_font(temp, make_fixnum(0x3042), Qnil))
+ && !NILP(family = XCAR(temp)))
+ /* font */
+ || (!NILP(font = font_spec_from_name(ime_font))
+ && SYMBOLP(family = AREF (font, FONT_FAMILY_INDEX))
+ && STRINGP(family = SYMBOL_NAME(family)))))
+
+ /* use font object */
+ /* frame-parameter */
+ || ((FONTP(font = ime_font)
+ /* frame fontset */
+ || ((fsid = FRAME_FONTSET(f)) >= 0
+ && !NILP(font =
+ Ffont_at(make_fixnum(0), Qnil,
+ temp = Fchar_to_string(make_fixnum(0x3042))))))
+ && SYMBOLP(family = Ffont_get(font, QCfamily))
+ && STRINGP(family = SYMBOL_NAME(family))
+ && !NILP(font = copy_font_spec(font)))) {
+ Lisp_Object tail;
+
+ fill_in_logfont (f, &logfont, font);
+
+ logfont.lfWidth = 0;
+
+ family = ENCODE_SYSTEM(family);
+
+ strcpy(logfont.lfFaceName, SSDATA(family));
+
+ /* rescale */
+ for (tail = Vface_font_rescale_alist; CONSP (tail); tail = XCDR (tail)) {
+ temp = XCAR (tail);
+ if (!FLOATP (XCDR (temp)))
+ continue;
+
+ if (STRINGP (XCAR (temp))) {
+ if (fast_string_match_ignore_case (XCAR (temp), family) >= 0) {
+ logfont.lfHeight *= XFLOAT_DATA (XCDR (temp));
+ break;
+ }
+ } else if (FONT_SPEC_P (XCAR (temp))) {
+ Lisp_Object name;
+ if (!NILP(name = Ffont_get(XCAR (temp), QCfamily)) &&
+ STRINGP(name) &&
+ xstrcasecmp(SSDATA(name), SSDATA(family)) == 0) {
+ logfont.lfHeight *= XFLOAT_DATA (XCDR (temp));
+ break;
+ }
+ }
+ }
+ } else {
+ HFONT hfont = FONT_HANDLE (FRAME_FONT (f));
+ GetObject (hfont, sizeof (logfont), &logfont);
+ }
+
+ if (need_set_ime_font (&logfont))
+ {
+ ime_logfont = logfont;
+ PostMessage (hwnd, WM_MULE_IMM_SET_IMEFONT, (WPARAM) f, 0);
+ }
+}
+static void
+w32_set_ime_font (HWND hwnd)
+{
+ HIMC himc;
+
+ if (!fIME || NILP (Vime_control))
+ return;
+
+ himc = (ImmGetContextProc) (hwnd);
+ if (!himc)
+ return;
+ (ImmSetCompositionFontProc) (himc, &ime_logfont);
+ (ImmReleaseContextProc) (hwnd, himc);
+}
+#endif /* HAVE_NTGUI */
+
+static LRESULT CALLBACK
+conversion_agent_wndproc (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+ switch (message)
+ {
+ case WM_MULE_IMM_SET_STATUS:
+ if (InSendMessage())
+ ReplyMessage(1);
+ w32_set_ime_status (hwnd, (int) wparam);
+ break;
+
+ case WM_MULE_IMM_GET_STATUS:
+ return w32_get_ime_status (hwnd);
+
+ case WM_MULE_IMM_SET_MODE:
+ return w32_set_ime_mode (hwnd, (int) wparam, (int) lparam);
+
+ case WM_MULE_IMM_SET_IMEFONT:
+ w32_set_ime_font (hwnd);
+ FALLTHROUGH;
+ case WM_MULE_IMM_SET_CONVERSION_WINDOW:
+ if (w32_get_ime_status (hwnd))
+ w32_set_ime_conv_window (hwnd, (struct frame *) wparam);
+ break;
+
+#ifdef RECONVERSION
+ case WM_MULE_IMM_PERFORM_RECONVERSION:
+ if (ime_enable_reconversion)
+ w32_perform_reconversion(hwnd, (RECONVERTSTRING*)lparam);
+ break;
+#endif
+
+#if 0
+ case WM_MULE_IMM_GET_COMPOSITION_STRING:
+ return w32_get_ime_composition_string (hwnd);
+#endif
+
+ default:
+ return DefWindowProc (hwnd, message, wparam, lparam);
+ }
+ return 0;
+}
+
+
+/*
+ Emacs Lisp function entries
+*/
+
+DEFUN ("ime-force-on", Fime_force_on, Sime_force_on, 0, 1, 0,
+ doc: /* Force status of IME open. */)
+ (Lisp_Object eventp)
+{
+ if (fIME && !NILP (Vime_control))
+ {
+ HWND hwnd;
+
+ if (!NILP (Fime_get_mode ()))
+ return Qnil;
+#ifdef HAVE_NTGUI
+ if (NILP (eventp))
+ IME_event_off_count++;
+ hwnd = FRAME_W32_WINDOW (SELECTED_FRAME ());
+#else
+ hwnd = hwndConsole;
+#endif
+ SendMessage (hwnd, WM_MULE_IMM_SET_STATUS, 1, 0);
+ }
+ return Qnil;
+}
+
+DEFUN ("ime-force-off", Fime_force_off, Sime_force_off, 0, 1, 0,
+ doc: /* Force status of IME close. */)
+ (Lisp_Object eventp)
+{
+ if (fIME && !NILP (Vime_control))
+ {
+ HWND hwnd;
+
+ if (NILP (Fime_get_mode ()))
+ return Qnil;
+#ifdef HAVE_NTGUI
+ if (NILP (eventp))
+ IME_event_off_count++;
+ hwnd = FRAME_W32_WINDOW (SELECTED_FRAME ());
+#else
+ hwnd = hwndConsole;
+#endif
+ SendMessage (hwnd, WM_MULE_IMM_SET_STATUS, 0, 0);
+ }
+ return Qnil;
+}
+
+DEFUN ("ime-get-mode", Fime_get_mode, Sime_get_mode, 0, 0, "",
+ doc: /* Get IME status.
+t means status of IME is open. nil means it is close. */)
+ (void)
+{
+ if (fIME && !NILP (Vime_control))
+ {
+ HWND hwnd;
+ int result;
+
+#ifdef HAVE_NTGUI
+ hwnd = FRAME_W32_WINDOW (SELECTED_FRAME ());
+#else
+ hwnd = hwndConsole;
+#endif
+ result = SendMessage (hwnd, WM_MULE_IMM_GET_STATUS, 0, 0);
+
+ return result ? Qt : Qnil;
+ }
+ else
+ return Qnil;
+}
+
+DEFUN ("w32-set-ime-mode",
+ Fw32_set_ime_mode,
+ Sw32_set_ime_mode, 1, 2, 0,
+ doc: /* Set IME mode to MODE. If FRAME is omitted, the selected frame is used. */)
+ (Lisp_Object mode, Lisp_Object frame)
+{
+ struct frame *f;
+
+ if (NILP (frame))
+ {
+ f = SELECTED_FRAME ();
+ }
+ else
+ {
+ CHECK_FRAME (frame);
+ f = XFRAME (frame);
+ }
+ if (fIME && !NILP (Vime_control))
+ {
+ HWND hwnd;
+ int ret;
+ int newmode, mask;
+
+ newmode = 0;
+ mask = 0;
+
+ hwnd = FRAME_W32_WINDOW (f);
+
+ if (EQ (mode, intern ("katakana")))
+ {
+ newmode |= IME_CMODE_KATAKANA;
+ mask |= IME_CMODE_KATAKANA;
+ }
+ else if (EQ (mode, intern ("hiragana")))
+ {
+ newmode &= ~IME_CMODE_KATAKANA;
+ mask |= IME_CMODE_KATAKANA;
+ }
+ else if (EQ (mode, intern ("kanji")))
+ {
+ newmode |= IME_CMODE_HANJACONVERT;
+ mask |= IME_CMODE_HANJACONVERT;
+ }
+ else if (EQ (mode, intern ("nokanji")))
+ {
+ newmode &= ~IME_CMODE_HANJACONVERT;
+ mask |= IME_CMODE_HANJACONVERT;
+ }
+ else if (EQ (mode, intern ("code")))
+ {
+ newmode |= IME_CMODE_CHARCODE;
+ mask |= IME_CMODE_CHARCODE;
+ }
+ else if (EQ (mode, intern ("nocode")))
+ {
+ newmode &= ~IME_CMODE_CHARCODE;
+ mask |= IME_CMODE_CHARCODE;
+ }
+ else if (EQ (mode, intern ("non-convert")))
+ {
+ newmode |= IME_CMODE_NOCONVERSION;
+ mask |= IME_CMODE_NOCONVERSION;
+ }
+ else if (EQ (mode, intern ("convert")))
+ {
+ newmode &= ~IME_CMODE_NOCONVERSION;
+ mask |= IME_CMODE_NOCONVERSION;
+ }
+ else
+ error ("unknown mode!!");
+
+ ret = SendMessage (hwnd, WM_MULE_IMM_SET_MODE,
+ (WPARAM) newmode, (LPARAM) mask);
+
+ if (!ret)
+ return Qnil;
+
+ return Qt;
+ }
+ return Qnil;
+}
+
+DEFUN ("w32-ime-register-word-dialog",
+ Fw32_ime_register_word_dialog,
+ Sw32_ime_register_word_dialog, 2, 2, 0,
+ doc: /* Open IME regist word dialog. */)
+ (Lisp_Object reading, Lisp_Object word)
+{
+ HKL hkl;
+ REGISTERWORD regword;
+ Lisp_Object encoded_reading, encoded_word;
+
+ CHECK_STRING (reading);
+ CHECK_STRING (word);
+
+ if (fIME && !NILP (Vime_control) && ImmConfigureIMEProc)
+ {
+ hkl = GetKeyboardLayout (0);
+ encoded_reading = Fencode_coding_string (reading,
+ Vlocale_coding_system,
+ Qnil, Qnil);
+ regword.lpReading = SSDATA (encoded_reading);
+
+ encoded_word = Fencode_coding_string (word,
+ Vlocale_coding_system,
+ Qnil, Qnil);
+ regword.lpWord = SSDATA (encoded_word);
+ (ImmConfigureIMEProc) (hkl, FRAME_W32_WINDOW (SELECTED_FRAME ()),
+ IME_CONFIG_REGISTERWORD, &regword);
+ }
+ return Qnil;
+}
+
+DEFUN ("ime-get-property", Fime_get_property, Sime_get_property, 1, 1, 0,
+ doc: /* Retrieves the property and capabilities of the IME associated with the specified input locale.
+INDEX is one of igp-property, igp-conversion, igp-sentence, igp-ui, igp-setcompstr, igp-select of igp-getimeversion*/)
+ (Lisp_Object index)
+{
+ int i;
+ Lisp_Object val;
+ DWORD v;
+
+ static const struct {
+ const char *name;
+ DWORD index;
+ } index_map[] = {
+ {"property", IGP_PROPERTY},
+ {"conversion", IGP_CONVERSION},
+ {"sentence", IGP_SENTENCE},
+ {"ui", IGP_UI},
+ {"setcompstr", IGP_SETCOMPSTR},
+ {"select", IGP_SELECT},
+ {"getimeversion", IGP_GETIMEVERSION},
+ }, prop_map[] = {
+ {"at-caret", IME_PROP_AT_CARET},
+ {"special-ui", IME_PROP_SPECIAL_UI},
+ {"candlist-start-from-1", IME_PROP_CANDLIST_START_FROM_1},
+ {"unicode", IME_PROP_UNICODE},
+ {"complete-on-unselect", IME_PROP_COMPLETE_ON_UNSELECT},
+ }, ui_map[] = {
+ {"rot2700", UI_CAP_2700},
+ {"rot90", UI_CAP_ROT90},
+ {"rotany", UI_CAP_ROTANY},
+ }, setcompstr_map[] = {
+ {"compstr", SCS_CAP_COMPSTR},
+ {"makeread", SCS_CAP_MAKEREAD},
+ {"setreconvertstring", SCS_CAP_SETRECONVERTSTRING},
+ }, select_map[] = {
+ {"conversion", SELECT_CAP_CONVERSION},
+ {"sentence", SELECT_CAP_SENTENCE},
+ }, imeversion_map[] = {
+ {"ver-0310", IMEVER_0310},
+ {"ver-0400", IMEVER_0400},
+ };
+
+ CHECK_SYMBOL(index);
+ for (i = 0; i < sizeof(index_map) / sizeof(index_map[0]); i++)
+ if (EQ(index, intern(index_map[i].name)))
+ break;
+ if (i >= sizeof(index_map) / sizeof(index_map[0]))
+ return Qnil;
+
+ v = (*ImmGetPropertyProc)(GetKeyboardLayout(0), index_map[i].index);
+ val = Qnil;
+#define MAKE_CAP_LIST(map) do { \
+ int j; \
+ for (j = sizeof(map) / sizeof(map[0]) - 1; j >= 0 ; j--) \
+ if (v & map[j].index) \
+ val = Fcons(intern(map[j].name), val); \
+} while(0)
+
+ switch (index_map[i].index) {
+ case IGP_PROPERTY:
+ MAKE_CAP_LIST(prop_map);
+ break;
+ case IGP_UI:
+ MAKE_CAP_LIST(ui_map);
+ break;
+ case IGP_SETCOMPSTR:
+ MAKE_CAP_LIST(setcompstr_map);
+ break;
+ case IGP_SELECT:
+ MAKE_CAP_LIST(select_map);
+ break;
+ case IGP_GETIMEVERSION:
+ MAKE_CAP_LIST(imeversion_map);
+ break;
+ }
+ return val;
+}
+
+#ifdef RECONVERSION
+BOOL w32_perform_reconversion(HWND hwnd, RECONVERTSTRING *reconv)
+{
+ struct frame *f = SELECTED_FRAME ();
+ HIMC himc;
+ BOOL result = FALSE;
+
+ himc = (ImmGetContextProc) (hwnd);
+ if (!himc) {
+ xfree(reconv);
+ return FALSE;
+ }
+
+ if ((*ImmSetCompositionStringProc) (himc,
+ SCS_QUERYRECONVERTSTRING,
+ reconv, reconv->dwSize,
+ NULL, 0 )
+ && (*ImmSetCompositionStringProc) (himc,
+ SCS_SETRECONVERTSTRING,
+ reconv, reconv->dwSize,
+ NULL, 0)) {
+ /* Set the position of candidate list dialog. */
+ (ImmReleaseContextProc) (hwnd, himc);
+ w32_set_ime_conv_window (hwnd, f);
+ result = TRUE;
+ } else
+ (ImmReleaseContextProc) (hwnd, himc);
+ xfree(reconv);
+ return result;
+}
+
+DEFUN ("w32-ime-perform-reconversion",
+ Fw32_ime_perform_reconversion,
+ Sw32_ime_perform_reconversion, 0, 0, "",
+ doc: /* perfom ime reconversion. */)
+ (void)
+{
+ HWND hwnd = FRAME_W32_WINDOW(SELECTED_FRAME());
+ DWORD size;
+ RECONVERTSTRING *reconv;
+
+ if (!ime_enable_reconversion ||
+ NILP(Fime_get_mode()))
+ return Qnil;
+
+ if ((size = get_reconversion_string (hwnd, NULL, NULL))
+ && (reconv = xmalloc (size)) != NULL
+ && (memset (reconv, 0, size), (reconv->dwSize = size))
+ && get_reconversion_string (hwnd, reconv, NULL))
+ PostMessage(hwnd, WM_MULE_IMM_PERFORM_RECONVERSION, 0, (LPARAM) reconv);
+
+ return Qt;
+}
+#endif
+
+#endif /* USE_W32_IME */
+
/***********************************************************************
w32 specialized functions
@@ -10357,6 +11513,10 @@ syms_of_w32fns (void)
PDUMPER_IGNORE (w32_visible_system_caret_hwnd);
DEFSYM (Qundefined_color, "undefined-color");
+#ifdef USE_W32_IME
+ DEFSYM (Qw32_ime_buffer_switch_p, "w32-ime-buffer-switch-p");
+ DEFSYM (Qime_font, "ime-font");
+#endif /* USE_W32_IME */
DEFSYM (Qcancel_timer, "cancel-timer");
DEFSYM (Qhyper, "hyper");
DEFSYM (Qsuper, "super");
@@ -10694,6 +11854,27 @@ syms_of_w32fns (void)
doc: /* Non-nil means don't display the abort dialog when aborting. */);
w32_disable_abort_dialog = 0;
+#ifdef USE_W32_IME
+#ifdef RECONVERSION
+ DEFVAR_BOOL ("ime-enable-reconversion", ime_enable_reconversion,
+ doc: /* Non-nil enables IME reconversion capability. */);
+ ime_enable_reconversion = 1;
+#endif
+#ifdef DOCUMENTFEED
+ DEFVAR_BOOL ("ime-enable-document-feed", ime_enable_document_feed,
+ doc: /* Non-nil enables IME document feed capability. */);
+ ime_enable_document_feed = 1;
+#endif
+ DEFVAR_LISP ("ime-control", Vime_control, doc: /* IME control flag. */);
+ Vime_control = Qnil;
+
+ DEFVAR_LISP ("w32-ime-composition-window",
+ Vw32_ime_composition_window,
+ doc: /* If this is a window of current frame, IME composition window appears on the
+window instead of current window. */);
+ Vw32_ime_composition_window = Qnil;
+#endif /* USE_W32_IME */
+
#if 0 /* TODO: Port to W32 */
defsubr (&Sx_change_window_property);
defsubr (&Sx_delete_window_property);
@@ -10747,6 +11928,18 @@ syms_of_w32fns (void)
defsubr (&Sw32_notification_close);
#endif
+#ifdef USE_W32_IME
+ defsubr (&Sw32_set_ime_mode);
+ defsubr (&Sw32_ime_register_word_dialog);
+ defsubr (&Sime_force_on);
+ defsubr (&Sime_force_off);
+ defsubr (&Sime_get_mode);
+ defsubr (&Sime_get_property);
+#ifdef RECONVERSION
+ defsubr (&Sw32_ime_perform_reconversion);
+#endif
+#endif /* USE_W32_IME */
+
#ifdef WINDOWSNT
defsubr (&Sw32_read_registry);
defsubr (&Sfile_system_info);
@@ -11024,6 +12217,7 @@ globals_of_w32fns (void)
get_title_bar_info_fn = (GetTitleBarInfo_Proc)
get_proc_addr (user32_lib, "GetTitleBarInfo");
+#ifndef USE_W32_IME
{
HMODULE imm32_lib = GetModuleHandle ("imm32.dll");
get_composition_string_fn = (ImmGetCompositionString_Proc)
@@ -11035,6 +12229,7 @@ globals_of_w32fns (void)
set_ime_composition_window_fn = (ImmSetCompositionWindow_Proc)
get_proc_addr (imm32_lib, "ImmSetCompositionWindow");
}
+#endif /* !USE_W32_IME */
HMODULE hm_kernel32 = GetModuleHandle ("kernel32.dll");
is_debugger_present = (IsDebuggerPresent_Proc)
diff --git a/src/w32font.c b/src/w32font.c
index c1d5f25..2853a46 100644
--- a/src/w32font.c
+++ b/src/w32font.c
@@ -55,7 +55,9 @@ #define VIETNAMESE_CHARSET 163
#define JOHAB_CHARSET 130
#endif
+#ifndef USE_W32_IME
static void fill_in_logfont (struct frame *, LOGFONT *, Lisp_Object);
+#endif
static BYTE w32_antialias_type (Lisp_Object);
static Lisp_Object lispy_antialias_type (BYTE);
@@ -2011,7 +2013,10 @@ w32_to_fc_weight (int n)
}
/* Fill in all the available details of LOGFONT from FONT_SPEC. */
-static void
+#ifndef USE_W32_IME
+static
+#endif
+void
fill_in_logfont (struct frame *f, LOGFONT *logfont, Lisp_Object font_spec)
{
Lisp_Object tmp, extra;
diff --git a/src/w32font.h b/src/w32font.h
index a76f8c3..ec91c65 100644
--- a/src/w32font.h
+++ b/src/w32font.h
@@ -83,6 +83,9 @@ #define CACHE_BLOCKSIZE 128
int uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec);
Lisp_Object intern_font_name (char *);
+#ifdef USE_W32_IME
+void fill_in_logfont (struct frame *, LOGFONT *, Lisp_Object);
+#endif
extern void globals_of_w32font (void);
diff --git a/src/w32term.c b/src/w32term.c
index 76cf6bd..9a2be97 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -5676,6 +5676,79 @@ w32_read_socket (struct terminal *terminal,
break;
#endif
+#ifdef USE_W32_IME
+ case WM_MULE_IME_STATUS:
+ f = w32_window_to_frame (dpyinfo, msg.msg.hwnd);
+
+ if (f && !f->iconified && f->visible)
+ {
+ inev.kind = NON_ASCII_KEYSTROKE_EVENT;
+ inev.code = VK_KANJI;
+ inev.modifiers = 0;
+ XSETFRAME (inev.frame_or_window, f);
+ inev.timestamp = msg.msg.time;
+ }
+ break;
+
+ case WM_MULE_IME_REPORT:
+ {
+ LPWSTR lpStr;
+ struct input_event buf;
+ HANDLE hw32_ime_string = (HANDLE) msg.msg.wParam;
+
+ f = (struct frame *) msg.msg.lParam;
+ if (f && !f->iconified && f->visible)
+ {
+ lpStr = (LPWSTR) hw32_ime_string;
+ while(lpStr)
+ {
+ EVENT_INIT (buf);
+ XSETFRAME (buf.frame_or_window, f);
+ buf.timestamp = msg.msg.time;
+ buf.modifiers = 0;
+ if (*lpStr)
+ {
+ if (*lpStr < 0x80)
+ buf.kind = ASCII_KEYSTROKE_EVENT;
+ else
+ buf.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
+ if ((*lpStr & 0xFC00) == 0xD800
+ && (*(lpStr + 1) & 0xFC00) == 0xDC00)
+ {
+ buf.code = 0x10000
+ + (((*lpStr & 0x3FF) << 10)
+ | (*(lpStr + 1) & 0x3FF));
+ lpStr++;
+ }
+ else
+ buf.code = *(lpStr++);
+ kbd_buffer_store_event (&buf);
+ }
+ else
+ {
+ buf.kind = NON_ASCII_KEYSTROKE_EVENT;
+ buf.code = VK_COMPEND;
+ kbd_buffer_store_event (&buf);
+ break;
+ }
+ }
+ HeapFree (GetProcessHeap (), 0, (LPVOID) hw32_ime_string);
+ }
+ }
+ break;
+
+ case WM_MULE_IME_DEL_RANGE:
+ del_range ((ptrdiff_t) msg.msg.wParam, (ptrdiff_t) msg.msg.lParam);
+ Fgoto_char (make_fixnum (msg.msg.wParam));
+ redisplay ();
+ break;
+
+ case WM_MULE_IME_SET_FONT:
+ w32_set_ime_logfont (msg.msg.hwnd, (struct frame *) msg.msg.wParam);
+ break;
+
+#endif /* USE_W32_IME */
+
default:
/* Check for messages registered at runtime. */
if (msg.msg.message == msh_mousewheel)
@@ -6042,7 +6115,12 @@ w32_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
+ WINDOW_HEADER_LINE_HEIGHT (w);
w32_system_caret_mode_height = WINDOW_MODE_LINE_HEIGHT (w);
+#ifdef USE_W32_IME
+ if (f && f == FRAME_DISPLAY_INFO (f)->highlight_frame)
+ PostMessage (hwnd, WM_MULE_IMM_SET_CONVERSION_WINDOW, (WPARAM) f, 0);
+#else
PostMessage (hwnd, WM_IME_STARTCOMPOSITION, 0, 0);
+#endif
/* If the size of the active cursor changed, destroy the old
system caret. */
@@ -7559,6 +7637,9 @@ #define LOAD_PROC(lib, fn) pfn##fn = (void *) GetProcAddress (lib, #fn)
horizontal_scroll_bar_left_border = horizontal_scroll_bar_right_border
= GetSystemMetrics (SM_CYHSCROLL);
}
+#ifdef USE_W32_IME
+ w32_ime_control_init();
+#endif /* USE_W32_IME */
}
void
diff --git a/src/w32term.h b/src/w32term.h
index f8a8a72..1faeadf 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -634,6 +634,8 @@ #define WM_MOUSEHWHEEL (WM_MOUSEWHEEL + 4)
#endif /* WM_MOUSEHWHEEL */
#ifndef WM_APPCOMMAND
#define WM_APPCOMMAND 0x319
+#endif
+#ifndef GET_APPCOMMAND_LPARAM
#define GET_APPCOMMAND_LPARAM(lParam) (HIWORD(lParam) & 0x7fff)
#endif
#ifndef WM_UNICHAR
@@ -672,6 +674,96 @@ #define WM_EMACS_INPUT_READY (WM_EMACS_START + 24)
#define WM_EMACS_FILENOTIFY (WM_EMACS_START + 25)
#define WM_EMACS_END (WM_EMACS_START + 26)
+#ifdef USE_W32_IME
+#ifndef VK_KANJI
+#define VK_KANJI 0x19
+#endif
+#ifndef VK_KANA
+#define VK_KANA 0x15
+#endif
+#define VK_COMPEND 0x1A
+
+#ifdef RECONVERSION
+#ifndef WM_IME_REQUEST
+#define WM_IME_REQUEST 0x288
+#endif
+#ifndef IMR_COMPOSITIONWINDOW
+#define IMR_COMPOSITIONWINDOW 0x0001
+#endif
+#ifndef IMR_CANDIDATEWINDOW
+#define IMR_CANDIDATEWINDOW 0x0002
+#endif
+#ifdef IMR_COMPOSITIONFONT
+#define IMR_COMPOSITIONFONT 0x0003
+#endif
+#ifndef IMR_RECONVERTSTRING
+#define IMR_RECONVERTSTRING 0x0004
+#endif
+#ifndef IMR_CONFIRMRECONVERTSTRING
+#define IMR_CONFIRMRECONVERTSTRING 0x0005
+#endif
+#endif
+#ifndef IME_PROP_COMPLETE_ON_UNSELECT
+#define IME_PROP_COMPLETE_ON_UNSELECT 0x00100000
+#endif
+#ifndef SCS_CAP_SETRECONVERTSTRING
+#define SCS_CAP_SETRECONVERTSTRING 0x00000004
+#endif
+
+/* For internal communications
+ from window procedure to event loop. */
+#define WM_MULE_IME_REPORT (WM_USER+2200)
+#define WM_MULE_IME_STATUS (WM_USER+2201)
+#define WM_MULE_IME_DEL_RANGE (WM_USER+2202)
+#define WM_MULE_IME_SET_FONT (WM_USER+2203)
+
+/* For internal communications
+ from main thread to window procedure. */
+#define WM_MULE_IMM_MESSAGE_START (WM_USER+2300)
+#define WM_MULE_IMM_SET_STATUS (WM_USER+2300)
+#define WM_MULE_IMM_GET_STATUS (WM_USER+2301)
+#if 0
+#define WM_MULE_IMM_DEAL_WITH_CONTEXT (WM_USER+2302)
+#define WM_MULE_IMM_SET_COMPOSITION_STRING (WM_USER+2303)
+#endif
+#define WM_MULE_IMM_GET_COMPOSITION_STRING (WM_USER+2304)
+#define WM_MULE_IMM_SET_MODE (WM_USER+2305)
+#if 0
+#define WM_MULE_IMM_NOTIFY (WM_USER+2310)
+#define WM_MULE_IMM_GET_UNDETERMINED_STRING_LENGTH (WM_USER+2320)
+#endif
+#define WM_MULE_IMM_SET_IMEFONT (WM_USER+2311)
+#define WM_MULE_IMM_SET_CONVERSION_WINDOW (WM_USER+2312)
+
+#define WM_MULE_IMM_PERFORM_RECONVERSION (WM_USER+2320)
+
+#define WM_MULE_IMM_MESSAGE_END (WM_USER+2399)
+#define MESSAGE_IMM_COM_P(message) \
+ (((message) >= WM_MULE_IMM_MESSAGE_START) && \
+ ((message) <= WM_MULE_IMM_MESSAGE_END))
+
+#ifdef RECONVERSION
+#ifndef HAVE_RECONVERTSTRING
+typedef struct tagRECONVERTSTRING {
+ DWORD dwSize;
+ DWORD dwVersion;
+ DWORD dwStrLen;
+ DWORD dwStrOffset;
+ DWORD dwCompStrLen;
+ DWORD dwCompStrOffset;
+ DWORD dwTargetStrLen;
+ DWORD dwTargetStrOffset;
+} RECONVERTSTRING, *PRECONVERTSTRING;
+#endif
+#ifndef SCS_SETRECONVERTSTRING
+#define SCS_SETRECONVERTSTRING 0x00010000
+#endif
+#ifndef SCS_QUERYRECONVERTSTRING
+#define SCS_QUERYRECONVERTSTRING 0x00020000
+#endif
+#endif /* RECONVERSION */
+#endif /* USE_W32_IME */
+
#define WND_FONTWIDTH_INDEX (0)
#define WND_LINEHEIGHT_INDEX (4)
#define WND_BORDER_INDEX (8)
@@ -888,3 +980,8 @@ #define GUI_SDATA(x) ((guichar_t*) SDATA (x))
#ifdef CYGWIN
extern int w32_message_fd;
#endif /* CYGWIN */
+
+#ifdef USE_W32_IME
+extern void w32_set_ime_logfont (HWND, struct frame *);
+extern void w32_ime_control_init (void);
+#endif /* USE_W32_IME */
diff --git a/src/window.c b/src/window.c
index ff17cd8..58239e3 100644
--- a/src/window.c
+++ b/src/window.c
@@ -507,6 +507,10 @@ DEFUN ("old-selected-window", Fold_selected_window,
EMACS_INT window_select_count;
+#ifdef USE_W32_IME
+extern int ime_in_conversion;
+#endif
+
/* If select_window is called with inhibit_point_swap true it will
not store point of the old selected window's buffer back into that
window's pointm slot. This is needed by Fset_window_configuration to
@@ -518,6 +522,9 @@ select_window (Lisp_Object window, Lisp_Object norecord,
{
struct window *w;
struct frame *sf;
+#ifdef USE_W32_IME
+ Lisp_Object oldwin = selected_window;
+#endif /* USE_W32_IME */
CHECK_LIVE_WINDOW (window);
@@ -571,6 +578,11 @@ select_window (Lisp_Object window, Lisp_Object norecord,
record_buffer (w->contents);
}
+#ifdef USE_W32_IME
+ if (!ime_in_conversion && !NILP (Vselect_window_functions))
+ run_hook_with_args_2 (Qselect_window_functions, oldwin, window);
+#endif /* USE_W32_IME */
+
return window;
}
@@ -4115,6 +4127,12 @@ buffer (that is `window-dedicated-p' returns t for WINDOW) and does not
set_window_buffer (window, buffer, true, !NILP (keep_margins));
+#ifdef USE_W32_IME
+ if (!ime_in_conversion && !NILP (Vset_selected_window_buffer_functions))
+ CALLN (Frun_hook_with_args, Qset_selected_window_buffer_functions,
+ tem, window, buffer);
+#endif /* USE_W32_IME */
+
return Qnil;
}
@@ -8157,6 +8175,10 @@ syms_of_window (void)
DEFSYM (Qwindow_size_change_functions, "window-size-change-functions");
DEFSYM (Qwindow_buffer_change_functions, "window-buffer-change-functions");
DEFSYM (Qwindow_selection_change_functions, "window-selection-change-functions");
+#ifdef USE_W32_IME
+ DEFSYM (Qset_selected_window_buffer_functions, "set-selected-window-buffer-functions");
+ DEFSYM (Qselect_window_functions, "select-window-functions");
+#endif
DEFSYM (Qwindowp, "windowp");
DEFSYM (Qwindow_configuration_p, "window-configuration-p");
DEFSYM (Qwindow_live_p, "window-live-p");
@@ -8248,6 +8270,17 @@ syms_of_window (void)
as argument. */);
Vwindow_buffer_change_functions = Qnil;
+#ifdef USE_W32_IME
+ DEFVAR_LISP ("set-selected-window-buffer-functions",
+ Vset_selected_window_buffer_functions,
+ doc: /* Functions to call when set-window-buffer is called. */);
+ Vset_selected_window_buffer_functions = Qnil;
+
+ DEFVAR_LISP ("select-window-functions", Vselect_window_functions,
+ doc: /* Functions to call when select-window is called. */);
+ Vselect_window_functions = Qnil;
+#endif
+
DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions,
doc: /* Functions called during redisplay when window sizes have changed.
The value should be a list of functions that take one argument.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment