diff lib/Xsj3clib/func.c @ 0:92745d501b9a

initial import from kinput2-v3.1
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 08 Mar 2010 04:44:30 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Xsj3clib/func.c	Mon Mar 08 04:44:30 2010 +0900
@@ -0,0 +1,3968 @@
+#ifndef lint
+static char *rcsid = "$Id: func.c,v 2.3 1993/09/21 09:42:57 nao Exp $";
+#endif
+/*
+ * Copyright 1991 Sony Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Sony not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Sony makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SONY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SONY
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Author: Naoshi Suzuki, SONY Corporation.  (nao@sm.sony.co.jp)
+ */
+
+#include <ctype.h>
+#include "common.h"
+#include "sj3ctype.h"
+#include "util.h"
+#include "func.h"
+
+extern Xsj3cCVServerIF  serverIF[SERVER_NUM];
+extern void             Xsj3cRCInit();
+extern int              _Xsj3cRomaConv();
+extern int              _Xsj3cKanaConv();
+extern Xsj3cCand        _Xsj3cCandidateInit();
+extern void             _Xsj3cFlushDictMsg();
+extern Xsj3cDictData    _Xsj3cCreateDictData();
+
+Xsj3cEvent              _Xsj3cConvert();
+Xsj3cEvent              _Xsj3cUnConvert();
+Xsj3cEvent              _Xsj3cFix();
+Xsj3cEvent              _Xsj3cReturn();
+
+Xsj3cEvent              _Xsj3cModeHAlpha();
+Xsj3cEvent              _Xsj3cModeZAlpha();
+Xsj3cEvent              _Xsj3cModeHKata();
+Xsj3cEvent              _Xsj3cModeZKata();
+Xsj3cEvent              _Xsj3cModeHira();
+Xsj3cEvent              _Xsj3cToHAlpha();
+Xsj3cEvent              _Xsj3cToZAlpha();
+Xsj3cEvent              _Xsj3cToHKata();
+Xsj3cEvent              _Xsj3cToZKata();
+Xsj3cEvent              _Xsj3cToHira();
+Xsj3cEvent              _Xsj3cZenkaku();
+Xsj3cEvent              _Xsj3cHankaku();
+Xsj3cEvent              _Xsj3cToUpper();
+Xsj3cEvent              _Xsj3cToLower();
+Xsj3cEvent              _Xsj3cModeSJIS();
+Xsj3cEvent              _Xsj3cModeEUC();
+Xsj3cEvent              _Xsj3cModeJIS();
+Xsj3cEvent              _Xsj3cModeKuten();
+Xsj3cEvent              _Xsj3cCodeRollDown();
+Xsj3cEvent              _Xsj3cModeRollDown();
+Xsj3cEvent              _Xsj3cModeRollUp();
+Xsj3cEvent              _Xsj3cNextMode();
+Xsj3cEvent              _Xsj3cPrevMode();
+Xsj3cEvent              _Xsj3cModeToggle();
+
+Xsj3cEvent              _Xsj3cForward();
+Xsj3cEvent              _Xsj3cBackward();
+Xsj3cEvent              _Xsj3cTop();
+Xsj3cEvent              _Xsj3cEnd();
+Xsj3cEvent              _Xsj3cUp();
+Xsj3cEvent              _Xsj3cDown();
+Xsj3cEvent              _Xsj3cFirst();
+Xsj3cEvent              _Xsj3cLast();
+Xsj3cEvent              _Xsj3cNextPage();
+Xsj3cEvent              _Xsj3cPrevPage();
+Xsj3cEvent              _Xsj3cNext();
+Xsj3cEvent              _Xsj3cPrev();
+Xsj3cEvent              _Xsj3cSelect();
+Xsj3cEvent              _Xsj3cCancel();
+
+Xsj3cEvent              _Xsj3cExpand();
+Xsj3cEvent              _Xsj3cShrink();
+
+Xsj3cEvent              _Xsj3cBackSpace();
+Xsj3cEvent              _Xsj3cDelete();
+Xsj3cEvent              _Xsj3cDelAfter();
+
+Xsj3cEvent              _Xsj3cStart();
+Xsj3cEvent              _Xsj3cReConnect();
+Xsj3cEvent              _Xsj3cReConvert();
+Xsj3cEvent              _Xsj3cEdit();
+
+Xsj3cEvent              _Xsj3cDRegBegin();
+Xsj3cEvent              _Xsj3cDClearBegin();
+
+Xsj3cEvent              _Xsj3cSymbolBegin();
+
+Xsj3cEvent              _Xsj3cQuote();
+Xsj3cEvent              _Xsj3cBell();
+Xsj3cEvent              _Xsj3cKana();
+Xsj3cEvent              _Xsj3cSjrc();
+Xsj3cEvent              _Xsj3cKill();
+Xsj3cEvent              _Xsj3cNull();
+Xsj3cEvent              _Xsj3cIgnore();
+
+Xsj3cEvent              _Xsj3cUnConvSeg();
+
+static Xsj3cEvent       _Xsj3cDeleteSeg();
+static Xsj3cEvent       _Xsj3cDeleteChar();
+static Xsj3cEvent       _Xsj3cBackSpaceChar();
+static Xsj3cEvent       _Xsj3cExpandNoConv();
+static Xsj3cEvent       _Xsj3cShrinkNoConv();
+
+/*
+ * _Xsj3cConvert() [henkan/convert]
+ *
+ * <InputMode> Do kana-kanji conversion.
+ * <ConvedMode> If character mode of current segment is zenkaku-hiragana,
+ *   pop up candidate panel, else convert to zenkaku-hiragana.
+ * <NoInputMode/SelectMode/DictMode> Rings bell.
+ *
+ * BeginConversionLast none: Set current segment out of segments. 
+ * BeginConversionLast off: Set current segment to the first segment.
+ * BeginConversionLast on: Set current segment to the last segment.
+ * DisplayModeChange on: Change the display mode string.  
+ * HenkanSegment all: Convert all segments.
+ * HenkanSegment after: Convert segments after current segment.
+ * HenkanSegment one: Convert current segment.
+ * BeforeSelectConversion on: Convert current segment to hiragana
+ *   and need one more step to display candidates.
+ * BeforeConversion on: Convert current segment to hiragana before
+ *   Kana-Kanji conversion.
+ * BeforeSelectCount: Work like "next/wrap" before popup candidate panel
+ *   at [ConvedMode].
+ * LastDoubleConversion on: Before Kana-Kanji conversion, convert current
+ *   segment to current character mode.
+ */
+Xsj3cEvent
+_Xsj3cConvert(buf)
+    Xsj3cBuf  buf;
+{
+    unsigned char               knjbuf[KANJIBUFSIZ];
+    unsigned char               kanabuf[KANJIBUFSIZ];
+    Xsj3cEvent                  ret = KEY_NULL;
+    SJ3_BUNSETU                 bun[BUNBUFSIZ];
+    int                         i,  value;
+    register int                conved, begin,  end;
+
+    if (buf->segnum && buf->curseg >= buf->segnum) {
+        buf->curseg = buf->segnum - 1;
+        if (buf->input[buf->curseg] &&
+                (buf->input[buf->curseg]->status & SEG_CONVED))
+            buf->convmode = ConvedModeMask;
+        else 
+            buf->convmode = InputModeMask;
+        ret = KEY_TEXT_CHANGE;
+    }
+    if ((buf->convmode & (InputModeMask|ConvedModeMask))
+            && buf->curseg < buf->segnum) {
+        if (buf->convmode & ConvedModeMask) {
+            if (buf->selectconv &&
+                    buf->input[buf->curseg]->cursegmode != MODE_HIRA) {
+                ret |= _Xsj3cModeChange(buf, MODE_HIRA, ON);
+                buf->convedsegnum--;
+                buf->input[buf->curseg]->status = SEG_NOCONV;
+            } else {
+                if (buf->selectcount > 0) {
+                    int     cur;
+                    if (!buf->candidate)
+                        Xsj3cGetCandidateNum(buf, &cur);
+                    if (buf->selectcount < buf->candnum) {
+                        if (buf->n_select < buf->selectcount) {
+                            buf->n_select++;
+                            return(_Xsj3cNext(buf));
+                        }
+                    }
+                }
+                buf->convmode = SelectModeMask;
+                ret |= KEY_CAND_START;
+                if (buf->dispmodechange) {
+                    buf->dispmode = MODE_CAND;
+                    ret |= KEY_MODE_CHANGE;
+                }
+                buf->selectstatus = SELECT_CAND;
+                buf->n_select = 0;
+                return (ret);
+            }
+        } else if (buf->beforeconv) {
+            register wchar  *p;
+            p = buf->input[buf->curseg]->yomi;
+            while (*p != '\0') {
+                if (!ishira(*p, serverIF[buf->server].lang)) {
+                    ret |= _Xsj3cModeChange(buf, MODE_HIRA, ON);
+                    break;
+                }
+                p++;
+            }
+        } else if (buf->lastdoubleconv && *buf->rkdouble != '\0') {
+            register unsigned char  *p, q;
+            i = buf->input[buf->curseg]->num - 1;
+            q = buf->input[buf->curseg]->yomi[i] & 0xff;
+            p = buf->rkdouble;
+            while (*p != '\0') {
+                if (*p == q) {
+                    ret |= _Xsj3cModeChange(buf,
+                        buf->input[buf->curseg]->cursegmode, ON);
+                    break;
+                }
+                p++;
+            }
+        }
+        ret |= KEY_TEXT_CHANGE;
+        switch (buf->henkanseg) {
+        case ALL:
+            begin = 0;
+            end = buf->segnum;
+            break;
+        case AFTER:
+            begin = buf->curseg;
+            end = buf->segnum;
+            break;
+        case ONE:
+        default:
+            begin = buf->curseg;
+            end = buf->curseg + 1;
+            break;
+        }
+
+        conved = buf->convedsegnum;
+        if (!buf->input[begin]->num) {
+            return (ret);
+        }
+        for (i = begin; i < end; i += value) {
+            if (buf->input[i]->status == SEG_CONVED) {
+                value = 1;
+                continue;
+            }
+            if (buf->input[i]->num > INPUT_YOMI_MAX || !buf->input[i]->num) {
+                Xsj3cWarning("Too long or short segment[%d].", i);
+                ret |= KEY_BELL;
+                value = 1;
+                continue;
+            }
+            buf->input[i]->n_roma = 0;
+            buf->input[i]->n_kana = -1;
+            *buf->input[i]->str = '\0';
+            buf->input[i]->sp = buf->input[i]->str;
+            *buf->input[i]->oldstr = '\0';
+            _Xsj3cwPStomPS(buf, kanabuf, buf->input[i]->yomi);
+            value = serverIF[buf->server].func[FUNC_CONV]
+                    (kanabuf, bun, knjbuf, KANJIBUFSIZ);
+            if (value  <= 0) {
+                if (value  < 0) 
+                    Xsj3cWarning("sj3serv is down. reconnect please");
+                else 
+                    Xsj3cWarning("Too long segment[%d]. Could not convert.", i);
+                ret |= KEY_BELL;
+                value = 1;
+                continue;
+            }
+            _Xsj3cStoreKanji(buf, bun, i, value, OFF);
+            buf->convedsegnum += value;
+            buf->segnum += (--value);
+        }
+        if (buf->henkanseg != ONE || !conved) {
+            switch (buf->beginlastseg) {
+            case NONE:
+                buf->curseg = buf->segnum;
+                break;
+            case ON:
+                buf->curseg = buf->segnum - 1;
+                break;
+            case OFF:
+                buf->curseg = 0;
+                break;
+            default:
+                buf->curseg = 0;
+                break;
+            }
+        }
+        if (buf->dispmodechange) {
+            buf->dispmode = (buf->convedsegnum == buf->segnum ? MODE_KANJI :
+                (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+            ret |= KEY_MODE_CHANGE;
+        }
+        return ret;
+    } else {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cUnConvert() [muhen/unconvert]
+ *
+ * <InputMode/ConvedMode> Unconvert segments.
+ * <SelectMode> pop down the panel candidate(symbol/hinsi) panel and
+ *   unconvert segments.
+ * <DictMode> Pop down Auxpanel and unconvert segments.
+ * <NoInputMode> Does nothing.
+ *
+ * DisplayModeChange on: Change the display mode string.  
+ * MuhenkanCursorLast on: Set cursor position to bottom of segment.
+ * MuhenkanCursorLast off: Set cursor position to top of segment.
+ * MuhenkanSegment all: Unconvert all segments.
+ * MuhenkanSegment after: Unconvert segments after current segment.
+ * MuhenkanSegment one: Unconvert current segment.
+ */
+Xsj3cEvent
+_Xsj3cUnConvert(buf)
+    Xsj3cBuf            buf;
+{
+    Xsj3cEvent          ret = KEY_NULL;
+
+    if (buf->convmode & SelectModeMask) {
+        ret |= KEY_SELECT_ABORT;
+        if (buf->selectstatus == SELECT_HINSI) {
+            ret |= KEY_DICT_END;
+        }
+    } else if (buf->convmode & DictModeMask) {
+        ret |= KEY_DICT_END;
+    } else if (buf->convmode & NoInputModeMask) {
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+    buf->convmode = InputModeMask;
+    ret |= _Xsj3cUnConvSeg(buf, buf->muhenseg, buf->muhencurlast);
+    _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+    return (ret);
+}
+
+/*
+ * _Xsj3cUnConvSeg()
+ *  Change current segment back to non converted
+ * and set converion mode to InputMode.
+ */
+Xsj3cEvent
+_Xsj3cUnConvSeg(buf, muhenseg, muhencurlast)
+    Xsj3cBuf            buf;
+    Xsj3cFlag           muhenseg,   muhencurlast;
+{
+    register int        i,  begin,  end,    unconved = 0;
+    Xsj3cEvent          ret = KEY_TEXT_CHANGE;
+
+    buf->n_select = 0;
+    if (buf->candidate) 
+        Xsj3cEndCandidate(buf, OFF);
+    switch (muhenseg) {
+    case ALL:
+        begin = 0;
+        end = buf->segnum;
+        break;
+    case AFTER:
+        begin = buf->curseg;
+        end = buf->segnum;
+        break;
+    case ONE:
+    default:
+        begin = buf->curseg;
+        end = buf->curseg + 1;
+        break;
+    }
+    for (i = begin; i < end; i++) {
+        if (buf->input[begin]->status == SEG_NOCONV)
+            unconved++;
+        else
+            break;
+    }
+    if (unconved == (end - begin)) {
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+    for (i = begin + 1; i < end; i++) {
+        _Xsj3cWcat(buf->input[begin]->yomi, buf->input[i]->yomi);
+        buf->input[begin]->num += buf->input[i]->num;
+    }
+    buf->input[begin]->cur = buf->input[begin]->num;
+    for (i = begin + 1; i < end; i++) {
+        Xsj3cFreeSegment(buf->input[i]);
+        buf->input[i] = NULL;
+    }
+    Xsj3cFreeSegment(buf->input[buf->segnum]);
+    buf->input[buf->segnum] = NULL;
+    buf->segnum -= (end - begin - 1);
+    buf->curseg = begin;
+    buf->convedsegnum -= (end - begin);
+    if (!buf->convedsegnum) {
+        if (buf->gakusyuu) 
+            _Xsj3cClearDcid(buf);
+        if (buf->dispmodechange) {
+            buf->dispmode = buf->inputmode;
+            ret |= KEY_MODE_CHANGE;
+        }
+    } else if (buf->dispmodechange) {
+        buf->dispmode = ((buf->segnum
+            && buf->convedsegnum == buf->segnum) ? MODE_KANJI :
+            (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+        ret |= KEY_MODE_CHANGE;
+    }
+    buf->input[begin]->change = OFF;
+    buf->input[begin]->status = SEG_NOCONV;
+    if (!(buf->movebyseg & SEG_NOCONV))
+        buf->input[begin]->edit = SEG_EDIT;
+    if (muhencurlast)
+        buf->input[begin]->cur = buf->input[begin]->num;
+    else
+        buf->input[begin]->cur = 0;
+    return (ret);
+}
+
+/*
+ * _Xsj3cFix() [kettei/flush/fix]
+ *
+ * <InputMode/ConvedMode> Fix all segments.
+ *    the candidate(symbol) panel.
+ * <SelectMode> Select reversed candidate(symbol/hinsi)
+ *   in the candidate(symbol/hinsi) panel and pop down the panel.
+ * <DictMode> (DICT_INPUT) Decide current yomi character string.
+ *            (DICT_CONFIRM) Confirm to register/eliminate word.
+ *            (DICT_END) Pop down Auxpanel
+ * <NoInputMode> Does nothing.
+ *
+ * DisplayModeChange on: Change the display mode string.  
+ */
+Xsj3cEvent
+_Xsj3cFix(buf)
+    Xsj3cBuf    buf;
+{
+    switch (buf->convmode) {
+    case SelectModeMask:
+        if (buf->selectstatus == SELECT_HINSI) {
+            buf->dict->status = DICT_CONFIRM;
+            if (buf->dispmodechange) {
+                buf->dispmode =
+                    (buf->dict->mode == REG_STATE ? MODE_TOROKU : MODE_SYOUKYO);
+                return (KEY_SELECT_END|KEY_DICT_CHANGE|KEY_MODE_CHANGE);
+            } else
+                return (KEY_SELECT_END|KEY_DICT_CHANGE);
+        } else {
+            if (buf->dispmodechange) {
+                buf->dispmode = buf->inputmode;
+                return (KEY_TEXT_FIXED|KEY_TEXT_CHANGE
+                    |KEY_SELECT_END|KEY_MODE_CHANGE);
+            } else
+                return (KEY_TEXT_FIXED|KEY_TEXT_CHANGE|KEY_SELECT_END);
+        }
+    case DictModeMask:
+        switch (buf->dict->status) {
+        case DICT_INPUT:
+            if (buf->dict->seg->num > 0) {
+                if (buf->dict->seg->num > DICT_YOMI_MAX) {
+                    buf->dict->status = DICT_END;
+                    buf->curhinsi = -1;
+                    buf->dict->value = SJ3_LONG_YOMI_STR;
+                    _Xsj3cFlushDictMsg(buf);
+                    return(KEY_DICT_CHANGE);
+                } else {
+                    if (buf->dict->mode == REG_STATE) {
+                        buf->dict->status = DICT_HINSI;
+                        buf->selectstatus = SELECT_HINSI;
+                        buf->convmode = SelectModeMask;
+                        _Xsj3cFlushDictMsg(buf);
+                        if (buf->dispmodechange) {
+                            buf->dispmode = MODE_HINSI;
+                            return (KEY_HINSI_START|KEY_MODE_CHANGE);
+                        } else 
+                            return (KEY_HINSI_START);
+                    } else {
+                        buf->dict->status = DICT_CONFIRM;
+                        _Xsj3cFlushDictMsg(buf);
+                        return (KEY_DICT_CHANGE);
+                    }
+                }
+            } else {
+                buf->dict->status = DICT_END;
+                buf->curhinsi = -1;
+                buf->dict->value = SJ3_NO_YOMI_STR;
+                _Xsj3cFlushDictMsg(buf);
+                return(KEY_DICT_CHANGE);
+            }
+        case DICT_CONFIRM:
+            buf->dict->status = DICT_END;
+            return (buf->dict->mode == REG_STATE ?
+                    KEY_DICT_REGISTER : KEY_DICT_CLEAR);
+        case DICT_END:
+            if (buf->dispmodechange) {
+                buf->dispmode
+                    = (buf->convedsegnum == buf->segnum ? MODE_KANJI :
+                    (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+                return(KEY_DICT_END|KEY_TEXT_CHANGE|KEY_MODE_CHANGE);
+            } else 
+                return(KEY_DICT_END|KEY_TEXT_CHANGE);
+        default:
+#ifdef THROUGH_CONT
+            return (KEY_BELL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_BELL);
+            else 
+                return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+        }
+    case NoInputModeMask:
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    case InputModeMask:
+    case ConvedModeMask:
+    default:
+        if (buf->dispmodechange) {
+            buf->dispmode = buf->inputmode;
+            return (KEY_TEXT_FIXED|KEY_TEXT_CHANGE|KEY_MODE_CHANGE);
+        } else 
+            return (KEY_TEXT_FIXED|KEY_TEXT_CHANGE);
+    }
+}
+
+/*
+ * _Xsj3cReturn() [return]
+ *
+ * <NoInputMode/InputMode> Put the carriage return after current position
+ *   and fix all segments.
+ * <ConvedMode> Put the carriage return after current segment
+ *   and fix all segments.
+ * <SelectMode> Select reversed candidate(symbol/hinsi)
+ *   in the candidate(symbol/hinsi) panel and pop down the panel.
+ * <DictMode> (DICT_INPUT) Decide current yomi character string.
+ *            (DICT_CONFIRM) Confirm to register/eliminate word.
+ *            (DICT_END) Pop down Auxpanel
+ *
+ * DisplayModeChange on: Change the display mode string.  
+ */
+Xsj3cEvent
+_Xsj3cReturn(buf)
+    Xsj3cBuf        buf;
+{
+    unsigned char   ch[2];
+    int             change_pos;
+    register int    i;
+
+    switch (buf->convmode) {
+    case NoInputModeMask:
+        buf->convmode = InputModeMask;
+    case InputModeMask:
+        if (buf->segnum == buf->curseg)
+            buf->segnum++;
+        ch[0] = '\r';
+        ch[1] = '\0';
+        change_pos = buf->input[buf->curseg]->cur;
+        _Xsj3cInsertChar(buf, buf->input[buf->curseg], ch, 1);
+        _Xsj3cStoreYomi(buf, buf->input[buf->curseg], change_pos);
+        if (buf->dispmodechange) {
+            buf->dispmode = buf->inputmode;
+            return (KEY_TEXT_FIXED|KEY_TEXT_CHANGE|KEY_MODE_CHANGE);
+        } else
+            return (KEY_TEXT_FIXED|KEY_TEXT_CHANGE);
+    case ConvedModeMask:
+        i = buf->input[buf->curseg]->dnum;
+        buf->input[buf->curseg]->disp[i++] = '\n';
+        buf->input[buf->curseg]->disp[i] = '\0';
+        buf->input[buf->curseg]->dnum++;
+        if (buf->dispmodechange) {
+            buf->dispmode = buf->inputmode;
+            return (KEY_TEXT_FIXED|KEY_TEXT_CHANGE|KEY_MODE_CHANGE);
+        } else
+            return (KEY_TEXT_FIXED|KEY_TEXT_CHANGE);
+    case DictModeMask:
+        switch (buf->dict->status) {
+        case DICT_INPUT:
+            if (buf->dict->seg->num) {
+                if (buf->dict->seg->num > DICT_YOMI_MAX) {
+                    buf->dict->status = DICT_END;
+                    buf->curhinsi = -1;
+                    buf->dict->value = SJ3_LONG_YOMI_STR;
+                    _Xsj3cFlushDictMsg(buf);
+                    return(KEY_DICT_CHANGE);
+                } else {
+                    if (buf->dict->mode == REG_STATE) {
+                        buf->dict->status = DICT_HINSI;
+                        buf->selectstatus = SELECT_HINSI;
+                        buf->convmode = SelectModeMask;
+                        _Xsj3cFlushDictMsg(buf);
+                        if (buf->dispmodechange) {
+                            buf->dispmode = MODE_HINSI;
+                            return (KEY_HINSI_START|KEY_MODE_CHANGE);
+                        } else 
+                            return (KEY_HINSI_START);
+                    } else {
+                        buf->dict->status = DICT_CONFIRM;
+                        _Xsj3cFlushDictMsg(buf);
+                        return (KEY_DICT_CHANGE);
+                    }
+                }
+            } else {
+                buf->dict->status = DICT_END;
+                buf->curhinsi = -1;
+                buf->dict->value = SJ3_NO_YOMI_STR;
+                _Xsj3cFlushDictMsg(buf);
+                return(KEY_DICT_CHANGE);
+            }
+        case DICT_CONFIRM:
+            buf->dict->status = DICT_END;
+            return (buf->dict->mode == REG_STATE ?
+                    KEY_DICT_REGISTER : KEY_DICT_CLEAR);
+        case DICT_END:
+            if (buf->dispmodechange) {
+                buf->dispmode
+                    = (buf->convedsegnum == buf->segnum ? MODE_KANJI :
+                    (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+                return(KEY_DICT_END|KEY_TEXT_CHANGE|KEY_MODE_CHANGE);
+            } else 
+                return(KEY_DICT_END|KEY_TEXT_CHANGE);
+        default:
+#ifdef THROUGH_CONT
+            return (KEY_BELL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_BELL);
+            else 
+                return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+        }
+    case SelectModeMask:
+        if (buf->selectstatus == SELECT_HINSI) {
+            buf->dict->status = DICT_CONFIRM;
+            if (buf->dispmodechange) {
+                buf->dispmode =
+                    (buf->dict->mode == REG_STATE ? MODE_TOROKU : MODE_SYOUKYO);
+                return (KEY_SELECT_END|KEY_DICT_CHANGE|KEY_MODE_CHANGE);
+            } else
+                return (KEY_SELECT_END|KEY_DICT_CHANGE);
+        } else {
+            if (buf->dispmodechange) {
+                buf->dispmode = (buf->convedsegnum == buf->segnum ? MODE_KANJI :
+                    (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+                return (KEY_SELECT_END|KEY_MODE_CHANGE);
+            } else
+                return (KEY_SELECT_END);
+        }
+    default:
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cModeHAlpha() [halpha]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Change character mode
+ *   to "hankaku-ascii".
+ * <SelectMode> Ring bell.
+ *
+ * ModeConversion on: Convert character mode of current segment
+ *   to "hankaku-ascii".
+ * ModeConversion off: Change character mode of input mode.
+ */
+Xsj3cEvent
+_Xsj3cModeHAlpha(buf)
+    Xsj3cBuf    buf;
+{
+    Xsj3cFlag   conv;
+
+    if (!buf->segnum) {
+        if (buf->modeconv[MODE_HALPHA] >> 2) {
+#ifdef THROUGH_CONT
+            return (KEY_NULL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_NULL);
+            else 
+                return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+        } else
+            conv = OFF;
+    } else if (buf->input[buf->curseg] &&
+            buf->input[buf->curseg]->status & buf->modeconv[MODE_HALPHA]) {
+        conv = ON;
+    } else {
+        conv = OFF;
+    }
+    return (_Xsj3cModeChange(buf, MODE_HALPHA, conv));
+}
+
+/*
+ * _Xsj3cModeZAlpha()  [zalpha]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Change character mode
+ *   to "zenkaku-ascii".
+ * <SelectMode> Ring bell.
+ *
+ * ModeConversion on: Convert character mode of current segment
+ *   to "zenkaku-ascii".
+ * ModeConversion off: Change character mode of input mode.
+ */
+Xsj3cEvent
+_Xsj3cModeZAlpha(buf)
+    Xsj3cBuf    buf;
+{
+    Xsj3cFlag   conv;
+
+    if (!buf->segnum) {
+        if (buf->modeconv[MODE_ZALPHA] >> 2) {
+#ifdef THROUGH_CONT
+            return (KEY_NULL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_NULL);
+            else 
+                return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+        } else
+            conv = OFF;
+    } else if (buf->input[buf->curseg] &&
+            buf->input[buf->curseg]->status & buf->modeconv[MODE_ZALPHA]) {
+        conv = ON;
+    } else {
+        conv = OFF;
+    }
+    return (_Xsj3cModeChange(buf, MODE_ZALPHA, conv));
+}
+
+/*
+ * _Xsj3cModeHKata() [hkatakana]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Change character mode
+ *   to "hankaku-katakana".
+ * <SelectMode> Ring bell.
+ *
+ * ModeConversion on: Convert character mode of current segment
+ *   to "hankaku-katakana".
+ * ModeConversion off: Change character mode of input mode.
+ */
+Xsj3cEvent
+_Xsj3cModeHKata(buf) 
+    Xsj3cBuf    buf;
+{
+    Xsj3cFlag   conv;
+
+    if (!buf->segnum) {
+        if (buf->modeconv[MODE_HKATA] >> 2) {
+#ifdef THROUGH_CONT
+            return (KEY_NULL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_NULL);
+            else 
+                return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+        } else
+            conv = OFF;
+    } else if (buf->input[buf->curseg] &&
+            buf->input[buf->curseg]->status & buf->modeconv[MODE_HKATA]) {
+        conv = ON;
+    } else {
+        conv = OFF;
+    }
+    return (_Xsj3cModeChange(buf, MODE_HKATA, conv));
+}
+
+/*
+ * _Xsj3cModeZKata() [zkatakana]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Change character mode
+ *   to "zenkaku-katakana".
+ * <SelectMode> Ring bell.
+ *
+ * ModeConversion on: Convert character mode of current segment
+ *   to "zenkaku-katakana".
+ * ModeConversion off: Change character mode of input mode.
+ */
+Xsj3cEvent
+_Xsj3cModeZKata(buf)
+    Xsj3cBuf    buf;
+{
+    Xsj3cFlag   conv;
+
+    if (!buf->segnum) {
+        if (buf->modeconv[MODE_ZKATA] >> 2) {
+#ifdef THROUGH_CONT
+            return (KEY_NULL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_NULL);
+            else 
+                return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+        } else
+            conv = OFF;
+    } else if (buf->input[buf->curseg] &&
+            buf->input[buf->curseg]->status & buf->modeconv[MODE_ZKATA]) {
+        conv = ON;
+    } else {
+        conv = OFF;
+    }
+    return (_Xsj3cModeChange(buf, MODE_ZKATA, conv));
+}
+
+
+/*
+ * _Xsj3cModeHira() [hiragana]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Change character mode
+ *   to "hiragana".
+ * <SelectMode> Ring bell.
+ *
+ * ModeConversion on: Convert character mode of current segment to "hiragana".
+ * ModeConversion off: Change character mode of input mode.
+ */
+Xsj3cEvent
+_Xsj3cModeHira(buf)
+    Xsj3cBuf    buf;
+{
+    Xsj3cFlag   conv;
+
+    if (!buf->segnum) {
+        if (buf->modeconv[MODE_HIRA] >> 2) {
+#ifdef THROUGH_CONT
+            return (KEY_NULL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_NULL);
+            else 
+                return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+        } else
+            conv = OFF;
+    } else if (buf->input[buf->curseg] &&
+            buf->input[buf->curseg]->status & buf->modeconv[MODE_HIRA]) {
+        conv = ON;
+    } else {
+        conv = OFF;
+    }
+    return (_Xsj3cModeChange(buf, MODE_HIRA, conv));
+}
+
+/*
+ * _Xsj3cToHAlpha() [tohalpha]
+ *
+ * <NoInputTo/InputMode/ConvedMode/DictMode> Convert character mode
+ *   to "hankaku-ascii".
+ * <SelectTo> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cToHAlpha(buf)
+    Xsj3cBuf    buf;
+{
+    return (_Xsj3cModeChange(buf, MODE_HALPHA, ON));
+}
+
+/*
+ * _Xsj3cToZAlpha()  [tozalpha]
+ *
+ * <NoInputTo/InputMode/ConvedMode/DictMode> Convert character mode
+ *   to "zenkaku-ascii".
+ * <SelectTo> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cToZAlpha(buf)
+    Xsj3cBuf    buf;
+{
+    return (_Xsj3cModeChange(buf, MODE_ZALPHA, ON));
+}
+
+/*
+ * _Xsj3cToHKata() [tohkatakana]
+ *
+ * <NoInputTo/InputMode/ConvedMode/DictMode> Convert character mode
+ *   to "hankaku-katakana".
+ * <SelectTo> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cToHKata(buf) 
+    Xsj3cBuf    buf;
+{
+    return (_Xsj3cModeChange(buf, MODE_HKATA, ON));
+}
+
+/*
+ * _Xsj3cToZKata() [tozkatakana]
+ *
+ * <NoInputTo/InputMode/ConvedMode/DictMode> Convert character mode
+ *   to "zenkaku-katakana".
+ * <SelectTo> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cToZKata(buf)
+    Xsj3cBuf    buf;
+{
+    return (_Xsj3cModeChange(buf, MODE_ZKATA, ON));
+}
+
+
+/*
+ * _Xsj3cToHira() [tohiragana]
+ *
+ * <NoInputTo/InputMode/ConvedMode/DictMode> Convert character mode
+ *   to "hiragana".
+ * <SelectTo> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cToHira(buf)
+    Xsj3cBuf    buf;
+{
+    return (_Xsj3cModeChange(buf, MODE_HIRA, ON));
+}
+
+/*
+ * _Xsj3cToZenkaku() [zenkaku]
+ *
+ * <NoInputTo/InputMode/ConvedMode/DictMode> Convert current segment
+ *   character mode to zenkaku.
+ * <SelectTo> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cZenkaku(buf)
+    Xsj3cBuf    buf;
+{
+    return (_Xsj3cModeChange(buf, MODE_ZENKAKU, ON));
+}
+
+/*
+ * _Xsj3cToHankaku() [zenkaku]
+ *
+ * <NoInputTo/InputMode/ConvedMode/DictMode> Convert current segment
+ *   character mode to hankaku.
+ * <SelectTo> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cHankaku(buf)
+    Xsj3cBuf    buf;
+{
+    return (_Xsj3cModeChange(buf, MODE_HANKAKU, ON));
+}
+
+/*
+ * _Xsj3cToUpper() [toupper]
+ *
+ * <NoInputTo/InputMode/ConvedMode/DictMode> Convert current segment
+ *   character mode to upper case.
+ * <SelectTo> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cToUpper(buf)
+    Xsj3cBuf    buf;
+{
+    return (_Xsj3cModeChange(buf, MODE_UPPER, ON));
+}
+
+/*
+ * _Xsj3cToLower() [tolower]
+ *
+ * <NoInputTo/InputMode/ConvedMode/DictMode> Convert current segment
+ *   character mode to lower case.
+ * <SelectTo> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cToLower(buf)
+    Xsj3cBuf    buf;
+{
+    return (_Xsj3cModeChange(buf, MODE_LOWER, ON));
+}
+
+/*
+ * _Xsj3cModeSJIS() [sjis]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> If now input
+ *   code is not "Shift-JIS", change to Shift-JIS code input mode,
+ *   else change to initialized input mode.
+ * <SelectMode> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cModeSJIS(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & SelectModeMask) 
+        return (KEY_BELL);
+    if (buf->inputmode != MODE_SJIS) {
+        buf->dispmode = buf->inputmode = MODE_SJIS;
+        return (_Xsj3cModeClear(buf));
+    } else {
+        buf->dispmode = buf->inputmode = buf->inmoderot[0];
+        return (_Xsj3cModeClear(buf));
+    }
+}
+
+/*
+ * _Xsj3cModeEUC() [euc]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> If now input code is not "EUC",
+ *   change to EUC code input mode, else change to initialized input mode.
+ * <SelectMode> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cModeEUC(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & SelectModeMask) 
+        return (KEY_BELL);
+    if (buf->inputmode != MODE_EUC) {
+        buf->dispmode = buf->inputmode = MODE_EUC;
+        return (_Xsj3cModeClear(buf));
+    } else {
+        buf->dispmode = buf->inputmode = buf->inmoderot[0];
+        return (_Xsj3cModeClear(buf));
+    }
+}
+
+/*
+ * _Xsj3cModeJIS() [jis]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> If now input code is not "JIS",
+ *   change to JIS code input mode, else change to initialized input mode.
+ * <SelectMode> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cModeJIS(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & SelectModeMask) 
+        return (KEY_BELL);
+    if (buf->inputmode != MODE_JIS) {
+        buf->dispmode = buf->inputmode = MODE_JIS;
+        return (_Xsj3cModeClear(buf));
+    } else {
+        buf->dispmode = buf->inputmode = buf->inmoderot[0];
+        return (_Xsj3cModeClear(buf));
+    }
+}
+
+/*
+ * _Xsj3cModeKuten() [kuten]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> If now input code is not "kuten",
+ *   change to kuten code input mode, else change to initialized input mode.
+ * <SelectMode> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cModeKuten(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & SelectModeMask) 
+        return (KEY_BELL);
+    if (buf->inputmode != MODE_KUTEN) {
+        buf->dispmode = buf->inputmode = MODE_KUTEN;
+        return (_Xsj3cModeClear(buf));
+    } else {
+        buf->dispmode = buf->inputmode = buf->inmoderot[0];
+        return (_Xsj3cModeClear(buf));
+    }
+}
+
+/*
+ * _Xsj3cCodeRollDown() [code]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Rotate down input code.
+ * <SelectMode> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cCodeRollDown(buf)
+    Xsj3cBuf        buf;
+{
+    register int    i;
+
+    if (buf->convmode & ~SelectModeMask) {
+        i = 0;
+        while (i < buf->coderotnum) {
+            if (buf->inputmode == buf->defcode[i++]) {
+                buf->dispmode = buf->inputmode = buf->defcode[i];
+                break;
+            }
+        }
+        if (i >= buf->coderotnum) {
+            buf->dispmode = buf->inputmode = buf->defcode[0];
+        }
+        return (_Xsj3cModeClear(buf));
+    } else {
+        return (KEY_BELL);
+    }
+}
+
+/*
+ * _Xsj3cModeRollDown() [toggle/modedown]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode>
+ *   Rotate down character mode to next mode.
+ * <SelectMode> Ring bell.
+ *
+ * ModeConversion on: Convert character mode of current segment to next.
+ * ModeConversion off: Rotate character mode of input mode.
+ */
+Xsj3cEvent
+_Xsj3cModeRollDown(buf)
+    Xsj3cBuf        buf;
+{
+    register int    i;
+    Xsj3csMode      premode,    postmode;
+    Xsj3cFlag       conv;
+
+    if (!buf->segnum) {
+        if (buf->modeconv[MODE_ROLLDOWN] >> 2) {
+#ifdef THROUGH_CONT
+            return (KEY_NULL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_NULL);
+            else 
+                return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+        } else
+            conv = OFF;
+    } else if (buf->input[buf->curseg] &&
+            buf->input[buf->curseg]->status & buf->modeconv[MODE_ROLLDOWN]) {
+        conv = ON;
+    } else {
+        conv = OFF;
+    }
+    if (conv) {
+        return (_Xsj3cNextMode(buf));
+    } else {
+        premode = buf->inputmode;
+        i = 0;
+        while (i < buf->inmoderotnum) {
+            if (premode == buf->inmoderot[i++]) {
+                postmode = buf->inmoderot[i];
+                break;
+            }
+        }
+        if (i >= buf->inmoderotnum)
+            postmode = buf->inmoderot[0];
+        return(_Xsj3cModeChange(buf, postmode, OFF));
+    }
+}
+
+/*
+ * _Xsj3cModeRollUp() [toggleback/modeup]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode>
+ *   Rotate up character mode to previous mode.
+ * <SelectMode> Ring bell.
+ *
+ * ModeConversion on: Convert character mode of current segment to next.
+ * ModeConversion off: Rotate character mode of input mode.
+ */
+Xsj3cEvent
+_Xsj3cModeRollUp(buf)
+    Xsj3cBuf        buf;
+{
+    register int    i;
+    Xsj3csMode      premode,    postmode;
+    Xsj3cFlag       conv;
+
+    if (!buf->segnum) {
+        if (buf->modeconv[MODE_ROLLDOWN] >> 2) {
+#ifdef THROUGH_CONT
+            return (KEY_NULL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_NULL);
+            else 
+                return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+        } else
+            conv = OFF;
+    } else if (buf->input[buf->curseg] &&
+            buf->input[buf->curseg]->status & buf->modeconv[MODE_ROLLDOWN]) {
+        conv = ON;
+    } else {
+        conv = OFF;
+    }
+    if (conv) {
+        return (_Xsj3cPrevMode(buf));
+    } else {
+        premode = buf->inputmode;
+        i = buf->inmoderotnum - 1;
+        while (i < buf->inmoderotnum) {
+            if (premode == buf->inmoderot[i--]) {
+                postmode = buf->inmoderot[i];
+                break;
+            }
+        }
+        if (i < 0)
+            postmode = buf->inmoderot[buf->inmoderotnum - 1];
+        return(_Xsj3cModeChange(buf, postmode, OFF));
+    }
+}
+
+/*
+ * _Xsj3cNextMode() [nextmode]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode>
+ *   Change current segment character mode to next mode.
+ * <SelectMode> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cNextMode(buf)
+    Xsj3cBuf        buf;
+{
+    register int    i;
+    Xsj3csMode      premode,    postmode,   aftermode = MODE_HIRA;
+    Xsj3cEvent      ret;
+
+    if (buf->convmode & NoInputModeMask) {
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+    premode = buf->input[buf->curseg]->cursegmode;
+    i = 0;
+    while (i < buf->outmoderotnum) {
+        if (premode == buf->outmoderot[i++]) {
+            postmode = buf->outmoderot[i];
+            break;
+        }
+    }
+    if (i >= buf->outmoderotnum) {
+        aftermode = premode;
+        premode = _Xsj3cCheckMode(buf, buf->input[buf->curseg]);
+        i = 0;
+        while (i < buf->outmoderotnum) {
+            if (premode == buf->outmoderot[i++]) {
+                postmode = buf->outmoderot[i];
+                break;
+            }
+        }
+        if (i >= buf->outmoderotnum)
+            postmode = buf->outmoderot[0];
+    }
+    ret = _Xsj3cModeChange(buf, postmode, ON);
+    if ((aftermode == MODE_UPPER || aftermode == MODE_LOWER)
+        && (postmode == MODE_ZALPHA || postmode == MODE_HALPHA)) {
+        ret |= _Xsj3cModeChange(buf, aftermode, ON);
+    }
+    return (ret);
+}
+
+/*
+ * _Xsj3cPrevMode() [prevmode]
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode>
+ *   Change current segment character mode to previous mode.
+ * <SelectMode> Ring bell.
+ */
+Xsj3cEvent
+_Xsj3cPrevMode(buf)
+    Xsj3cBuf        buf;
+{
+    register int    i;
+    Xsj3csMode      premode,    postmode,   aftermode = MODE_HIRA;
+    Xsj3cEvent      ret;
+
+    if (buf->convmode & NoInputModeMask) {
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+    premode = buf->input[buf->curseg]->cursegmode;
+    i = buf->outmoderotnum - 1;
+    while (i >= 0) {
+        if (premode == buf->outmoderot[i--]) {
+            postmode = buf->outmoderot[i];
+            break;
+        }
+    }
+    if (i < 0) {
+        aftermode = premode;
+        premode = _Xsj3cCheckMode(buf, buf->input[buf->curseg]);
+        i = buf->outmoderotnum - 1;
+        while (i >= 0) {
+            if (premode == buf->outmoderot[i--]) {
+                postmode = buf->outmoderot[i];
+                break;
+            }
+        }
+        if (i < 0)
+            postmode = buf->outmoderot[buf->outmoderotnum - 1];
+    }
+    ret = _Xsj3cModeChange(buf, postmode, ON);
+    if ((aftermode == MODE_UPPER || aftermode == MODE_LOWER)
+        && (postmode == MODE_ZALPHA || postmode == MODE_HALPHA)) {
+        ret |= _Xsj3cModeChange(buf, aftermode, ON);
+    }
+    return(ret);
+}
+
+/*
+ * _Xsj3cModeToggle() [muhenkan]
+ *
+ * Emulating of sj2/sj3/sjx's muhenkan stroke.
+ * <NoInputMode/InputMode> Change input character mode to "MuhenkanMode".
+ * <ConvedMode/DictMode> Converts current segment character input mode first to
+ *   hiragana, second to zenkaku-katakana , third to "MuhenkanInEdit".
+ * <SelectMode> Does nothing.
+ *
+ * MuhenkanMode mode: Mode of toggling in InputMode after input chacter mode
+ *   is changed to hiragana.
+ * MuhenkanInEdit mode: Mode of toggling in ConvedMode after segment is
+ *   converted to hiragana and zenkaku-katakana.
+ * MuhenkanToggle off: Stop toggling in InputMode.
+ */
+Xsj3cEvent
+_Xsj3cModeToggle(buf)
+    Xsj3cBuf        buf;
+{
+    register int    i;
+    register wchar  (*conv)();
+    unsigned char  *mbs;
+    Xsj3cEvent      ret;
+    Xsj3cSeg        seg = buf->input[buf->curseg];
+
+    if (buf->convmode & ~(SelectModeMask|DictModeMask)) {
+        if (buf->convmode & ConvedModeMask ||((buf->convmode & InputModeMask)
+                && (seg->edit & SEG_NOEDIT))) {
+            if ((mbs = (unsigned char *)malloc(seg->size * 2 * sizeof(wchar)))
+                    == NULL)
+                Xsj3cError("Cannot allocate for mode conversion buffer");
+
+            switch (seg->cursegmode) {
+            case MODE_HIRA:
+                if (seg->num != seg->dnum) {
+                    ret = _Xsj3cModeChange(buf, MODE_HIRA, ON);
+                } else {
+                    if (conv =
+                        CodeConvFunc[serverIF[buf->server].lang][out_lang]) {
+                        register wchar  w1, w2;
+                        for (i = 0;i < seg->dnum; i++) {
+                            w1 = seg->yomi[i];
+                            if (iskan1(w1 >> 8, serverIF[buf->server].lang) &&
+                                iskan2(w1 & 0xff, serverIF[buf->server].lang))
+                                w2 = conv(w1);
+                            else 
+                                w2 = w1;
+                            if (w2 != seg->disp[i])
+                                break;
+                        }
+                    } else {
+                        for (i = 0;i < seg->dnum;i++) {
+                            if (seg->disp[i] != seg->yomi[i])
+                                break;
+                        }
+                    }
+                    if (i < seg->dnum)
+                        ret = _Xsj3cModeChange(buf, MODE_HIRA, ON);
+                    else {
+                        ret = _Xsj3cModeChange(buf, MODE_ZKATA, ON);
+                    }
+                }
+                break;
+            case MODE_ZKATA:
+                ret = _Xsj3cModeChange(buf, buf->togglemode, ON);
+                break;
+            default:
+                ret = _Xsj3cModeChange(buf, MODE_HIRA, ON);
+                break;
+            }
+            free(mbs);
+            return(ret);
+        } else {
+            if (buf->inputmode == MODE_HIRA)
+                return (_Xsj3cModeChange(buf, buf->muhenmode, OFF));
+            else if (buf->dotoggle)
+                return (_Xsj3cModeChange(buf, MODE_HIRA, OFF));
+            else {
+#ifdef THROUGH_CONT
+                return (KEY_NULL);
+#else /* THROUGH_CONT */
+                if (buf->cntrlsame)
+                    return (KEY_NULL);
+                else 
+                    return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+            }
+        }
+    } else {
+        return (KEY_BELL);
+    }
+}
+
+/*
+ * _Xsj3cForward() [right/forward]
+ *
+ * <InputMode/ConvedMode> Move to next segment or next character position.
+ * <DictMode> Move reversed segment to next segment if not expanded.
+ * <SelectMode> Move to right candidate(symbol/hinsi)
+ *   in the candidate(symbol/hinsi) panel.
+ * <NoInputMode> Does nothing.
+ *
+ * MovebySegment on: Move by segment.
+ * MovebySegment off: Move by character.
+ * BeginConversionLast none: Allow to move out of segments. 
+ * MoveSegmentLoop on: Loop back to the first segment.
+ */
+Xsj3cEvent
+_Xsj3cForward(buf)
+    Xsj3cBuf    buf;
+{
+    Xsj3cEvent  ret = KEY_TEXT_CHANGE;
+
+    switch (buf->convmode) {
+    case ConvedModeMask:
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, ON);
+    case InputModeMask:
+        buf->input[buf->curseg]->n_roma = 0;
+        buf->input[buf->curseg]->n_kana = -1;
+        *buf->input[buf->curseg]->oldstr = '\0';
+        *buf->input[buf->curseg]->str = '\0';
+        buf->input[buf->curseg]->sp = buf->input[buf->curseg]->str;
+        if (buf->input[buf->curseg]->status & buf->movebyseg
+            && (buf->input[buf->curseg]->edit & SEG_NOEDIT)) {
+            if (buf->beginlastseg == NONE) {
+                if (buf->curseg < buf->segnum)
+                    buf->curseg++;
+                else if (buf->moveloop)
+                    buf->curseg = 0;
+            } else {
+                if (buf->curseg < buf->segnum - 1)
+                    buf->curseg++;
+                else if (buf->moveloop)
+                    buf->curseg = 0;
+            }
+        } else {
+            if (buf->curseg < buf->segnum
+                    && buf->input[buf->curseg]->status == SEG_CONVED)
+                ret |= _Xsj3cUnConvSeg(buf, ONE, OFF);
+                _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+            if (buf->input[buf->curseg]->cur < buf->input[buf->curseg]->num) {
+                buf->input[buf->curseg]->cur++;
+            } else {
+                if (buf->beginlastseg == NONE) {
+                    if (buf->curseg < buf->segnum) {
+                        buf->curseg++;
+                        if (buf->curseg < buf->segnum)
+                            buf->input[buf->curseg]->cur = 0;
+                    } else if (buf->moveloop) {
+                        buf->curseg = 0;
+                        buf->input[buf->curseg]->cur = 0;
+                    }
+                } else {
+                    if (buf->curseg < buf->segnum - 1) {
+                        buf->curseg++;
+                        buf->input[buf->curseg]->cur = 0;
+                    } else if (buf->moveloop) {
+                        buf->curseg = 0;
+                        buf->input[buf->curseg]->cur = 0;
+                    }
+                }
+            }
+        }
+        return ret;
+    case DictModeMask:
+        if (buf->dict->n_dict) {
+            return (KEY_BELL);
+        } else {
+            if (buf->curseg < buf->segnum - 1 )
+                buf->curseg++;
+            else 
+                buf->curseg = buf->segnum - 1;
+            return (ret);
+        }
+    case SelectModeMask:
+        return (KEY_SELECT_RIGHT);
+    case NoInputModeMask:
+    default:
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cBackward() [left/backward]
+ *
+ * <InputMode/ConvedMode> Move to previous segment or
+ *   previous character position.
+ * <DictMode> Move reversed segment to previous segment if not expanded.
+ * <SelectMode> Move to left candidate(symbol/hinsi)
+ *   in the candidate(symbol/hinsi) panel.
+ * <NoInputMode> Does nothing.
+ *
+ * MovebySegment on: Move by segment.
+ * MovebySegment off: Move by character.
+ * MoveSegmentLoop on: Loop back to the last segment.
+ */
+Xsj3cEvent
+_Xsj3cBackward(buf)
+    Xsj3cBuf    buf;
+{
+    Xsj3cEvent  ret = KEY_TEXT_CHANGE;
+
+    switch (buf->convmode) {
+    case ConvedModeMask:
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, ON);
+    case InputModeMask:
+        if (buf->curseg < buf->segnum) {
+            buf->input[buf->curseg]->n_roma = 0;
+            buf->input[buf->curseg]->n_kana = -1;
+            *buf->input[buf->curseg]->oldstr = '\0';
+            *buf->input[buf->curseg]->str = '\0';
+            buf->input[buf->curseg]->sp = buf->input[buf->curseg]->str;
+            if (buf->input[buf->curseg]->status & buf->movebyseg
+                    && (buf->input[buf->curseg]->edit & SEG_NOEDIT)) {
+                if (buf->curseg > 0)
+                    buf->curseg--;
+                else if (buf->moveloop) {
+                    if (buf->beginlastseg == NONE)
+                        buf->curseg = buf->segnum;
+                    else 
+                        buf->curseg = buf->segnum - 1;
+                }
+            } else {
+                if (buf->curseg < buf->segnum
+                        && buf->input[buf->curseg]->status == SEG_CONVED)
+                    ret |= _Xsj3cUnConvSeg(buf, ONE, ON);
+                    _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+                if (buf->input[buf->curseg]->cur > 0) {
+                    buf->input[buf->curseg]->cur--;
+                } else {
+                    if (buf->curseg > 0) {
+                        buf->curseg--;
+                        buf->input[buf->curseg]->cur
+                                = buf->input[buf->curseg]->num;
+                    } else if (buf->moveloop) {
+                        if (buf->beginlastseg == NONE)
+                            buf->curseg = buf->segnum;
+                        else {
+                            buf->curseg = buf->segnum - 1;
+                            buf->input[buf->curseg]->cur
+                                    = buf->input[buf->curseg]->num;
+                        }
+                    }
+                }
+            }
+            return (ret);
+        } else if (buf->curseg > 0) {
+            buf->curseg--;
+            return (ret);
+        } else {
+            return (KEY_NULL);
+        }
+    case DictModeMask:
+        if (buf->dict->n_dict) {
+            return (KEY_BELL);
+        } else {
+            if (buf->curseg > 0)
+                buf->curseg--;
+            else 
+                buf->curseg = 0;
+            return (ret);
+        }
+    case SelectModeMask:
+        return (KEY_SELECT_LEFT);
+    case NoInputModeMask:
+    default:
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cTop() [top]
+ *
+ * <InputMode/ConvedMode> Move to the first segment or top of current segment.
+ * <DictMode> Move reversed segment to the first segment if not expanded.
+ * <SelectMode> Move to first candidate(symbol/hinsi)
+ *   in popuped candidate(symbol/hinsi) panel.
+ * <NoInputMode> Does nothing.
+ *
+ * JumpbySegment on: Move by segment.
+ * JumpbySegment off: Move by character.
+ */
+Xsj3cEvent
+_Xsj3cTop(buf)
+    Xsj3cBuf    buf;
+{
+    switch (buf->convmode) {
+    case ConvedModeMask:
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, ON);
+    case InputModeMask:
+        if (buf->curseg < buf->segnum) {
+            buf->input[buf->curseg]->n_roma = 0;
+            buf->input[buf->curseg]->n_kana = -1;
+            *buf->input[buf->curseg]->oldstr = '\0';
+            *buf->input[buf->curseg]->str = '\0';
+            buf->input[buf->curseg]->sp = buf->input[buf->curseg]->str;
+            if (buf->input[buf->curseg]->status & buf->jumpbyseg
+                    && (buf->input[buf->curseg]->edit & SEG_NOEDIT)) {
+                buf->curseg = 0;
+            } else if (buf->curseg < buf->segnum) {
+                buf->input[buf->curseg]->cur = 0;
+            }
+            return KEY_TEXT_CHANGE;
+        } else if (buf->segnum > 0) {
+            buf->curseg = 0;
+            return KEY_TEXT_CHANGE;
+        } else {
+            return KEY_NULL;
+        }
+    case DictModeMask:
+        if (buf->dict->n_dict) {
+            return (KEY_BELL);
+        } else {
+            buf->curseg = 0;
+            return (KEY_TEXT_CHANGE);
+        }
+    case SelectModeMask:
+        return (KEY_SELECT_LEFTMOST);
+    case NoInputModeMask:
+    default:
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cEnd() [end]
+ *
+ * <InputMode/ConvedMode> Move to the last segment or top of current segment.
+ * <DictMode> Move reversed segment to the last segment if not expanded.
+ * <SelectMode> Move to last candidate(symbol/hinsi)
+ *   in popuped candidate(symbol/hinsi) panel.
+ * <NoInputMode> Does nothing.
+ *
+ * JumpbySegment on: Move by segment.
+ * JumpbySegment off: Move by character.
+ * BeginConversionLast none: Allow to move out of segments. 
+ */
+Xsj3cEvent
+_Xsj3cEnd(buf)
+    Xsj3cBuf    buf;
+{
+    switch (buf->convmode) {
+    case ConvedModeMask:
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, ON);
+    case InputModeMask:
+        if (buf->curseg >= buf->segnum)
+            return KEY_NULL;
+        buf->input[buf->curseg]->n_roma = 0;
+        buf->input[buf->curseg]->n_kana = -1;
+        *buf->input[buf->curseg]->oldstr = '\0';
+        *buf->input[buf->curseg]->str = '\0';
+        buf->input[buf->curseg]->sp = buf->input[buf->curseg]->str;
+        if (buf->input[buf->curseg]->status & buf->jumpbyseg
+                    && (buf->input[buf->curseg]->edit & SEG_NOEDIT)) {
+            if (buf->beginlastseg == NONE)
+                buf->curseg = buf->segnum;
+            else 
+                buf->curseg = buf->segnum - 1;
+        } else {
+            buf->input[buf->curseg]->cur = buf->input[buf->curseg]->num;
+        }
+        return KEY_TEXT_CHANGE;
+    case DictModeMask:
+        if (buf->dict->n_dict) {
+            return (KEY_BELL);
+        } else {
+            buf->curseg = buf->segnum - 1;
+            return (KEY_TEXT_CHANGE);
+        }
+    case SelectModeMask:
+        return (KEY_SELECT_RIGHTMOST);
+    case NoInputModeMask:
+    default:
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cUp() [up]
+ *
+ * <SelectMode> Move to above candidate(symbol/hinsi)
+ *   in the candidate(symbol/hinsi) panel.
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Rings bell.
+ */
+Xsj3cEvent
+_Xsj3cUp(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & SelectModeMask)
+        return (KEY_SELECT_UP);
+    else
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+}
+
+/*
+ * _Xsj3cDown() [down]
+ *
+ * <SelectMode> Move to below candidate(symbol/hinsi)
+ *   in the candidate(symbol/hinsi) panel.
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Rings bell.
+ */
+Xsj3cEvent
+_Xsj3cDown(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & SelectModeMask)
+        return (KEY_SELECT_DOWN);
+    else
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+}
+
+/*
+ * _Xsj3cFirst() [first]
+ *
+ * <ConvedMode> Set top candidate the current segment.
+ * <SelectMode> Move to first candidate(symbol/hinsi)
+ *   in all candidate(symbol/hinsi) pages.
+ * <NoInputMode/InputMode/DictMode> Rings bell.
+ */
+Xsj3cEvent
+_Xsj3cFirst(buf)
+    Xsj3cBuf    buf;
+{
+    int         changed,    flush;
+
+    if (buf->convmode & ConvedModeMask) {
+        if (!buf->candidate)
+            if ((buf->candidate = _Xsj3cCandidateInit(buf)) == NULL)
+                return (KEY_NULL);
+        Xsj3cSetCandidate(buf, 0, &changed, &flush);
+        return KEY_TEXT_CHANGE;
+    } else if (buf->convmode & SelectModeMask) {
+        return (KEY_SELECT_FIRST);
+    } else {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cLast() [last]
+ *
+ * <ConvedMode> Set bottom candidate the current segment.
+ * <SelectMode> Move to last candidate(symbol/hinsi)
+ *   in all candidate(symbol/hinsi) pages.
+ * <NoInputMode/InputMode/DictMode> Rings bell.
+ */
+Xsj3cEvent
+_Xsj3cLast(buf)
+    Xsj3cBuf    buf;
+{
+    int         changed,    flush;
+
+    if (buf->convmode & ConvedModeMask) {
+        if (!buf->candidate)
+            if ((buf->candidate = _Xsj3cCandidateInit(buf)) == NULL)
+                return (KEY_NULL);
+        Xsj3cSetCandidate(buf, buf->candnum - 1, &changed, &flush);
+        return (KEY_TEXT_CHANGE);
+    } else if (buf->convmode & SelectModeMask) {
+        return (KEY_SELECT_LAST);
+    } else {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cNextPage() [nextp]
+ * <SelectMode> Change contents of the candidate(symbol/hinsi) panel
+ *   to the next page.
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Rings bell.
+ */
+Xsj3cEvent
+_Xsj3cNextPage(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & SelectModeMask)
+        return (KEY_SELECT_NEXTP);
+    else
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+}
+
+/*
+ * _Xsj3cPrevPage() [prevp]
+ * <SelectMode> Change contents of the candidate(symbol/hinsi) panel
+ *   to the previous page.
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Rings bell.
+ */
+Xsj3cEvent
+_Xsj3cPrevPage(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & SelectModeMask)
+        return (KEY_SELECT_PREVP);
+    else
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+}
+
+/*
+ * _Xsj3cNext() [next]
+ *
+ * <ConvedMode> Set next candidate the current segment.
+ * <SelectMode> Move to right(next) candidate(symbol/hinsi)
+ *   in the candidate(symbol/hinsi) panel.
+ * <NoInputMode/InputMode/DictMode> Rings bell.
+ */
+Xsj3cEvent
+_Xsj3cNext(buf)
+    Xsj3cBuf    buf;
+{
+    int         changed,    flush;
+
+    if (buf->convmode & ConvedModeMask) {
+        if (!buf->candidate)
+            if ((buf->candidate = _Xsj3cCandidateInit(buf)) == NULL)
+                return (KEY_NULL);
+        if (buf->curcand == buf->candnum - 1)
+            Xsj3cSetCandidate(buf, 0, &changed, &flush);
+        else 
+            Xsj3cSetCandidate(buf, buf->curcand + 1, &changed, &flush);
+        return KEY_TEXT_CHANGE;
+    } else if (buf->convmode & SelectModeMask) {
+        return (KEY_SELECT_RIGHT);
+    } else {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cPrev() [prev]
+ *
+ * <ConvedMode> Set previous candidate the current segment.
+ * <SelectMode> Move to left(previous) candidate(symbol/hinsi)
+ *   in the candidate(symbol/hinsi) panel.
+ * <NoInputMode/InputMode/DictMode> Rings bell.
+ */
+Xsj3cEvent
+_Xsj3cPrev(buf)
+    Xsj3cBuf    buf;
+{
+    int         changed,    flush;
+
+    if (buf->convmode & ConvedModeMask) {
+        if (!buf->candidate)
+            if ((buf->candidate = _Xsj3cCandidateInit(buf)) == NULL)
+                return (KEY_NULL);
+        if (!buf->curcand)
+            Xsj3cSetCandidate(buf, buf->candnum - 1, &changed, &flush);
+        else 
+            Xsj3cSetCandidate(buf, buf->curcand - 1, &changed, &flush);
+        return KEY_TEXT_CHANGE;
+    } else if (buf->convmode & SelectModeMask) {
+        return (KEY_SELECT_LEFT);
+    } else {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cSelect() [select]
+ *
+ * <SelectMode> Select reversed candidate(symbol/hinsi)
+ *   in the candidate(symbol/hinsi) panel and pop down the panel.
+ * <NoInputMode/InputMode/ConvedMode/DictMode> Rings bell.
+ *  Select now selected candidate(symbol) in the candidate(symbol) panel.
+ */
+Xsj3cEvent
+_Xsj3cSelect(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & SelectModeMask) {
+        if (buf->selectstatus == SELECT_HINSI) {
+            buf->dict->status = DICT_CONFIRM;
+            if (buf->dispmodechange) {
+                buf->dispmode =
+                    (buf->dict->mode == REG_STATE ? MODE_TOROKU : MODE_SYOUKYO);
+                return (KEY_SELECT_END|KEY_DICT_CHANGE|KEY_MODE_CHANGE);
+            } else
+                return (KEY_SELECT_END|KEY_DICT_CHANGE);
+        } else {
+            if (buf->dispmodechange) {
+                buf->dispmode = (buf->convedsegnum == buf->segnum ? MODE_KANJI :
+                    (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+                return (KEY_SELECT_END|KEY_MODE_CHANGE);
+            } else
+                return (KEY_SELECT_END);
+        }
+    } else if (buf->convmode & DictModeMask) {
+        if (buf->dict->status == DICT_CONFIRM) {
+            buf->dict->status = DICT_END;
+            _Xsj3cFlushDictMsg(buf);
+            if (buf->dict->mode == REG_STATE)
+                return(KEY_DICT_REGISTER);
+            else
+                return(KEY_DICT_CLEAR);
+        } else {
+            return (KEY_BELL);
+        }
+    } else {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cCancel() [cancel]
+ *
+ * <InputMode/ConvedMode> Clear all segments.
+ * <SelectMode> Pop down candidate(symbol/hinsi) panel.
+ * <DictMode> (DICT_INPUT) Pop down Auxpanel.
+ *            (DICT_CONFIRM/DICT_END) Return back to DICT_INPUT status.
+ * <NoInputMode> Does nothing.
+ *
+ * DisplayModeChange on: Change the display mode string.  
+ */
+Xsj3cEvent
+_Xsj3cCancel(buf)
+    Xsj3cBuf    buf;
+{
+    int         i;
+
+    switch (buf->convmode) {
+    case ConvedModeMask:
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, OFF);
+    case InputModeMask:
+        if (buf->gakusyuu)
+            _Xsj3cClearDcid(buf);
+        buf->convedsegnum = 0;
+        for (i = 1; i < buf->segnum + 1; i++) {
+            Xsj3cFreeSegment(buf->input[i]);
+            buf->input[i] = NULL;
+        }
+        if (buf->input[0])
+            Xsj3cClearSegment(buf, buf->input[0]);
+        buf->convedsegnum = 0;
+        buf->segnum = 0;
+        buf->curseg = 0;
+        if (buf->dispmodechange) {
+            buf->dispmode = buf->inputmode;
+            return (KEY_TEXT_CHANGE|KEY_MODE_CHANGE);
+        } else
+            return (KEY_TEXT_CHANGE);
+    case SelectModeMask:
+        if (buf->selectstatus == SELECT_HINSI) {
+            buf->dict->status = DICT_INPUT;
+            _Xsj3cFlushDictMsg(buf);
+            if (buf->dispmodechange) {
+                buf->dispmode = (buf->dict->mode == REG_STATE ?
+                    MODE_TOROKU : MODE_SYOUKYO);
+                return (KEY_SELECT_ABORT|KEY_MODE_CHANGE);
+            } else
+                return (KEY_SELECT_ABORT);
+        } else {
+            if (buf->dispmodechange) {
+                buf->dispmode = (buf->convedsegnum == buf->segnum ? MODE_KANJI :
+                    (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+                return (KEY_SELECT_ABORT|KEY_MODE_CHANGE);
+            } else
+                return (KEY_SELECT_ABORT);
+        }
+    case DictModeMask:
+        if (buf->dict->status == DICT_CONFIRM
+                || buf->dict->status == DICT_END) {
+            buf->dict->status = DICT_INPUT;
+            _Xsj3cFlushDictMsg(buf);
+            return(KEY_DICT_CHANGE);
+        } else {
+            if (buf->dispmodechange) {
+                buf->dispmode = (buf->convedsegnum == buf->segnum ? MODE_KANJI:
+                    (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+                return (KEY_DICT_END|KEY_TEXT_CHANGE|KEY_MODE_CHANGE);
+            } else {
+                return (KEY_DICT_END|KEY_TEXT_CHANGE);
+            }
+        }
+    case NoInputModeMask:
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    default:
+        return (KEY_TEXT_CHANGE);
+    }
+}
+
+/*
+ * _Xsj3cExpand() [kakucyou/expand]
+ *
+ * <InputMode/ConvedMode> Expand the current segment by getting in
+ *   the first character of the next segment.
+ * <DictMode> Increase the reversed segments by adding the next segment.
+ * <NoInputMode/SelectMode> Rings bell.  
+ *   
+ * ExpandModeConversion on: Change the expanded segment's character mode.
+ * ExpandKanjiConversion on: Do kana-kanji conversion for current
+ *   and next segment.
+ */
+Xsj3cEvent
+_Xsj3cExpand(buf)
+    Xsj3cBuf                buf;
+{
+    int                     nextseg = buf->curseg + 1,  value = 0;
+    Xsj3cFlag               conv = 0,   modematch = 0;
+    register int            i;
+    unsigned char           tmp[YBUFSIZ];
+    unsigned char          *kanabuf;
+    unsigned char           knjbuf[KANJIBUFSIZ];
+    SJ3_BUNSETU             bun[BUNBUFSIZ];
+
+    if (buf->convmode & DictModeMask) {
+        return (_Xsj3cExpandNoConv(buf));
+    } else if ((buf->convmode & SelectModeMask) || nextseg >= buf->segnum
+            || !buf->input[nextseg]->num) {
+        /* $B8=J8@a$,:G8e$NJ8@a$N;~$O3HD%$G$-$J$$!#(B */
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    } else if (buf->convmode & ConvedModeMask) {
+        buf->n_select = 0;
+        if (buf->candidate)
+            Xsj3cEndCandidate(buf, OFF);
+    } else if (buf->convmode & ~InputModeMask) {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+
+    /* temporary $B$N%P%C%U%!$r:n@.$9$k(B   */
+    if ((kanabuf = (unsigned char *)
+            malloc(buf->input[buf->curseg]->size * sizeof(wchar))) == NULL)
+        Xsj3cError("Cannot allocate for temporary buffer");
+
+    /* $B<!J8@a$NF,$N#1J8;z$r8:$8!"0l;~%P%C%U%!$K%3%T!<$9$k(B   */
+    buf->input[nextseg]->cur = 1;
+    _Xsj3cExtractChar(buf, buf->input[nextseg], tmp, 1);
+    if (buf->input[nextseg]->status & SEG_CONVED)
+        buf->convedsegnum--;
+
+    if (buf->input[nextseg]->cursegmode == buf->input[buf->curseg]->cursegmode)
+        modematch++;
+    if (!buf->input[nextseg]->num) {
+
+        /* $B<!J8@a$,#1J8;z$7$+$J$+$C$?>l9g!"J8@a?t$r#1$D8:$8(B */
+        /*  $B99$K!"<!J8@a$NNN0h$r2rJ|$9$k!#(B                  */
+        Xsj3cFreeSegment(buf->input[buf->segnum]);
+        buf->input[buf->segnum] = NULL;
+        buf->segnum--;
+        Xsj3cFreeSegment(buf->input[nextseg]);
+        buf->input[nextseg] = NULL;
+        if (nextseg < buf->segnum) {
+            for ( i = nextseg; i < buf->segnum; i++) {
+                buf->input[i] = buf->input[i + 1];
+            }
+        } 
+        buf->input[buf->segnum] = NULL;
+    } else {
+
+        /* $B<!J8@a$,#2J8;z0J>e$"$C$?>l9g(B ExpandKanjiConversion   */
+        /* on $B$N;~$O:FEY$+$J4A;zJQ49JQ49$9$k(B                    */
+        if (buf->expandkconv & buf->input[nextseg]->status) {
+            if (buf->input[nextseg]->num < INPUT_YOMI_MAX) {
+                _Xsj3cwPStomPS(buf, kanabuf, buf->input[nextseg]->yomi);
+                value = serverIF[buf->server].func[FUNC_CONV]
+                        (kanabuf, bun, knjbuf, KANJIBUFSIZ);
+            } else {
+                Xsj3cWarning("Too long segment[num = %d]",nextseg);
+            }
+            if (value > 0) {
+                _Xsj3cStoreKanji(buf, bun, nextseg, value, ON);
+                buf->segnum += (value - 1);
+                buf->convedsegnum += value;
+            } else {
+                if (value < 0) 
+                    Xsj3cWarning("sj3serv is down. reconnect please");
+                _Xsj3cStoreYomi(buf, buf->input[nextseg], 0);
+                buf->input[nextseg]->status = SEG_NOCONV;
+                if (!(buf->movebyseg & SEG_NOCONV))
+                    buf->input[nextseg]->edit = SEG_EDIT;
+            }
+        } else {
+            _Xsj3cStoreYomi(buf, buf->input[nextseg], 0);
+            buf->input[nextseg]->status = SEG_NOCONV;
+            if (!(buf->movebyseg & SEG_NOCONV))
+                buf->input[nextseg]->edit = SEG_EDIT;
+        }
+        if (buf->gakusyuu)
+            buf->input[nextseg]->change = ON;
+    }
+
+    /* $B%+%l%s%HJ8@a$N:G8e$K<!J8@a$N#1J8;z$rB-$9(B */
+    buf->input[buf->curseg]->cur = buf->input[buf->curseg]->num;
+    _Xsj3cInsertChar(buf, buf->input[buf->curseg], tmp, 1);
+
+    if (buf->input[buf->curseg]->status & SEG_CONVED)
+        buf->convedsegnum--;
+
+    /* ExpandModeConversion on $B$N;~$O9g$o$;$?ItJ,$N(B */
+    /* $BJ8;z<o$r8=J8@a$NI=<(J8;z<o$KJQ49$9$k(B         */
+    if ((buf->expandmconv & buf->input[buf->curseg]->status) && !modematch) {
+        Xsj3cSeg        seg = buf->input[buf->curseg];
+
+        conv++;
+        _Xsj3cwPStomPS(buf, kanabuf, seg->yomi);
+        Xsj3cModeConv(buf, kanabuf, seg->cursegmode, seg->size);
+        seg->num = _Xsj3cmPStowPSn(buf, seg->yomi, kanabuf, seg->size);
+        if (seg->num > seg->size - YBUFSIZ) {
+            Xsj3cResizeSegment(seg, seg->size * 2);
+            seg->num = _Xsj3cmPStowPS(buf, seg->yomi, kanabuf);
+        }
+        seg->cur = seg->num;
+    }
+
+    /* ExpandKanjiConversion on $B$N;~$O%+%l%s%H(B  */
+    /* $BJ8@a$r:FEY$+$J4A;zJQ49JQ49$9$k(B           */
+    if (buf->expandkconv & buf->input[buf->curseg]->status) {
+        value = 0;
+        if (!conv)
+            _Xsj3cwPStomPS(buf, kanabuf, buf->input[buf->curseg]->yomi);
+        if (buf->input[buf->curseg]->num < INPUT_YOMI_MAX) {
+            value = serverIF[buf->server].func[FUNC_CONV]
+                    (kanabuf, bun, knjbuf, KANJIBUFSIZ);
+        } else {
+            Xsj3cWarning("Too long segment[num = %d]",buf->curseg);
+        }
+        if (value > 0) {
+            buf->convedsegnum++;
+            buf->input[buf->curseg]->status = SEG_CONVED;
+            buf->input[buf->curseg]->edit = SEG_NOEDIT;
+            buf->input[buf->curseg]->dnum
+                = _Xsj3cmPStowOUT(buf, buf->input[buf->curseg]->disp, knjbuf);
+            if (buf->gakusyuu)
+                buf->input[buf->curseg]->dcid = bun[0].dcid;
+            if (value > 1) {
+                int         changed,    flush;
+                if ((buf->candidate = _Xsj3cCandidateInit(buf)) == NULL) {
+                    Xsj3cWarning("sj3serv maybe down, or any trouble");
+                } else {
+                    Xsj3cSetCandidate(buf, 0, &changed, &flush);
+                }
+            }
+        } else  {
+            if (value < 0) 
+                Xsj3cWarning("sj3serv is down. reconnect please");
+            _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+            buf->input[buf->curseg]->status = SEG_NOCONV;
+            if (!(buf->movebyseg & SEG_NOCONV))
+                buf->input[buf->curseg]->edit = SEG_EDIT;
+        }
+    } else {
+        value = 1;
+        _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+        buf->input[buf->curseg]->status = SEG_NOCONV;
+        if (!(buf->movebyseg & SEG_NOCONV))
+            buf->input[buf->curseg]->edit = SEG_EDIT;
+    }
+
+    /* temporary $B$N%P%C%U%!$r3+J|$9$k(B   */
+    free(kanabuf);
+
+    /* $BJ8@aD93X=,$N$?$a$N%U%i%0$rN)$F$k(B */
+    if (buf->gakusyuu)
+        buf->input[buf->curseg]->change = ON;
+
+    if (value > 0)
+        return KEY_TEXT_CHANGE;
+    else 
+        return (KEY_TEXT_CHANGE|KEY_BELL);
+}
+
+/*
+ * _Xsj3cExpandNoConv()
+ *  Expand current segment by adding next segment.
+ */
+static Xsj3cEvent
+_Xsj3cExpandNoConv(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->curseg + buf->dict->n_dict < buf->segnum - 1) {
+        buf->dict->n_dict++;
+        return KEY_TEXT_CHANGE;
+    } else {
+        return KEY_BELL;
+    }
+}
+
+/*
+ * _Xsj3cShrink()
+ *
+ * <InputMode/ConvedMode> Shrink the current segment by pushing 
+ *   the last character to the next segment.
+ * <DictMode> Decrease reversed segments by getting off the last segment.
+ * <NoInputMode/SelectMode> Rings bell.  
+ *   
+ * ShrinkModeConversion on: Change the next segment's character mode.
+ * ShrinkKanjiConversion on: Do kana-kanji conversion for
+ *   current and next segments.
+ * ShrinkAll on: When there is only one character in current segment,
+ *   combine with the previous segment
+ *   unless current segment is the first segment.
+ * ShrinkAll off: When there is only one character in current segment,
+ *    ring bell.
+ */
+Xsj3cEvent
+_Xsj3cShrink(buf)
+    Xsj3cBuf                buf;
+{
+    int                     nextseg = buf->curseg + 1;
+    int                     prevseg = buf->curseg - 1, value = 0;
+    Xsj3cFlag               conv1 = 0,  conv2 = 0;
+    register int            i,  size;
+    unsigned char           tmp[YBUFSIZ];
+    unsigned char          *kanabuf1,  *kanabuf2;
+    unsigned char           knjbuf[KANJIBUFSIZ];
+    SJ3_BUNSETU             bun[BUNBUFSIZ];
+    Xsj3cFlag               erase_seg_flg = 0;
+
+    if (buf->convmode & DictModeMask)
+        return (_Xsj3cShrinkNoConv(buf));
+    else if ((buf->convmode & (SelectModeMask|NoInputModeMask))
+            || nextseg > buf->segnum)
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    else if (buf->input[buf->curseg]->num > 1 || (buf->shrinkall
+            && buf->input[buf->curseg]->num > 0 && buf->curseg)) {
+        /* $B%+%l%s%HJ8@a$,#2J8;z0J>e$"$k>l9g!"$^$?$O#1J8;z(B   */
+        /* $B$"$k>l9g$G(B .ShrinkAll on $B$G8=J8@a$,:G=i$NJ8@a$G(B  */
+        /* $B$J$$>l9g!"%+%l%s%HJ8@a$N:G8e$N#1J8;z$r<h$j=P$9(B   */
+
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, OFF);
+        buf->input[buf->curseg]->cur = buf->input[buf->curseg]->num;
+        _Xsj3cExtractChar(buf, buf->input[buf->curseg], tmp, 1);
+
+        /* .ShrinkAll on $B$G8=J8@a$,#1J8;z$7$+$J$+$C$?>l9g(B   */
+        /* $BA0J8@a$H9g@a$9$k$3$H$r;X<($9$k%U%i%0$r(B ON $B$K$9$k(B */
+        if (!buf->input[buf->curseg]->num)
+            erase_seg_flg++;
+    } else {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+
+    /* temporary $B$N%P%C%U%!$r:n@.$9$k(B   */
+    if (buf->input[nextseg])
+        size = buf->input[nextseg]->size;
+    else 
+        size = KANABUFSIZ;
+    if ((kanabuf2 = (unsigned char *)malloc(size * sizeof(wchar))) == NULL)
+        Xsj3cError("Cannot allocate for temporary buffer");
+
+    if (buf->curseg)
+        size = buf->input[prevseg]->size;
+    else 
+        size = KANABUFSIZ;
+    if ((kanabuf1 = (unsigned char *)malloc(size * sizeof(wchar))) == NULL)
+        Xsj3cError("Cannot allocate for temporary buffer");
+
+
+    if (buf->input[buf->curseg]->status & SEG_CONVED)
+        buf->convedsegnum--;
+    if (buf->shrinkall && buf->curseg && erase_seg_flg) {
+        /* .ShrinkAll on $B$GA0J8@a$H9g@a$9$k$3$H$r;X<($9$k(B   */
+        /* $B%U%i%0$,(B ON $B$N;~!"%+%l%s%HJ8@a$+$i<h$j=P$7$?(B     */
+        /* $B#1J8;z$rA0J8@a$N:G8e$KA^F~$9$k(B                   */
+        
+        buf->input[prevseg]->cur = buf->input[prevseg]->num;
+        _Xsj3cInsertChar(buf, buf->input[prevseg], tmp, 1);
+
+        /* ShrinkModeConversion on $B$N;~$O9g$o$;$?ItJ,$N(B */
+        /* $BJ8;z<o$rA0J8@a$NI=<(J8;z<o$KJQ49$9$k(B         */
+        if ((buf->shrinkmconv & buf->input[prevseg]->status)
+                && buf->input[prevseg]->cursegmode
+                != buf->input[buf->curseg]->cursegmode) {
+            Xsj3cSeg        seg = buf->input[prevseg];
+
+            conv1++;
+            _Xsj3cwPStomPS(buf, kanabuf1, seg->yomi);
+            Xsj3cModeConv(buf, kanabuf1, seg->cursegmode, seg->size);
+            seg->num = _Xsj3cmPStowPSn(buf, seg->yomi, kanabuf1, seg->size);
+            if (seg->num > buf->input[buf->curseg - 1]->size - YBUFSIZ) {
+                Xsj3cResizeSegment(seg, seg->size * 2);
+                seg->num = _Xsj3cmPStowPS(buf, seg->yomi, kanabuf1);
+            }
+            seg->cur = seg->num;
+        }
+
+        /* $BJ8@a?t$r8:$8%+%l%s%HJ8@a$NNN0h$r3+J|$9$k(B         */
+        Xsj3cFreeSegment(buf->input[buf->segnum]);
+        buf->input[buf->segnum] = NULL;
+        buf->segnum--;
+        Xsj3cFreeSegment(buf->input[buf->curseg]);
+        buf->input[buf->curseg] = NULL;
+        if (nextseg <= buf->segnum) {
+            for ( i = buf->curseg; i < buf->segnum; i++) {
+                buf->input[i] = buf->input[i + 1];
+            }
+        }
+        buf->input[buf->segnum] = NULL;
+        buf->curseg--;
+    } else {
+        /* $B%+%l%s%HJ8@a$,#2J8;z0J>e$@$C$?>l9g(B   */
+
+        if (nextseg < buf->segnum) {
+            /* $B%+%l%s%HJ8@a$,:G8e$NJ8@a$G$J$$;~!"(B       */
+            /* $B<h$j=P$7$?#1J8;z$r<!J8@a$N@hF,$KA^F~$9$k(B */
+
+            buf->input[nextseg]->cur = 0;
+            _Xsj3cInsertChar(buf, buf->input[nextseg], tmp, 1);
+            if (buf->input[nextseg]->status & SEG_CONVED)
+                buf->convedsegnum--;
+
+            /* ShrinkModeConversion on $B$N;~$OJ,N%$7$?(B       */
+            /* $BItJ,$NJ8;z<o$r<!J8@a$NI=<(J8;z<o$KJQ49$9$k(B   */
+            if ((buf->shrinkmconv & buf->input[nextseg]->status)
+                    && buf->input[nextseg]->cursegmode
+                    != buf->input[buf->curseg]->cursegmode) {
+                Xsj3cSeg        seg = buf->input[nextseg];
+
+                conv2++;
+                _Xsj3cwPStomPS(buf, kanabuf2, seg->yomi);
+                Xsj3cModeConv(buf, kanabuf2, seg->cursegmode, seg->size);
+                seg->num = _Xsj3cmPStowPSn(buf, seg->yomi, kanabuf2, seg->size);
+                if (seg->num > seg->size - YBUFSIZ) {
+                    Xsj3cResizeSegment(seg, seg->size * 2);
+                    seg->num = _Xsj3cmPStowPS(buf, seg->yomi, kanabuf2);
+                }
+                seg->cur = seg->num;
+            }
+        } else {
+            /* $B%+%l%s%HJ8@a$,:G8e$NJ8@a$N;~!"J8@a$r#1$DA}$d$7$F(B */
+            /* $B<!J8@a$r:n@.$7!"<h$j=P$7$?#1J8;z$r%3%T!<$7$F(B     */
+            /* $B%+%l%s%HJ8@a$NB0@-$r<!J8@a$K%3%T!<$9$k(B           */
+
+            if (!buf->input[nextseg]) {
+                if ((buf->input[nextseg]
+                        = (Xsj3cSeg)Xsj3cCreateSegment(buf)) == NULL) {
+                    Xsj3cError("Failed to allocate segment");
+                }
+            } else
+                Xsj3cClearSegment(buf, buf->input[nextseg]);
+            _Xsj3cInsertChar(buf, buf->input[nextseg], tmp, 1);
+            buf->input[nextseg]->change = OFF;
+            buf->input[nextseg]->edit = buf->input[buf->curseg]->edit;
+            buf->input[nextseg]->status = buf->input[buf->curseg]->status;
+            if (buf->input[nextseg]->status & SEG_CONVED)
+                buf->convedsegnum--;
+            buf->segnum++;
+            buf->input[nextseg]->cursegmode
+                = buf->input[buf->curseg]->cursegmode;
+            buf->input[nextseg]->dcid = buf->input[buf->curseg]->dcid;
+        }
+
+        /* ShrinkKanjiConversion on $B$N;~$OJ,N%$7$?(B      */
+        /* $BItJ,$r9g$o$;$F<!J8@a$r:FEY$+$J4A;zJQ49$9$k(B   */
+        if (buf->shrinkkconv & buf->input[nextseg]->status) {
+            if (!conv2)
+                _Xsj3cwPStomPS(buf, kanabuf2, buf->input[nextseg]->yomi);
+            if (buf->input[nextseg]->num < INPUT_YOMI_MAX) {
+                value = serverIF[buf->server].func[FUNC_CONV]
+                        (kanabuf2, bun, knjbuf, KANJIBUFSIZ);
+            } else {
+                Xsj3cWarning("Too long segment[num = %d]",nextseg);
+            }
+            if (value > 0) {
+                _Xsj3cStoreKanji(buf, bun, nextseg, value, ON);
+                buf->segnum += (value - 1);
+                buf->convedsegnum += value;
+            } else {
+                if (value < 0) 
+                    Xsj3cWarning("sj3serv is down. reconnect please");
+                _Xsj3cStoreYomi(buf, buf->input[nextseg], 0);
+                buf->input[nextseg]->status = SEG_NOCONV;
+                if (!(buf->movebyseg & SEG_NOCONV))
+                    buf->input[nextseg]->edit = SEG_EDIT;
+            }
+        } else {
+            _Xsj3cStoreYomi(buf, buf->input[nextseg], 0);
+            buf->input[nextseg]->status = SEG_NOCONV;
+            if (!(buf->movebyseg & SEG_NOCONV))
+                buf->input[nextseg]->edit = SEG_EDIT;
+        }
+        if (buf->gakusyuu)
+            buf->input[nextseg]->change = ON;
+    }
+
+    /* ExpandKanjiConversion on $B$N;~$O%+%l%s%H(B  */
+    /* $BJ8@a$r:FEY$+$J4A;zJQ49JQ49$9$k(B           */
+    if (buf->shrinkkconv & buf->input[buf->curseg]->status) {
+        value = 0;
+        if (!conv1)
+            _Xsj3cwPStomPS(buf, kanabuf1, buf->input[buf->curseg]->yomi);
+        if (buf->input[buf->curseg]->num < INPUT_YOMI_MAX) {
+            value = serverIF[buf->server].func[FUNC_CONV]
+                    (kanabuf1, bun, knjbuf, KANJIBUFSIZ);
+        } else {
+            Xsj3cWarning("Too long segment[num = %d]",buf->curseg);
+        }
+        if (value > 0) {
+            buf->convedsegnum++;
+            buf->input[buf->curseg]->status = SEG_CONVED;
+            buf->input[buf->curseg]->edit = SEG_NOEDIT;
+            buf->input[buf->curseg]->dnum
+                = _Xsj3cmPStowOUT(buf, buf->input[buf->curseg]->disp, knjbuf);
+            if (buf->gakusyuu)
+                buf->input[buf->curseg]->dcid = bun[0].dcid;
+        } else {
+            if (value < 0)
+                Xsj3cWarning("sj3serv is down. reconnect please");
+            _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+            buf->input[buf->curseg]->status = SEG_NOCONV;
+            if (!(buf->movebyseg & SEG_NOCONV))
+                buf->input[buf->curseg]->edit = SEG_EDIT;
+        }
+    } else {
+        value = 1;
+        _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+        buf->input[buf->curseg]->status = SEG_NOCONV;
+        if (!(buf->movebyseg & SEG_NOCONV))
+            buf->input[buf->curseg]->edit = SEG_EDIT;
+    }
+
+    /* temporary $B$N%P%C%U%!$r3+J|$9$k(B   */
+    free(kanabuf1);
+    free(kanabuf2);
+
+    /* $BJ8@aD93X=,$N$?$a$N%U%i%0$rN)$F$k(B */
+    if (buf->gakusyuu)
+        buf->input[buf->curseg]->change = ON;
+
+    if (value > 0)
+        return KEY_TEXT_CHANGE;
+    else 
+        return (KEY_TEXT_CHANGE|KEY_BELL);
+}
+
+/*
+ * _Xsj3cShrinkNoConv()
+ *  Shrink current segment by reducing last segment.
+ */
+static Xsj3cEvent
+_Xsj3cShrinkNoConv(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->dict->n_dict) {
+        buf->dict->n_dict--;
+        return KEY_TEXT_CHANGE;
+    } else {
+        return (KEY_BELL);
+    }
+}
+
+/*
+ * _Xsj3cBackSpace()
+ *
+ * <InputMode/ConvedMode> Delete previous segment or character.
+ * <DictMode> Delete previous character for yomi.
+ * <SelectMode> Popdown the panel and delete previous segment or character.
+ * <NoInputMode> Does nothing.
+ *
+ * DeleteBySegment on: Delete previous segment.
+ * DeleteBySegment off: Delete previous character.
+ * DeleteChangeSegment all: Unconvert all segments when "DeleteBySegment"
+ *   is off.
+ * DeleteChangeSegment one: Unconvert segments after previous segment 
+ *   when "DeleteBySegment" is off.
+ * DeleteChangeSegment after: Unconvert previous segment
+ *   when "DeleteBySegment" is off.
+ * SelectBackSpaceMove on: Move target segment to current segment.
+ */
+Xsj3cEvent
+_Xsj3cBackSpace(buf)
+    Xsj3cBuf        buf;
+{
+    Xsj3cEvent      ret = KEY_NULL;
+
+    if (buf->convmode & SelectModeMask) {
+        /* SelectMode $B$N;~$O8uJdA*Br!?5-9fA*Br(B    */
+        /* $B%&%#%s%I%&$r%]%C%W%@%&%s(B             */
+        ret |= KEY_SELECT_ABORT;
+        if (buf->selectstatus == SELECT_HINSI) {
+            buf->convmode = DictModeMask;
+            buf->dict->status = DICT_INPUT;
+        } else if (buf->selectstatus == SELECT_CAND) {
+            buf->convmode = ConvedModeMask;
+            if (buf->selectback)
+                buf->curseg++;
+        } else {
+            buf->convmode = InputModeMask;
+            if (!buf->segnum)
+                return(ret);
+        }
+    } else if (buf->convmode & NoInputModeMask) {
+        /* $BJ8@a(B(segement)$B?t$,(B 0$B$N$H$-$OL5;k$9$k(B */
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+
+    switch(buf->convmode) {
+    case InputModeMask:
+        if ((buf->input[buf->curseg]->edit & SEG_NOEDIT) && 
+                (buf->delbyseg & buf->input[buf->curseg]->status)) {
+            if (buf->curseg > 0) {
+                buf->curseg--;
+                return(_Xsj3cDeleteSeg(buf, ret, buf->dellastmove));
+            } else {
+                return (KEY_BELL);
+            }
+        } else {
+            if (buf->input[buf->curseg]->cur == 0 && buf->curseg > 0) {
+                buf->curseg--;
+                if ((buf->input[buf->curseg]->edit & SEG_NOEDIT) &&
+                        buf->delbyseg & buf->input[buf->curseg]->status)
+                    return(_Xsj3cDeleteSeg(buf, ret, buf->dellastmove));
+                else {
+                    ret |= _Xsj3cUnConvSeg(buf, buf->delchange, ON);
+                    _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+                }
+            }
+            return(_Xsj3cBackSpaceChar(buf, buf->input[buf->curseg], ret)
+                    & ~KEY_DICT_CHANGE);
+        }
+    case ConvedModeMask:
+        if (buf->curseg > 0) {
+            buf->curseg--;
+        } else {
+            return (KEY_BELL);
+        }
+        if (buf->delbyseg & buf->input[buf->curseg]->status) {
+            return(_Xsj3cDeleteSeg(buf, ret, buf->dellastmove));
+        } else {
+            ret |= _Xsj3cUnConvSeg(buf, buf->delchange, ON);
+            _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+            return(_Xsj3cBackSpaceChar(buf, buf->input[buf->curseg], ret)
+                    & ~KEY_DICT_CHANGE);
+        }
+    case DictModeMask:
+        /* DictMode $B$N;~(B  */
+        if (buf->dict->status == DICT_INPUT) {
+            ret = _Xsj3cBackSpaceChar(buf, buf->dict->seg, ret)
+                & ~KEY_TEXT_CHANGE;
+            _Xsj3cFlushDictMsg(buf);
+            return(ret);
+        } else {
+            return(KEY_NULL);
+        }
+    default:
+        return(ret);
+    }
+}
+
+/*
+ * _Xsj3cDelete()
+ *
+ * <InputMode/ConvedMode> Delete current segment or character.
+ * <DictMode> Delete the character of current position.
+ * <SelectMode> Popdown the panel and delete current segment or character.
+ * <NoInputMode> Rings bell.
+ *
+ * DeleteBySegment on: Delete current segment.
+ * DeleteBySegment off: Delete current character.
+ * DeleteChangeSegment all: Unconvert all segments when "DeleteBySegment"
+ *   is off.
+ * DeleteChangeSegment one: Unconvert segments after current segment 
+ *   when "DeleteBySegment" is off.
+ * DeleteChangeSegment after: Unconvert current segment
+ *   when "DeleteBySegment" is off.
+ * DeleteLastMove on: Move current segment to previous
+ *   after deleting last segment. 
+ */
+Xsj3cEvent
+_Xsj3cDelete(buf)
+    Xsj3cBuf        buf;
+{
+    Xsj3cEvent      ret = KEY_NULL;
+
+    if (buf->convmode & SelectModeMask) {
+        ret |= KEY_SELECT_ABORT;
+        if (buf->selectstatus == SELECT_HINSI) {
+            buf->convmode = DictModeMask;
+            buf->dict->status = DICT_INPUT;
+        } else if (buf->selectstatus == SELECT_CAND) {
+            buf->convmode = ConvedModeMask;
+        } else {
+            buf->convmode = InputModeMask;
+            if (buf->curseg >= buf->segnum) {
+                return (ret);
+            }
+        }
+        /* SelectMode $B$N;~$O8uJdA*Br!?5-9fA*Br(B    */
+        /* $B%&%#%s%I%&$r%]%C%W%@%&%s(B             */
+    } else if (buf->convmode & NoInputModeMask) {
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    } else if (buf->curseg >= buf->segnum) {
+        /* $B$"$k$$$O%+%l%s%HJ8@aHV9f$,J8@a?t$h$j(B */
+        /* $B>.$5$/$J$$;~$O%Y%k$rLD$i$9(B           */
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+
+    switch(buf->convmode) {
+    case InputModeMask:
+        if ((buf->input[buf->curseg]->edit & SEG_NOEDIT) && 
+                (buf->delbyseg & buf->input[buf->curseg]->status)) {
+            return(_Xsj3cDeleteSeg(buf, ret, buf->dellastmove));
+        } else {
+            if (buf->input[buf->curseg]->num == buf->input[buf->curseg]->cur
+                    && buf->curseg < buf->segnum - 1) {
+                buf->curseg++;
+                if ((buf->input[buf->curseg]->edit & SEG_NOEDIT) &&
+                        buf->delbyseg & buf->input[buf->curseg]->status)
+                    return(_Xsj3cDeleteSeg(buf, ret, buf->dellastmove));
+                else {
+                    ret |= _Xsj3cUnConvSeg(buf, buf->delchange, OFF);
+                    _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+                }
+            }
+            return(_Xsj3cDeleteChar(buf, buf->input[buf->curseg], ret)
+                    & ~KEY_DICT_CHANGE);
+        }
+    case ConvedModeMask:
+        if (buf->delbyseg & buf->input[buf->curseg]->status) {
+            return(_Xsj3cDeleteSeg(buf, ret, buf->dellastmove));
+        } else {
+            ret |= _Xsj3cUnConvSeg(buf, buf->delchange, OFF);
+            _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+            return(_Xsj3cDeleteChar(buf, buf->input[buf->curseg], ret)
+                    & ~KEY_DICT_CHANGE);
+        }
+    case DictModeMask:
+        /* DictMode $B$N;~(B  */
+        if (buf->dict->status == DICT_INPUT) {
+            ret = _Xsj3cDeleteChar(buf, buf->dict->seg, ret)
+                & ~KEY_TEXT_CHANGE;
+            _Xsj3cFlushDictMsg(buf);
+            return(ret);
+        } else {
+            return(KEY_NULL);
+        }
+    default:
+        return(ret);
+    }
+}
+
+/*
+ * _Xsj3cBackSpaceChar()
+ *  Delete last character of string buffers.
+ */
+static Xsj3cEvent
+_Xsj3cBackSpaceChar(buf, seg, ret)
+    Xsj3cBuf                buf;
+    Xsj3cSeg                seg;
+    Xsj3cEvent              ret;
+{
+    unsigned char           tmp[YBUFSIZ];
+    wchar                   wcs[RBUFSIZ];
+    int                     change_pos, len;
+    register int            i;
+
+    if (seg->cur > 0) {
+        /* $B%+!<%=%k0LCV$h$jA0$KI=<(J8;zNs$,B8:_$9$k$H$-(B */
+
+        if (buf->backdisplay) {
+
+            /* .BackDisplay  on $B$N;~(B    */
+
+            change_pos = seg->cur - 1;
+            if (seg->n_roma) {
+                /* $B$R$i$,$J!?A43Q%+%?%+%J!?H>3Q%+%?%+%JF~NO%b!<%I$N(B */
+                /* $B$H$-$G%m!<%^;z%P%C%U%!$KJ8;z$,;D$C$F$$$k$H$-(B     */
+                /* $B$^$:0lJ8;z:o=|$9$k(B                               */
+                _Xsj3cExtractChar(buf, seg, tmp, 1);
+                change_pos = seg->cur;
+                if (*seg->oldstr != '\0' && seg->value < 0) {
+                    /* $BB`Hr%P%C%U%!$KJ8;z$,$"$C$FD>A0$N%m!<%^;z$+$J(B */
+                    /* $BJQ49$N7k2L$,JQ49ITG=$N>l9g$OB`Hr%P%C%U%!$N(B   */
+                    /* $BJ8;z$r%m!<%^;z%P%C%U%!$K%3%T!<$9$k(B           */
+                    strcpy(seg->str, seg->oldstr);
+                    seg->n_roma = strlen(seg->oldstr);
+                    seg->sp = seg->str;
+                    seg->sp += seg->n_roma;
+                    *(seg->sp) = '\0';
+                    *seg->oldstr = '\0';
+                } else {
+                    /* $B%m!<%^;zF~NO$GD>A0$NJQ497k2L>uBV$,ITDj$N$H$-(B */
+                    /* $B$O$H$-$O%m!<%^;z%P%C%U%!$NH>3Q%"%k%U%!%Y%C%H(B */
+                    /* $B$r#1J8;z:o=|$7!"FI$_%P%C%U%!$dI=<(%P%C%U%!$N(B */
+                    /* $B%"%k%U%!%Y(B $B%C%H$b#1J8;z>C5n$9$k(B      */
+                    seg->sp--;
+                    *seg->sp = '\0';
+                    seg->n_roma--;
+                }
+            } else if (seg->n_kana > 0) {
+                /* $B$+$JF~NO$G$R$i$,$J!?A43Q%+%?%+%JF~NO%b!<%I$N;~$G(B */
+                /* $B$+$J%P%C%U%!$KJ8;z$,;D$C$F$$$k;~$O$+$J%P%C%U%!Cf(B */
+                /* $B$N%+%J$HFI$_%P%C%U%!!"I=<(%P%C%U%!Cf$N$R$i$,$JA4(B */
+                /* $B3Q%+%?%+%J$r#1J8;z>C5n$7!"99$K$b$&#1J8;zA0$NA43Q(B */
+                /* $B$+$J$rH>3Q%+%?%+%J$KJQ49$7$F$+$J%P%C%U%!$KF~$l$k(B */
+                _Xsj3cExtractChar(buf, seg, tmp, 1);
+                change_pos = seg->cur;
+                seg->sp = seg->str;
+                *seg->str = '\0';
+                if (seg->cur > 0 &&
+                (ishira(seg->yomi[seg->cur - 1], serverIF[buf->server].lang) ||
+                iskata(seg->yomi[seg->cur - 1], serverIF[buf->server].lang))) {
+                    wcs[0] = seg->yomi[seg->cur - 1];
+                    wcs[1] = '\0';
+                    _Xsj3cwPStomPS(buf, tmp, wcs);
+                    _Xsj3cZKanaToHKata(buf, seg->str, tmp);
+                    if (isdakuon(*seg->str)
+                            && strlen(seg->str) == 1) {
+                        *(++seg->sp) = '\0';
+                        seg->n_kana = 1;
+                    } else {
+                        seg->n_kana = 0;
+                    }
+                } else {
+                    seg->n_kana = 0;
+                }
+            } else  {
+                /* $B%m!<%^;zF~NO;~$N%m!<%^;z%P%C%U%!$d$+$JF~NO;~$N(B   */
+                /* $B$+$J%P%C%U%!$KJ8;z$,;D$C$F$$$J$$$H$-(B             */
+                if (*seg->oldstr != '\0' &&
+                iskan1(seg->yomi[seg->cur - 1] >> 8, serverIF[buf->server].lang)
+                    && iskan2(seg->yomi[seg->cur - 1] & 0xff,
+                    serverIF[buf->server].lang)) {
+                    /* $BB`Hr%P%C%U%!$KJ8;z$,$"$C$F:o=|$9$k:G8e$N(B */
+                    /* $BJ8;z$,A43QJ8;z$N$H$-(B                     */
+                    if (seg->n_kana < 0) {
+                        /* $B%m!<%^;zF~NO!?%3!<%IF~NO$N>l9g!"#1J8;z:o(B */
+                        /* $B=|$7$FB`Hr%P%C%U%!$NJ8;z$r%3%T!<$9$k(B     */
+                        strcpy(seg->str, seg->oldstr);
+                        seg->n_roma = strlen(seg->oldstr);
+                        _Xsj3cExtractChar(buf, seg, tmp, seg->oldlen);
+                        change_pos = seg->cur;
+                        if (buf->alphaconv && buf->inputmode != MODE_HKATA) {
+                            _Xsj3cHAlphaToZKana(buf, tmp, seg->oldstr);
+                            _Xsj3cInsertChar(buf, seg, tmp, seg->n_roma);
+                        } else {
+                            _Xsj3cInsertChar(buf, seg, seg->oldstr,
+                                    seg->n_roma);
+                        }
+                        seg->sp = seg->str;
+                        seg->sp += seg->n_roma;
+                    } else {
+                        /* $B$+$JF~NO$N>l9g#1J8;z:o=|$7$FB`Hr%P%C%U%!(B */
+                        /* $BJ8;z$r%3%T!<$7$=$NJ8;z$r:FEY$+$JJQ49$9$k(B */
+                        _Xsj3cExtractChar(buf, seg, tmp, 1);
+                        change_pos = seg->cur;
+                        seg->sp = seg->str;
+                        strcpy(seg->str, seg->oldstr);
+                        if ((seg->value = _Xsj3cKanaConv(buf, seg, seg->str,
+                                tmp, buf->inputmode)) > 0) {
+                            seg->n_kana = 0;
+                        } else if (seg->value == 0) {
+                            seg->n_kana = 1;
+                            *(++seg->sp) = '\0';
+                            len = _Xsj3cmPStowPS(buf, wcs, tmp);
+                            _Xsj3cInsertWchar(seg, wcs, len);
+                        } else {
+                            seg->n_kana = 0;
+                        }
+                    }
+                    *seg->oldstr = '\0';
+                    seg->oldlen = 0;
+                } else if (*seg->oldstr != '\0') {
+                    /* $B%3!<%IF~NO$GH>3Q$KJQ49$5$l$k;~(B   */
+                    /* $B$^$?$OH>%+%J%b!<%I$N;~(B           */
+                    strcpy(seg->str, seg->oldstr);
+                    seg->n_roma = strlen(seg->oldstr);
+                    _Xsj3cExtractChar(buf, seg, tmp, seg->oldlen);
+                    change_pos = seg->cur;
+                    if (buf->alphaconv && buf->inputmode != MODE_HKATA) {
+                        _Xsj3cHAlphaToZKana(buf, tmp, seg->oldstr);
+                        _Xsj3cInsertChar(buf, seg, tmp, seg->n_roma);
+                    } else {
+                        _Xsj3cInsertChar(buf, seg, seg->oldstr,
+                                seg->n_roma);
+                    }
+                    seg->sp = seg->str;
+                    seg->sp += seg->n_roma;
+                    *seg->oldstr = '\0';
+                    seg->oldlen = 0;
+                } else {
+                    /* $BB`Hr%P%C%U%!$KJ8;z$,;D$C$F$$$J$$$H$-(B     */
+                    _Xsj3cExtractChar(buf, seg, tmp, 1);
+                    change_pos = seg->cur;
+                    *seg->str = '\0';
+                    seg->sp = seg->str;
+                    if (seg->n_kana >= 0) {
+                        if (seg->cur > 0 && (ishira(seg->yomi[seg->cur - 1],
+                                serverIF[buf->server].lang) ||
+                                iskata(seg->yomi[seg->cur - 1],
+                                serverIF[buf->server].lang))) {
+                            /* $B$+$JF~NO$N$H$-$O99$K#1J8;zA0(B */
+                            /* $B$NA43Q$+$J$rH>3Q%+%?%+%J$KJQ(B */
+                            /* $B49$7$F$+$J%P%C%U%!$KF~$l$k(B   */
+                            wcs[0] = seg->yomi[seg->cur - 1];
+                            wcs[1] = '\0';
+                            _Xsj3cwPStomPS(buf, tmp, wcs);
+                            _Xsj3cZKanaToHKata(buf, seg->str, tmp);
+                            if (isdakuon(*seg->str)
+                                    && strlen(seg->str) == 1) {
+                                *(++seg->sp) = '\0';
+                                seg->n_kana = 1;
+                            } else {   
+                                seg->n_kana = 0;
+                                *seg->str = '\0';
+                            }
+                        } else {
+                            seg->n_kana = 0;
+                        }
+                    } else {
+                        seg->n_kana = -1;
+                    }
+                }
+            }
+        } else {
+            /* .BackDisplay  off $B$N;~(B   */
+
+            _Xsj3cExtractChar(buf, seg, tmp, 1);
+            change_pos = seg->cur;
+            if (seg->n_roma) {
+                /* $B%m!<%^;zF~NO$G%m!<%^;z%P%C%U%!$KJ8;z$,$"$k>l9g(B  */
+                seg->sp--;
+                *seg->sp = '\0';
+                seg->n_roma--;
+            } else if (seg->n_kana >= 0) {
+                /* $B$+$JF~NO$N$H$-$O99$K#1J8;zA0$NA43Q$+$J(B   */
+                /* $B$rH>3Q%+%?%+%J$KJQ49$7$F!"$=$l$,By2;(B     */
+                /* $B8uJd$@$C$?$i$+$J%P%C%U%!$KF~$l$k(B         */
+                *seg->str = '\0';
+                seg->sp = seg->str;
+                if (seg->cur > 0 && (ishira(seg->yomi[seg->cur - 1],
+                        serverIF[buf->server].lang) ||
+                        iskata(seg->yomi[seg->cur - 1],
+                        serverIF[buf->server].lang))) {
+                    wcs[0] = seg->yomi[seg->cur - 1];
+                    wcs[1] = '\0';
+                    _Xsj3cwPStomPS(buf, tmp, wcs);
+                    _Xsj3cZKanaToHKata(buf, seg->str, tmp);
+                    if (isdakuon(*seg->str)
+                            && strlen(seg->str) == 1) {
+                        *(++seg->sp) = '\0';
+                        seg->n_kana = 1;
+                    } else {   
+                        seg->n_kana = 0;
+                        *seg->str = '\0';
+                    }
+                } else {
+                    seg->n_kana = 0;
+                }
+            } else {
+                *seg->str = '\0';
+                seg->sp = seg->str;
+                seg->n_kana = -1;
+            }
+        }
+        _Xsj3cStoreYomi(buf, seg, change_pos);
+        if (seg->num < seg->size - KANABUFSIZ - YBUFSIZ) 
+            Xsj3cResizeSegment(seg, seg->size - KANABUFSIZ);
+        if (seg->num == 0 && (buf->convmode & ~DictModeMask)) {
+            Xsj3cFreeSegment(buf->input[buf->segnum]);
+            buf->input[buf->segnum] = NULL;
+            buf->segnum--;
+            Xsj3cFreeSegment(seg);
+            seg = NULL;
+            for (i = buf->curseg; i < buf->segnum; i++) {
+                buf->input[i] = buf->input[i + 1];
+            }
+            buf->input[buf->segnum] = NULL;
+        }
+        if (buf->dispmodechange) {
+            buf->dispmode = ((buf->segnum &&
+                buf->convedsegnum == buf->segnum) ? MODE_KANJI :
+                (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+            ret |= KEY_MODE_CHANGE;
+        }
+        if (buf->curseg && buf->curseg == buf->segnum && buf->dellastmove)
+            buf->curseg--;
+
+        return(ret|KEY_TEXT_CHANGE|KEY_DICT_CHANGE);
+    } else {
+        /* $B%+!<%=%k0LCV$h$jA0$KI=<(J8;zNs$,$J$$$H$-(B */
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cDeleteChar()
+ *  Delete next character of string buffers.
+ */
+static Xsj3cEvent
+_Xsj3cDeleteChar(buf, seg, ret)
+    Xsj3cBuf                buf;
+    Xsj3cSeg                seg;
+    Xsj3cEvent              ret;
+{
+    unsigned char           tmp[YBUFSIZ];
+    int                     change_pos;
+    register int            i;
+
+    if (seg->cur < seg->num) {
+        /* $B%+!<%=%k0LCV$h$j8e$m$KI=<(J8;zNs$,B8:_$9$k$H$-(B */
+
+        change_pos = seg->cur;
+        seg->cur++;
+        _Xsj3cExtractChar(buf, seg, tmp, 1);
+        _Xsj3cStoreYomi(buf, seg, change_pos);
+        if (seg->num < seg->size - KANABUFSIZ - YBUFSIZ) 
+            Xsj3cResizeSegment(seg, seg->size - KANABUFSIZ);
+        if (seg->num == 0 && (buf->convmode & ~DictModeMask)) {
+            Xsj3cFreeSegment(buf->input[buf->segnum]);
+            buf->input[buf->segnum] = NULL;
+            buf->segnum--;
+            Xsj3cFreeSegment(seg);
+            seg = NULL;
+            for (i = buf->curseg; i < buf->segnum; i++) {
+                buf->input[i] = buf->input[i + 1];
+            }
+            buf->input[buf->segnum] = NULL;
+            if (buf->dispmodechange) {
+                buf->dispmode = ((buf->segnum &&
+                    buf->convedsegnum == buf->segnum) ? MODE_KANJI :
+                    (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+                ret |= KEY_MODE_CHANGE;
+            }
+            if (buf->curseg && buf->curseg == buf->segnum && buf->dellastmove)
+                buf->curseg--;
+        }
+        return(ret|KEY_TEXT_CHANGE|KEY_DICT_CHANGE);
+    } else {
+        /* $B%+!<%=%k0LCV$h$j8e$m$KI=<(J8;zNs$,$J$$$H$-(B */
+
+        return(KEY_NULL);
+    }
+}
+
+/*
+ * _Xsj3cDeleteSeg()
+ *  Delete current segment.
+ */
+static Xsj3cEvent
+_Xsj3cDeleteSeg(buf, ret, move)
+    Xsj3cBuf                buf;
+    Xsj3cEvent              ret;
+    Xsj3cFlag               move;
+{
+    register int            i;
+
+    buf->n_select = 0;
+    if ((buf->convmode & ConvedModeMask) && buf->candidate) 
+        Xsj3cEndCandidate(buf, OFF);
+    if (buf->segnum <= buf->curseg) {
+        return (ret);
+    }
+    Xsj3cFreeSegment(buf->input[buf->segnum]);
+    buf->input[buf->segnum] = NULL;
+    buf->segnum--;
+    if (!buf->segnum) {
+        /* $BJ8@a?t$,(B 0 $B$K$J$C$?$H$-$OJQ49MQJ8;z(B   */
+        /* $B%P%C%U%!$r%/%j%"$7$F(B InputMode $B$K$9$k(B */
+
+        buf->convedsegnum = 0;
+        buf->curseg = 0;
+        Xsj3cClearSegment(buf, buf->input[0]);
+    } else if (buf->curseg == buf->segnum) {
+
+        if (buf->input[buf->curseg]->status & SEG_CONVED) {
+            buf->convedsegnum--;
+            if (!buf->convedsegnum && buf->gakusyuu) {
+                _Xsj3cClearDcid(buf);
+            }
+        }
+        Xsj3cFreeSegment(buf->input[buf->curseg]);
+        buf->input[buf->curseg] = NULL;
+        /* $BJQ49Cf$NJ8>O$N:G8e$NJ8@a$N;~$O8=J8@a$r$R$H$DA0$K$:$i$9(B */
+        if (move)
+            buf->curseg--;
+    } else if (buf->curseg < buf->segnum) {
+        /* $B:G8e$NJ8@a$G$J$$$N;~$O0J9_$NJ8@a$r(B   */
+        /* $B$R$H$D$:$DA0$K$:$i$9(B                 */
+
+        if (buf->input[buf->curseg]->status & SEG_CONVED) {
+            buf->convedsegnum--;
+            if (!buf->convedsegnum && buf->gakusyuu) {
+                _Xsj3cClearDcid(buf);
+            }
+        }
+        Xsj3cFreeSegment(buf->input[buf->curseg]);
+        buf->input[buf->curseg] = NULL;
+        for (i = buf->curseg; i < buf->segnum; i++) {
+            buf->input[i] = buf->input[i + 1];
+        }
+        buf->input[buf->segnum] = NULL;
+    }
+    if (buf->dispmodechange) {
+        buf->dispmode = ((buf->segnum &&
+            buf->convedsegnum == buf->segnum) ? MODE_KANJI :
+            (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+        ret |= KEY_MODE_CHANGE;
+    }
+    ret |= KEY_TEXT_CHANGE;
+    return(ret);
+}
+
+/*
+ * _Xsj3cDelAfter()
+ *
+ * <InputMode/ConvedMode> Delete current segment and all segments after
+ *   current segment or cursor position.
+ * <DictMode> Delete all yomi strings.
+ * <SelectMode> Popdown the panel and delete strings after current segment
+ *  or cursor position.
+ * <NoInputMode> Rings bell.
+ *
+ * DeleteBySegment on: Delete current segment and all segments after current.
+ * DeleteBySegment off: Delete strings after current cursor position
+ *   in current segment.
+ * DeleteLastMove on: Move current segment to previous
+ *   after deleting last segment. 
+ */
+Xsj3cEvent
+_Xsj3cDelAfter(buf)
+    Xsj3cBuf            buf;
+{
+    Xsj3cEvent          ret = KEY_NULL;
+    register int        i,  begin;
+    int                 del_num;
+    unsigned char      *tmp;
+
+    if (buf->convmode & SelectModeMask) {
+        if (buf->selectstatus == SELECT_HINSI || buf->curseg >= buf->segnum) {
+            if (buf->selectstatus == SELECT_HINSI)
+                buf->dict->status = DICT_INPUT;
+            if (buf->dispmodechange) {
+                buf->dispmode =
+                    (buf->dict->mode == REG_STATE ? MODE_TOROKU : MODE_SYOUKYO);
+                return (KEY_SELECT_ABORT|KEY_MODE_CHANGE);
+            } else
+                return (KEY_SELECT_ABORT);
+        } else {
+            ret |= KEY_SELECT_ABORT;
+        }
+        /* SelectMode $B$N;~$O8uJdA*Br!?5-9fA*Br(B    */
+        /* $B%&%#%s%I%&$r%]%C%W%@%&%s(B             */
+    } else if (buf->convmode & (NoInputModeMask|DictModeMask)) {
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    } else if (buf->curseg >= buf->segnum) {
+        /* $B$"$k$$$O%+%l%s%HJ8@aHV9f$,J8@a?t$h$j(B */
+        /* $B>.$5$/$J$$;~$O%Y%k$rLD$i$9(B           */
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+
+    ret |= KEY_TEXT_CHANGE;
+    if (buf->killbyseg & buf->input[buf->curseg]->status) {
+        if (buf->input[buf->curseg]->edit & SEG_NOEDIT) {
+            begin = buf->curseg;
+        } else {
+            if (!buf->input[buf->curseg]->cur) {
+                begin = buf->curseg;
+            } else {
+                begin = buf->curseg + 1;
+                if (buf->input[buf->curseg]->cur
+                        < buf->input[buf->curseg]->num) {
+                    del_num = buf->input[buf->curseg]->num
+                            - buf->input[buf->curseg]->cur;
+                    buf->input[buf->curseg]->cur = buf->input[buf->curseg]->num;
+                    if ((tmp = (unsigned char *)
+                            malloc(buf->input[buf->curseg]->size
+                            * sizeof(wchar))) == NULL)
+                        Xsj3cError("Cannot allocate for temporary buffer");
+                    _Xsj3cExtractChar(buf, buf->input[buf->curseg], tmp, del_num);
+                    free(tmp);
+                    _Xsj3cStoreYomi(buf, buf->input[buf->curseg],
+                            buf->input[buf->curseg]->cur);
+                }
+            }
+        }
+        for (i = begin; i < buf->segnum + 1; i++) {
+            if (buf->input[i]->status & SEG_CONVED)
+                buf->convedsegnum--;
+            Xsj3cFreeSegment(buf->input[i]);
+            buf->input[i] = NULL;
+        }
+        buf->segnum = begin;
+        if (begin == buf->curseg && buf->dellastmove && buf->curseg) 
+            buf->curseg--;
+        if (buf->dispmodechange) {
+            buf->dispmode = ((buf->segnum &&
+                buf->convedsegnum == buf->segnum) ? MODE_KANJI :
+                (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+            ret |= KEY_MODE_CHANGE;
+        }
+        if (buf->gakusyuu && !buf->convedsegnum) 
+            _Xsj3cClearDcid(buf);
+    } else {
+        if (buf->input[buf->curseg]->edit & SEG_NOEDIT
+                || !buf->input[buf->curseg]->cur) {
+            ret |= _Xsj3cDeleteSeg(buf, ret, buf->dellastmove);
+        } else {
+            if (buf->input[buf->curseg]->cur
+                    < buf->input[buf->curseg]->num) {
+                del_num = buf->input[buf->curseg]->num
+                        - buf->input[buf->curseg]->cur;
+                buf->input[buf->curseg]->cur = buf->input[buf->curseg]->num;
+                if ((tmp = (unsigned char *)
+                        malloc(buf->input[buf->curseg]->size
+                        * sizeof(wchar))) == NULL)
+                    Xsj3cError("Cannot allocate for temporary buffer");
+                _Xsj3cExtractChar(buf, buf->input[buf->curseg], tmp, del_num);
+                free(tmp);
+                _Xsj3cStoreYomi(buf, buf->input[buf->curseg],
+                        buf->input[buf->curseg]->cur);
+            }
+        }
+    }
+
+    return(ret);
+}
+
+/*
+ * _Xsj3cStart()
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode/SelectMode> If now on converting,
+ *   fix all segments, then end kana-kanji converting.
+ *
+ * FlushEndConversion on: Flush converting strings before ending.  
+ * DisplayModeChange on: Change the display mode string.  
+ */
+Xsj3cEvent
+_Xsj3cStart(buf)
+    Xsj3cBuf            buf;
+{
+    Xsj3cEvent          ret = KEY_HENKAN_END;
+    register int        i;
+
+    if (buf->dispmodechange) {
+        buf->dispmode = buf->inputmode;
+    }
+    switch(buf->convmode) {
+    case ConvedModeMask:
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, OFF);
+    case InputModeMask:
+        break;
+    case SelectModeMask:
+        if (buf->flusheconv)
+            ret |= KEY_SELECT_END;
+        else 
+            ret |= KEY_SELECT_ABORT;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, OFF);
+        buf->n_select = 0;
+        break;
+    case DictModeMask:
+        ret |= KEY_DICT_END;
+        break;
+    case NoInputModeMask:
+        return (KEY_HENKAN_END);
+    default:
+        /* Not supported    */
+        return (KEY_HENKAN_START);
+    }
+    if (buf->flusheconv) {
+        ret |= KEY_TEXT_FIXED;
+    } else {
+        for (i = 1; i < buf->segnum + 1; i++) {
+            Xsj3cFreeSegment(buf->input[i]);
+            buf->input[i] = NULL;
+        }
+        if (buf->input[0])
+            Xsj3cClearSegment(buf, buf->input[0]);
+        buf->segnum = 0;
+        buf->convedsegnum = 0;
+        buf->curseg = 0;
+    }
+    return ret;
+}
+
+/*
+ * _Xsj3cReConnect()
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode/SelectMode> Popdown the panel
+ *   and clear all segments, then reonnect to sj3serv.
+ *  
+ * FlushEndConversion on: Flush converting strings before reconnecting.  
+ * DisplayModeChange on: Change the display mode string.  
+ */
+Xsj3cEvent
+_Xsj3cReConnect(buf)
+    Xsj3cBuf    buf;
+{
+    Xsj3cEvent  ret = KEY_TEXT_CHANGE;
+
+    if (buf->gakusyuu) {
+        _Xsj3cClearDcid(buf);
+    }
+    switch (buf->convmode) {
+    case ConvedModeMask:
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, OFF);
+    case InputModeMask:
+    case NoInputModeMask:
+        ret = KEY_RECONNECT;
+        break;
+    case SelectModeMask:
+        ret = KEY_SELECT_ABORT|KEY_RECONNECT;
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, OFF);
+        break;
+    case DictModeMask:
+        ret = KEY_DICT_END|KEY_RECONNECT;
+        break;
+    default:
+        ret = KEY_RECONNECT;
+        break;
+    }
+    if (buf->dispmodechange) {
+        buf->dispmode = buf->inputmode;
+        ret |= KEY_MODE_CHANGE;
+    }
+    return ret;
+}
+
+/*
+ * _Xsj3cReConvert()
+ *
+ * <NoInputMode> If there is no string in input buffer,
+ *   copy from backup buffer which saved last fixed or flushed.
+ *   But there is any strings in input buffer or backup buffer is null,
+ *   ring bell.
+ * <InputMode/UnputMode/SelectMode/DictMode> Ring bell.
+ *
+ * BeginConversionLast on: Set current segment to the last one. 
+ * BeginConversionLast none: Allow to move out of segments. 
+ */
+Xsj3cEvent
+_Xsj3cReConvert(buf)
+    Xsj3cBuf            buf;
+{
+    register int        i,  conved;
+
+    if ((buf->convmode & NoInputModeMask) && buf->backup) {
+        buf->segnum = buf->backsegnum;
+        if (!buf->segnum)
+#ifdef THROUGH_CONT
+            return (KEY_NULL);
+#else /* THROUGH_CONT */
+            if (buf->cntrlsame)
+                return (KEY_NULL);
+            else 
+                return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+        for (i = 0, conved = 0; i < buf->segnum; i++) {
+            if (!buf->input[i]) {
+                if ((buf->input[i]
+                        = (Xsj3cSeg)Xsj3cCreateSegment(buf)) == NULL) {
+                    Xsj3cError("Failed to allocate segment");
+                }
+            } else {
+                *buf->input[i]->oldstr = '\0';
+                buf->input[i]->oldlen = 0;
+                *buf->input[i]->str = '\0';
+                buf->input[i]->sp = buf->input[i]->str;
+                buf->input[i]->change = OFF;
+                buf->input[i]->n_roma = 0;
+                buf->input[i]->n_kana = -1;
+                buf->input[i]->value = 0;
+            }
+            _Xsj3cWcpy(buf->input[i]->yomi, buf->backup[i]->yomi);
+            buf->input[i]->num = buf->backup[i]->num;
+            buf->input[i]->cur = buf->backup[i]->cur;
+            _Xsj3cWcpy(buf->input[i]->disp, buf->backup[i]->disp);
+            buf->input[i]->dnum = buf->backup[i]->dnum;
+            buf->input[i]->dcid = buf->backup[i]->dcid;
+            buf->input[i]->edit = buf->backup[i]->edit;
+            buf->input[i]->cursegmode = buf->backup[i]->cursegmode;
+            if ((buf->input[i]->status = buf->backup[i]->status) == SEG_CONVED)
+                conved++;
+            buf->input[i]->size = buf->backup[i]->size;
+        }
+        buf->convedsegnum = conved;
+        switch (buf->beginlastseg) {
+        case NONE:
+            buf->curseg = buf->segnum;
+            break;
+        case ON:
+            buf->curseg = buf->segnum - 1;
+            break;
+        case OFF:
+            buf->curseg = 0;
+            break;
+        default:
+            buf->curseg = 0;
+            break;
+        }
+        return (KEY_TEXT_CHANGE);
+    } else {
+        return KEY_NULL;
+    }
+}
+
+/*
+ * _Xsj3cEdit() [edit]
+ *
+ * <InputMode/ConvedMode> Unconvert segments.
+ * <SelectMode> pop down the panel candidate(symbol/hinsi) panel and
+ *   unconvert current segment.
+ * <DictMode> Pop down Auxpanel and unconvert current segment.
+ * <NoInputMode> Does nothing.
+ *
+ * DisplayModeChange on: Change the display mode string.  
+ * EditCursorLast on: Set cursor position to bottom of segment.
+ * EditCursorLast off: Set cursor position to top of segment.
+ */
+Xsj3cEvent
+_Xsj3cEdit(buf)
+    Xsj3cBuf            buf;
+{
+    Xsj3cEvent          ret = KEY_NULL;
+
+    if (buf->convmode & SelectModeMask) {
+        ret |= KEY_SELECT_ABORT;
+        if (buf->selectstatus == SELECT_HINSI) {
+            ret |= KEY_DICT_END;
+        }
+    } else if (buf->convmode & DictModeMask) {
+        ret |= KEY_DICT_END;
+    } else if (buf->convmode & NoInputModeMask) {
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    }
+    ret |= _Xsj3cUnConvSeg(buf, ONE, buf->editcurlast);
+    _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+    buf->input[buf->curseg]->edit = SEG_EDIT;
+    return (ret);
+}
+
+/*
+ * _Xsj3cDRegBegin()
+ *
+ * <InputMode/ConvedMode> Begin to registr the word in the dictionary.
+ * <NoInputMode/DictMode/SelectMode> Rings bell.
+ *  
+ * DisplayModeChange on: Change the display mode string.  
+ */
+Xsj3cEvent
+_Xsj3cDRegBegin(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & (ConvedModeMask|InputModeMask)) {
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, ON);
+        buf->dict = _Xsj3cCreateDictData(buf, REG_STATE);
+        buf->convmode = DictModeMask;
+        _Xsj3cFlushDictMsg(buf);
+        if (buf->dispmodechange) {
+            buf->dispmode = MODE_TOROKU;
+            return (KEY_DICT_START|KEY_MODE_CHANGE);
+        } else
+            return (KEY_DICT_START);
+    } else {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cDClearBegin()
+ *
+ * <InputMode/ConvedMode> Begin to eliminate the word in the dictionary.
+ * <NoInputMode/DictMode/SelectMode> Rings bell.
+ *  
+ * DisplayModeChange on: Change the display mode string.  
+ */
+Xsj3cEvent
+_Xsj3cDClearBegin(buf)
+    Xsj3cBuf    buf;
+{
+    if (buf->convmode & (ConvedModeMask|InputModeMask)) {
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, OFF);
+        buf->dict = _Xsj3cCreateDictData(buf, CLR_STATE);
+        buf->convmode = DictModeMask;
+        _Xsj3cFlushDictMsg(buf);
+        if (buf->dispmodechange) {
+            buf->dispmode = MODE_SYOUKYO;
+            return (KEY_DICT_START|KEY_MODE_CHANGE);
+        } else
+            return (KEY_DICT_START);
+    } else {
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+}
+
+/*
+ * _Xsj3cSymbolBegin()
+ *
+ * <NoInputMode/InputMode/ConvedMode> Begin symbol selecting
+ *   and popup the panel.
+ * <DictMode/SelectMode> Ring bell.
+ *  
+ * DisplayModeChange on: Change the display mode string.  
+ */
+Xsj3cEvent
+_Xsj3cSymbolBegin(buf)
+    Xsj3cBuf        buf;
+{
+    Xsj3cEvent      ret = KEY_SYMBOL_START;
+
+    if (buf->convmode & (InputModeMask|NoInputModeMask|ConvedModeMask)) {
+        if (buf->dispmodechange) {
+            buf->dispmode = MODE_SYMBOL;
+            ret |= KEY_MODE_CHANGE;
+        }
+        buf->selectstatus = SELECT_SYMBOL;
+        buf->convmode = SelectModeMask;
+        return (ret);
+    } else {
+        return (KEY_BELL);
+    }
+}
+
+/*
+ * _Xsj3cFlushBefore()
+ *
+ * <InputMode/ConvedMode> Delete current segment and all segments after
+ *   current segment or cursor position.
+ * <DictMode> Delete all yomi strings.
+ * <SelectMode> Popdown the panel and delete strings after current segment
+ *  or cursor position.
+ * <NoInputMode> Does nothing.
+ *
+ * FlushChangeSegment off: Fix strings before current cursor position
+ * FlushChangeSegment one: Fix strings before current cursor position
+ *   and unconvert one segment.
+ * FlushChangeSegment all: Fix strings before current cursor position
+ *   and unconvert all segments.
+ * FlushCursorLast on: Set cursor position to bottom of segment.
+ * FlushCursorLast off: Set cursor position to top of segment.
+ */
+Xsj3cEvent
+_Xsj3cFlushBefore(buf)
+    Xsj3cBuf        buf;
+{
+    Xsj3cEvent      ret = KEY_NULL;
+    register int    i,  j;
+    int             store_num;
+    unsigned char  *tmp;
+    
+    if (buf->convmode & SelectModeMask) {
+        if (buf->selectstatus == SELECT_HINSI || buf->curseg >= buf->segnum) {
+            if (buf->selectstatus == SELECT_HINSI)
+                buf->dict->status = DICT_INPUT;
+            if (buf->dispmodechange) {
+                buf->dispmode =
+                    (buf->dict->mode == REG_STATE ? MODE_TOROKU : MODE_SYOUKYO);
+                return (KEY_SELECT_ABORT|KEY_MODE_CHANGE);
+            } else
+                return (KEY_SELECT_ABORT);
+        } else {
+            ret |= KEY_SELECT_END;
+        }
+        /* SelectMode $B$N;~$O8uJdA*Br!?5-9fA*Br(B    */
+        /* $B%&%#%s%I%&$r%]%C%W%@%&%s(B             */
+    } else if (buf->convmode & (NoInputModeMask|DictModeMask)) {
+#ifdef THROUGH_CONT
+        return (KEY_NULL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_NULL);
+        else 
+            return (KEY_TEXT_CHANGE);   /* dummy */
+#endif /* THROUGH_CONT */
+    } else if (buf->curseg >= buf->segnum) {
+        /* $B$"$k$$$O%+%l%s%HJ8@aHV9f$,J8@a?t$h$j(B */
+        /* $B>.$5$/$J$$;~$O%Y%k$rLD$i$9(B           */
+#ifdef THROUGH_CONT
+        return (KEY_BELL);
+#else /* THROUGH_CONT */
+        if (buf->cntrlsame)
+            return (KEY_BELL);
+        else 
+            return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+    }
+
+    if (!buf->backup) {
+        if ((buf->backup = (Xsj3cSeg *)calloc(BUNBUFSIZ,
+                sizeof(Xsj3cSeg))) == NULL) {
+            Xsj3cError("Cannot allocate for backup buffers");
+        }
+    } else { 
+        for (i = 0; i < buf->backsegnum + 1; i++) {
+            Xsj3cFreeSegment(buf->backup[i]);
+            buf->backup[i] = NULL;
+        }
+    }
+
+    switch(buf->flushchange) {
+    case ONE:
+        ret |= _Xsj3cUnConvSeg(buf, ONE, buf->flushcurlast);
+        _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+        break;
+    case ALL:
+        ret |= _Xsj3cUnConvSeg(buf, AFTER, buf->flushcurlast);
+        _Xsj3cStoreYomi(buf, buf->input[buf->curseg], 0);
+        buf->input[buf->curseg]->edit = SEG_EDIT;
+        break;
+    case OFF:
+    default:
+        break;
+    }
+
+    ret |= (KEY_TEXT_CHANGE|KEY_TEXT_FLUSH);
+    for (i = buf->curseg, j = 0; i < buf->segnum; i++, j++) {
+        buf->backup[j] = buf->input[i];
+        buf->input[i] = NULL;
+    }
+    buf->backsegnum = j;
+    Xsj3cFreeSegment(buf->input[buf->segnum]);
+    buf->input[buf->segnum] = NULL;
+    buf->segnum = buf->curseg;
+    for (i = 0; i < buf->curseg; i++)
+        if (buf->input[i]->status & SEG_CONVED)
+            buf->convedsegnum--;
+
+    if (buf->flushchange == OFF && (buf->backup[0]->edit & SEG_EDIT)
+        && (buf->backup[0]->cur < buf->backup[0]->num) 
+        && buf->backup[0]->cur) {
+        /* .FlushChangeSegment $B$,(B off $B$G%+!<%=%k$,C<$K$J$$$H$-(B */
+
+        buf->backup[0]->cur = buf->backup[0]->num;
+        if ((tmp = (unsigned char *)malloc(buf->backup[0]->size
+                * sizeof(wchar))) == NULL)
+            Xsj3cError("Cannot allocate for temporary buffer");
+        store_num = buf->backup[0]->cur;
+        _Xsj3cExtractChar(buf, buf->backup[0], tmp, buf->backup[0]->cur);
+        _Xsj3cStoreYomi(buf, buf->backup[0], 0);
+        if (!buf->input[buf->segnum]) {
+            if ((buf->input[buf->segnum]
+                    = (Xsj3cSeg)Xsj3cCreateSegment(buf)) == NULL) {
+                Xsj3cError("Failed to allocate segment.");
+            }
+        } else
+            Xsj3cClearSegment(buf, buf->input[buf->segnum]);
+        _Xsj3cInsertChar(buf, buf->input[buf->segnum], tmp, store_num);
+        _Xsj3cStoreYomi(buf, buf->input[buf->segnum], 0);
+        buf->segnum++;
+        free(tmp);
+    }
+
+    if (buf->gakusyuu && !buf->convedsegnum) 
+        _Xsj3cClearDcid(buf);
+    if (buf->dispmodechange) {
+        buf->dispmode = ((buf->segnum &&
+            buf->convedsegnum == buf->segnum) ? MODE_KANJI :
+            (buf->convedsegnum ? MODE_EDIT : buf->inputmode));
+        ret |= KEY_MODE_CHANGE;
+    }
+    return(ret);
+}
+
+/*
+ * _Xsj3cQuote()
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode/SelectMode> Set "through flag"
+ *    and input next character unconditionally.
+ */
+Xsj3cEvent
+_Xsj3cQuote(buf)
+    Xsj3cBuf        buf;
+{
+    Xsj3cEvent      ret = KEY_NULL;
+    
+    buf->throughflg = QUOTE;
+    if (buf->dispmodechange) {
+        buf->dispmode = MODE_QUOTE;
+        ret |= KEY_MODE_CHANGE;
+    }
+#ifndef THROUGH_CONT
+    if (!buf->cntrlsame)
+        ret |= KEY_TEXT_CHANGE;     /* dummy    */
+#endif /* THROUGH_CONT */
+    return (ret);
+}
+
+/*
+ * _Xsj3cBell()
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode/SelectMode> Rings bell.
+ */
+Xsj3cEvent
+_Xsj3cBell(buf)
+    Xsj3cBuf    buf;
+{
+#ifdef THROUGH_CONT
+    return (KEY_BELL);
+#else /* THROUGH_CONT */
+    if (buf->cntrlsame)
+        return (KEY_BELL);
+    else 
+        return (KEY_TEXT_CHANGE|KEY_BELL);  /* dummy */
+#endif /* THROUGH_CONT */
+}
+
+/*
+ * _Xsj3cKana()
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode/SelectMode> 
+ *   Toggle keyboard input mode between ASCII and Kana.
+ *
+ * KanaInputOnly on: Set toggle on in initializing.
+ */
+Xsj3cEvent
+_Xsj3cKana(buf)
+    Xsj3cBuf    buf;
+{
+    Xsj3cEvent  ret = KEY_NULL;
+
+    if ((buf->convmode & DictModeMask)||((buf->convmode & SelectModeMask)
+            && buf->selectstatus == SELECT_HINSI)) {
+        buf->dict->seg->n_roma = 0;
+        buf->dict->seg->n_kana = -1;
+        *buf->dict->seg->oldstr = '\0';
+        *buf->dict->seg->str = '\0';
+        buf->dict->seg->sp = buf->dict->seg->str;
+    }
+    if (buf->convmode & ~NoInputModeMask) {
+        buf->input[buf->curseg]->n_roma = 0;
+        buf->input[buf->curseg]->n_kana = -1;
+        *buf->input[buf->curseg]->oldstr = '\0';
+        *buf->input[buf->curseg]->str = '\0';
+        buf->input[buf->curseg]->sp = buf->input[buf->curseg]->str;
+    }
+    if (buf->kanaonly)
+        buf->kanaonly = OFF;
+    else 
+        buf->kanaonly = ON;
+#ifndef THROUGH_CONT
+    if (!buf->cntrlsame)
+        ret |= KEY_TEXT_CHANGE;     /* dummy    */
+#endif /* THROUGH_CONT */
+    return ret;
+}
+
+/*
+ * _Xsj3cSjrc()
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode/SelectMode> Reset customize.
+ *
+ * NextRCFile filename: Set file name to read next.
+ */
+Xsj3cEvent
+_Xsj3cSjrc(buf)
+    Xsj3cBuf            buf;
+{
+    Xsj3cEvent          ret = (KEY_TEXT_CHANGE|KEY_MODE_CHANGE);
+    register int        i;
+
+    if (buf->dispmodechange) {
+        ret |= KEY_MODE_CHANGE;
+        buf->dispmode = buf->inputmode;
+    }
+    switch(buf->convmode) {
+    case ConvedModeMask:
+        buf->n_select = 0;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, OFF);
+    case InputModeMask:
+        break;
+    case SelectModeMask:
+        buf->n_select = 0;
+        if (buf->flusheconv)
+            ret |= KEY_SELECT_END;
+        else 
+            ret |= KEY_SELECT_ABORT;
+        if (buf->candidate) 
+            Xsj3cEndCandidate(buf, OFF);
+        break;
+    case DictModeMask:
+        ret |= KEY_DICT_END;
+        break;
+    case NoInputModeMask:
+    default:
+        break;
+    }
+    if (buf->flusheconv) {
+        ret |= KEY_TEXT_FIXED;
+        if (buf->gakusyuu)
+            _Xsj3cFlushDcid(buf);
+    } else {
+        for (i = 1; i < buf->segnum + 1; i++) {
+            Xsj3cFreeSegment(buf->input[i]);
+            buf->input[i] = NULL;
+        }
+        if (buf->input[0])
+            Xsj3cClearSegment(buf, buf->input[0]);
+        buf->segnum = 0;
+        buf->curseg = 0;
+    }
+    if (buf->setnormal) {
+        free(buf->setnormal);
+        buf->setnormal = NULL;
+    }
+    if (buf->throughnext) {
+        free(buf->throughnext);
+        buf->throughnext = NULL;
+    }
+    Xsj3cRCInit(buf, NULL, NULL);
+    return ret;
+}
+
+/*
+ * _Xsj3cKill()
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode/SelectMode> Exit.
+ */
+Xsj3cEvent
+_Xsj3cKill(buf)
+    Xsj3cBuf    buf;
+{
+    /* Not Yet  */
+    return (KEY_NULL);
+}
+
+/*
+ * _Xsj3cNull()
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode/SelectMode> Does nothing.
+ */
+Xsj3cEvent
+_Xsj3cNull(buf)
+    Xsj3cBuf    buf;
+{
+    return (KEY_NULL|KEY_CONTROL);
+}
+
+/*
+ * _Xsj3cIgnore()
+ *
+ * <NoInputMode/InputMode/ConvedMode/DictMode/SelectMode> Does nothing.
+ */
+Xsj3cEvent
+_Xsj3cIgnore(buf)
+    Xsj3cBuf    buf;
+{
+    return (KEY_NULL|KEY_CONTROL);
+}