显示标签为“Emacs”的博文。显示所有博文
显示标签为“Emacs”的博文。显示所有博文

星期五, 十一月 14, 2008

Emacs-CVS的Win32版本输入太快丢失汉字

前天下载了最新的Source编译了一下Emacs-CVS发现Windows输入法部分的处理现在已经是接收的UNICODE的字符了,处理方法是对WM_IME_CHAR这个消息进行处理。不过在Emacs里用了一个标志ignore_ime_char来判断是否处理后续的WM_IME_CHAR消息。因为Windows默认的是为每个字符都生成一个WM_IME_CHAR消息,这个消息如果没有被程序处理,转入默认处理程序,就会变成两个WM_CHAR消息,分开传高字节和低字节。Emacs-CVS的WM_IME_CHAR的事件里调用了ImmGetCompositionString把整个输入都取出来了,所以必须要这个标志来跳过后续的WM_IME_CHAR消息。

这个标志在WM_IME_ENDCOMPOSITION消息被收到事回复的。也就是如果输入法没有发这个消息过来,比如我用日文输入法是,自动上词的时候就没有这个消息,所以标志没恢复,只要一直是自动上词就一直输入不了。

另一个问题是,光标跟随无法工作。
由于以前修改过Emacs的输入法部分,所以对Win32输入法的部分还是有点了解的。
所以对Emacs的输入法部分做了些修改再编译。改成监听WM_IME_COMPOSITION消息。
另外添加了光标跟随。
如果要完美的话,还应该添加字体设置,把光标处的字体信息传给输入法。这个以后有空再做吧。


Index: src/w32fns.c
===================================================================
RCS file: /sources/emacs/emacs/src/w32fns.c,v
retrieving revision 1.349
diff -U 3 -r1.349 w32fns.c
--- src/w32fns.c 30 Oct 2008 01:27:07 -0000 1.349
+++ src/w32fns.c 14 Nov 2008 01:40:32 -0000
@@ -255,6 +255,9 @@
typedef HMONITOR (WINAPI * MonitorFromPoint_Proc) (IN POINT pt, IN DWORD flags);
typedef BOOL (WINAPI * GetMonitorInfo_Proc)
(IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
+typedef HWND (WINAPI * ImmReleaseContext_Proc) (IN HWND hWnd, IN HIMC himc);
+typedef HWND (WINAPI * ImmSetCompositionWindow_Proc)
+ (IN HIMC himc, IN LPCOMPOSITIONFORM compform);

TrackMouseEvent_Proc track_mouse_event_fn = NULL;
ClipboardSequence_Proc clipboard_sequence_fn = NULL;
@@ -262,11 +265,11 @@
ImmGetContext_Proc get_ime_context_fn = NULL;
MonitorFromPoint_Proc monitor_from_point_fn = NULL;
GetMonitorInfo_Proc get_monitor_info_fn = NULL;
+ImmReleaseContext_Proc release_ime_context_fn = NULL;
+ImmSetCompositionWindow_Proc set_ime_composition_window_fn = NULL;

extern AppendMenuW_Proc unicode_append_menu;

-/* Flag to selectively ignore WM_IME_CHAR messages. */
-static int ignore_ime_char = 0;

/* W95 mousewheel handler */
unsigned int msh_mousewheel = 0;
@@ -3134,15 +3601,14 @@
}
break;

- case WM_IME_CHAR:
+ case WM_IME_COMPOSITION:
/* If we can't get the IME result as unicode, use default processing,
which will at least allow characters decodable in the system locale
get through. */
if (!get_composition_string_fn)
goto dflt;
-
- else if (!ignore_ime_char)
- {
+ if (lParam & GCS_RESULTSTR)
+ {
wchar_t * buffer;
int size, i;
W32Msg wmsg;
@@ -3159,14 +3625,47 @@
my_post_msg (&wmsg, hwnd, WM_UNICHAR, (WPARAM) buffer[i],
lParam);
}
- /* We output the whole string above, so ignore following ones
- until we are notified of the end of composition. */
- ignore_ime_char = 1;
+ release_ime_context_fn (hwnd, context);
}
+ else
+ {
+ goto dflt;
+ }
break;
-
+ case WM_IME_STARTCOMPOSITION:
+ if (!set_ime_composition_window_fn)
+ goto dflt;
+ HIMC context = get_ime_context_fn (hwnd);
+ if (!context)
+ {
+ break;
+ }
+ f = x_window_to_frame (dpyinfo, hwnd);
+ COMPOSITIONFORM compform;
+ struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+ 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);
+
+ 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));
+
+ compform.rcArea.bottom = (WINDOW_BOTTOM_EDGE_Y (w)
+ - WINDOW_MODE_LINE_HEIGHT (w));
+ set_ime_composition_window_fn(context, &compform);
+ release_ime_context_fn (hwnd, context);
+
+ break;
case WM_IME_ENDCOMPOSITION:
- ignore_ime_char = 0;
goto dflt;

/* Simulate middle mouse button events when left and right buttons
@@ -7258,6 +7842,10 @@
GetProcAddress (imm32_lib, "ImmGetCompositionStringW");
get_ime_context_fn = (ImmGetContext_Proc)
GetProcAddress (imm32_lib, "ImmGetContext");
+ release_ime_context_fn = (ImmReleaseContext_Proc)
+ GetProcAddress (imm32_lib, "ImmReleaseContext");
+ set_ime_composition_window_fn = (ImmSetCompositionWindow_Proc)
+ GetProcAddress (imm32_lib, "ImmSetCompositionWindow");
}
DEFVAR_INT ("w32-ansi-code-page",
&w32_ansi_code_page,
Index: src/w32term.c
===================================================================
RCS file: /sources/emacs/emacs/src/w32term.c,v
retrieving revision 1.308
diff -U 3 -r1.308 w32term.c
--- src/w32term.c 27 Oct 2008 22:20:27 -0000 1.308
+++ src/w32term.c 14 Nov 2008 01:43:34 -0000
@@ -33,6 +33,7 @@
#include
#include
#include
+#include

#include "charset.h"
#include "character.h"
@@ -5059,7 +5060,11 @@
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
HWND hwnd = FRAME_W32_WINDOW (f);
-
+ if (f == FRAME_W32_DISPLAY_INFO (f)->x_highlight_frame)
+ {
+ PostMessage (hwnd,
+ WM_IME_STARTCOMPOSITION, 0, 0);
+ }
w32_system_caret_x
= WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
w32_system_caret_y




星期四, 三月 29, 2007

对Emacs进行了改造

下载了Emacs23的源代码,把里面的win32的输入法处理部分改成了使用Unicode 的API.
这样用windows的输入法,输入去当前codepage不一样的语言就没问题了。

我等这个功能等了很久了,一直看不到别人加,终于忍不住自己加了。
做过了才发现,如果对Win32的系统很熟的话,修改还是非常容易的。

Emacs23的代码很多,我没有去尝试看懂它的全部代码。即使我修改好了,我也不知道Emacs到底是什么样的结构。

我看代码是直接用cscope。首先找到Win32的消息循环部分。因为输入法的几个消息必须从这里进入Emacs。
我首先查看现在的WM_CHAR是如何处理的。发现Emacs会把操作系统过来的消息,封装成平台无关的消息,送到自己的消息循环中。

而且在自己的消息循环里可以处理unicode的字符和ascii的字符。这就方便多了。我只要把Windows的输入法的字符串用unicode API取出,一个字一个字送入Emacs内部的消息循环就行了。我知道应用程序没有处理输入法的完成编码的消息时,Windows默认会把字符串一个个的转成WM_IME_CHAR消息,如果还没有处理,会把每个WM_IME_CHAR转成2个WM_CHAR。这就是现在的Emacs的win32输入法部分的工作情况。由于Emacs使用的是win32的ansi API。窗口类是非unicode api注册的,所以只能接受ANSI的消息,WM_IME_CHAR的消息里是双字节的字符,不是Unicode的,所以我必须在这之前处理。用unicode的API自己取出字符串,自己一个个的转成Emacs内部消息,这样修改是最小的。

实际用了三天的时间研究代码和修改。最后还加了光标跟随和设置输入法用的字体的功能。

开发过程中发现,一个日本人维护着一个功能更复杂的输入法部分的patch.
不过我的代码更短,功能当然也只有最基本的。

http://yyyccclll.googlepages.com/emacs.patch

星期三, 一月 31, 2007

学习Emacs

我一直用的VIM,自认用得很熟了,基本上用来完成所有的文本编辑。也会自己定义 ftplugin.

最近想学学Emacs看看。

发现一打开emacs,我连最简单的编辑任务都不能完成,看来还得找点资料。

在网上搜索了一下发现两个简单点的。
http://zhdotemacs.sourceforge.net/emacs/book.html
http://www.cbi.pku.edu.cn/chinese/documents/csdoc/emacs/

感觉VIM在帮助方面做得很好,联机帮助都是中文的。面且内容的量还是可以阅读的。
面emacs全是英文的不说,内容也太多了,可能因为功能太强大了,但是这么长的帮助让人望而却步。