diff -Naur vim82.orig/src/Make_mvc.mak vim82+im_custom/src/Make_mvc.mak
--- vim82.orig/src/Make_mvc.mak	2019-12-09 20:45:45.000000000 +0000
+++ vim82+im_custom/src/Make_mvc.mak	2021-11-21 03:35:52.223276900 +0000
@@ -829,6 +829,12 @@
 OBJ = $(OBJ) $(OUTDIR)\dimm_i.obj $(OUTDIR)\glbl_ime.obj
 !endif
 
+!if "$(IMC)" == "yes"
+CFLAGS = $(CFLAGS) -DFEAT_IM_CUSTOM -DFEAT_SKK -DFEAT_POBOX
+IMC_OBJ = $(OUTDIR)\skk.obj $(OUTDIR)\pobox.obj
+IMC_PRO = proto/skk.pro proto/pobox.pro
+!endif
+
 !if "$(GUI)" == "yes"
 SUBSYSTEM = windows
 CFLAGS = $(CFLAGS) -DFEAT_GUI_MSWIN
@@ -1727,6 +1733,10 @@
 $(OUTDIR)/xpm_w32.obj: $(OUTDIR) xpm_w32.c
 	$(CC) $(CFLAGS_OUTDIR) $(XPM_INC) xpm_w32.c
 
+$(OUTDIR)/skk.obj:	$(OUTDIR) skk.c  $(INCL)
+
+$(OUTDIR)/pobox.obj:	$(OUTDIR) pobox.c  $(INCL)
+
 !if "$(VIMDLL)" == "yes"
 $(OUTDIR)/vimc.res:	$(OUTDIR) vim.rc gvim.exe.mnf version.h gui_w32_rc.h \
 				vim.ico
@@ -1905,6 +1915,7 @@
 	proto/window.pro \
 	$(SOUND_PRO) \
 	$(NETBEANS_PRO) \
+	$(IMC_PRO) \
 	$(CHANNEL_PRO)
 
 .SUFFIXES: .cod .i
diff -Naur vim82.orig/src/Makefile vim82+im_custom/src/Makefile
--- vim82.orig/src/Makefile	2019-12-12 12:14:23.000000000 +0000
+++ vim82+im_custom/src/Makefile	2021-11-21 03:35:52.223276900 +0000
@@ -1390,6 +1390,11 @@
 ALL_GUI_PRO  = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w32.pro gui_photon.pro
 
 # }}}
+### IM_CUSTOM  {{{1
+IM_CUSTOM_SRC = canna.c skk.c skklib.c pobox.c
+IM_CUSTOM_OBJ = objects/canna.o objects/skk.o objects/pobox.o
+IM_CUSTOM_PRO = canna.pro skk.pro pobox.pro
+# }}}
 
 TERM_DEPS = \
 	libvterm/include/vterm.h \
@@ -1702,7 +1707,7 @@
 RUN_UNITTESTS = run_json_test run_kword_test run_memfile_test run_message_test
 
 # All sources, also the ones that are not configured
-ALL_LOCAL_SRC = $(BASIC_SRC) $(ALL_GUI_SRC) $(UNITTEST_SRC) $(EXTRA_SRC)
+ALL_LOCAL_SRC = $(BASIC_SRC) $(ALL_GUI_SRC) $(UNITTEST_SRC) $(EXTRA_SRC) $(IM_CUSTOM_SRC)
 ALL_SRC = $(ALL_LOCAL_SRC) $(TERM_SRC) $(XDIFF_SRC)
 
 # Which files to check with lint.  Select one of these three lines.  ALL_SRC
@@ -1816,6 +1821,7 @@
 	$(RUBY_OBJ) \
 	$(OS_EXTRA_OBJ) \
 	$(NETBEANS_OBJ) \
+	$(IM_CUSTOM_OBJ) \
 	$(CHANNEL_OBJ) \
 	$(XDIFF_OBJS)
 
@@ -3449,6 +3455,15 @@
 objects/channel.o: channel.c
 	$(CCC) -o $@ channel.c
 
+objects/canna.o: canna.c
+	$(CCC) -o $@ canna.c
+
+objects/skk.o: skk.c skklib.c
+	$(CCC) -o $@ skk.c
+
+objects/pobox.o: pobox.c
+	$(CCC) -o $@ pobox.c
+
 Makefile:
 	@echo The name of the makefile MUST be "Makefile" (with capital M)!!!!
 
diff -Naur vim82.orig/src/auto/configure vim82+im_custom/src/auto/configure
--- vim82.orig/src/auto/configure	2019-11-21 16:04:15.000000000 +0000
+++ vim82+im_custom/src/auto/configure	2021-11-21 03:35:52.223276900 +0000
@@ -843,6 +843,9 @@
 enable_gpm
 enable_sysmouse
 enable_nls
+enable_canna
+enable_skk
+enable_pobox
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1518,6 +1521,9 @@
   --disable-gpm           Don't use gpm (Linux mouse daemon).
   --disable-sysmouse      Don't use sysmouse (mouse in *BSD console).
   --disable-nls           Don't support NLS (gettext()).
+  --enable-canna          Include canna support. default=yes
+  --enable-skk            Include skk support. default=yes
+  --enable-pobox          Include pobox support. default=yes
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -14797,6 +14803,90 @@
 $as_echo "no" >&6; }
 fi
 
+# Check whether --enable-canna was given.
+if test "${enable_canna+set}" = set; then :
+  enableval=$enable_canna;
+else
+  enable_canna="yes"
+fi
+
+	if test "$enable_canna" = "yes"; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for jrKanjiControl in -lcanna" >&5
+$as_echo_n "checking for jrKanjiControl in -lcanna... " >&6; }
+if ${ac_cv_lib_canna_jrKanjiControl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcanna  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char jrKanjiControl ();
+int
+main ()
+{
+return jrKanjiControl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_canna_jrKanjiControl=yes
+else
+  ac_cv_lib_canna_jrKanjiControl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_canna_jrKanjiControl" >&5
+$as_echo "$ac_cv_lib_canna_jrKanjiControl" >&6; }
+if test "x$ac_cv_lib_canna_jrKanjiControl" = xyes; then :
+  libcanna="yes"
+fi
+
+		if test "$libcanna" = "yes"; then
+			imcustom=yes
+			$as_echo "#define FEAT_CANNA 1" >>confdefs.h
+
+			LIBS="$LIBS -lcanna"
+		fi
+	fi
+# Check whether --enable-skk was given.
+if test "${enable_skk+set}" = set; then :
+  enableval=$enable_skk;
+else
+  enable_skk="yes"
+fi
+
+	if test "$enable_skk" = "yes"; then
+		imcustom=yes
+		$as_echo "#define FEAT_SKK 1" >>confdefs.h
+
+	fi
+# Check whether --enable-pobox was given.
+if test "${enable_pobox+set}" = set; then :
+  enableval=$enable_pobox;
+else
+  enable_pobox="yes"
+fi
+
+	if test "$enable_pobox" = "yes"; then
+		imcustom=yes
+		$as_echo "#define FEAT_POBOX 1" >>confdefs.h
+
+	fi
+if test "$imcustom" = "yes"; then
+	$as_echo "#define FEAT_IM_CUSTOM 1" >>confdefs.h
+
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking linker --as-needed support" >&5
 $as_echo_n "checking linker --as-needed support... " >&6; }
 LINK_AS_NEEDED=
diff -Naur vim82.orig/src/canna.c vim82+im_custom/src/canna.c
--- vim82.orig/src/canna.c	1970-01-01 00:00:00.000000000 +0000
+++ vim82+im_custom/src/canna.c	2021-11-21 03:35:52.223276900 +0000
@@ -0,0 +1,640 @@
+/* vim: set sw=4 ts=4 sts=4: */
+#include "vim.h"
+
+#ifdef FEAT_CANNA
+#include <canna/jrkanji.h>
+
+typedef struct {
+	char_u		*echoStr;
+	int			length;
+	int			revPos;
+	int			revLen;
+} echoback_T;
+
+static jrKanjiStatus			ks;
+static jrKanjiStatusWithValue	ksv;
+static char_u	curMode[BUFSIZ];
+static char_u	curBuff[BUFSIZ];
+static char_u	*server = NULL;
+static char_u	*initfile = NULL;
+static char_u	*old_enc = NULL;
+static echoback_T curEcho;
+static echoback_T curGLine;
+static int	canna_enable = FALSE;
+static int	nbytes = 0;
+static int	orig_x, orig_y;
+static void canna_save_echoback();
+static int echoback_later = 0;
+
+#ifdef USE_ICONV
+static vimconv_T	canna_convt;
+#endif
+
+static struct {
+	int		vimkey;
+	int		cannakey;
+} canna_keytable[] = {
+	{K_UP,			CANNA_KEY_Up},
+	{K_DOWN,		CANNA_KEY_Down},
+	{K_LEFT,		CANNA_KEY_Left},
+	{K_RIGHT,		CANNA_KEY_Right},
+	{K_F1,			CANNA_KEY_F1},
+	{K_F2,			CANNA_KEY_F2},
+	{K_F3,			CANNA_KEY_F3},
+	{K_F4,			CANNA_KEY_F4},
+	{K_F5,			CANNA_KEY_F5},
+	{K_F6,			CANNA_KEY_F6},
+	{K_F7,			CANNA_KEY_F7},
+	{K_F8,			CANNA_KEY_F8},
+	{K_F9,			CANNA_KEY_F9},
+	{K_F10,			CANNA_KEY_F10},
+	{K_HOME,		CANNA_KEY_Home},
+#ifdef CANNA_KEY_End
+	{K_END,			CANNA_KEY_End},
+#endif
+#ifdef CANNA_KEY_PageUp
+	{K_PAGEUP,		CANNA_KEY_PageUp},
+#endif
+#ifdef CANNA_KEY_PageDown
+	{K_PAGEDOWN,	CANNA_KEY_PageDown},
+#endif
+	{K_BS,			'\b'},
+	{K_DEL,			'\177'},
+	{NUL,			NUL}
+};
+
+static int
+canna_getmode(void)
+{
+	char buf[2];
+	jrKanjiControl(0, KC_SETMODEINFOSTYLE, (char *)1);
+	jrKanjiControl(0, KC_QUERYMODE, buf);
+	jrKanjiControl(0, KC_SETMODEINFOSTYLE, (char *)0);
+	return buf[0] - '@';
+}
+
+int
+canna_set_active(int act)
+{
+	int mode;
+	if (act)
+		canna_enabled(TRUE);
+	if (!canna_enable)
+		return FALSE;
+	ksv.ks = &ks;
+	ksv.buffer = curBuff;
+	ksv.bytes_buffer = sizeof curBuff;
+	mode = canna_getmode();
+	if (act && mode == CANNA_MODE_AlphaMode)
+	{
+		ksv.val = CANNA_MODE_HenkanNyuryokuMode;
+		jrKanjiControl(0, KC_CHANGEMODE, (char *)&ksv);
+		canna_save_echoback();
+		/*
+		 * When we get into CANNA_MODE_HenkanNyuryokuMode,
+		 * ks.info may not set. 
+		 */
+		jrKanjiControl(0, KC_QUERYMODE, (char *)curMode);
+	}
+	else if (!act && mode != CANNA_MODE_AlphaMode)
+	{
+		jrKanjiControl(0, KC_KILL, (char *)&ksv);
+		ksv.val = CANNA_MODE_AlphaMode;
+		jrKanjiControl(0, KC_CHANGEMODE, (char *)&ksv);
+		canna_save_echoback();
+		echoback_later = 0;
+	}
+	return TRUE;
+}
+
+int
+canna_get_active()
+{
+	if (!canna_enable)
+		return FALSE;
+	return (canna_getmode() == CANNA_MODE_AlphaMode) ? FALSE : TRUE;
+}
+
+static int
+canna_puts(char_u *src, int *x, int *y, int attr)
+{
+	int	len = 1;
+	int	all_cells = 0;
+	char_u	*ptr;
+	char_u	cell[MB_MAXBYTES];
+
+	for(ptr = src; *ptr; ptr+=len)
+	{
+		int	cells = 0;
+		int	diffs = 0;
+		cells = mb_ptr2cells(ptr);
+
+		len = (*mb_ptr2len)(ptr);
+		vim_strncpy(cell, ptr, len);
+		if (State & CMDLINE || *y == Rows - 1)
+		{
+			diffs = *x + cells - Columns;
+			if (diffs > 0)
+			{
+				if (diffs < cells)
+					screen_putchar('>', *y, *x, HL_ATTR(HLF_AT));
+				*x = 0;
+			}
+		}
+		else
+		{
+			diffs = *x + cells - W_ENDCOL(curwin);
+			if (diffs > 0)
+			{
+				if (diffs < cells)
+					screen_putchar('>', *y, *x, HL_ATTR(HLF_AT));
+				*x = curwin->w_wincol;
+				if (*y < W_WINROW(curwin) + curwin->w_height - 1)
+					*y += 1;
+			}
+		}
+		screen_puts(cell, *y, *x, attr);
+		*x += cells;
+		all_cells += cells;
+	}
+	if ((State & CMDLINE) == 0)
+	{
+		if (*x == W_ENDCOL(curwin))
+		{
+			*x = curwin->w_wincol;
+			if (*y < W_WINROW(curwin) + curwin->w_height - 1)
+				*y += 1;
+			windgoto(*y, *x);
+		}
+	}
+	return all_cells;
+}
+
+static void
+canna_getxy(int *x, int *y)
+{
+	if (State & CMDLINE)
+	{
+		*x = msg_col;
+		*y = msg_row;
+	}
+	else
+	{
+		*x = curwin->w_wincol + curwin->w_wcol;
+		*y = W_WINROW(curwin) + curwin->w_wrow;
+	}
+
+}
+
+static void
+canna_conv_free(char_u* src)
+{
+#ifdef USE_ICONV
+	vim_free(src);
+#else
+	if (enc_dbcs == DBCS_JPNU)
+		return;
+	vim_free(src);
+#endif
+}
+
+static char_u*
+canna_conv_alloc(char_u* src)
+{
+	char_u	*ret;
+
+#ifdef USE_ICONV
+	ret = string_convert(&canna_convt, (char_u*)src, NULL);
+	if (!ret)
+		ret = vim_strsave(src);
+#else
+	char_u	c1, c2;
+	char_u	*dst;
+	ret = dst = vim_strsave(src);
+	switch(enc_dbcs)
+	{
+	case DBCS_JPNU:
+		break;
+	case DBCS_JPN:
+		while(*src)
+		{
+			c1 = *src;
+			c2 = *(src+1);
+			if (c2 == 0x00 || (c1 & 0x80) == 0)
+				*dst++ = c1;
+			else
+			if (c1 == 0x8e)
+			{
+				*dst++ = c2;
+				src++;
+			}
+			else
+			{
+				if (c1 % 2 == 0)
+					c2 -= 0x02;
+				else
+					c2 -= (c2 > 0xdf) ? 0x60 : 0x61;
+				if (c1 < 0xdf)
+					c1 = (c1 + 1) / 2 + 0x30;
+				else
+					c1 = (c1 + 1) / 2 + 0x70;
+				*dst++ = c1;
+				*dst++ = c2;
+				src++;
+			}
+			src++;
+		}
+		*dst = 0;
+		break;
+	default:
+		break;
+	}
+#endif
+	return ret;
+}
+
+/* must free using vim_free(), not canna_conv_free()! */
+static char_u *
+canna_conv_alloc_n(char_u *p, int len)
+{
+	char_u	*tmp;
+	char_u	*dst;
+	tmp = vim_strnsave(p, len);
+	dst = canna_conv_alloc(tmp);
+	canna_conv_free(tmp);		/* ugly! */
+	return dst;
+}
+
+static void
+canna_save_echoback()
+{
+	if (ks.length != -1)
+	{
+		vim_free(curEcho.echoStr);
+		curEcho.echoStr = vim_strnsave(ks.echoStr, ks.length);
+		curEcho.length = ks.length;
+		curEcho.revPos = ks.revPos;
+		curEcho.revLen = ks.revLen;
+	}
+
+	if (ks.info & KanjiModeInfo)
+		STRCPY(curMode, ks.mode);
+
+	vim_free(curGLine.echoStr);
+	curGLine.echoStr = NULL;
+	if (ks.info & KanjiGLineInfo && ks.gline.length != 0) {
+		curGLine.echoStr = vim_strnsave(ks.gline.line, ks.gline.length);
+		curGLine.length = ks.gline.length;
+		curGLine.revPos = ks.gline.revPos;
+		curGLine.revLen = ks.gline.revLen;
+	}
+}
+
+static int
+canna_echoback(echoback_T *pecho, int *px, int *py, int attr)
+{
+	int		off;
+	int		cells;
+	char_u	*msg;
+	if (!pecho || !pecho->echoStr)
+		return 0;
+	off = pecho->revPos;
+	msg = canna_conv_alloc_n(pecho->echoStr, off);
+	cells = canna_puts(msg, px, py, attr);
+	vim_free(msg);
+	
+	msg = canna_conv_alloc_n(pecho->echoStr + off, pecho->revLen);
+	cells += canna_puts(msg, px, py, HL_STANDOUT);
+	vim_free(msg);
+
+	off += pecho->revLen;
+	msg = canna_conv_alloc_n(pecho->echoStr + off, pecho->length - off);
+	cells += canna_puts(msg, px, py, attr);
+	vim_free(msg);
+	return cells;
+}
+
+static int
+canna_beep(void)
+{
+	vim_beep(BO_ERROR);
+	return 0;
+}
+
+extern int (*jrBeepFunc)(void);
+int
+canna_enabled(int verbose)
+{
+	if (!canna_enable)
+	{
+		char_u	**ptr = NULL;
+		int r;
+		if (server)
+			jrKanjiControl(0, KC_SETSERVERNAME, (char *)server);
+		if (initfile)
+			jrKanjiControl(0, KC_SETINITFILENAME, (char *)initfile);
+		r = jrKanjiControl(0, KC_INITIALIZE, (char *)&ptr);
+		if (r)
+		{
+			if (verbose)
+			{
+				char_u	*dst = canna_conv_alloc((char_u *)jrKanjiError);
+				emsg((char *)dst);
+				canna_conv_free(dst);
+			}
+			return FALSE;
+		}
+		else if (ptr)
+		{
+			if (verbose)
+			{
+				while(*ptr)
+				{
+					char_u	*dst = canna_conv_alloc(*ptr++);
+					emsg((char *)dst);
+					canna_conv_free(dst);
+				}
+			}
+		}
+		else
+		{
+    		jrKanjiControl(0, KC_SETAPPNAME, "vim");
+#if 0
+			if (!initfile)
+    			jrKanjiControl(0, KC_SETBUNSETSUKUGIRI, (char*) &ksv);
+#endif
+    		jrKanjiControl(0, KC_SETUNDEFKEYFUNCTION, kc_normal);
+			jrKanjiControl(0, KC_SETWIDTH,
+					(char*) ((State & CMDLINE) ? 0 : (Columns-8)));
+			curBuff[0] = '\0';
+			nbytes = 0;
+		}
+		jrBeepFunc = &canna_beep;
+		ksv.ks = &ks;
+		ksv.buffer = curBuff;
+		ksv.bytes_buffer = sizeof curBuff;
+		ksv.val = CANNA_MODE_AlphaMode;
+		jrKanjiControl(0, KC_CHANGEMODE, (char*) &ksv);
+		curBuff[0] = '\0';
+		nbytes = 0;
+		curEcho.echoStr = NULL;
+		canna_save_echoback();
+		echoback_later = 0;
+		canna_enable = TRUE;
+	}
+#ifdef USE_ICONV
+	if (canna_enable && old_enc != p_enc)
+	{
+		canna_convt.vc_fd = (iconv_t)-1;
+		if (!convert_setup(&canna_convt, (char_u *)"euc-jisx0213", p_enc))
+        {
+            convert_setup(&canna_convt, (char_u *)"euc-jp", p_enc);
+        }
+	}
+#endif
+	return canna_enable;
+
+}
+
+int
+canna_end()
+{
+	if (canna_enable)
+    	jrKanjiControl(0, KC_FINALIZE, 0);
+	canna_enable = FALSE;
+	echoback_later = 0;
+	return TRUE;
+}
+
+static void
+canna_kakutei(char_u* p)
+{
+	char_u	*dst;
+	dst = canna_conv_alloc(p);
+	vim_strncpy(curBuff, dst, sizeof curBuff - 1);
+	canna_conv_free(dst);
+}
+
+static int
+canna_fetch()
+{
+	int	c;
+	c = mb_ptr2char(curBuff+nbytes);
+	if (c)
+		nbytes += (*mb_ptr2len)(curBuff+nbytes);
+	return c;
+}
+
+int
+canna_vgetc()
+{
+    int c, c2, length;
+
+	if (canna_enable == FALSE)
+		return 0;
+
+	c = canna_fetch();
+	if (c)
+		return c;
+
+	canna_getxy(&orig_x, &orig_y);
+
+    curBuff[0] = '\0';
+	nbytes = 0;
+    length = 0;
+    ksv.ks = &ks;
+    ksv.buffer = curBuff;
+    ksv.bytes_buffer = sizeof curBuff;
+
+    while (1)
+	{
+		int	idx;
+		
+		if (echoback_later)
+		{
+			if (ks.length == 0)
+			{
+				update_screen(NOT_VALID);
+				if (State & CMDLINE)
+					redrawcmd();
+				windgoto(orig_y, orig_x);
+				length = 0;
+			}
+			else
+			{
+				int		newlen;
+				int		x, y, xx, yy;
+				int		i;
+				if (State & CMDLINE)
+					redrawcmd();
+				else
+					showmode();
+				x = orig_x;
+				y = orig_y;
+				newlen = canna_echoback(&curEcho, &x, &y, HL_UNDERLINE);
+				xx = x;
+				yy = y;
+				for (i = newlen; i < length; i++)
+					canna_puts((char_u *)" ", &xx, &yy, HL_NORMAL);
+				length = newlen;
+				windgoto(y, x);
+				echoback_later = 0;
+			}
+		}
+
+		c = c2 = vgetc();
+	    if (ex_normal_busy || KeyStuffed)
+			return c;
+        if (c == 0)
+            continue;
+		else if (c >= 0x80)
+			return c;
+
+		for (idx = 0; canna_keytable[idx].vimkey; idx++)
+		{
+			if (canna_keytable[idx].vimkey == c)
+			{
+				c = canna_keytable[idx].cannakey;
+				break;
+			}
+		}
+
+		jrKanjiControl(0, KC_SETWIDTH,
+				(char*) ((State & CMDLINE) ? 0 : (Columns-8)));
+        nbytes = jrKanjiString(0, c, (char*)curBuff, sizeof curBuff, &ks);
+		canna_save_echoback();
+		if (!(State & CMDLINE))
+			redraw_cmdline = TRUE;
+
+		if (ks.info & KanjiThroughInfo)
+		{
+			curBuff[0] = '\0';
+			nbytes = 0;
+			return c2;
+		}
+
+		got_int = FALSE;
+
+        if (nbytes > 0)
+		{
+            curBuff[nbytes] = '\0';
+			canna_kakutei(curBuff);
+			nbytes = 0;
+            length = 0;
+			redraw_later(NOT_VALID);
+			if (ks.length >= 0)
+			{
+				echoback_later = 1;
+			}
+			break;
+        }
+
+        if (nbytes < 0)
+		{
+            jrKanjiControl(0, KC_KILL, (char*) &ksv);
+			canna_save_echoback();
+            curBuff[0] = '\0';
+            length = 0;
+			redraw_later(NOT_VALID);
+			continue;
+        }
+
+		if (ks.length == 0)
+		{
+			update_screen(NOT_VALID);
+			if (State & CMDLINE)
+				redrawcmd();
+			windgoto(orig_y, orig_x);
+			length = 0;
+		}
+		else
+		{
+			int		newlen;
+			int		x, y, xx, yy;
+			int		i;
+			if (State & CMDLINE)
+				redrawcmd();
+			else
+				showmode();
+			x = orig_x;
+			y = orig_y;
+			newlen = canna_echoback(&curEcho, &x, &y, HL_UNDERLINE);
+			xx = x;
+			yy = y;
+			for (i = newlen; i < length; i++)
+				canna_puts((char_u *)" ", &xx, &yy, HL_NORMAL);
+			length = newlen;
+			windgoto(y, x);
+		}
+    }
+	return canna_fetch();
+}
+
+int
+canna_redraw(void)
+{
+	jrKanjiControl(0, KC_SETWIDTH,
+			(char*) (State & CMDLINE ? 0 : (Columns-8)));
+	jrKanjiControl(0, KC_KILL, (char*) &ksv);
+	canna_save_echoback();
+	echoback_later = 0;
+	return TRUE;
+}
+
+char *
+canna_imopts(char_u *opts)
+{
+	char	*errmsg = NULL;
+	char_u	*org, *ptr;
+	char_u	*name, *val = NULL;	/* for gcc */
+	vim_free(server);
+	vim_free(initfile);
+	server = NULL;
+	initfile = NULL;
+	org = ptr = vim_strsave(opts);
+	while(*ptr)
+	{
+		name = ptr;
+		while(*ptr != ':' && *ptr != ',' && *ptr != '\0')
+			ptr++;
+		switch(*ptr)
+		{
+		case ',':
+			*ptr++ = 0;
+			name = NULL;
+			val = NULL;
+			continue;
+			break;
+		case ':':
+			*ptr++ = 0;
+			val = ptr;
+			while(*ptr != ',' && *ptr != '\0')
+				ptr++;
+			if (*ptr != '\0')
+				*ptr++ = 0;
+		}
+		if (!STRICMP(name, "serv"))
+			server = vim_strsave(val);
+		else if (!STRICMP(name, "ini"))
+			initfile = vim_strsave(val);
+		else
+			errmsg = _("illegal imoptions");
+	}
+	vim_free(org);
+	return errmsg;
+}
+
+int
+canna_showmode(void)
+{
+	char_u	*p;
+	if (!canna_get_active())
+		return FALSE;
+	p = canna_conv_alloc(curMode);
+	canna_puts(p, &msg_col, &msg_row, HL_NORMAL);
+	canna_conv_free(p);
+	if (curGLine.echoStr)
+		canna_echoback(&curGLine, &msg_col, &msg_row, HL_NORMAL);
+	return TRUE;
+}
+#endif /* FEAT_CANNA */
diff -Naur vim82.orig/src/config.h.in vim82+im_custom/src/config.h.in
--- vim82.orig/src/config.h.in	2019-11-21 16:03:13.000000000 +0000
+++ vim82+im_custom/src/config.h.in	2021-11-21 03:35:52.238902000 +0000
@@ -459,6 +459,18 @@
 /* Define if you want XSMP interaction as well as vanilla swapfile safety */
 #undef USE_XSMP_INTERACT
 
+/* Define if use im_custom */
+# undef FEAT_IM_CUSTOM
+
+/* Define if use canna */
+#undef FEAT_CANNA
+
+/* Define if use skk */
+# undef FEAT_SKK
+
+/* Define if use pobox */
+# undef FEAT_POBOX
+
 /* Define if fcntl()'s F_SETFD command knows about FD_CLOEXEC */
 #undef HAVE_FD_CLOEXEC
 
diff -Naur vim82.orig/src/configure.ac vim82+im_custom/src/configure.ac
--- vim82.orig/src/configure.ac	2019-11-21 16:03:01.000000000 +0000
+++ vim82+im_custom/src/configure.ac	2021-11-21 03:35:52.238902000 +0000
@@ -4483,6 +4483,35 @@
   AC_MSG_RESULT(no)
 fi
 
+AC_ARG_ENABLE(canna,
+	[  --enable-canna          Include canna support. [default=yes]], ,
+	[enable_canna="yes"])
+	if test "$enable_canna" = "yes"; then
+		AC_CHECK_LIB(canna, jrKanjiControl, libcanna="yes")
+		if test "$libcanna" = "yes"; then
+			imcustom=yes
+			AC_DEFINE(FEAT_CANNA)
+			LIBS="$LIBS -lcanna"
+		fi
+	fi
+AC_ARG_ENABLE(skk,
+	[  --enable-skk            Include skk support. [default=yes]], ,
+	[enable_skk="yes"])
+	if test "$enable_skk" = "yes"; then
+		imcustom=yes
+		AC_DEFINE(FEAT_SKK)
+	fi
+AC_ARG_ENABLE(pobox,
+	[  --enable-pobox          Include pobox support. [default=yes]], ,
+	[enable_pobox="yes"])
+	if test "$enable_pobox" = "yes"; then
+		imcustom=yes
+		AC_DEFINE(FEAT_POBOX)
+	fi
+if test "$imcustom" = "yes"; then
+	AC_DEFINE(FEAT_IM_CUSTOM)
+fi
+
 dnl link.sh tries to avoid overlinking in a hackish way.
 dnl At least GNU ld supports --as-needed which provides the same functionality
 dnl at linker level. Let's use it.
diff -Naur vim82.orig/src/evalfunc.c vim82+im_custom/src/evalfunc.c
--- vim82.orig/src/evalfunc.c	2019-12-01 20:10:25.000000000 +0000
+++ vim82+im_custom/src/evalfunc.c	2021-11-21 03:35:52.238902000 +0000
@@ -3412,6 +3412,18 @@
 #if defined(HAVE_ICONV_H) && defined(USE_ICONV)
 	"iconv",
 #endif
+#if defined(FEAT_IM_CUSTOM)
+	"im_custom",
+# if defined(FEAT_CANNA)
+	"im_custom/canna",
+# endif
+# if defined(FEAT_SKK)
+	"im_custom/skk",
+# endif
+# if defined(FEAT_POBOX)
+	"im_custom/pobox",
+# endif
+#endif
 	"insert_expand",
 #ifdef FEAT_JOB_CHANNEL
 	"job",
diff -Naur vim82.orig/src/getchar.c vim82+im_custom/src/getchar.c
--- vim82.orig/src/getchar.c	2019-12-01 20:50:57.000000000 +0000
+++ vim82+im_custom/src/getchar.c	2021-11-21 03:35:52.238902000 +0000
@@ -1847,7 +1847,16 @@
 {
     int	c;
 
-    c = vgetc();
+#ifdef FEAT_IM_CUSTOM
+    if (!p_imdisable && im_custom_enabled && im_custom_enabled(FALSE)
+#ifdef FEAT_EX_EXTRA
+	    && !ex_normal_busy
+#endif
+	    )
+	c = im_custom_vgetc();
+    else
+#endif
+	c = vgetc();
     if (c == NUL)
 	c = get_keystroke();
     return c;
diff -Naur vim82.orig/src/globals.h vim82+im_custom/src/globals.h
--- vim82.orig/src/globals.h	2019-11-30 21:40:44.000000000 +0000
+++ vim82+im_custom/src/globals.h	2021-11-21 03:35:52.238902000 +0000
@@ -1737,3 +1737,15 @@
 # define REPEATED_MSG_LOOKING	    1
 # define REPEATED_MSG_SAFESTATE	    2
 #endif
+
+#ifdef FEAT_IM_CUSTOM
+EXTERN int	(*im_custom_vgetc)(void)	INIT(=NULL);
+EXTERN int	(*im_custom_enabled)(int)	INIT(=NULL);
+EXTERN int	(*im_custom_end)(void)		INIT(=NULL);
+EXTERN char *   (*im_custom_imopts)(char_u *)	INIT(=NULL);
+EXTERN int	(*im_custom_get_active)(void)	INIT(=NULL);
+EXTERN int	(*im_custom_set_active)(int)	INIT(=NULL);
+EXTERN int	(*im_custom_redraw)(void)	INIT(=NULL);
+EXTERN int	(*im_custom_showmode)(void)	INIT(=NULL);
+#endif
+
diff -Naur vim82.orig/src/gui_mac.c vim82+im_custom/src/gui_mac.c
--- vim82.orig/src/gui_mac.c	2019-12-02 21:15:16.000000000 +0000
+++ vim82+im_custom/src/gui_mac.c	2021-11-21 03:35:52.254523900 +0000
@@ -6226,6 +6226,13 @@
     ScriptLanguageRecord *slptr = NULL;
     OSStatus err;
 
+# if defined(FEAT_IM_CUSTOM)
+    if (im_custom_set_active)
+    {
+	im_custom_set_active(active);
+	return;
+    }
+# endif
     if (!gui.in_use)
 	return;
 
@@ -6282,6 +6289,11 @@
     int
 im_get_status(void)
 {
+# if defined(FEAT_IM_CUSTOM)
+    if (im_custom_get_active)
+	return im_custom_get_active();
+# endif
+
     if (! gui.in_use)
 	return 0;
 
diff -Naur vim82.orig/src/gui_w32.c vim82+im_custom/src/gui_w32.c
--- vim82.orig/src/gui_w32.c	2019-12-02 21:32:33.000000000 +0000
+++ vim82+im_custom/src/gui_w32.c	2021-11-21 03:35:52.254523900 +0000
@@ -5748,6 +5748,13 @@
     HIMC	hImc;
     static HIMC	hImcOld = (HIMC)0;
 
+#ifdef FEAT_IM_CUSTOM
+    if (im_custom_set_active)
+    {
+	im_custom_set_active(active);
+	return;
+    }
+#endif
 # ifdef VIMDLL
     if (!gui.in_use && !gui.starting)
     {
@@ -5825,6 +5832,11 @@
     int		status = 0;
     HIMC	hImc;
 
+#ifdef FEAT_IM_CUSTOM
+    if (im_custom_get_active)
+	return im_custom_get_active();
+#endif
+
 # ifdef VIMDLL
     if (!gui.in_use && !gui.starting)
 	return mbyte_im_get_status();
diff -Naur vim82.orig/src/mbyte.c vim82+im_custom/src/mbyte.c
--- vim82.orig/src/mbyte.c	2019-12-04 20:50:22.000000000 +0000
+++ vim82+im_custom/src/mbyte.c	2021-11-21 03:35:52.254523900 +0000
@@ -4855,6 +4855,16 @@
 {
     int was_active;
 
+#  if defined(FEAT_IM_CUSTOM)
+    if (im_custom_set_active)
+    {
+	if (p_imdisable)
+	    active = FALSE;
+	im_custom_set_active(active);
+	active = FALSE;
+    }
+#   endif /* FEAT_IM_CUSTOM */
+
     was_active = !!im_get_status();
     im_is_active = (active && !p_imdisable);
 
@@ -5850,6 +5860,10 @@
     int
 im_get_status(void)
 {
+#  ifdef FEAT_IM_CUSTOM
+    if (im_custom_get_active && im_custom_get_active())
+	return TRUE;
+#  endif /* FEAT_IM_CUSTOM */
 #  ifdef FEAT_EVAL
     if (USE_IMSTATUSFUNC)
 	return call_imstatusfunc();
@@ -5888,6 +5902,15 @@
 {
     int active = active_arg;
 
+#  if defined(FEAT_IM_CUSTOM)
+    if (im_custom_set_active)
+    {
+	if (p_imdisable)
+	    active = FALSE;
+	im_custom_set_active(active);
+	active = FALSE;
+    }
+#  endif /* FEAT_IM_CUSTOM */
     // If 'imdisable' is set, XIM is never active.
     if (p_imdisable)
 	active = FALSE;
@@ -6327,6 +6350,16 @@
     int
 im_get_status(void)
 {
+#   ifdef FEAT_IM_CUSTOM
+    if (im_custom_get_active) {
+	if (im_custom_get_active())
+	    return TRUE;
+#    if 1
+	else if (input_style & XIMPreeditPosition)
+	    return FALSE;
+#    endif
+    }
+#   endif /* FEAT_IM_CUSTOM */
 #  ifdef FEAT_EVAL
     if (USE_IMSTATUSFUNC)
 	return call_imstatusfunc();
@@ -6453,7 +6486,7 @@
 
 #else // !defined(FEAT_XIM)
 
-# if defined(IME_WITHOUT_XIM) || defined(VIMDLL)
+# if defined(FEAT_IM_CUSTOM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL)
 static int im_was_set_active = FALSE;
 
     int
@@ -6463,6 +6496,10 @@
 im_get_status(void)
 #  endif
 {
+#  if defined(FEAT_IM_CUSTOM)
+    if (im_custom_get_active)
+	return im_custom_get_active();
+#  endif
 #  if defined(FEAT_EVAL)
     if (USE_IMSTATUSFUNC)
 	return call_imstatusfunc();
@@ -6477,9 +6514,18 @@
 im_set_active(int active_arg)
 #  endif
 {
-#  if defined(FEAT_EVAL)
+#  if defined(FEAT_IM_CUSTOM) || defined(IME_WITHOUT_XIM)
     int	    active = !p_imdisable && active_arg;
+#  endif
 
+#  if defined(FEAT_IM_CUSTOM)
+    if (im_custom_set_active)
+    {
+	im_custom_set_active(active);
+	active = FALSE;
+    }
+#  endif
+#  if defined(FEAT_EVAL)
     if (USE_IMACTIVATEFUNC && active != im_get_status())
     {
 	call_imactivatefunc(active);
@@ -6511,6 +6557,94 @@
 }
 #endif
 
+#ifdef FEAT_IM_CUSTOM
+    char *
+set_imoptions(
+    char_u	**varp
+    )
+{
+    char_u  *p, *settings = NULL;
+    char *errmsg = NULL;
+    p = *varp;
+
+    if (im_custom_end)
+	im_custom_end();
+
+    if (!p || !STRICMP(p, "none"))
+    {
+	im_custom_vgetc = NULL;
+	im_custom_enabled = NULL;
+	im_custom_end = NULL;
+	im_custom_imopts = NULL;
+	im_custom_set_active = NULL;
+	im_custom_get_active = NULL;
+	im_custom_redraw = NULL;
+	im_custom_showmode = NULL;
+	errmsg = NULL;
+    }
+#ifdef FEAT_CANNA
+    else
+    if (!STRNICMP(p, "canna",5) && (*(p+5) == ',' || *(p+5) == NUL))
+    {
+	im_custom_vgetc = canna_vgetc;
+	im_custom_enabled = canna_enabled;
+	im_custom_end = canna_end;
+	im_custom_imopts = canna_imopts;
+	im_custom_set_active = canna_set_active;
+	im_custom_get_active = canna_get_active;
+	im_custom_redraw = canna_redraw;
+	im_custom_showmode = canna_showmode;
+	settings = p+5;
+    }
+#endif
+#ifdef FEAT_SKK
+    else
+    if (!STRNICMP(p, "skk",3) && (*(p+3) == ',' || *(p+3) == NUL))
+    {
+	im_custom_vgetc = skk_vgetc;
+	im_custom_enabled = skk_enabled;
+	im_custom_end = skk_end;
+	im_custom_imopts = skk_imopts;
+	im_custom_set_active = skk_set_active;
+	im_custom_get_active = skk_get_active;
+	im_custom_redraw = skk_redraw;
+	im_custom_showmode = skk_showmode;
+	settings = p+3;
+    }
+#endif
+#ifdef FEAT_POBOX
+    else
+    if (!STRNICMP(p, "pobox",5) && (*(p+5) == ',' || *(p+5) == NUL))
+    {
+	im_custom_vgetc = pobox_vgetc;
+	im_custom_enabled = pobox_enabled;
+	im_custom_end = pobox_end;
+	im_custom_imopts = pobox_imopts;
+	im_custom_set_active = pobox_set_active;
+	im_custom_get_active = pobox_get_active;
+	im_custom_redraw = pobox_redraw;
+	im_custom_showmode = pobox_showmode;
+	settings = p+5;
+    }
+#endif
+    else
+    {
+	errmsg = _("illegal imoptions");
+    }
+
+    if (!errmsg && im_custom_enabled)
+    {
+	errmsg = (char *)im_custom_imopts(settings);
+	if (!errmsg)
+	{
+	    if (im_custom_enabled(TRUE) == FALSE)
+		errmsg = _("can't load custom im");
+	}
+    }
+    return errmsg;
+}
+#endif
+
 /*
  * Setup "vcp" for conversion from "from" to "to".
  * The names must have been made canonical with enc_canonize().
diff -Naur vim82.orig/src/option.c vim82+im_custom/src/option.c
--- vim82.orig/src/option.c	2019-12-05 19:11:19.000000000 +0000
+++ vim82+im_custom/src/option.c	2021-11-21 03:35:52.254523900 +0000
@@ -373,6 +373,10 @@
 
     save_file_ff(curbuf);	// Buffer is unchanged
 
+#ifdef FEAT_IM_CUSTOM
+    (void)set_imoptions(&p_imoptions);
+#endif
+
 #if defined(FEAT_ARABIC)
     // Detect use of mlterm.
     // Mlterm is a terminal emulator akin to xterm that has some special
diff -Naur vim82.orig/src/option.h vim82+im_custom/src/option.h
--- vim82.orig/src/option.h	2019-11-30 21:40:44.000000000 +0000
+++ vim82+im_custom/src/option.h	2021-11-21 03:35:52.254523900 +0000
@@ -644,6 +644,9 @@
 EXTERN int	p_imcmdline;	// 'imcmdline'
 EXTERN int	p_imdisable;	// 'imdisable'
 EXTERN long	p_iminsert;	// 'iminsert'
+#if defined(FEAT_IM_CUSTOM)
+EXTERN char_u	*p_imoptions;	// 'imoptions'
+#endif
 EXTERN long	p_imsearch;	// 'imsearch'
 EXTERN int	p_inf;		// 'infercase'
 #if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
diff -Naur vim82.orig/src/optiondefs.h vim82+im_custom/src/optiondefs.h
--- vim82.orig/src/optiondefs.h	2019-11-30 21:40:44.000000000 +0000
+++ vim82+im_custom/src/optiondefs.h	2021-11-21 03:35:52.270144800 +0000
@@ -1337,6 +1337,12 @@
 			    (char_u *)&p_iminsert, PV_IMI,
 			    {(char_u *)B_IMODE_NONE, (char_u *)0L}
 			    SCTX_INIT},
+#ifdef FEAT_IM_CUSTOM
+    {"imoptions",   "imo",  P_STRING|P_VI_DEF|P_RALL|P_COMMA|P_NODUP,
+			    (char_u *)&p_imoptions, PV_NONE,
+			    {(char_u *)"none", (char_u *)0L}
+			    SCTX_INIT},
+#endif
     {"imsearch",    "ims",  P_NUM|P_VI_DEF,
 			    (char_u *)&p_imsearch, PV_IMS,
 			    {(char_u *)B_IMODE_USE_INSERT, (char_u *)0L}
diff -Naur vim82.orig/src/optionstr.c vim82+im_custom/src/optionstr.c
--- vim82.orig/src/optionstr.c	2019-11-30 21:40:44.000000000 +0000
+++ vim82+im_custom/src/optionstr.c	2021-11-21 03:35:52.270144800 +0000
@@ -1293,6 +1293,14 @@
 	}
     }
 
+#ifdef FEAT_IM_CUSTOM
+    // 'imoptions'
+    else if (varp == &p_imoptions)
+    {
+	errmsg = set_imoptions(&p_imoptions);
+    }
+#endif
+
     // 'listchars'
     else if (varp == &p_lcs)
     {
diff -Naur vim82.orig/src/pobox.c vim82+im_custom/src/pobox.c
--- vim82.orig/src/pobox.c	1970-01-01 00:00:00.000000000 +0000
+++ vim82+im_custom/src/pobox.c	2021-11-21 03:35:52.270144800 +0000
@@ -0,0 +1,705 @@
+/* vim: set sw=4 ts=4 sts=4: */
+#include "vim.h"
+
+#ifdef FEAT_POBOX
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#ifdef WIN32
+#include <winsock.h>
+#include <io.h>
+typedef u_short inet_port_T;
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#define closesocket(s)	close(s)
+typedef uint16_t inet_port_T;
+#endif
+
+#ifdef BCOPY
+#define bincopy(a,b,n)	bcopy(a,b,n)
+#define fillzero(a,n)	bzero(a,n)
+#else
+#define bincopy(a,b,n)	memcpy(b,a,n)
+#define fillzero(a,n)	memset(a,0,n)
+#endif
+
+#define iseuckanji(c)	(0xa1 <= c && c <= 0xfe)
+
+static char_u					*svr_name = NULL;
+static inet_port_T				svr_port = 1178;
+static char_u					*old_enc = NULL;
+
+#define MAXCANDS 50
+#ifdef WIN32
+static int	win32poboxfd = -1;
+#endif
+static int	poboxfd = -1;
+static char_u	curBuff[50];
+static char_u	inpBuff[50];
+static char_u cands[MAXCANDS][100];
+static int	ncands = 0;
+static int	candindex = 0;
+static int	exact = 0;
+
+static int	maybe_skk = FALSE;
+static int	nbytes = 0;
+static int	pobox_enable = FALSE;
+static int	pobox_active = FALSE;
+static int	orig_x, orig_y;
+static int	activate_key = 28;
+
+static int	length = 0;
+int	pobox_enabled(int verborse);
+
+#ifdef USE_ICONV
+static vimconv_T	pobox_convt;
+#endif
+
+int
+pobox_set_active(int act)
+{
+	if (act)
+		pobox_enabled(TRUE);
+	if (pobox_enable)
+		pobox_active = act;
+	return TRUE;
+}
+
+int
+pobox_get_active()
+{
+	return pobox_active;
+}
+
+static int
+pobox_puts(char_u *src, int *x, int *y, int attr)
+{
+	int	len = 1;
+	int	all_cells = 0;
+	char_u	*ptr;
+	char_u	cell[MB_MAXBYTES];
+
+	for(ptr = src; *ptr; ptr+=len)
+	{
+		int	cells = 0;
+		int	diffs = 0;
+		cells = mb_ptr2cells(ptr);
+
+		len = (*mb_ptr2len)(ptr);
+		STRNCPY(cell, ptr, len);
+		cell[len] = 0;
+		if (State & CMDLINE) {
+			diffs = *x + cells - Columns;
+			if (diffs > 0) {
+				if (diffs < cells)
+					screen_putchar('>', *y, *x, HL_ATTR(HLF_AT));
+				*x = 0;
+			}
+		} else {
+			diffs = *x + cells - W_ENDCOL(curwin);
+			if (diffs > 0) {
+				if (diffs < cells)
+					screen_putchar('>', *y, *x, HL_ATTR(HLF_AT));
+				*x = curwin->w_wincol;
+				if (*y < W_WINROW(curwin) + curwin->w_height - 1)
+					*y += 1;
+			}
+		}
+		screen_puts(cell, *y, *x, attr);
+		*x += cells;
+		all_cells += cells;
+	}
+	if ((State & CMDLINE) == 0) {
+		if (*x == W_ENDCOL(curwin)) {
+			*x = curwin->w_wincol;
+			if (*y < W_WINROW(curwin) + curwin->w_height - 1)
+				*y += 1;
+			windgoto(*y, *x);
+		}
+	}
+	return all_cells;
+}
+
+static void
+pobox_getxy(int *x, int *y)
+{
+	if (State & CMDLINE) {
+		*x = msg_col;
+		*y = msg_row;
+	} else {
+		*x = curwin->w_wincol + curwin->w_wcol;
+		*y = W_WINROW(curwin) + curwin->w_wrow;
+	}
+
+}
+
+static void
+pobox_conv_free(char_u* src)
+{
+#ifdef USE_ICONV
+	vim_free(src);
+#else
+	if (enc_dbcs == DBCS_JPNU)
+		return;
+	vim_free(src);
+#endif
+}
+
+static char_u*
+pobox_conv_alloc(char_u* src)
+{
+	char_u	*ret;
+
+#ifdef USE_ICONV
+	ret = string_convert(&pobox_convt, (char_u*)src, NULL);
+	if (!ret)
+		ret = vim_strsave(src);
+#else
+	char_u	c1, c2;
+	char_u	*dst;
+	ret = dst = vim_strsave(src);
+	switch(enc_dbcs)
+	{
+	case DBCS_JPNU:
+		break;
+	case DBCS_JPN:
+		while(*src)
+		{
+			c1 = *src;
+			c2 = *(src+1);
+			if (c2 == 0x00 || !iseuckanji(c1))
+				*dst++ = c1;
+			else if (c1 == 0x8e) {
+				*dst++ = c2;
+				src++;
+			} else {
+				if (c1 % 2 == 0)
+					c2 -= 0x02;
+				else
+					c2 -= (c2 > 0xdf) ? 0x60 : 0x61;
+				if (c1 < 0xdf)
+					c1 = (c1 + 1) / 2 + 0x30;
+				else
+					c1 = (c1 + 1) / 2 + 0x70;
+				*dst++ = c1;
+				*dst++ = c2;
+				src++;
+			}
+			src++;
+		}
+		*dst = 0;
+		break;
+	default:
+		break;
+	}
+#endif
+	return ret;
+}
+
+int init_socket(char_u *server, inet_port_T port)
+{
+	int sd;
+	struct sockaddr_in	sin;
+	struct hostent	*hp;
+	struct in_addr	hp_addr;
+
+#ifdef WIN32
+	{
+		WORD wVersionRequested;
+		WSADATA wsaData;
+		int sockopt = SO_SYNCHRONOUS_NONALERT;
+		wVersionRequested = MAKEWORD(1, 1);
+		if (WSAStartup(wVersionRequested, &wsaData) != 0) {
+			return -1;
+		}
+		/* Enable the use of sockets as filehandles */
+		setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
+			   (char *)&sockopt, sizeof(sockopt));
+	}
+#endif
+	if ((hp=gethostbyname((char *)server))==0) {
+		emsg("Unknown host");
+		return -1;
+	}
+
+	fillzero((char *)&sin,sizeof(sin));
+	bincopy(hp->h_addr, (char *)&hp_addr, hp->h_length);
+
+	sin.sin_family = AF_INET;
+	sin.sin_addr = hp_addr;
+	sin.sin_port = htons(port); 
+
+	if ((sd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
+		emsg("Invalid socket");
+		return -1;
+	}
+	if (connect(sd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+		emsg("Can't connect server");
+		return -1;
+	}
+#ifdef WIN321
+	if ((poboxfd = _open_osfhandle(sd, 0)) < 0) {
+		emsg("Can't connect server");
+		closesocket(sd);
+		return -1;
+	}
+	win32poboxfd = sd;
+#endif
+	return sd;
+}
+
+int
+pobox_enabled(int verbose)
+{
+	if (!pobox_enable) {
+		if (svr_name) {
+			poboxfd = init_socket(svr_name, svr_port);
+			if (poboxfd != -1)
+			{
+				curBuff[0] = '\0';
+    			inpBuff[0] = '\0';
+				nbytes = 0;
+				pobox_enable = TRUE;
+			}
+			else
+			{
+				pobox_enable = FALSE;
+				vim_free(svr_name);
+				svr_name = NULL;
+			}
+		}
+	}
+#ifdef USE_ICONV
+	if (pobox_enable && old_enc != p_enc)
+	{
+		pobox_convt.vc_fd = (iconv_t)-1;
+		convert_setup(&pobox_convt, (char_u *)"euc-jp", p_enc);
+	}
+#endif
+	return pobox_enable;
+}
+
+int
+pobox_end()
+{
+	if (pobox_enable) {
+		closesocket(poboxfd);
+		poboxfd = -1;
+#ifdef WIN32
+		closesocket(win32poboxfd);
+		win32poboxfd = -1;
+		WSACleanup();
+#endif
+		if (svr_name)
+			vim_free(svr_name);
+		svr_name = NULL;
+	}
+	pobox_enable = FALSE;
+	return TRUE;
+}
+
+static void
+pobox_kakutei(char_u* p)
+{
+	char_u	*dst;
+	dst = pobox_conv_alloc(p);
+	STRCPY(curBuff, dst);
+	pobox_conv_free(dst);
+}
+
+static int
+pobox_henkan(char_u* p, int len)
+{
+	char_u	*dst, *cpy;
+	int	x, y, cells = 0;
+
+	pobox_getxy(&x, &y);
+
+	cpy = vim_strsave(p);
+	cpy[len] = 0;
+	dst = pobox_conv_alloc(cpy);
+	cells += pobox_puts(dst, &x, &y, HL_UNDERLINE);
+	pobox_conv_free(dst);
+	vim_free(cpy);
+
+	return cells;
+}
+
+static void
+pobox_delhenkan(int len)
+{
+    if (len > 0) {
+		int		x, y;
+		char_u	*ptr;
+
+		x = orig_x;
+		y = orig_y;
+		ptr = alloc(len+1);
+		memset(ptr, ' ', len);
+		ptr[len] = 0;
+		pobox_puts(ptr, &x, &y, HL_NORMAL);
+		vim_free(ptr);
+    }
+	windgoto(orig_y, orig_x);
+}
+
+static void
+pobox_gline(int pos)
+{
+	char_u	*dst;
+	int	n, lastn;
+	int	x, y;
+	char_u	*ptr;
+	int	len;
+
+	if (State & CMDLINE || State & NORMAL)
+		return;
+
+	x = 0;
+	y = Rows - 1;
+
+	dst = alloc(Columns+1);
+	memset(dst, ' ', Columns);
+	dst[Columns] = 0;
+	pobox_puts(dst, &x, &y, HL_NORMAL);
+	vim_free(dst);
+	if (pos == -2)
+		return;
+
+	len = 0;
+	lastn = 0;
+	if (pos >= 0) {
+		for(n = 0; n < ncands; n++) {
+			if (n == pos)
+				break;
+			dst = pobox_conv_alloc(cands[n]);
+			for(ptr = dst; *ptr; ptr += (*(*mb_ptr2len))(ptr))
+				len += (*mb_ptr2cells)(ptr);
+			pobox_conv_free(dst);
+			len++;
+			if (len >= Columns) {
+				lastn = n;
+				len = 0;
+			}
+		}
+	}
+
+	x = 0;
+	y = Rows - 1;
+
+	len = 0;
+	for(n = lastn; n < ncands; n++) {
+		dst = pobox_conv_alloc(cands[n]);
+		for(ptr = dst; *ptr; ptr += (*(*mb_ptr2len))(ptr))
+			len += (*mb_ptr2cells)(ptr);
+		len++;
+		if (len >= Columns) {
+			pobox_conv_free(dst);
+			break;
+		}
+		if (n == pos)
+			pobox_puts(dst, &x, &y, HL_INVERSE);
+		else
+			pobox_puts(dst, &x, &y, HL_NORMAL);
+		pobox_conv_free(dst);
+		pobox_puts((char_u *)" ", &x, &y, HL_NORMAL);
+	}
+
+	windgoto(orig_y, orig_x);
+}
+
+static int
+pobox_fetch()
+{
+	int	c;
+	c = mb_ptr2char(curBuff+nbytes);
+	if (c)
+		nbytes += (*mb_ptr2len)(curBuff+nbytes);
+	return c;
+}
+
+void Insert(char_u *s)
+{
+	STRCAT(inpBuff, s);
+}
+
+void SelCand()
+{
+	char buf[100];
+
+	if (maybe_skk == TRUE)
+		return;
+	if (candindex == 0)
+		return;
+	sprintf(buf,"8%d\n",candindex-1);
+	send(poboxfd,buf,STRLEN(buf),0);
+	recv(poboxfd,buf,10,0);
+}
+
+void Search()
+{
+	char_u buf[2000];
+	char_u buf2[100];
+	char_u *s,*se;
+	int bytes;
+	int len;
+
+	sprintf((char *)buf,"1%s",inpBuff);
+	if (!exact) STRCAT(buf," ");
+	STRCAT(buf,"\n");
+	send(poboxfd,buf,STRLEN(buf),0);
+	
+	len = 0;
+	while((bytes = recv(poboxfd,(char *)buf+len,sizeof(buf)-len,0)) != 0) {
+		if (bytes < 0) {
+			emsg("Can't read from POBox server");
+			return;
+		}
+		if (buf[0] == '0')
+			return;
+		len += bytes;
+		if (buf[len-1] == '\n')
+			break;
+	}
+	buf[len] = '\0';
+	for(bytes = 0; nbytes < len; bytes++)
+	{
+		if (buf[bytes] == '/')
+		{
+			buf[bytes] = '\t';
+			maybe_skk = TRUE;
+		}
+		else
+		if (buf[bytes] == '\n')
+		{
+			buf[bytes] = '\0';
+			break;
+		}
+	}
+	
+	if (buf[1] == '\t')
+		s = buf + 2;
+	else
+		s = buf + 1;
+	for(ncands=0; *s && *s != '\n' && ncands < MAXCANDS; ncands++) {
+		for(se = s; *se && *se != '\t'; se++);
+		if (se-s > sizeof(buf2))
+			se = s + sizeof(buf2) - 1;
+		STRNCPY(buf2,s,se-s);
+		buf2[se-s] = '\0';
+		STRCPY(cands[ncands], buf2);
+		if (*se == '\t')
+			s = se+1;
+		else
+			s = se;
+	}
+}
+
+int
+pobox_vgetc()
+{
+    int c;
+	int	candindex = 0;
+
+	if (pobox_enable == FALSE)
+		return 0;
+
+	c = pobox_fetch();
+	if (c)
+		return c;
+
+	pobox_getxy(&orig_x, &orig_y);
+
+    curBuff[0] = '\0';
+    inpBuff[0] = '\0';
+	length = 0;
+	nbytes = 0;
+
+    while (1)
+	{
+		c = vgetc();
+	    if (ex_normal_busy || KeyStuffed)
+			return c;
+        if (c == 0)
+            continue;
+
+		if (pobox_active)
+		{
+        	if (c == activate_key || c == ESC)
+			{
+				memset(inpBuff, 0, sizeof(inpBuff));
+            	curBuff[0] = '\0';
+            	inpBuff[0] = '\0';
+				nbytes = 0;
+				redraw_later(NOT_VALID);
+				windgoto(orig_y, orig_x);
+				pobox_active = FALSE;
+				if (c == ESC)
+					return c;
+				else
+					return '\0';
+			}
+		}
+		else
+		{
+        	if (c == activate_key)
+			{
+				pobox_active = TRUE;
+				continue;
+			}
+			else
+				return c;
+		}
+		got_int = FALSE;
+
+        pobox_delhenkan(length);
+
+        if (c == activate_key || c == ESC) {
+        }
+
+		switch(c)
+		{
+		case '\b':
+		case K_BS:
+		case K_DEL:
+			if (candindex > 0)
+				candindex--;
+			else if (nbytes == 0)
+				return c;
+			else if (nbytes > 0) {
+				inpBuff[--nbytes] = '\0';
+				if (nbytes > 0)
+					Search();
+			}
+			break;
+		case '\t':
+		case ' ':
+			if (nbytes > 0)
+				candindex = (candindex % ncands) + 1;
+			else {
+				nbytes = 0;
+				ncands = 0;
+				candindex = 0;
+				exact = 0;
+				return ' ';
+			}
+			break;
+		case '\n':
+		case '\r':
+			if (candindex > 0) {
+				pobox_kakutei(cands[candindex-1]);
+				SelCand();
+				nbytes = 0;
+				ncands = 0;
+				candindex = 0;
+				exact = 0;
+			} else if (nbytes == 0) {
+				inpBuff[0] = '\0';
+				nbytes = 0;
+				ncands = 0;
+				candindex = 0;
+				exact = 0;
+				return c;
+			} else {
+				candindex = 1;
+				pobox_kakutei(cands[candindex-1]);
+				SelCand();
+				nbytes = 0;
+				ncands = 0;
+				candindex = 0;
+				exact = 0;
+			}
+			nbytes = 0;
+			pobox_gline(-2);
+			return pobox_fetch();
+			break;
+		default:
+			if (isupper(c))
+				c = tolower(c);
+			if (nbytes < sizeof(inpBuff)-1)
+			{
+				inpBuff[nbytes++] = (char_u)c;
+				inpBuff[nbytes] = '\0';
+			}
+			candindex = 0;
+			exact = 1;
+			Search();
+			break;
+		}
+		pobox_gline(candindex-1);
+		if (candindex > 0)
+			length = pobox_henkan(cands[candindex-1], STRLEN(cands[candindex-1]));
+		else
+			length = pobox_henkan(inpBuff, STRLEN(inpBuff));
+	}
+
+	return pobox_fetch();
+}
+
+int
+pobox_redraw(void)
+{
+	if (pobox_get_active()) {
+	}
+	return TRUE;
+}
+
+int
+pobox_showmode()
+{
+	return FALSE;
+}
+
+char *
+pobox_imopts(char_u *opts)
+{
+	char	*errmsg = NULL;
+	char_u	*org, *ptr;
+	char_u	*name, *val;
+	org = ptr = vim_strsave(opts);
+	svr_name = NULL;
+	while(*ptr)
+	{
+		name = ptr;
+		while(*ptr != ':' && *ptr != ',' && *ptr != '\0')
+			ptr++;
+		switch(*ptr)
+		{
+		case ',':
+			*ptr++ = 0;
+			name = NULL;
+			val = NULL;
+			continue;
+			break;
+		case ':':
+			*ptr++ = 0;
+			val = ptr;
+			while(*ptr != ',' && *ptr != '\0')
+				ptr++;
+			if (*ptr != '\0')
+				*ptr++ = 0;
+			break;
+		}
+		if (!STRICMP(name, "serv")) {
+			if (svr_name)
+				vim_free(svr_name);
+			svr_name = vim_strsave(val);
+		}
+		else if (!STRICMP(name, "port")) {
+			svr_port = (inet_port_T)atoi((char*)val);
+		}
+		else if (!STRICMP(name, "key"))
+			activate_key = atol((char *)val);
+		else
+			errmsg = _("illegal imoptions");
+	}
+	if (!svr_name)
+		errmsg = _("Didn't set server name");
+	vim_free(org);
+	return errmsg;
+}
+#endif /* FEAT_POBOX */
diff -Naur vim82.orig/src/proto/canna.pro vim82+im_custom/src/proto/canna.pro
--- vim82.orig/src/proto/canna.pro	1970-01-01 00:00:00.000000000 +0000
+++ vim82+im_custom/src/proto/canna.pro	2021-11-21 03:35:52.285766200 +0000
@@ -0,0 +1,10 @@
+/* canna.c */
+int canna_enabled(int verbose);
+int canna_end(void);
+int canna_set_active(int act);
+int canna_get_active(void);
+int canna_vgetc(void);
+char *canna_imopts(char_u *opts);
+int canna_redraw(void);
+int canna_showmode(void);
+/* vim: set ft=c : */
diff -Naur vim82.orig/src/proto/mbyte.pro vim82+im_custom/src/proto/mbyte.pro
--- vim82.orig/src/proto/mbyte.pro	2019-12-12 11:55:26.000000000 +0000
+++ vim82+im_custom/src/proto/mbyte.pro	2021-11-21 03:35:52.285766200 +0000
@@ -90,6 +90,7 @@
 void xim_set_status_area(void);
 int xim_get_status_area_height(void);
 void f_getimstatus(typval_T *argvars, typval_T *rettv);
+char *set_imoptions (char_u **varp);
 int convert_setup(vimconv_T *vcp, char_u *from, char_u *to);
 int convert_setup_ext(vimconv_T *vcp, char_u *from, int from_unicode_is_utf8, char_u *to, int to_unicode_is_utf8);
 int convert_input(char_u *ptr, int len, int maxlen);
diff -Naur vim82.orig/src/proto/pobox.pro vim82+im_custom/src/proto/pobox.pro
--- vim82.orig/src/proto/pobox.pro	1970-01-01 00:00:00.000000000 +0000
+++ vim82+im_custom/src/proto/pobox.pro	2021-11-21 03:35:52.285766200 +0000
@@ -0,0 +1,10 @@
+/* pobox.c */
+int pobox_enabled(int verbose);
+int pobox_end(void);
+int pobox_set_active(int act);
+int pobox_get_active(void);
+int pobox_vgetc(void);
+char *pobox_imopts(char_u *opts);
+int pobox_redraw(void);
+int pobox_showmode(void);
+/* vim: set ft=c : */
diff -Naur vim82.orig/src/proto/skk.pro vim82+im_custom/src/proto/skk.pro
--- vim82.orig/src/proto/skk.pro	1970-01-01 00:00:00.000000000 +0000
+++ vim82+im_custom/src/proto/skk.pro	2021-11-21 03:35:52.285766200 +0000
@@ -0,0 +1,10 @@
+/* skk.c */
+int skk_enabled(int verbose);
+int skk_end(void);
+int skk_set_active(int act);
+int skk_get_active(void);
+int skk_vgetc(void);
+char *skk_imopts(char_u *opts);
+int skk_redraw(void);
+int skk_showmode(void);
+/* vim: set ft=c : */
diff -Naur vim82.orig/src/proto.h vim82+im_custom/src/proto.h
--- vim82.orig/src/proto.h	2019-12-01 17:52:53.000000000 +0000
+++ vim82+im_custom/src/proto.h	2021-11-21 03:35:52.270144800 +0000
@@ -337,6 +337,15 @@
 #  include "if_perl.pro"
 #  include "if_perlsfio.pro"
 # endif
+#if defined(FEAT_CANNA)
+# include "canna.pro"
+#endif
+#if defined(FEAT_SKK)
+# include "skk.pro"
+#endif
+#if defined(FEAT_POBOX)
+# include "pobox.pro"
+#endif
 
 # ifdef MACOS_CONVERT
 #  include "os_mac_conv.pro"
diff -Naur vim82.orig/src/screen.c vim82+im_custom/src/screen.c
--- vim82.orig/src/screen.c	2019-12-06 18:04:54.000000000 +0000
+++ vim82+im_custom/src/screen.c	2021-11-21 03:35:52.285766200 +0000
@@ -4038,6 +4038,9 @@
     int		attr;
     int		nwr_save;
     int		sub_attr;
+#ifdef FEAT_IM_CUSTOM
+    int		nomore = FALSE;
+#endif
 
     do_mode = ((p_smd && msg_silent == 0)
 	    && ((State & INSERT)
@@ -4061,8 +4064,22 @@
 	// Position on the last line in the window, column 0
 	msg_pos_mode();
 	cursor_off();
+#ifdef FEAT_IM_CUSTOM
+	if (do_mode && im_custom_showmode)
+	{
+	    if (im_custom_showmode())
+	    {
+		nomore = TRUE;
+		need_clear = TRUE;
+	    }
+	}
+#endif
 	attr = HL_ATTR(HLF_CM);			// Highlight mode
-	if (do_mode)
+	if (do_mode
+#ifdef FEAT_IM_CUSTOM
+		&& !nomore
+#endif
+	   )
 	{
 	    msg_puts_attr("--", attr);
 #if defined(FEAT_XIM)
@@ -4203,7 +4220,11 @@
 
     // If the last window has no status line, the ruler is after the mode
     // message and must be redrawn
-    if (redrawing() && lastwin->w_status_height == 0)
+    if (redrawing() && lastwin->w_status_height == 0
+# ifdef FEAT_IM_CUSTOM
+	    && !nomore
+# endif
+	    )
 	win_redr_ruler(lastwin, TRUE, FALSE);
 #endif
     redraw_cmdline = FALSE;
diff -Naur vim82.orig/src/skk.c vim82+im_custom/src/skk.c
--- vim82.orig/src/skk.c	1970-01-01 00:00:00.000000000 +0000
+++ vim82+im_custom/src/skk.c	2021-11-21 03:35:52.301386800 +0000
@@ -0,0 +1,1850 @@
+/* vim: set sw=4 ts=4 sts=4: */
+#include "vim.h"
+
+#ifdef FEAT_SKK
+#define USE_SERVER
+#include "skklib.c"
+
+#define SKK_INPUT_HALP	0
+#define SKK_INPUT_HIRA	1
+#define SKK_INPUT_KATA	2
+#define SKK_INPUT_ZALP	3
+#define SKK_RET_UNK		0
+#define SKK_RET_FND		1
+#define SKK_RET_OKR		2
+#define SKK_DIC_USR		0
+#define SKK_DIC_MST		1
+#define SKK_DIC_SVR		2
+#define iseuckanji(c)	(0xa1 <= c && c <= 0xfe)
+
+static Dictionary				dic_usr = NULL;
+static Dictionary				dic_mst = NULL;
+static char_u					*usr_dic_path = NULL;
+static char_u					*mst_dic_path = NULL;
+static char_u					*svr_dic_host = NULL;
+static unsigned short			svr_dic_port = SKK_PORT_NUMBER;
+static char_u					*old_enc = NULL;
+static char_u	curBuff[256];
+static char_u	inpBuff[128];
+static int	input_mode = SKK_INPUT_HALP;
+static char_u	*regs_key = NULL;
+static char_u	*regs_str = NULL;
+static int	nfetch = 0;
+static int	preedit = 0;
+static int	skk_enable = FALSE;
+static int	skk_active = FALSE;
+static int	orig_x, orig_y;
+static int	dic_from = SKK_DIC_USR;
+int	skk_enabled(int verborse);
+#ifdef USE_SERVER
+static int  has_server = FALSE;
+#endif
+
+#ifdef USE_ICONV
+static vimconv_T	skk_convt;
+#endif
+
+struct iroha_struct {
+	char	*key;
+	char	*str;
+} iroha_table[] = {
+  /* ん行 */
+  {"n","\xa4\xf3"}, /* ん */
+  /* あ行 */
+  {"a","\xa4\xa2"}, /* あ */
+  {"i","\xa4\xa4"}, /* い */
+  {"u","\xa4\xa6"}, /* う */
+  {"e","\xa4\xa8"}, /* え */
+  {"o","\xa4\xaa"}, /* お */
+  {"xa","\xa4\xa1"}, /* ぁ */
+  {"xi","\xa4\xa3"}, /* ぃ */
+  {"xu","\xa4\xa5"}, /* ぅ */
+  {"xe","\xa4\xa7"}, /* ぇ */
+  {"xo","\xa4\xa9"}, /* ぉ */
+  /* か行 */
+  {"ka","\xa4\xab"}, /* か */
+  {"ki","\xa4\xad"}, /* き */
+  {"ku","\xa4\xaf"}, /* く */
+  {"ke","\xa4\xb1"}, /* け */
+  {"ko","\xa4\xb3"}, /* こ */
+  {"ca","\xa4\xab"}, /* か */
+  {"cu","\xa4\xaf"}, /* く */
+  {"co","\xa4\xb3"}, /* こ */
+  {"kya","\xa4\xad\xa4\xe3"}, /* きゃ */
+  {"kyi","\xa4\xad\xa4\xa3"}, /* きぃ */
+  {"kyu","\xa4\xad\xa4\xe5"}, /* きゅ */
+  {"kye","\xa4\xad\xa4\xa7"}, /* きぇ */
+  {"kyo","\xa4\xad\xa4\xe7"}, /* きょ */
+  {"ga","\xa4\xac"}, /* が */
+  {"gi","\xa4\xae"}, /* ぎ */
+  {"gu","\xa4\xb0"}, /* ぐ */
+  {"ge","\xa4\xb2"}, /* げ */
+  {"go","\xa4\xb4"}, /* ご */
+  {"gya","\xa4\xae\xa4\xe3"}, /* ぎゃ */
+  {"gyi","\xa4\xae\xa4\xa3"}, /* ぎぃ */
+  {"gyu","\xa4\xae\xa4\xe5"}, /* ぎゅ */
+  {"gye","\xa4\xae\xa4\xa7"}, /* ぎぇ */
+  {"gyo","\xa4\xae\xa4\xe7"}, /* ぎょ */
+  /* さ行 */
+  {"sa","\xa4\xb5"}, /* さ */
+  {"si","\xa4\xb7"}, /* し */
+  {"su","\xa4\xb9"}, /* す */
+  {"se","\xa4\xbb"}, /* せ */
+  {"so","\xa4\xbd"}, /* そ */
+  {"ci","\xa4\xb7"}, /* し */
+  {"ce","\xa4\xbb"}, /* せ */
+  {"sha","\xa4\xb7\xa4\xe3"}, /* しゃ */
+  {"shi","\xa4\xb7"}, /* し   */
+  {"shu","\xa4\xb7\xa4\xe5"}, /* しゅ */
+  {"she","\xa4\xb7\xa4\xa7"}, /* しぇ */
+  {"sho","\xa4\xb7\xa4\xe7"}, /* しょ */
+  {"sya","\xa4\xb7\xa4\xe3"}, /* しゃ */
+  {"syi","\xa4\xb7\xa4\xa3"}, /* しぃ */
+  {"syu","\xa4\xb7\xa4\xe5"}, /* しゅ */
+  {"sye","\xa4\xb7\xa4\xa7"}, /* しぇ */
+  {"syo","\xa4\xb7\xa4\xe7"}, /* しょ */
+  {"za","\xa4\xb6"}, /* ざ */
+  {"zi","\xa4\xb8"}, /* じ */
+  {"zu","\xa4\xba"}, /* ず */
+  {"ze","\xa4\xbc"}, /* ぜ */
+  {"zo","\xa4\xbe"}, /* ぞ */
+  {"ja","\xa4\xb8\xa4\xe3"},  /* じゃ */
+  {"ji","\xa4\xb8"}, /* じ */
+  {"ju","\xa4\xb8\xa4\xe5"},  /* じゅ */
+  {"je","\xa4\xb8\xa4\xa7"},  /* じぇ */
+  {"jo","\xa4\xb8\xa4\xe7"}, /* じょ */
+  {"zya","\xa4\xb8\xa4\xe3"}, /* じゃ */
+  {"zyi","\xa4\xb8\xa4\xa3"}, /* じぃ */
+  {"zyu","\xa4\xb8\xa4\xe5"}, /* じゅ */
+  {"zye","\xa4\xb8\xa4\xa7"}, /* じぇ */
+  {"zyo","\xa4\xb8\xa4\xe7"}, /* じょ */
+  {"jya","\xa4\xb8\xa4\xe3"}, /* じゃ */
+  {"jyi","\xa4\xb8\xa4\xa3"}, /* じぃ */
+  {"jyu","\xa4\xb8\xa4\xe5"}, /* じゅ */
+  {"jye","\xa4\xb8\xa4\xa7"}, /* じぇ */
+  {"jyo","\xa4\xb8\xa4\xe7"}, /* じょ */
+  /* た行 */
+  {"ta","\xa4\xbf"}, /* た */
+  {"ti","\xa4\xc1"}, /* ち */
+  {"tu","\xa4\xc4"}, /* つ */
+  {"te","\xa4\xc6"}, /* て */
+  {"to","\xa4\xc8"}, /* と */
+  {"cha","\xa4\xc1\xa4\xe3"}, /* ちゃ */
+  {"chi","\xa4\xc1"}, /* ち */
+  {"chu","\xa4\xc1\xa4\xe5"}, /* ちゅ */
+  {"che","\xa4\xc1\xa4\xa7"}, /* ちぇ */
+  {"cho","\xa4\xc1\xa4\xe7"}, /* ちょ */
+  {"tya","\xa4\xc1\xa4\xe3"}, /* ちゃ */
+  {"tyi","\xa4\xc1\xa4\xa3"}, /* ちぃ */
+  {"tyu","\xa4\xc1\xa4\xe5"}, /* ちゅ */
+  {"tye","\xa4\xc1\xa4\xa7"}, /* ちぇ */
+  {"tyo","\xa4\xc1\xa4\xe7"}, /* ちょ */
+  {"tsa","\xa4\xc4\xa4\xa1"}, /* つぁ */
+  {"tsi","\xa4\xc4\xa4\xa3"}, /* つぃ */
+  {"tsu","\xa4\xc4"}, /* つ */
+  {"tse","\xa4\xc4\xa4\xa7"}, /* つぇ */
+  {"tso","\xa4\xc4\xa4\xa9"}, /* つぉ */
+  {"tha","\xa4\xc6\xa4\xe3"}, /* てゃ */
+  {"thi","\xa4\xc6\xa4\xa3"}, /* てぃ */
+  {"thu","\xa4\xc6\xa4\xe5"}, /* てゅ */
+  {"the","\xa4\xc6\xa4\xa7"}, /* てぇ */
+  {"tho","\xa4\xc6\xa4\xe7"}, /* てょ */
+  {"da","\xa4\xc0"}, /* だ */
+  {"di","\xa4\xc2"}, /* ぢ */
+  {"du","\xa4\xc5"}, /* づ */
+  {"de","\xa4\xc7"}, /* で */
+  {"do","\xa4\xc9"}, /* ど */
+  {"dya","\xa4\xc2\xa4\xe3"}, /* ぢゃ */
+  {"dyi","\xa4\xc2\xa4\xa3"}, /* ぢぃ */
+  {"dyu","\xa4\xc2\xa4\xe5"}, /* ぢゅ */
+  {"dye","\xa4\xc2\xa4\xa7"}, /* ぢぇ */
+  {"dyo","\xa4\xc2\xa4\xe7"}, /* ぢょ */
+  {"dha","\xa4\xc7\xa4\xe3"}, /* でゃ */
+  {"dhi","\xa4\xc7\xa4\xa3"}, /* でぃ */
+  {"dhu","\xa4\xc7\xa4\xe5"}, /* でゅ */
+  {"dhe","\xa4\xc7\xa4\xa7"}, /* でぇ */
+  {"dho","\xa4\xc7\xa4\xe7"}, /* でょ */
+  {"xtu","\xa4\xc3"}, /* っ */
+  {"xtsu","\xa4\xc3"}, /* っ */
+  /* な行 */
+  {"na","\xa4\xca"}, /* な */
+  {"ni","\xa4\xcb"}, /* に */
+  {"nu","\xa4\xcc"}, /* ぬ */
+  {"ne","\xa4\xcd"}, /* ね */
+  {"no","\xa4\xce"}, /* の */
+  {"nya","\xa4\xcb\xa4\xe3"}, /* にゃ */
+  {"nyi","\xa4\xcb\xa4\xa3"}, /* にぃ */
+  {"nyu","\xa4\xcb\xa4\xe5"}, /* にゅ */
+  {"nye","\xa4\xcb\xa4\xa7"}, /* にぇ */
+  {"nyo","\xa4\xcb\xa4\xe7"}, /* にょ */
+  /* は行 */
+  {"fa","\xa4\xd5\xa4\xa1"}, /* ふぁ */
+  {"fi","\xa4\xd5\xa4\xa3"}, /* ふぃ */
+  {"fu","\xa4\xd5"}, /* ふ */
+  {"fe","\xa4\xd5\xa4\xa7"}, /* ふぇ */
+  {"fo","\xa4\xd5\xa4\xa9"}, /* ふぉ */
+  {"ha","\xa4\xcf"}, /* は */
+  {"hi","\xa4\xd2"}, /* ひ */
+  {"hu","\xa4\xd5"}, /* ふ */
+  {"he","\xa4\xd8"}, /* へ */
+  {"ho","\xa4\xdb"}, /* ほ */
+  {"hya","\xa4\xd2\xa4\xe3"}, /* ひゃ */
+  {"hyi","\xa4\xd2\xa4\xa3"}, /* ひぃ */
+  {"hyu","\xa4\xd2\xa4\xe5"}, /* ひゅ */
+  {"hye","\xa4\xd2\xa4\xa7"}, /* ひぇ */
+  {"hyo","\xa4\xd2\xa4\xe7"}, /* ひょ */
+  {"ba","\xa4\xd0"}, /* ば */
+  {"bi","\xa4\xd3"}, /* び */
+  {"bu","\xa4\xd6"}, /* ぶ */
+  {"be","\xa4\xd9"}, /* べ */
+  {"bo","\xa4\xdc"}, /* ぼ */
+  {"bya","\xa4\xd3\xa4\xe3"}, /* びゃ */
+  {"byi","\xa4\xd3\xa4\xa3"}, /* びぃ */
+  {"byu","\xa4\xd3\xa4\xe5"}, /* びゅ */
+  {"bye","\xa4\xd3\xa4\xa7"}, /* びぇ */
+  {"byo","\xa4\xd3\xa4\xe7"}, /* びょ */
+  {"pa","\xa4\xd1"}, /* ぱ */
+  {"pi","\xa4\xd4"}, /* ぴ */
+  {"pu","\xa4\xd7"}, /* ぷ */
+  {"pe","\xa4\xda"}, /* ぺ */
+  {"po","\xa4\xdd"}, /* ぽ */
+  {"pya","\xa4\xd4\xa4\xe3"}, /* ぴゃ */
+  {"pyi","\xa4\xd4\xa4\xa3"}, /* ぴぃ */
+  {"pyu","\xa4\xd4\xa4\xe5"}, /* ぴゅ */
+  {"pye","\xa4\xd4\xa4\xa7"}, /* ぴぇ */
+  {"pyo","\xa4\xd4\xa4\xe7"}, /* ぴょ */
+  /* ま行 */
+  {"ma","\xa4\xde"}, /* ま */
+  {"mi","\xa4\xdf"}, /* み */
+  {"mu","\xa4\xe0"}, /* む */
+  {"me","\xa4\xe1"}, /* め */
+  {"mo","\xa4\xe2"}, /* も */
+  {"mya","\xa4\xdf\xa4\xe3"}, /* みゃ */
+  {"myi","\xa4\xdf\xa4\xa3"}, /* みぃ */
+  {"myu","\xa4\xdf\xa4\xe5"}, /* みゅ */
+  {"mye","\xa4\xdf\xa4\xa7"}, /* みぇ */
+  {"myo","\xa4\xdf\xa4\xe7"}, /* みょ */
+  /* や行 */
+  {"ya","\xa4\xe4"}, /* や */
+  {"yu","\xa4\xe6"}, /* ゆ */
+  {"yo","\xa4\xe8"}, /* よ */
+  {"xya","\xa4\xe3"}, /* ゃ */
+  {"xyu","\xa4\xe5"}, /* ゅ */
+  {"xyo","\xa4\xe7"}, /* ょ */
+  /* ら行 */
+  {"ra","\xa4\xe9"}, /* ら */
+  {"ri","\xa4\xea"}, /* り */
+  {"ru","\xa4\xeb"}, /* る */
+  {"re","\xa4\xec"}, /* れ */
+  {"ro","\xa4\xed"}, /* ろ */
+  {"rya","\xa4\xea\xa4\xe3"}, /* りゃ */
+  {"ryi","\xa4\xea\xa4\xa3"}, /* りぃ */
+  {"ryu","\xa4\xea\xa4\xe5"}, /* りゅ */
+  {"rye","\xa4\xea\xa4\xa7"}, /* りぇ */
+  {"ryo","\xa4\xea\xa4\xe7"}, /* りょ */
+  /* わ行 */
+  {"wa","\xa4\xef"}, /* わ */
+  {"wi","\xa4\xf0"}, /* ゐ */
+  {"wu","\xa4\xa6"}, /* う */
+  {"we","\xa4\xf1"}, /* ゑ */
+  {"wo","\xa4\xf2"}, /* を */
+  /* ヴ行 */
+  {"va","\xa5\xf4\xa4\xa1"}, /* ヴぁ */
+  {"vi","\xa5\xf4\xa4\xa3"}, /* ヴぃ */
+  {"vu","\xa5\xf4"}, /* ヴ */
+  {"ve","\xa5\xf4\xa4\xa7"}, /* ヴぇ */
+  {"vo","\xa5\xf4\xa4\xa9"}, /* ヴぉ */
+  /* ん */
+  {"nn","\xa4\xf3"}, /* ん */
+  /* 記号 */
+  {"!", "\xa1\xaa"}, /* ！ */
+  {"\"","\xa1\xc9"}, /* ” */
+  {"#", "\xa1\xf4"}, /* ＃ */
+  {"$", "\xa1\xf0"}, /* ＄ */
+  {"%", "\xa1\xf3"}, /* ％ */
+  {"&", "\xa1\xf5"}, /* ＆ */
+  {"'", "\xa1\xc7"}, /* ’ */
+  {"(", "\xa1\xca"}, /* （ */
+  {")", "\xa1\xcb"}, /* ） */
+  {"=", "\xa1\xe1"}, /* ＝ */
+  {"^", "\xa1\xb0"}, /* ＾ */
+  {"~", "\xa1\xc1"}, /* ￣ */
+  {"\\","\xa1\xef"}, /* ￥ */
+  {"|", "\xa1\xc3"}, /* ｜ */
+  {"@", "\xa1\xf7"}, /* ＠ */
+  {"`", "\xa1\xae"}, /* ｀ */
+  {"{", "\xa1\xd0"}, /* ｛ */
+  {"}", "\xa1\xd1"}, /* ｝ */
+  {"+", "\xa1\xdc"}, /* ＋ */
+  {"*", "\xa1\xf6"}, /* ＊ */
+  {"/", "\xa1\xbf"}, /* ／ */
+  {"<", "\xa1\xe3"}, /* ＜ */
+  {">", "\xa1\xe4"}, /* ＞ */
+  {"?", "\xa1\xa9"}, /* ？ */
+  {"_", "\xa1\xb2"}, /* ＿ */
+  {",", "\xa1\xa2"}, /* 、 */
+  {".", "\xa1\xa3"}, /* 。 */
+  {"-", "\xa1\xbc"}, /* ー */
+  {":", "\xa1\xa7"}, /* ： */
+  {";", "\xa1\xa8"}, /* ； */
+  {"[", "\xa1\xd6"}, /* 「 */
+  {"]", "\xa1\xd7"}, /* 」 */
+  {NULL, NULL}
+};
+
+#define is_kuten(c)   ((\
+	(c == ',') || (c == '.') || (c == '-') || \
+	(c == '-') || (c == ':') || (c == ';') || \
+	(c == '[') || (c == ']') || (c == '{') || (c == '}') || \
+	(c == '=') || (c == '~') || (c == '|')) ? 1 : 0)
+
+int
+skk_set_active(int act)
+{
+	if (act)
+		skk_enabled(TRUE);
+	if (skk_enable)
+		skk_active = act;
+	return TRUE;
+}
+
+int
+skk_get_active()
+{
+	return skk_active;
+}
+
+int
+skk_dicload()
+{
+	if (skk_enable)
+	{
+		static int at_first = 0;
+		if (!at_first && mst_dic_path)
+		{
+			if ((State & CMDLINE) == 0)
+				msg("Loading Master dictionary...");
+			dic_mst = openSKK((char *)mst_dic_path);
+			if (!dic_mst)
+			{
+				vim_free(mst_dic_path);
+				mst_dic_path = NULL;
+			}
+			at_first = 1;
+		}
+		if (!dic_usr)
+		{
+			if ((State & CMDLINE) == 0)
+				msg("Loading User dictionary...");
+			dic_usr = openSKK((char *)usr_dic_path);
+			at_first = 1;
+		}
+#ifdef USE_SERVER
+		if (dic_usr)
+		{
+			if (has_server == FALSE && svr_dic_host)
+			{
+				if (openSKKserv((char *)svr_dic_host, svr_dic_port) != 0)
+				{
+					vim_free(svr_dic_host);
+					svr_dic_host = NULL;
+					if ((State & CMDLINE) == 0)
+						emsg("Can't connect server");
+				}
+				else
+					has_server = TRUE;
+				at_first = 1;
+			}
+		}
+#endif
+		else
+			skk_enable = FALSE;
+		if (skk_enable && at_first && (State & CMDLINE) == 0)
+			msg("Loading Done...");
+	}
+	return 0;
+}
+
+static char_u*
+skk_iroha2alpha(char_u *src)
+{
+	int		idx, hit;
+	char_u	*ptr;
+	char_u	*str1;
+	char_u	buffer[256];
+	memset(buffer, 0x00, sizeof(buffer));
+	ptr = src;
+	while(*ptr)
+	{
+		hit = -1;
+		for (idx = 0; iroha_table[idx].str; idx++)
+		{
+			str1 = (char_u *)iroha_table[idx].str;
+			if (!STRNICMP(str1, ptr, STRLEN(str1)))
+				hit = idx;
+		}
+		str1 = (char_u *)iroha_table[hit].str;
+		if (hit >= 0)
+		{
+			STRCAT(buffer, iroha_table[hit].key);
+			ptr += STRLEN(iroha_table[hit].str);
+		}
+		else
+		{
+			char_u	ch = tolower(*ptr);
+			STRNCAT(buffer, &ch, 1);
+			ptr++;
+		}
+	}
+	if (ptr == src)
+		STRCPY(buffer, ptr);
+	return vim_strsave(buffer);
+}
+
+static char_u*
+skk_alpha2iroha(char_u *src, int flg)
+{
+	int		idx, hit, dup;
+	char_u	*ptr;
+	char_u	*key1, *key2;
+	char_u	buffer[256];
+	memset(buffer, 0x00, sizeof(buffer));
+	ptr = src;
+	while(*ptr)
+	{
+		hit = -1;
+		dup = 0;
+		for (idx = 0; iroha_table[idx].key; idx++)
+		{
+			key1 = (char_u *)iroha_table[idx].key;
+			if (!STRNICMP(key1, ptr, STRLEN(key1)))
+				hit = idx;
+		}
+		key1 = (char_u *)iroha_table[hit].key;
+		if (hit >= 0)
+		{
+			if (!flg)
+			{
+				for (idx = 0; iroha_table[idx].key; idx++)
+				{
+					key2 = (char_u *)iroha_table[idx].key;
+					if (!STRNICMP(key2, ptr, STRLEN(ptr)))
+					{
+						dup++;
+						if (hit != idx)
+							hit = -1;
+					}
+				}
+				if (dup == 0)
+					dup = 1;
+			}
+			else
+				dup = 1;
+		}
+		//if (*ptr == '.' && input_mode == SKK_INPUT_ZALP)
+		//{
+			//STRCAT(buffer, "\x1a\xa5");
+			//ptr++;
+		//}
+		//else
+		if (hit >= 0 && dup == 1)
+		{
+			char_u	ch = tolower(*ptr);
+			size_t	buflen;
+			if (flg == SKK_RET_OKR
+				&& !*(ptr + STRLEN(iroha_table[hit].key)))
+			{
+				STRNCAT(buffer, &ch, 1);
+				break;
+			}
+			buflen = STRLEN(buffer);
+			if (buflen && buffer[buflen-1] == *ptr)
+			{
+				buffer[buflen-1] = 0;
+				STRCAT(buffer, "\xa4\xc3");
+			}
+			STRCAT(buffer, iroha_table[hit].str);
+			ptr += STRLEN(iroha_table[hit].key);
+		}
+		else
+		{
+			char_u	ch = tolower(*ptr);
+			size_t	buflen = STRLEN(buffer);
+			if (buflen && buffer[buflen-1] == *ptr)
+			{
+				buffer[buflen-1] = 0;
+				STRCAT(buffer, "\xa4\xc3");
+			}
+			STRNCAT(buffer, &ch, 1);
+			ptr++;
+		}
+	}
+	if (ptr == src)
+		STRCPY(buffer, ptr);
+	return vim_strsave(buffer);
+}
+
+static void
+skk_regist(char_u *key, char_u *str)
+{
+	CandList fcand = (CandList)NULL;
+	CandList ncand = (CandList)NULL;
+	CandList tcand = (CandList)NULL;
+	DicList		dlist;
+
+	skk_dicload();
+	if (skk_enable)
+		tcand = getCand(dic_usr, (char *)key);
+	if (tcand)
+	{
+		fcand = tcand;
+		while(tcand)
+		{
+			if (!STRICMP(str, tcand->candword))
+			{
+				selectCand(&fcand, tcand);
+				tcand->dicitem->cand = fcand;
+				msg("Updated");
+				break;
+			}
+			tcand = tcand->nextcand;
+		}
+		if (!tcand) {
+			ncand = _NEW2(CandList,STRLEN(str));
+			ncand->okuri = NULL;
+			ncand->nextcand = fcand;
+			ncand->prevcand = NULL;
+			STRCPY(ncand->candword, str);
+			ncand->dicitem = fcand->dicitem;
+			fcand->prevcand = ncand;
+			fcand->dicitem->cand = ncand;
+			msg("Inserted");
+		}
+	}
+	else
+	{
+		dlist = _NEW2(DicList,STRLEN(key));
+		dlist->nextitem = NULL;
+		STRCPY(dlist->kanaword, key);
+
+		ncand = _NEW2(CandList,STRLEN(str));
+		ncand->okuri = NULL;
+		ncand->prevcand = NULL;
+		ncand->nextcand = NULL;
+		STRCPY(ncand->candword, str);
+		dlist->cand = ncand;
+
+		addHash(dic_usr->dhash, dlist);
+		if (dic_usr->dlist)
+			dic_usr->dlist->nextitem = dlist;
+		else
+			dic_usr->dlist = dlist;
+		if (isConjugate((char *)str, STRLEN(str))) {
+			if (!dic_usr->okuriAriFirst)
+				dic_usr->okuriAriFirst = dlist;
+		} else {
+			if (!dic_usr->okuriNasiFirst)
+				dic_usr->okuriNasiFirst = dlist;
+		}
+		msg("Created New");
+	}
+}
+
+static CandList
+skk_commitcand(char_u *inp, int okuri_pos, CandList scand)
+{
+	CandList fcand = (CandList)NULL;
+	CandList ncand = (CandList)NULL;
+	CandList tcand = (CandList)NULL;
+	DicList		dlist;
+	char_u *yomi;
+	char_u *iroha;
+
+	if (okuri_pos == 0)
+		yomi = iroha = skk_alpha2iroha(inp, SKK_RET_FND);
+	else
+	{
+		size_t len;
+		char_u	*ptr = vim_strsave(inp);
+		ptr[okuri_pos] = 0;
+		iroha = skk_alpha2iroha(ptr, SKK_RET_FND);
+		len = STRLEN(iroha);
+		yomi = alloc(len + 2);
+		STRCPY(yomi, iroha);
+		yomi[len] = (char_u)tolower(inp[okuri_pos]);
+		yomi[len + 1] = NUL;
+		vim_free(iroha);
+		vim_free(ptr);
+	}
+	tcand = getCand(dic_usr,(char *)yomi);
+	if (tcand)
+	{
+		fcand = tcand;
+		while(tcand)
+		{
+			if (!STRICMP(scand->candword, tcand->candword))
+			{
+				selectCand(&fcand, tcand);
+				tcand->dicitem->cand = fcand;
+				msg("Updated");
+				break;
+			}
+			tcand = tcand->nextcand;
+		}
+		if (!tcand) {
+			ncand = _NEW2(CandList,STRLEN(scand->candword));
+			ncand->okuri = NULL;
+			ncand->nextcand = fcand;
+			ncand->prevcand = NULL;
+			STRCPY(ncand->candword, scand->candword);
+			ncand->dicitem = fcand->dicitem;
+			fcand->prevcand = ncand;
+			fcand->dicitem->cand = ncand;
+			msg("Inserted");
+		}
+	}
+	else
+	{
+		dlist = _NEW2(DicList,STRLEN(yomi));
+		dlist->nextitem = NULL;
+		STRCPY(dlist->kanaword, yomi);
+
+		ncand = _NEW2(CandList,STRLEN(scand->candword));
+		ncand->okuri = NULL;
+		ncand->prevcand = NULL;
+		ncand->nextcand = NULL;
+		STRCPY(ncand->candword, scand->candword);
+		dlist->cand = ncand;
+
+		addHash(dic_usr->dhash, dlist);
+		if (dic_usr->dlist)
+			dic_usr->dlist->nextitem = dlist;
+		else
+			dic_usr->dlist = dlist;
+		if (okuri_pos) {
+			if (!dic_usr->okuriAriFirst)
+				dic_usr->okuriAriFirst = dlist;
+		} else {
+			if (!dic_usr->okuriNasiFirst)
+				dic_usr->okuriNasiFirst = dlist;
+		}
+		msg("Created New");
+	}
+	return scand;
+}
+
+static CandList
+skk_alpha2cand(char_u *alpha, char_u ch, int *from)
+{
+	char_u *iroha;
+	char_u *yomi;
+	CandList scand = NULL;
+
+	if (ch == NUL)
+		yomi = iroha = skk_alpha2iroha(alpha, SKK_RET_FND);
+	else
+	{
+		size_t len;
+		iroha = skk_alpha2iroha(alpha, SKK_RET_FND);
+		len = STRLEN(iroha);
+		yomi = alloc(len + 2);
+		STRCPY(yomi, iroha);
+		yomi[len] = (char_u)tolower(ch);
+		yomi[len + 1] = NUL;
+		vim_free(iroha);
+	}
+
+	if (STRLEN(yomi) > 1)
+	{
+		skk_dicload();
+		if (skk_enable)
+		{
+			if (*from == SKK_DIC_USR && !scand) {
+				scand = getCand(dic_usr, (char *)yomi);
+				if (!scand) (*from)++;
+			}
+
+			if (*from == SKK_DIC_MST && !scand && dic_mst) {
+				scand = getCand(dic_mst, (char *)yomi);
+				if (!scand) (*from)++;
+			}
+#ifdef USE_SERVER
+			if (*from == SKK_DIC_SVR && !scand && svr_dic_host) {
+				scand = getCandFromServer((char *)yomi);
+				if (!scand) (*from)++;
+			}
+#endif
+		}
+	}
+	vim_free(yomi);
+	return scand;
+}
+
+static void
+skk_hira2kata(char_u *src)
+{
+	char_u *ptr;
+	for (ptr = src; *ptr; ptr++)
+	{
+		if (*ptr == 0xa4 && *(ptr+1) >= 0xa1 &&
+				*(ptr+1) <= 0xf3)
+			*(ptr++) = 0xa5;
+		else if (*ptr & 0x80)
+			ptr++;
+	}
+}
+
+static int
+skk_puts(char_u *src, int *x, int *y, int attr)
+{
+	int	len = 1;
+	int	all_cells = 0;
+	char_u	*ptr;
+	char_u	cell[MB_MAXBYTES];
+
+	for(ptr = src; *ptr; ptr+=len)
+	{
+		int	cells = 0;
+		int	diffs = 0;
+		cells = mb_ptr2cells(ptr);
+
+		len = (*mb_ptr2len)(ptr);
+		STRNCPY(cell, ptr, len);
+		cell[len] = 0;
+		if (State & CMDLINE)
+		{
+			diffs = *x + cells - Columns;
+			if (diffs > 0)
+			{
+				if (diffs < cells)
+					screen_putchar('>', *y, *x, HL_ATTR(HLF_AT));
+				*x = 0;
+			}
+		}
+		else
+		{
+			diffs = *x + cells - W_ENDCOL(curwin);
+			if (diffs > 0)
+			{
+				if (diffs < cells)
+					screen_putchar('>', *y, *x, HL_ATTR(HLF_AT));
+				*x = curwin->w_wincol;
+				if (*y < W_WINROW(curwin) + curwin->w_height - 1)
+					*y += 1;
+			}
+		}
+		screen_puts(cell, *y, *x, attr);
+		*x += cells;
+		all_cells += cells;
+	}
+	if ((State & CMDLINE) == 0)
+	{
+		if (*x == W_ENDCOL(curwin))
+		{
+			*x = curwin->w_wincol;
+			if (*y < W_WINROW(curwin) + curwin->w_height - 1)
+				*y += 1;
+			windgoto(*y, *x);
+		}
+	}
+	return all_cells;
+}
+
+static void
+skk_getxy(int *x, int *y)
+{
+	if (State & CMDLINE)
+	{
+		*x = msg_col;
+		*y = msg_row;
+	}
+	else
+	{
+		*x = curwin->w_wincol + curwin->w_wcol;
+		*y = W_WINROW(curwin) + curwin->w_wrow;
+	}
+}
+
+static void
+skk_conv_free(char_u* src)
+{
+#ifdef USE_ICONV
+	vim_free(src);
+#else
+	if (enc_dbcs == DBCS_JPNU)
+		return;
+	vim_free(src);
+#endif
+}
+
+static char_u*
+skk_conv_alloc(char_u* src)
+{
+	char_u	*ret;
+
+#ifdef USE_ICONV
+	ret = string_convert(&skk_convt, (char_u*)src, NULL);
+	if (!ret)
+		ret = vim_strsave(src);
+#else
+	char_u	c1, c2;
+	char_u	*dst;
+	ret = dst = vim_strsave(src);
+	switch(enc_dbcs)
+	{
+	case DBCS_JPNU:
+		break;
+	case DBCS_JPN:
+		while(*src)
+		{
+			c1 = *src;
+			c2 = *(src+1);
+			if (c2 == 0x00 || !iseuckanji(c1))
+				*dst++ = c1;
+			else
+			if (c1 == 0x8e)
+			{
+				*dst++ = c2;
+				src++;
+			}
+			else
+			{
+				if (c1 % 2 == 0)
+					c2 -= 0x02;
+				else
+					c2 -= (c2 > 0xdf) ? 0x60 : 0x61;
+				if (c1 < 0xdf)
+					c1 = (c1 + 1) / 2 + 0x30;
+				else
+					c1 = (c1 + 1) / 2 + 0x70;
+				*dst++ = c1;
+				*dst++ = c2;
+				src++;
+			}
+			src++;
+		}
+		*dst = 0;
+		break;
+	default:
+		break;
+	}
+#endif
+	return ret;
+}
+
+int
+skk_showmode()
+{
+	char_u	*dst;
+	static char *mode_table[] = {
+		"[\xc8\xbe\xb3\xd1]",			/* [半角] */
+		"[\xa4\xab\xa4\xca]",			/* [かな] */
+		"[\xa5\xab\xa5\xca]",			/* [カナ] */
+		"[\xc1\xb4\xb1\xd1]",			/* [全英] */
+		NULL
+	};
+
+	dst = skk_conv_alloc((char_u *)mode_table[input_mode]);
+	msg_puts(dst);
+	skk_conv_free(dst);
+	return TRUE;
+}
+
+#ifdef SKK_UNUSED
+static void
+skk_mode(int mode)
+{
+	char_u	*dst;
+	int	x, y;
+	static char *mode_table[] = {
+		"[\xc8\xbe\xb3\xd1]",			/* [半角] */
+		"[\xa4\xab\xa4\xca]",			/* [かな] */
+		"[\xa5\xab\xa5\xca]",			/* [カナ] */
+		"[\xc1\xb4\xb1\xd1]",			/* [全英] */
+		NULL
+	};
+
+	if (State & CMDLINE || State & NORMAL)
+		return;
+	x = 0;
+	y = Rows - 1;
+
+	dst = alloc(Columns+1);
+	memset(dst, ' ', Columns);
+	dst[Columns] = 0;
+	skk_puts(dst, &x, &y, HL_NORMAL);
+	vim_free(dst);
+
+	x = 0;
+	dst = skk_conv_alloc((char_u *)mode_table[mode]);
+	skk_puts(dst, &x, &y, HL_NORMAL);
+	skk_conv_free(dst);
+
+	windgoto(orig_y, orig_x);
+}
+#endif /* SKK_UNUSED */
+
+int
+skk_enabled(int verbose)
+{
+	if (!skk_enable)
+	{
+		curBuff[0] = '\0';
+    	inpBuff[0] = '\0';
+		nfetch = 0;
+		skk_enable = TRUE;
+	}
+#ifdef USE_ICONV
+	if (skk_enable && old_enc != p_enc)
+	{
+		skk_convt.vc_fd = (iconv_t)-1;
+		convert_setup(&skk_convt, (char_u *)"euc-jp", p_enc);
+	}
+#endif
+	return skk_enable;
+}
+
+int
+skk_end()
+{
+	if (skk_enable)
+	{
+		if (dic_usr)
+			closeSKK(dic_usr,(char *)usr_dic_path);
+		dic_usr = NULL;
+		if (usr_dic_path)
+			vim_free(usr_dic_path);
+		usr_dic_path = NULL;
+
+		if (dic_mst)
+			closeSKK(dic_mst,NULL);
+		dic_mst = NULL;
+		if (mst_dic_path)
+			vim_free(mst_dic_path);
+		mst_dic_path = NULL;
+
+#ifdef USE_SERVER
+		if (has_server && getSKKservStatus())
+	         closeSKKserv();
+		has_server = FALSE;
+		if (svr_dic_host)
+			vim_free(svr_dic_host);
+		svr_dic_host = NULL;
+#endif
+	}
+	skk_enable = FALSE;
+	return TRUE;
+}
+
+static void
+skk_kakutei(char_u* p)
+{
+	char_u	*dst;
+	if (p)
+	{
+		dst = skk_conv_alloc(p);
+		STRCPY(curBuff, dst);
+		skk_conv_free(dst);
+		nfetch = 0;
+	}
+	else
+	{
+		curBuff[0] = 0;
+		nfetch = 0;
+	}
+}
+
+static int
+skk_henkan(char_u* p, int pos, int len, int flg)
+{
+	char_u	*dst, *cpy;
+	int	x, y, cells = 0;
+	static char	*mark_list[] = {
+		"\xa2\xa6", "\xa2\xa7",
+	};
+
+	skk_getxy(&x, &y);
+
+	if (flg)
+	{
+		cpy = vim_strsave((char_u *)mark_list[flg-1]);
+		dst = skk_conv_alloc(cpy);
+		cells += skk_puts(dst, &x, &y, HL_INVERSE);
+		skk_conv_free(dst);
+		vim_free(cpy);
+	}
+
+	cpy = vim_strsave(p);
+	cpy[pos] = 0;
+	dst = skk_conv_alloc(cpy);
+	cells += skk_puts(dst, &x, &y, HL_UNDERLINE);
+	skk_conv_free(dst);
+	vim_free(cpy);
+
+	cpy = vim_strsave(p+pos);
+	cpy[len] = 0;
+	dst = skk_conv_alloc(cpy);
+	if (flg)
+		cells += skk_puts(dst, &x, &y, HL_INVERSE);
+	else
+		cells += skk_puts(dst, &x, &y, HL_UNDERLINE);
+	skk_conv_free(dst);
+	vim_free(cpy);
+
+	cpy = vim_strsave(p+pos+len);
+	dst = skk_conv_alloc(cpy);
+	cells += skk_puts(dst, &x, &y, HL_UNDERLINE);
+	vim_free(cpy);
+
+	return cells;
+}
+
+static void
+skk_delhenkan(int len)
+{
+	int		x, y;
+    if (len > 0)
+	{
+		char_u	*ptr;
+
+		skk_getxy(&x, &y);
+		ptr = alloc(len+1);
+		memset(ptr, ' ', len);
+		ptr[len] = 0;
+		skk_puts(ptr, &x, &y, HL_NORMAL);
+		vim_free(ptr);
+    }
+	skk_getxy(&x, &y);
+	windgoto(y, x);
+}
+
+#ifdef SKK_UNUSED
+static void
+skk_gline(char_u* p, char_u* l, int pos, int len)
+{
+	char_u	*dst, *cpy;
+	int	x, y;
+
+	if (State & CMDLINE || State & NORMAL)
+		return;
+	x = 0;
+	y = Rows - 1;
+
+	dst = skk_conv_alloc(p);
+	skk_puts(dst, &x, &y, HL_NORMAL);
+	skk_conv_free(dst);
+
+	skk_puts((char_u *)" ", &x, &y, HL_NORMAL);
+
+	cpy = vim_strsave(l);
+	cpy[pos] = 0;
+	dst = skk_conv_alloc(cpy);
+	skk_puts(dst, &x, &y, HL_NORMAL);
+	skk_conv_free(dst);
+	vim_free(cpy);
+
+	cpy = vim_strsave(l+pos);
+	cpy[len] = 0;
+	dst = skk_conv_alloc(cpy);
+	skk_puts(dst, &x, &y, HL_INVERSE);
+	skk_conv_free(dst);
+	vim_free(cpy);
+
+	cpy = vim_strsave(l+pos+len);
+	dst = skk_conv_alloc(cpy);
+	skk_puts(dst, &x, &y, HL_NORMAL);
+	skk_conv_free(dst);
+	vim_free(cpy);
+
+	windgoto(orig_y, orig_x);
+}
+#endif /* SKK_UNUSED */
+
+static int
+skk_fetch()
+{
+	int	c;
+	c = mb_ptr2char(curBuff+nfetch);
+	if (c)
+		nfetch += (*mb_ptr2len)(curBuff+nfetch);
+	return c;
+}
+
+int
+skk_vgetc()
+{
+	unsigned int length;
+	int c;
+	CandList scand = (CandList)NULL;
+	int	okuri_pos = 0;
+	int old_mode;
+
+	if (skk_enable == FALSE)
+		return 0;
+
+	c = skk_fetch();
+	if (c)
+		return c;
+
+	skk_getxy(&orig_x, &orig_y);
+
+	skk_kakutei(NULL);
+	length = 0;
+	if (STRLEN(inpBuff))
+	{
+		char_u	*iroha;
+		iroha = skk_alpha2iroha(inpBuff, SKK_RET_UNK);
+		if (preedit)
+			length = skk_henkan(iroha, 0, STRLEN(iroha), 1);
+		else
+			length = skk_henkan(iroha, 0, STRLEN(iroha), 0);
+		vim_free(iroha);
+	}
+
+    while (1)
+	{
+		c = vgetc();
+	    if (ex_normal_busy || KeyStuffed)
+			return c;
+        if (c == 0)
+            continue;
+		got_int = FALSE;
+
+		if (c == '\t')
+		{
+			if (STRLEN(inpBuff) == 0)
+				return c;
+			else
+				continue;
+		}
+
+        skk_delhenkan(length);
+
+		if (c == ESC)
+		{
+			okuri_pos = 0;
+			length = 0;
+			preedit = 0;
+			inpBuff[0] = 0;
+			skk_kakutei(NULL);
+			input_mode = SKK_INPUT_HALP;
+			showmode();
+			return c;
+		}
+
+		old_mode = input_mode;
+
+		if (preedit != 2)
+		{
+			switch(c)
+			{
+			case 'l':
+				if (input_mode != SKK_INPUT_ZALP &&
+						input_mode != SKK_INPUT_HALP)
+					input_mode = SKK_INPUT_HALP;
+				break;
+			case 'L':
+				if (input_mode != SKK_INPUT_ZALP &&
+						input_mode != SKK_INPUT_HALP)
+					input_mode = SKK_INPUT_ZALP;
+				break;
+			case 'q':
+				if (input_mode == SKK_INPUT_KATA ||
+						input_mode == SKK_INPUT_HIRA)
+					input_mode = (input_mode == SKK_INPUT_KATA ) ?
+						SKK_INPUT_HIRA : SKK_INPUT_KATA;
+				break;
+			case Ctrl_J:
+				input_mode = SKK_INPUT_HIRA;
+				break;
+			}
+		}
+		if (old_mode != input_mode)
+		{
+			if (!(State & CMDLINE))
+			{
+				showmode();
+				windgoto(orig_y, orig_x);
+			}
+			if (scand)
+			{
+				scand = skk_commitcand(inpBuff, okuri_pos, scand);
+				if (okuri_pos)
+				{
+					char_u	*ptr;
+					char_u	*iroha;
+
+					iroha = skk_alpha2iroha(&inpBuff[okuri_pos], SKK_RET_UNK);
+					if (old_mode == SKK_INPUT_KATA)
+						skk_hira2kata(iroha);
+					ptr = alloc(STRLEN(scand->candword) + STRLEN(iroha)  + 1);
+					STRCPY(ptr, scand->candword);
+					STRCAT(ptr, iroha);
+					vim_free(iroha);
+					skk_kakutei(ptr);
+					vim_free(ptr);
+				}
+				else
+					skk_kakutei((char_u *)scand->candword);
+				okuri_pos = 0;
+				length = 0;
+				preedit = 0;
+			}
+			else
+			if (STRLEN(inpBuff))
+			{
+				char_u	*iroha;
+	
+				iroha = skk_alpha2iroha(inpBuff, SKK_RET_FND);
+				switch(old_mode)
+				{
+				case SKK_INPUT_HIRA:
+					if (preedit)
+					{
+						skk_hira2kata(iroha);
+						input_mode = SKK_INPUT_HIRA;
+					}
+					break;
+				case SKK_INPUT_KATA:
+					if (!preedit)
+						input_mode = SKK_INPUT_KATA;
+					else
+						skk_hira2kata(iroha);
+					break;
+				}
+				showmode();
+				skk_kakutei(iroha);
+				vim_free(iroha);
+				okuri_pos = 0;
+				length = 0;
+				preedit = 0;
+			}
+			if (STRLEN(inpBuff) == 0)
+				continue;
+			inpBuff[0] = 0;
+			break;
+		}
+
+        if (c == Ctrl_G)
+		{
+			if (scand)
+			{
+				scand = NULL;
+				c = 0;
+			}
+			else
+			{
+				if (preedit)
+					c = 0;
+				inpBuff[0] = 0;
+				skk_kakutei(NULL);
+				length = 0;
+				preedit = 0;
+				okuri_pos = 0;
+				if (c)
+					return c;
+			}
+        }
+		else
+		if (c == 'x' && scand)
+			scand = scand->prevcand;
+		else
+        if (!regs_key && STRLEN(inpBuff) > 0 && c == Ctrl_R)
+		{
+			char_u	*ptr, *dst;
+			char_u	*old_inpBuff;
+			CandList	scand = NULL;
+
+			regs_key = skk_alpha2iroha(inpBuff, SKK_RET_FND);
+			if (!regs_key)
+				continue;
+			dst = skk_conv_alloc(regs_key);
+			ptr = alloc(STRLEN(dst) + 2);
+			STRCPY(ptr, dst);
+			skk_conv_free(dst);
+			STRCAT(ptr, ":");
+
+			old_inpBuff = vim_strsave(inpBuff);
+			inpBuff[0] = 0;
+
+			regs_str = getcmdline_prompt('@', ptr, HL_NORMAL, EXPAND_NOTHING, NULL);
+
+			vim_free(ptr);
+			STRCPY(inpBuff, old_inpBuff);
+			vim_free(old_inpBuff);
+
+			if (!regs_str || STRLEN(regs_str) == 0)
+			{
+				if (regs_str)
+					vim_free(regs_str);
+				regs_str = NULL;
+				vim_free(regs_key);
+				regs_key = NULL;
+				continue;
+			}
+
+			skk_regist(regs_key, regs_str);
+
+           	skk_kakutei(regs_str);
+			okuri_pos = 0;
+			inpBuff[0] = 0;
+			length = 0;
+			scand = NULL;
+			preedit = 0;
+
+			skk_active = TRUE;
+			vim_free(regs_str);
+			regs_str = NULL;
+			vim_free(regs_key);
+			regs_key = NULL;
+			break;
+		}
+		else
+		if (c == '\n' || c == '\r')
+		{
+			if (scand)
+			{
+				scand = skk_commitcand(inpBuff, okuri_pos, scand);
+				if (okuri_pos)
+				{
+					char_u	*ptr;
+					char_u	*iroha;
+					
+					iroha = skk_alpha2iroha(&inpBuff[okuri_pos], SKK_RET_FND);
+					ptr = alloc(STRLEN(scand->candword) + STRLEN(iroha)  + 1);
+					STRCPY(ptr, scand->candword);
+					STRCAT(ptr, iroha);
+					vim_free(iroha);
+            		skk_kakutei(ptr);
+					vim_free(ptr);
+				}
+				else
+            		skk_kakutei((char_u *)scand->candword);
+			}
+			else
+			{
+				if (STRLEN(inpBuff))
+				{
+					if (preedit == 1)
+					{
+						char_u	*iroha;
+						iroha = skk_alpha2iroha(inpBuff, SKK_RET_FND);
+						if (input_mode == SKK_INPUT_KATA)
+							skk_hira2kata(iroha);
+						skk_kakutei(iroha);
+						vim_free(iroha);
+					}
+					else
+						skk_kakutei(inpBuff);
+				}
+				else
+            		skk_kakutei((char_u *)"\n");
+
+				if (State & CMDLINE)
+					input_mode = SKK_INPUT_HALP;
+			}		
+
+			okuri_pos = 0;
+			inpBuff[0] = 0;
+           	length = 0;
+			scand = NULL;
+			preedit = 0;
+			break;
+		}
+		else
+        if (c == ' ' && STRLEN(inpBuff))
+		{
+			char_u *old_candword = NULL;
+
+			if (!preedit)
+			{
+				char_u	*iroha;
+				iroha = skk_alpha2iroha(inpBuff, SKK_RET_FND);
+           		length = skk_henkan(iroha,
+					0, STRLEN(iroha), 0);
+				vim_free(iroha);
+				continue;
+			}
+
+			if (scand) {
+				old_candword = vim_strsave((char_u *)scand->candword);
+				scand = scand->nextcand;
+				if (!scand) dic_from++;
+			}
+			else
+				dic_from = SKK_DIC_USR;
+
+			if (!scand)
+			{
+				if (okuri_pos)
+				{
+					char_u	*ptr = vim_strsave(inpBuff);
+					ptr[okuri_pos] = 0;
+					scand = skk_alpha2cand(ptr, inpBuff[okuri_pos], &dic_from);
+					vim_free(ptr);
+
+					if (scand)
+					{
+						CandList *ocand;
+						CandList old_cand = (CandList)scand;
+
+						ptr = skk_alpha2iroha(&inpBuff[okuri_pos], SKK_RET_UNK);
+						scand = searchOkuri(scand, (char *)ptr, &ocand);
+						if (!scand)
+							scand = old_cand;
+						vim_free(ptr);
+					}
+				}
+				else
+				{
+					scand = skk_alpha2cand(inpBuff, 0, &dic_from);
+				}
+			}
+			if (scand && scand->okuri)
+				scand = scand->okuri->nextcand;
+			if (old_candword) {
+				while(scand) {
+					if (STRCMP(old_candword, scand->candword))
+						break;
+					scand = scand->nextcand;
+				}
+				vim_free(old_candword);
+			}
+		}
+		else
+       	if (c == K_BS || c == K_DEL || c == Ctrl_H)
+		{
+			char_u	*ptr, *old;
+			if (regs_str && STRLEN(regs_str))
+			{
+				for (ptr = regs_str, old = regs_str; *ptr; ptr++)
+				{
+					old = ptr;
+					if (*ptr & 0x80)
+						ptr++;
+				}
+				*old = '\0';
+			}
+			else
+			if (!scand)
+			{
+				if (STRLEN(inpBuff) > 0)
+				{
+					if (preedit == 2)
+					{
+						int	nbytes = STRLEN(inpBuff);
+						if (nbytes)
+							inpBuff[nbytes-1] = 0;
+					}
+					else
+					{
+						char_u	*iroha;
+						char_u	*alpha;
+
+						iroha = skk_alpha2iroha(inpBuff, SKK_RET_FND);
+						for (ptr = iroha, old = iroha; *ptr; ptr++)
+						{
+							old = ptr;
+							if (*ptr & 0x80)
+								ptr++;
+						}
+						*old = '\0';
+						alpha = skk_iroha2alpha(iroha);
+						vim_free(iroha);
+						STRCPY(inpBuff, alpha);
+						vim_free(alpha);
+					}
+				}
+				else
+				{
+					if (preedit)
+					{
+						preedit = 0;
+						c = 0;
+					}
+					else
+						return c;
+				}
+			}
+			else
+			{
+				scand = NULL;
+			}
+			c = 0;
+			okuri_pos = 0;
+		} else
+		if (IS_SPECIAL(c))
+		{
+			if (regs_key)
+				return c;
+		}
+		else
+		if (isprint(c))
+		{
+			if (scand)
+			{
+				char_u	*ptr;
+				char_u	*iroha;
+
+				scand = skk_commitcand(inpBuff, okuri_pos, scand);
+				if (okuri_pos)
+				{
+					iroha = skk_alpha2iroha(&inpBuff[okuri_pos], SKK_RET_UNK);
+					if (input_mode == SKK_INPUT_KATA)
+						skk_hira2kata(iroha);
+					ptr = alloc(STRLEN(scand->candword) + STRLEN(iroha)  + 1);
+					STRCPY(ptr, scand->candword);
+					STRCAT(ptr, iroha);
+					vim_free(iroha);
+				}
+				else
+					ptr = vim_strsave((char_u *)scand->candword);
+
+				inpBuff[0] = tolower(c);
+				inpBuff[1] = 0;
+				if (isupper(c))
+					preedit = 1;
+				else
+				{
+					preedit = 0;
+					iroha = skk_alpha2iroha(inpBuff, SKK_RET_UNK);
+					if (STRICMP(inpBuff, iroha))
+					{
+						ptr = vim_realloc(ptr, STRLEN(ptr) + STRLEN(iroha) + 1);
+						STRCAT(ptr, iroha);
+						vim_free(iroha);
+						inpBuff[0] = 0;
+					}
+				}
+				skk_kakutei(ptr);
+				vim_free(ptr);
+				okuri_pos = 0;
+				nfetch = 0;
+				length = 0;
+				break;
+			}
+
+			switch(input_mode)
+			{
+			case SKK_INPUT_HALP:
+				return c;
+				break;
+			case SKK_INPUT_HIRA:
+			case SKK_INPUT_KATA:
+				if (preedit == 0 && STRLEN(inpBuff) == 0 && c == '/')
+					preedit = 2;
+				else
+				if (c)
+				{
+					if (preedit != 2 && isupper(c))
+					{
+       					if (preedit && c > 0 && okuri_pos == 0)
+							okuri_pos = STRLEN(inpBuff);
+						preedit = 1;
+					}
+					inpBuff[STRLEN(inpBuff)+1] = 0;
+					inpBuff[STRLEN(inpBuff)] = c;
+				}
+				break;
+			case SKK_INPUT_ZALP:
+				if (isalnum(c))
+				{
+					int	nbytes = STRLEN(inpBuff);
+					inpBuff[nbytes++] = 0xa3;
+					inpBuff[nbytes++] = c + 0x880;
+					inpBuff[nbytes] = 0;
+				}
+				else
+				{
+					int	nbytes = STRLEN(inpBuff);
+					char_u	*iroha;
+					inpBuff[nbytes++] = c;
+					inpBuff[nbytes] = 0;
+					iroha = skk_alpha2iroha(inpBuff, SKK_RET_UNK);
+					STRCPY(inpBuff, iroha);
+					vim_free(iroha);
+				}
+				break;
+			}
+			if (scand)
+			{
+				scand = NULL;
+				break;
+			}
+		}
+		else
+			return c;
+
+		if (scand)
+		{
+			if (okuri_pos)
+			{
+				char_u	*ptr;
+				char_u	*iroha;
+
+				iroha = skk_alpha2iroha(&inpBuff[okuri_pos], SKK_RET_UNK);
+				if (input_mode == SKK_INPUT_KATA)
+					skk_hira2kata(iroha);
+				ptr = alloc(STRLEN(scand->candword) + STRLEN(iroha)  + 1);
+				STRCPY(ptr, scand->candword);
+				STRCAT(ptr, iroha);
+				vim_free(iroha);
+           		length = skk_henkan(ptr, 0, STRLEN(scand->candword), 2);
+				vim_free(ptr);
+			}
+			else {
+           		length = skk_henkan((char_u *)scand->candword, 0, STRLEN(scand->candword), 2);
+			}
+		}
+		else
+		if (!preedit)
+		{
+			if (c == ' ')
+			{
+          		skk_kakutei((char_u *)" ");
+				inpBuff[0] = 0;
+				okuri_pos = 0;
+           		length = 0;
+				scand = NULL;
+				preedit = 0;
+				break;
+			}
+			else
+			{
+				char_u	*iroha;
+				iroha = skk_alpha2iroha(inpBuff, SKK_RET_UNK);
+				if (STRICMP(inpBuff,iroha) ||
+					(input_mode != SKK_INPUT_HIRA &&
+						input_mode != SKK_INPUT_KATA))
+				{
+					char_u	*ptr;
+					unsigned int	n;
+	
+					if (input_mode == SKK_INPUT_ZALP)
+					{
+						for (ptr = iroha; *ptr; ptr++)
+						{
+							if (*ptr == 0xa1 && *(ptr+1) == 0xa2)
+								*(ptr+1) = 0xa4;
+							else
+							if (*ptr == 0xa1 && *(ptr+1) == 0xa3)
+								*(ptr+1) = 0xa5;
+							else
+							if (*ptr & 0x80)
+								ptr++;
+						}
+					}
+					if (input_mode == SKK_INPUT_KATA)
+						skk_hira2kata(iroha);
+	
+					for(n = 0; n < STRLEN(iroha);)
+						if (!iseuckanji(*(iroha+n)))
+							n ++;
+						else
+							break;
+					for(; n < STRLEN(iroha);)
+						if (iseuckanji(*(iroha+n)))
+							n += 2;
+						else
+							break;
+					ptr = vim_strsave(iroha);
+					iroha[n] = 0;
+					skk_kakutei(iroha);
+					STRCPY(inpBuff, ptr+n);
+					vim_free(iroha);
+					vim_free(ptr);
+	
+					okuri_pos = 0;
+          			length = 0;
+					scand = NULL;
+					preedit = 0;
+					break;
+				}
+				else
+          			length = skk_henkan(iroha, 0, STRLEN(iroha), 0);
+				vim_free(iroha);
+			}
+		}
+		else
+		{
+			if (okuri_pos && c)
+			{
+				char_u	*iroha;
+				char_u	*iroha1, *iroha2;
+				char_u	*ptr1 = vim_strsave(inpBuff);
+				char_u	*ptr2 = vim_strsave(&inpBuff[okuri_pos]);
+
+				dic_from = SKK_DIC_USR;
+				if (okuri_pos)
+					ptr1[okuri_pos] = 0;
+				iroha1 = skk_alpha2iroha(ptr1, SKK_RET_FND);
+				iroha2 = skk_alpha2iroha(ptr2, SKK_RET_UNK);
+				if (STRICMP(ptr2,iroha2)
+								&& *(iroha2+STRLEN(iroha2)-1) & 0x80)
+				{
+					if (okuri_pos)
+					{
+						char_u	*ptr = vim_strsave(inpBuff);
+						ptr[okuri_pos] = 0;
+						scand = skk_alpha2cand(ptr, inpBuff[okuri_pos], &dic_from);
+						vim_free(ptr);
+
+						if (scand)
+						{
+							CandList *ocand;
+							CandList old_cand = (CandList)scand;
+
+							ptr = skk_alpha2iroha(&inpBuff[okuri_pos], SKK_RET_UNK);
+							scand = searchOkuri(scand, (char *)ptr, &ocand);
+							if (!scand)
+								scand = old_cand;
+							vim_free(ptr);
+						}
+					}
+					else
+					{
+						scand = skk_alpha2cand(inpBuff, 0, &dic_from);
+					}
+				}
+				vim_free(ptr1);
+				vim_free(ptr2);
+				if (scand)
+				{
+					iroha = alloc(STRLEN(scand->candword) + STRLEN(iroha2)  + 2);
+					STRCPY(iroha, scand->candword);
+					STRCAT(iroha, iroha2);
+				}
+				else
+				{
+					iroha = alloc(STRLEN(iroha1) + STRLEN(iroha2)  + 2);
+					STRCPY(iroha, iroha1);
+					STRCAT(iroha, "*");
+					STRCAT(iroha, iroha2);
+				}
+				vim_free(iroha1);
+				vim_free(iroha2);
+
+				if (input_mode == SKK_INPUT_KATA)
+					skk_hira2kata(iroha);
+				if (scand)
+					length = skk_henkan(iroha, 0, STRLEN(scand->candword), 2);
+				else
+					length = skk_henkan(iroha, 0, STRLEN(iroha), 1);
+
+				vim_free(iroha);
+			}
+			else
+			{
+				if (preedit == 1)
+				{
+					char_u	*iroha;
+					iroha = skk_alpha2iroha(inpBuff, SKK_RET_UNK);
+					if (input_mode == SKK_INPUT_KATA)
+						skk_hira2kata(iroha);
+					length = skk_henkan(iroha, 0, STRLEN(iroha), 1);
+					vim_free(iroha);
+				}
+				else
+					length = skk_henkan(inpBuff, 0, STRLEN(inpBuff), 1);
+			}
+		}
+    }
+	return skk_fetch();
+}
+
+int
+skk_redraw(void)
+{
+	return TRUE;
+}
+
+char *
+skk_imopts(char_u *opts)
+{
+	char	*errmsg = NULL;
+	char_u	*org, *ptr;
+	char_u	*name, *val;
+	org = ptr = vim_strsave(opts);
+	usr_dic_path = NULL;
+	svr_dic_host = NULL;
+	svr_dic_port = SKK_PORT_NUMBER;
+	while(*ptr)
+	{
+		name = ptr;
+		while(*ptr != ':' && *ptr != ',' && *ptr != '\0')
+			ptr++;
+		switch(*ptr)
+		{
+		case ',':
+			*ptr++ = 0;
+			name = NULL;
+			val = NULL;
+			continue;
+			break;
+		case ':':
+			*ptr++ = 0;
+			val = ptr;
+			while(*ptr != ',' && *ptr != '\0')
+				ptr++;
+			if (*ptr != '\0')
+				*ptr++ = 0;
+			break;
+		}
+		if (!STRICMP(name, "dict"))
+		{
+			expand_T	xpc;
+			if (usr_dic_path)
+				vim_free(usr_dic_path);
+			ExpandInit(&xpc);
+			xpc.xp_context = EXPAND_FILES;
+			usr_dic_path = ExpandOne(&xpc, val, NULL, 
+				WILD_SILENT|WILD_USE_NL, WILD_ALL);
+		}
+		else
+		if (!STRICMP(name, "master"))
+		{
+			expand_T	xpc;
+			if (mst_dic_path)
+				vim_free(mst_dic_path);
+			ExpandInit(&xpc);
+			xpc.xp_context = EXPAND_FILES;
+			mst_dic_path = ExpandOne(&xpc, val, NULL, 
+				WILD_SILENT|WILD_USE_NL, WILD_ALL);
+		}
+#ifdef USE_SERVER
+		else
+		if (!STRICMP(name, "serv"))
+		{
+			if (svr_dic_host)
+				vim_free(svr_dic_host);
+			svr_dic_host = vim_strsave(val);
+		}
+		else
+		if (!STRICMP(name, "port"))
+		{
+			svr_dic_port = (unsigned short)atoi((char*)val);
+		}
+#endif
+		else
+			errmsg = _("illegal imoptions");
+	}
+	if (!usr_dic_path)
+	{
+		expand_T	xpc;
+		char_u *newfile;
+		ExpandInit(&xpc);
+		xpc.xp_context = EXPAND_FILES;
+		usr_dic_path = ExpandOne(&xpc, (char_u *)"~/", NULL, 
+			WILD_SILENT|WILD_USE_NL, WILD_ALL);
+		newfile = alloc(STRLEN(usr_dic_path) + STRLEN(".skk-jisyo") + 1);
+		if (newfile) {
+			STRCPY(newfile, usr_dic_path);
+			STRCAT(newfile, ".skk-jisyo");
+		}
+		vim_free(usr_dic_path);
+		usr_dic_path = newfile;
+	}
+	vim_free(org);
+	return errmsg;
+}
+#endif /* FEAT_SKK */
diff -Naur vim82.orig/src/skklib.c vim82+im_custom/src/skklib.c
--- vim82.orig/src/skklib.c	1970-01-01 00:00:00.000000000 +0000
+++ vim82+im_custom/src/skklib.c	2021-11-21 03:35:52.301386800 +0000
@@ -0,0 +1,730 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "skklib.h"
+
+#ifdef WIN32
+#include <winsock.h>
+#include <io.h>	/* for prototypes of read(), write(), etc. */
+#pragma comment(lib, "ws2_32.lib")
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#define closesocket(s)	close(s)
+#endif
+
+#ifdef INT_SIGNAL
+typedef int SignalFunc;
+#else
+typedef void SignalFunc;
+#endif
+
+#define SKK_PORT_NUMBER	1178
+#define SKK_SERVICENAME	"skkserv"
+
+#ifdef BCOPY
+#define bincopy(a,b,n)	bcopy(a,b,n)
+#define fillzero(a,n)	bzero(a,n)
+#else
+#define bincopy(a,b,n)	memcpy(b,a,n)
+#define fillzero(a,n)	memset(a,0,n)
+#endif
+
+#ifdef WIN32
+static int win32skkservsock = -1;
+#endif
+static int skkservsock = -1;
+static FILE *rserv,*wserv;
+
+/*
+ * Open SKK
+ */
+Dictionary
+openSKK(char *dicname)
+{
+	FILE *f;
+	DicList ditem,ditem2;
+	DicList globaldic;
+	char buf[512];
+	char *p,c;
+	Hash *dhash;
+	Dictionary dic;
+	int i,nitem = 0;
+	int okuriAri = 1;
+	struct stat st;
+
+	dhash = (Hash*)calloc(HASHSIZE,sizeof(Hash));
+	if (!dhash)
+		return NULL;
+	memset(dhash, 0x00, sizeof(Hash));
+	dic = _NEW(Dictionary);
+	if (!dic)
+		return NULL;
+	dic->dhash = dhash;
+	dic->okuriAriFirst = NULL;
+	dic->okuriNasiFirst = NULL;
+	dic->dlist = NULL;
+	ditem2 = NULL;
+	globaldic = NULL;
+	if ((f = fopen(dicname,"r")) == NULL) {
+		return dic;
+	}
+	fstat(fileno(f),&st);
+	while (!feof(f)) {
+		while ((c = fgetc(f)) == ' ' || c == '\t' || c == '\n');
+		if (feof(f)) break;
+		if (c == ';') {	/* comment */
+			i = 0;
+			while (c != '\n' && !feof(f)) {
+				c = fgetc(f);
+				buf[i++] = c;
+			}
+			buf[i] = '\0';
+			if (!strncmp(buf,"; okuri-ari entries.",20)) {
+				okuriAri = 1;
+			}
+			else if (!strncmp(buf,"; okuri-nasi entries.",21)) {
+				okuriAri = 0;
+			}
+			continue;
+		}
+		nitem++;
+		for (buf[0] = c, p = buf+1; 
+		     !feof(f) && (*p = fgetc(f)) != ' '; 
+		     p++) {
+		}
+		*p = '\0';
+		ditem = _NEW2(DicList,strlen(buf));
+		if (!ditem)
+			break;
+		ditem->nextitem = NULL;
+		if (ditem2)
+			ditem2->nextitem = ditem;
+		if (globaldic == NULL)
+			globaldic = ditem;
+		strcpy(ditem->kanaword,buf);
+		ditem->cand = getCandList(f,ditem,okuriAri);
+		if (!ditem->cand)
+			break;
+		addHash(dhash,ditem);
+		ditem2 = ditem;
+		if (okuriAri) {
+			if (!dic->okuriAriFirst)
+				dic->okuriAriFirst = ditem2;
+		}
+		else {
+			if (!dic->okuriNasiFirst)
+				dic->okuriNasiFirst = ditem2;
+		}
+	}
+	fclose(f);
+	dic->dlist = globaldic;
+	dic->mtime = st.st_mtime;
+	return dic;
+}
+
+/*
+ * Check if word is an OKURI-ARI entry or not 
+ */
+int
+isConjugate(word,l)
+char word[];
+int l;
+{
+	int r;
+	if ((word[0] & 0x80) || word[0] == '#') {
+		if (word[l-1] & 0x80)
+			r = 0;
+		else
+			r = (word[l-1] != '#');
+	}
+	else
+		r = 0;
+	return r;
+}
+
+/*
+ * Add new word entry to the dictionary
+ */
+DicList
+addNewItem(Dictionary dic, char *word, CandList clist)
+{
+	DicList ditem;
+	int l = strlen(word);
+
+	ditem = _NEW2(DicList,l);
+	if (!ditem)
+		return NULL;
+	strcpy(ditem->kanaword,word);
+	ditem->cand = clist;
+	addHash(dic->dhash,ditem);
+	if (isConjugate(word,l)) {
+		if (dic->okuriAriFirst) {
+			ditem->nextitem = dic->okuriAriFirst->nextitem;
+			dic->okuriAriFirst->nextitem = ditem;
+		}
+		else {
+			if (dic->dlist) {
+				dic->okuriAriFirst = ditem;
+				ditem->nextitem = dic->okuriNasiFirst;
+				dic->dlist = ditem;
+			}
+			else {
+				dic->dlist = ditem;
+				dic->okuriAriFirst = ditem;
+			}
+		}
+	}
+	else {
+		if (dic->okuriNasiFirst) {
+			ditem->nextitem = dic->okuriNasiFirst->nextitem;
+			dic->okuriNasiFirst->nextitem = ditem;
+		}
+		else {
+			if (dic->dlist) {
+				ditem->nextitem = dic->dlist->nextitem;
+				dic->dlist->nextitem = ditem;
+				dic->okuriNasiFirst = ditem;
+			}
+			else {
+				dic->dlist = ditem;
+				dic->okuriNasiFirst = ditem;
+			}
+		}
+	}
+	return ditem;
+}
+
+CandList
+getCandList(FILE *f, DicList ditem, int okuri)
+{
+	char buf[256];
+	CandList citem,citem2,citem0 = NULL;
+	CandList ccitem,ccitem2;
+	char c,*p;
+	
+	citem2 = NULL;
+	while ((c = fgetc(f)) != '\n' && !feof(f)) {
+		if (c == 9)
+		{
+		    fclose(f);
+		    break;
+		}
+		if (c == '/')
+			continue;
+		if (okuri && c == '[') {
+			for (p = buf; (*p = fgetc(f)) != '/' && !feof(f); p++);
+			*p = '\0';
+			citem = _NEW2(CandList,strlen(buf));
+			if (!citem)
+				break;
+			citem->okuri = NULL;
+			citem->nextcand = NULL;
+			citem->prevcand = citem2;
+			citem->dicitem = ditem;
+			strcpy(citem->candword,buf);
+			ccitem2 = citem;
+			for (;;) {
+				if ((c = fgetc(f)) == ']' || feof(f))
+					break;
+				for (buf[0] = c, p = buf+1;
+				     (*p = fgetc(f)) != '/' && !feof(f);
+				     p++);
+				*p = '\0';
+				ccitem = _NEW2(CandList,strlen(buf));
+				if (!ccitem)
+					break;
+				ccitem->nextcand = NULL;
+				strcpy(ccitem->candword,buf);
+				if (ccitem2 == citem) {
+					ccitem2->okuri = ccitem;
+					ccitem->prevcand = NULL;
+				}
+				else {
+					ccitem2->nextcand = ccitem;
+					ccitem->prevcand = ccitem2;
+				}
+				ccitem2 = ccitem;
+			}
+		}
+		else {
+			for (buf[0] = c, p = buf+1;
+			     (*p = fgetc(f)) != '/' && !feof(f); p++);
+			*p = '\0';
+			citem = _NEW2(CandList,strlen(buf));
+			if (!citem)
+				break;
+			citem->okuri = NULL;
+			citem->nextcand = NULL;
+			citem->prevcand = citem2;
+			citem->dicitem = ditem;
+			strcpy(citem->candword,buf);
+		}
+		if (citem2)
+			citem2->nextcand = citem;
+		else
+			citem0 = citem;
+		citem2 = citem;
+	}
+	return citem0;
+}
+
+void
+closeSKK(dic,dicname)
+Dictionary dic;
+char *dicname;
+{
+	char *buf;
+	FILE *f;
+	DicList dlist,dlist2;
+	DicList globaldic = dic->dlist;
+	int okuri = 1;
+	int l;
+	char *wd;
+	struct stat sbuf;
+	int old = 0;
+
+	if (dicname)
+	{
+		buf = (char *)alloc(256);
+		if (!buf)
+			return;
+		/* backup skk-jisyo if jisyo is not empty. */
+		sprintf(buf,"%s.BAK",dicname);
+		if ((stat(dicname, &sbuf) == 0) && (sbuf.st_size != 0)) {
+			if (dic->mtime < sbuf.st_mtime) {
+				msg("The dictionary is changed. merging...");
+				mergeDictionary(dic,dicname);
+			}
+			rename(dicname,buf);
+			old = 1;
+		}
+		if ((f = fopen(dicname,"w")) == NULL) {
+			free(buf);
+			return;
+		}
+
+		fprintf(f,";; okuri-ari entries.\n");
+		for (dlist = globaldic;
+			 dlist != NULL;
+			 dlist2 = dlist, dlist = dlist->nextitem, free(dlist2)) {
+			wd = dlist->kanaword;
+			l = strlen(wd);
+			if (okuri && (!isConjugate(wd,l))) {
+				fprintf(f,";; okuri-nasi entries.\n");
+				okuri = 0;
+			}
+			fprintf(f,"%s ",dlist->kanaword);
+			printCand(dlist->cand,f,FREE_CAND);
+		}
+		fclose(f);
+		if (old)
+			chmod(dicname,sbuf.st_mode);
+
+		for (l = 0; l < HASHSIZE; l++) {
+			Hash h1, h2;
+
+			for (h1 = dic->dhash[l]; h1; h1 = h2) {
+				h2 = h1->next;
+				free(h1);
+			}
+		}
+		free(buf);
+	}
+	free(dic->dhash);
+	free(dic);
+}				     
+
+/* #define DEBUG_MERGE */ /* debug dictionary merge */
+void
+mergeDictionary(Dictionary dic, char *dicname)
+{
+	FILE *f;
+	CandList cand,dcand;
+	DicList ditem;
+	char *buf;
+	char *p,c;
+	int i;
+#ifdef DEBUG_MERGE
+	DicList change[10]; int n = 0;
+#endif
+
+	buf = (char *)alloc(512);
+	if (buf)
+		return;
+	if ((f = fopen(dicname,"r")) == NULL) {
+		free(buf);
+		return;
+	}
+	while (!feof(f)) {
+		while ((c = fgetc(f)) == ' ' || c == '\t' || c == '\n');
+		if (feof(f)) break;
+		if (c == ';') {	/* comment */
+			while (c != '\n' && !feof(f)) {
+				c = fgetc(f);
+			}
+			continue;
+		}
+		for (buf[0] = c, p = buf+1; 
+		     !feof(f) && (*p = fgetc(f)) != ' '; 
+		     p++) {
+		}
+		*p = '\0';
+		i = strlen(buf);
+		dcand = getCand(dic,buf);
+		if (dcand == NULL) {
+			cand = getCandList(f,NULL,isConjugate(buf,i));
+			if (!cand)
+				break;
+			ditem = addNewItem(dic,buf,cand);
+			for (; cand; cand = cand->nextcand)
+				cand->dicitem = ditem;
+#ifdef DEBUG_MERGE
+			change[n++] = ditem;
+#endif
+		}
+		else {
+			cand = getCandList(f,dcand->dicitem,isConjugate(buf,i));
+			cand = deleteCand(cand,dcand);
+			if (cand) {
+				dcand->dicitem->cand = cand;
+				while (cand->nextcand != NULL)
+					cand = cand->nextcand;
+				cand->nextcand = dcand;
+				dcand->prevcand = cand;
+#ifdef DEBUG_MERGE
+				change[n++] = dcand->dicitem;
+#endif
+			}
+		}	
+	}
+	fclose(f);
+#ifdef DEBUG_MERGE
+	for (i=0;i<n;i++) {
+		printf("i=%d; ",i); fflush(stdout);
+		printf("register(%d): %s (%x)",i,change[i]->kanaword,change[i]->cand); fflush(stdout);
+		printCand(change[i]->cand,stdout,NOFREE_CAND); putchar('\n');
+	}
+#endif
+	free(buf);
+}
+
+void
+printCand(CandList cl, FILE *f, int fre)
+{
+	CandList clist,clist2,cclist,cclist2;
+
+	fputc('/',f);
+	for (clist = cl;
+	     clist != NULL;
+	     clist2 = clist, clist = clist->nextcand,
+	     (fre ? (free(clist2),0) : 0)) {
+		if (clist->okuri) {
+			fprintf(f,"[%s/",clist->candword);
+			for (cclist = clist->okuri;
+			     cclist != NULL;
+			     cclist2 = cclist,
+			     cclist = cclist->nextcand,
+			     (fre ? (free(cclist2),0) : 0)) {
+				fprintf(f,"%s/",cclist->candword);
+			}
+			fputs("]/",f);
+		}
+		else
+			fprintf(f,"%s/",clist->candword);
+	}
+	fputc('\n',f);
+}
+
+int
+hashVal(s)
+char *s;
+{
+	int n = 0;
+
+	while (*s) {
+		n += (*s)*(*s);
+		s++;
+	}
+	return n%HASHSIZE;
+}
+
+void
+addHash(Hash *hash, DicList ditem)
+{
+	Hash h;
+	int v;
+
+	v = hashVal(ditem->kanaword);
+	h = _NEW(Hash);
+	if (!h)
+		return;
+	h->h_index = ditem;
+	h->length = strlen(ditem->kanaword);
+	h->next = hash[v];
+	hash[v] = h;
+}
+
+CandList
+getCand(Dictionary dic, char *s)
+{
+	int l,v;
+	Hash h;
+
+	l = strlen(s);
+	v = hashVal(s);
+	for (h = dic->dhash[v]; h != NULL; h = h->next) {
+		if (h->length != l ||
+		    strcmp(h->h_index->kanaword,s)) continue;
+		return h->h_index->cand;
+	}
+	return NULL;
+}
+
+void
+selectCand(CandList *first, CandList cand)
+{
+	if (cand->prevcand) {
+		cand->prevcand->nextcand = cand->nextcand;
+		if (cand->nextcand)
+			cand->nextcand->prevcand = cand->prevcand;
+		cand->prevcand = NULL;
+	}
+	if (*first != cand) {
+		(*first)->prevcand = cand;
+		cand->nextcand = *first;
+		*first = cand;
+	}
+}
+
+void
+freeCand(cl)
+CandList cl;
+{
+	CandList clist,clist2,cclist,cclist2;
+
+	for (clist = cl;
+	     clist != NULL;
+	     clist2 = clist, clist = clist->nextcand, free(clist2)) {
+		if (clist->okuri) {
+			for (cclist = clist->okuri;
+			     cclist != NULL;
+			     cclist2 = cclist,
+			     cclist = cclist->nextcand,
+			     free(cclist2)) ;
+		}
+	}
+}
+
+CandList
+deleteCand(CandList frlist, CandList itlist)
+{
+	CandList l;
+	while (itlist != NULL) {
+		for (l = frlist; l != NULL; l = l->nextcand) {
+			if (!strcmp(itlist->candword, l->candword)) {
+				if (l->prevcand == NULL) {
+					frlist = l->nextcand;
+					if (l->nextcand)
+						l->nextcand->prevcand = NULL;
+				}
+				else {
+					l->prevcand->nextcand = l->nextcand;
+					if (l->nextcand)
+						l->nextcand->prevcand = l->prevcand;
+				}
+				l->nextcand = NULL;
+				freeCand(l);
+				break;
+			}
+		}
+		itlist = itlist->nextcand;
+	}
+	return frlist;
+}
+
+CandList
+firstCand(CandList l)
+{
+	while (l->prevcand)
+		l = l->prevcand;
+	return l;
+}
+
+CandList
+searchOkuri(CandList cl, char *okuri, CandList **newfirst)
+{
+	CandList ll;
+
+	for (ll = cl; ll != NULL; ll = ll->nextcand) {
+		if (ll->okuri && !strcmp(ll->candword,okuri)) {
+			if (newfirst)
+				*newfirst = &(ll->okuri);
+			return ll->okuri;
+		}
+	}
+	if (newfirst && cl->dicitem) {
+		if (cl->dicitem->cand->okuri) {
+			return NULL;
+		}
+		*newfirst = &(cl->dicitem->cand);
+	}
+	return cl;
+}
+
+int
+getSKKservStatus()
+{
+	return (skkservsock != -1);
+}
+
+int
+openSKKserv(char *svrname, unsigned short port)
+{
+	int sock;
+	struct sockaddr_in hostaddr;
+	struct hostent *entry;
+	struct servent *serv;
+	struct protoent *proto;
+	int a1,a2,a3,a4;
+	char *hostname;
+
+	if (skkservsock != -1)
+		return 0;
+
+	if (svrname)
+		hostname = svrname;
+	else if ((hostname = getenv("SKKSERVER")) == NULL) {
+		return -1;
+	}
+	if (strcmp(hostname, "!skkserv") == 0) {
+		return -1;	/* specified not to use skkserv */
+	}
+
+#ifdef WIN32
+	{
+		WORD wVersionRequested;
+		WSADATA wsaData;
+		int sockopt = SO_SYNCHRONOUS_NONALERT;
+		wVersionRequested = MAKEWORD(1, 1);
+		if (WSAStartup(wVersionRequested, &wsaData) != 0) {
+			return -1;
+		}
+		/* Enable the use of sockets as filehandles */
+		setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
+			   (char *)&sockopt, sizeof(sockopt));
+	}
+#endif
+	serv = getservbyname(SKK_SERVICENAME,"tcp");
+	fillzero((char*)&hostaddr,sizeof(struct sockaddr_in));
+	if ((proto = getprotobyname("tcp")) == NULL) {
+		return -1;
+	}
+
+	if ('0' <= *hostname && *hostname <= '9') {
+		if (sscanf(hostname,"%d.%d.%d.%d",&a1,&a2,&a3,&a4) != 4) {
+			return -1;
+		}
+		a1 = (a1<<24)|(a2<<16)|(a3<<8)|a4;
+		hostaddr.sin_addr.s_addr = htonl(a1);
+	}
+	else {
+		if ((entry = gethostbyname(hostname)) == NULL) {
+			return -1;
+		}
+		bincopy(entry->h_addr, &hostaddr.sin_addr, entry->h_length);
+	}
+
+	if ((sock = socket(AF_INET,SOCK_STREAM,proto->p_proto)) < 0) {
+		return -1;
+	}
+        hostaddr.sin_family = AF_INET;
+	hostaddr.sin_port = serv ? serv->s_port : htons(port);
+	if (connect(sock,(struct sockaddr *)&hostaddr,sizeof(struct sockaddr_in)) < 0) {
+		closesocket(sock);
+		return -1;
+	}
+#ifdef WIN32
+	if ((skkservsock = _open_osfhandle(sock, 0)) < 0) {
+		closesocket(sock);
+    		return -1;
+	}
+	win32skkservsock = sock;
+	rserv = fdopen(skkservsock,"rb");
+	wserv = fdopen(skkservsock,"wb");
+#else
+	skkservsock = sock;
+	rserv = fdopen(sock,"r");
+	wserv = fdopen(sock,"w");
+#endif
+	return 0;
+}
+
+CandList
+getCandFromServer(s)
+char *s;
+{
+	char r;
+	CandList res;
+
+	if (skkservsock < 0)
+		return NULL;
+#ifdef WIN32
+	if (win32skkservsock < 0) {
+		closeSKKserv();
+		return NULL;
+	}
+#endif
+	if (!rserv || !wserv) {
+		closeSKKserv();
+		return NULL;
+	}
+	fprintf(wserv,"1%s \n",s);
+	fflush(wserv);
+	if (read(skkservsock,&r,1) <= 0) {
+#ifdef SIGPIPE
+		SignalFunc (*sigfunc)();
+#endif
+
+#ifdef SIGPIPE	/* WIN32 may not define SIGPIPE */
+		sigfunc = signal(SIGPIPE, SIG_IGN);
+#endif
+		closeSKKserv();
+#ifdef SIGPIPE
+		signal(SIGPIPE, sigfunc);
+#endif
+		return NULL;
+	}
+	if (r == '1') {  /* succeeded */
+		res = getCandList(rserv,NULL,isConjugate(s,strlen(s)));
+		return res;
+	}
+	else
+	if (r == '4')
+	{
+		read(skkservsock,&r,1);
+		return NULL;
+	}
+	else
+		while (read(skkservsock,&r,1) > 0 && r != '\n');
+	return NULL;
+}
+
+void
+closeSKKserv()
+{
+	if (skkservsock >= 0) {
+		fprintf(wserv,"0\n");
+		fflush(wserv);
+		fclose(wserv);
+		fclose(rserv);
+		closesocket(skkservsock);
+		skkservsock = -1;
+#ifdef WIN32
+		close(win32skkservsock);
+		win32skkservsock = -1;
+		WSACleanup();
+#endif
+	}
+}
diff -Naur vim82.orig/src/skklib.h vim82+im_custom/src/skklib.h
--- vim82.orig/src/skklib.h	1970-01-01 00:00:00.000000000 +0000
+++ vim82+im_custom/src/skklib.h	2021-11-21 03:35:52.301386800 +0000
@@ -0,0 +1,69 @@
+#ifndef SKKLIB_H
+#define SKKLIB_H
+
+#ifndef NO_MALLOC_H
+#include <malloc.h>
+#endif
+
+/*
+ * Structure for Dictionary
+ */
+typedef struct DicList {
+	struct CandList *cand;
+	struct DicList *nextitem;
+	char kanaword[1];
+} *DicList;
+
+/*
+ * Structure for Candidate
+ */
+typedef struct CandList {
+	struct CandList *okuri;
+	struct CandList *nextcand;
+	struct CandList *prevcand;
+	struct DicList *dicitem;
+	char candword[1];
+} *CandList;
+
+typedef struct Hash {
+	DicList h_index;
+	short length;
+	struct Hash *next;
+} *Hash;
+
+#define HASHSIZE 256
+
+typedef struct Dictionary {
+	DicList dlist;
+	DicList okuriAriFirst;
+	DicList okuriNasiFirst;
+	Hash *dhash;
+	time_t mtime;
+} *Dictionary;
+
+#define _NEW(type) ((type)malloc(sizeof(struct type)))
+#define _NEW2(type,add)	((type)malloc(sizeof(struct type)+(add)))
+
+Dictionary openSKK(char*);
+void closeSKK();
+CandList getCand(Dictionary, char*);
+CandList getCandList(FILE*, DicList, int);
+#ifdef USE_SERVER
+int openSKKserv(char *svrname, unsigned short);
+void closeSKKserv();
+CandList getCandFromServer();
+int getSKKservStatus();
+#endif
+CandList firstCand(CandList);
+CandList deleteCand(CandList, CandList);
+CandList searchOkuri(CandList, char*, CandList**);
+DicList addNewItem(Dictionary, char*, CandList);
+void addHash(Hash*,DicList);
+void mergeDictionary(Dictionary, char*);
+void printCand(CandList, FILE*, int);
+
+/* flags for printCand() */
+#define NOFREE_CAND 0
+#define FREE_CAND 1
+
+#endif /* SKKLIB_H */
diff -Naur vim82.orig/src/term.c vim82+im_custom/src/term.c
--- vim82.orig/src/term.c	2019-12-07 16:34:32.000000000 +0000
+++ vim82+im_custom/src/term.c	2021-11-21 03:35:52.301386800 +0000
@@ -3413,6 +3413,13 @@
 	}
 	cursor_on();	    // redrawing may have switched it off
     }
+#ifdef FEAT_IM_CUSTOM
+    if (im_custom_get_active)
+    {
+	if (im_custom_get_active() && im_custom_redraw)
+	    im_custom_redraw();
+    }
+#endif
     out_flush();
     --busy;
 }
diff -Naur vim82.orig/src/ui.c vim82+im_custom/src/ui.c
--- vim82.orig/src/ui.c	2019-12-05 20:39:28.000000000 +0000
+++ vim82+im_custom/src/ui.c	2021-11-21 03:35:52.317008500 +0000
@@ -3059,12 +3059,18 @@
     // And don't save when the GUI is running but our window doesn't have
     // input focus (e.g., when a find dialog is open).
     if (!p_imdisable && KeyTyped && !KeyStuffed
+	    && ((TRUE
 # ifdef FEAT_XIM
-	    && xic != NULL
+		    && xic != NULL
 # endif
 # ifdef FEAT_GUI
-	    && (!gui.in_use || gui.in_focus)
+		    && (!gui.in_use || gui.in_focus)
 # endif
+		   )
+# ifdef FEAT_IM_CUSTOM
+		|| (im_custom_enabled && im_custom_enabled(FALSE))
+# endif
+	       )
 	)
     {
 	// Do save when IM is on, or IM is off and saved status is on.
diff -Naur vim82.orig/src/version.c vim82+im_custom/src/version.c
--- vim82.orig/src/version.c	2019-12-12 11:54:31.000000000 +0000
+++ vim82+im_custom/src/version.c	2021-11-21 03:35:52.320519000 +0000
@@ -143,6 +143,11 @@
 #else
 	"-channel",
 #endif
+#ifdef FEAT_IM_CUSTOM
+	"+im_custom",
+#else
+	"-im_custom",
+#endif
 #ifdef FEAT_CINDENT
 	"+cindent",
 #else
diff -Naur vim82.orig/src/vim.h vim82+im_custom/src/vim.h
--- vim82.orig/src/vim.h	2019-12-05 22:05:26.000000000 +0000
+++ vim82+im_custom/src/vim.h	2021-11-21 03:35:52.320519000 +0000
@@ -2171,6 +2171,7 @@
 #endif
 
 #if defined(FEAT_XIM) \
+	|| defined(FEAT_IM_CUSTOM) \
 	|| defined(IME_WITHOUT_XIM) \
 	|| (defined(FEAT_GUI_MSWIN) \
 	    && (defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME))) \
