/****************************************************************************** tmk.c Version 2.00 Copyright (C) 2001 Sunomono (付:メールアドレス内の「@」を「◎」に変更した。2005-01-30) ******************************************************************************/ #include #include /* iscntrl() */ #include /* getch() */ #include "tmk.h" #define YES 1 #define NO 0 #define QWERTY 0 #define DVORAK 1 #define ASCII 0 #define TCODE 1 #define BS '\x08' #define CR '\x0d' static int input(void); static int dvorak(int); static unsigned int tcode(int); static unsigned int tcode_jf(int); static unsigned int tcode_fj(int); static unsigned int tcode_fj_sub(unsigned char*); static void erase(int); static int mode1 = ASCII; /* 入力モード1。ASCII または TCODE */ static int mode2 = DVORAK; /* 入力モード2。QWERTY または DVORAK */ /* 都合により、自前で ungetch を行なう */ static int ungetched = NO; /* ungetch されているか? */ static int ungetchedchar; /* ungetch されているキー */ static int pushed = NO; /* 全角文字の2バイト目が push されているか? */ static char pushedchar; /* その2バイト目 */ /****************************************************************************** 【関数名】 mygets() 【機 能】 エコーありの一行入力。Dvorak 配列、Tコードによる入力が可能。 【引 数】 バッファへのポインタ、バッファの大きさ('\0' の分も含む)、タブを 何カラムに展開するか。 【返り値】 入力された文字列の長さ。\0 は含まない。 行頭で CTRL+Z が押されたときは EOF が返る。 【注 意】 BS (CTRL+H) が入力された場合、直前の文字を削除する。 TAB (CTRL+T) はこの関数内で自前で展開している。 入力が長すぎて全角文字の一バイト目で終わった場合も、エコーは乱れな い。呼び出し側では、返り値が len - 1(len ではない)より小さいこと をチェックしてから先へ進むべきである。 ******************************************************************************/ int mygets(char* buf, int len, int tabstop) { int i, col, zenkaku; unsigned char c; unsigned char* s = (unsigned char*) buf; unsigned char* p; i = col = 0; while (i < len - 1 && (c = mygetch()) != '\x1a' && c != CR) { if (c == BS && i == 0) { /* 行頭で BS が打たれた場合 */ continue; } else if (c == BS && i > 0) { /* 行頭以外で BS が打たれた場合 */ if (s[i-1] == '\t') { /* 直前の文字が tab のとき */ int co = 0; /* その tab の前までのカラム数を計算する */ for (p = s; p - s < i - 1; p++) { if (*p == '\t') { do { ; } while (++co % tabstop != 0); } else { co++; } } erase(tabstop - co % tabstop); /* 何文字か戻って消す */ i--; col = co; } else { /* 直前の文字が tab 以外のとき */ for (p = s; p - s < i; p++) { /* それが半角か全角か調べる */ if (*p > 0x80 && *p < 0xa0 || *p >= 0xe0 && *p < 0xf0) { p++; zenkaku = YES; } else { zenkaku = NO; } } if (zenkaku == YES) { erase(2); i -= 2; col -= 2; /* 直前が全角文字のとき */ } else { erase(1); i--; col--; /* そうでなかったとき */ } } } else if (c == '\t') { /* tab が入力されたとき */ s[i++] = '\t'; do { putchar(' '); } while (++col % tabstop != 0); /* 何個かスペースを出力 */ } else { /* 一般の文字のとき */ putchar(s[i++] = c); col++; } } /* while */ if (c == '\x1a' && i == 0) { /* 行頭で CTRL+Z が押されたとき */ return EOF; } s[i] = '\0'; if (pushed == YES) { /* 全角文字の1バイト目で終わってしまった場合 */ pushed = NO; putchar('@'); erase(1); /* '@' はダミーの2バイト目 */ } putchar('\n'); return i; } /* mygets */ /****************************************************************************** 【関数名】 mygetch() 【機 能】 キーを一つ取得し、Tコードなどに従って変換したうえでコードを返す。 変換しなければ getch() と同じにふるまう(と思う)。エコーはしない。 【引 数】 なし。 【返り値】 ascii コード、または全角文字のコード(を一度に一バイトずつ)。 【注意0】 Ctrl+C などもそのまま返ってくる。 【注意1】 モード変更は「:」に続く一打で行なう。それらは入力とみなされない。 【注意2】 Tコードはマルチストローク入力だが、どのストロークでもモード変更が 可能である。 【注意3】 全角文字のコードは、ソースがシフト JIS ならシフト JIS, 日本語 EUC なら日本語 EUC で返る(と思う)。JIS はサポートしない。 ******************************************************************************/ unsigned char mygetch(void) { int c; unsigned int k; do { if (pushed == YES) { /* 2 バイト目が残っていた */ pushed = NO; return pushedchar; /* 場合はそれを返す */ } if ((c = input()) == -1) { /* モード変更がなされた場合 */ continue; } else if (iscntrl(c)) { /* コントロールコードの場合 */ return c; } if (mode1 == ASCII) { /* ascii モードの場合 */ return mode2 == QWERTY ? c : dvorak(c); } else { /* Tコードモードの場合 */ ungetched = YES; ungetchedchar = c; if ((k = tcode(0)) == (unsigned) -1 || k == ' ') { continue; } else if (k <= 0xff && iscntrl(k)) { /* コントロールコード */ return (unsigned char) k; } pushed = YES; pushedchar = k & 0xff; /* 下 8 ビットを push */ return (unsigned char) (k >> 8 & 0xff); /* 上 8 ビットを返す */ } } while (1); } /* mygetch0 */ /****************************************************************************** 【関数名】 input 【機 能】 次に打たれたキーの ascii コードを返す。「:」だったら、その次に 打たれたキーに応じてモードを変更する。 【引 数】 なし。 【返り値】 キーの ascii コード。モード変更が行なわれた場合に限り -1 。 【注意1】 「:」に続いて、モード変更に使われないキーが打たれた場合は「:」が 返る。これが本プログラムにおける唯一の「:」の入力法である。 【注意2】 モード変更に使うキーは SPECIAL_KEY の #define を変えれば変更 できる。 【注意3】 「:」が ungetch されていたときは、それをモード変換のキーとは みなさない。これが、自前で ungetch する理由である。 ******************************************************************************/ #define SPECIAL_KEY ':' static int input(void) { int c; if (ungetched == YES) { ungetched = NO; return ungetchedchar; } if ((c = getch()) == SPECIAL_KEY) { switch (getch()) { case 'A': case 'a': mode1 = ASCII; return -1; case 'D': case 'd': mode2 = DVORAK; return -1; case 'Q': case 'q': mode2 = QWERTY; return -1; case 'T': case 't': mode1 = TCODE; return -1; } } return c; } /* input */ /****************************************************************************** 【関数名】 dvorak() 【機 能】 Dvorak に変換。 【引 数】 ascii コード。 【返り値】 Dvorak 配列においてそのキーで入力できる文字の ascii コード。 【注意1】 アルファベットと「;」「,」「.」「/」の三段×10個のキーだけを以下 のように変更する。 ?<>PY FGCRL /,.py fgcrl AOEUI DHTNS aoeui dhtns +QJKX BMWVZ ;qjkx bmwvz シフト時 非シフト時 【注意2】 Qwerty と Dvorak とでアルファベットキーの位置が違うので、Caps Lock はうまく働かない。 ******************************************************************************/ static int dvorak(int c) { switch(c) { case '+': return 'S'; case ',': return 'w'; case '.': return 'v'; case '/': return 'z'; case ';': return 's'; case '<': return 'W'; case '>': return 'V'; case '?': return 'Z'; /* case 'A': return 'A'; */ case 'B': return 'X'; case 'C': return 'J'; case 'D': return 'E'; case 'E': return '>'; case 'F': return 'U'; case 'G': return 'I'; case 'H': return 'D'; case 'I': return 'C'; case 'J': return 'H'; case 'K': return 'T'; case 'L': return 'N'; /* case 'M': return 'M'; */ case 'N': return 'B'; case 'O': return 'R'; case 'P': return 'L'; case 'Q': return '?'; case 'R': return 'P'; case 'S': return 'O'; case 'T': return 'Y'; case 'U': return 'G'; case 'V': return 'K'; case 'W': return '<'; case 'X': return 'Q'; case 'Y': return 'F'; case 'Z': return '+'; /* case 'a': return 'a'; */ case 'b': return 'x'; case 'c': return 'j'; case 'd': return 'e'; case 'e': return '.'; case 'f': return 'u'; case 'g': return 'i'; case 'h': return 'd'; case 'i': return 'c'; case 'j': return 'h'; case 'k': return 't'; case 'l': return 'n'; /* case 'm': return 'm'; */ case 'n': return 'b'; case 'o': return 'r'; case 'p': return 'l'; case 'q': return '/'; case 'r': return 'p'; case 's': return 'o'; case 't': return 'y'; case 'u': return 'g'; case 'v': return 'k'; case 'w': return ','; case 'x': return 'q'; case 'y': return 'f'; case 'z': return ';'; default: return c; } /* switch */ } /* dvorak */ /****************************************************************************** ascii コードから(本プログラムでの)キーコードへの変換表 キーボード上の配置とキーコードとの関係は以下の通りである。ここにないキーは -1 である。Caps Lock してもキーコードは変わらない。 1 2 3 4 5 6 7 8 9 0 00 01 02 03 04 32 33 34 35 36 q w e r t y u i o p 08 09 10 11 12 40 41 42 43 44 a s d f g h j k l ; 16 17 18 19 20 48 49 50 51 52 z x c v b n m , . / 24 25 26 27 28 56 57 58 59 60 キーコードは次の方針でつけてある。 00 0 00 000 | | | | | 下 3 ビットはどのキーかを示す | 次の 2 ビットはどの段かを示す その次の 1 ビットは左手か右手かを示す 数字の段の指使いを変えたい場合、カナがロックされていてもTコードが使えるように したい場合は適当に書き換えること。 ******************************************************************************/ static char keycode[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* ^@ ^A ^B ^C ^D ^E ^F ^G ^H ^I ^J ^K ^L ^M ^N ^O */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* ^P ^Q ^R ^S ^T ^U ^V ^W ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, 59, 60, /* ' ' ! " # $ % & ' ( ) * + , - . / */ 36, 0, 1, 2, 3, 4, 32, 33, 34, 35, -1, 52, -1, -1, -1, -1, /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ -1, 16, 28, 26, 18, 10, 19, 20, 48, 42, 49, 50, 51, 57, 56, 43, /* @ A B C D E F G H I J K L M N O */ 44, 8, 11, 17, 12, 41, 27, 9, 25, 40, 24, -1, -1, -1, -1, -1, /* P Q R S T U V W X Y Z [ \ ] ^ _ */ -1, 16, 28, 26, 18, 10, 19, 20, 48, 42, 49, 50, 51, 57, 56, 43, /* ` a b c d e f g h i j k l m n o */ 44, 8, 11, 17, 12, 41, 27, 9, 25, 40, 24, -1, -1, -1, -1, -1, /* p q r s t u v w x y z { | } ~ */ /* あとは全部 -1 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; /****************************************************************************** Tコードの表 ******************************************************************************/ static unsigned char tcode_table[] = /* 左手(内枠)→左手(外枠) */ "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "ヲ●●●●" "ゥ●●●●" "ヴ●●●●" "ヂ●●●●" "ヅ●●●●" "果告策首農" "概買詳由死" "武残両在!" "風階能論増" "細古利ペゃ" "報紙館夜位" "音王放々応" "案曲情引職" "横興刺側覚" "崎白ぐ官球" "欠夏彼妻善" "財針裏居差" "従骨厚顔量" "適類御宇推" "母奥因酒伸" "ぱ●●●●" "ぴ●●●●" "ぷ●●●●" "ぺ●●●●" "ぽ●●●●" "収際太園船" "若雄査ふ賞" "指氏丸続ェ" "ぎ格次習火" "思術広門聞" "種岡結進真" "宅熟待取科" "料土活ね参" "受予切育池" "英ボ加室少" "ヒ江別考権" "及久蔵早造" "投義算半県" "込沢軍青清" "転空性使級" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "徳渡守登退" "械刊訪融雨" "帝始了極熱" "読鈴恐督況" "族丁未才返" "件友卒初慣" "宮伊求技写" "局頭配黒院" "向府富直倉" "割ぶ番望元" "ヨ誤証含%" "判規感値ギ" "済吉ゆ器昭" "説週号葉派" "休省央福毎" /* 右手(内枠)→左手(外枠) */ "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "請境系探象" "尚賀岸責漁" "舎喜幹丘糖" "布苦圧恵固" "姿絶密秘押" "盛革突温捕" "益援周域荒" "康徒景処ぜ" "邦舞雑漢緊" "衆節杉肉除" "依繊借須訳" "織父枚乱香" "譲ヘ模降走" "激干彦均又" "測血散笑弁" "酸昼炭稲湯" "貿捜異隣旧" "攻焼闘奈夕" "盤帯易速拡" "汽換延雪互" "歩回務島開" "キせ区百木" "や出タ手保" "コ山者発立" "ナ金マ和女" "給員ど代レ" "分よル千ア" "7か(トれ" "きっ日国二" "上く8え年" "相家的対歴" "付プばュ作" "内工八テ見" "九名川機チ" "サ建パ第入" "桜瀬鳥催障" "典博筋忠乳" "採謡希仏察" "君純副盟標" "犯余堀肩療" "中スもお定" "わラ東生ろ" "う4)十リ" "あこ6学月" "本さら高シ" "3と〇てる" "ーした一が" "い、の51" "。◆0・2" "ではになを" "ッ人三京ち" "ロク万方フ" "んまンつ四" "けイす電地" "業時「長み" "呼幅歓功盗" "紀破郡抗幡" "房績識属衣" "去疑ぢ綿離" "秒範核影麻" "店持町所ほ" "全じ自議明" "バ部六経動" "後間場ニ産" "問ム七住北" "行ド円小ジ" "通カ社野同" "だり−め大" "新」9子五" "事田会前そ" "海道ず西げ" "当理メウグ" "不合面政オ" "委化ビ目市" "気売下都株" /* 左手(内枠)→右手(外枠) */ "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "湖礼著移郷" "端飾郵塩群" "刷寿順危砂" "震扱片札乞" "弘痛票訴遺" "償欧努底亜" "紅傷豪維脱" "舗充喫腕暴" "輪倒操柄魚" "則存倍牛釈" "禁硝樹句礎" "絹被源願臨" "批慶渉竜併" "就駐揮丹鮮" "綱潟創背皮" "簡徴触宗植" "承章候途複" "快否歯筆里" "包納頼逃寝" "唱暮憲勉罪" "害賃整軽評" "撃折追隊角" "浴秀糸春幸" "積程断低減" "故鉱提児敷" "服声任検豊" "変審改昇芸" "限研労統役" "逆企精ざ印" "令違装然確" "爆仲茶率比" "陽構旅施曜" "ァ導認健尾" "殺負何履般" "券悪秋非便" "朱遅甲致汎" "陣鶴鹿貨絡" "眼繁誌招季" "執紹夢卸阿" "岳刑弱雲窓" "病終起路越" "常張薬防得" "寺質づ港条" "停領容玉右" "河置供試席" "勢必講愛管" "輸形助◆流" "基好味宝争" "足草築観言" "婦段衛額渋" "素兵専親寮" "毛永申袋良" "等浅頃落命" "板客師税飛" "伝庭課着坂" "欲巣茂述朗" "迫災恋脳老" "留列刻豆看" "替沼?辞献" "還更占箱矢" "帰庁昨跡ゲ" "監寄裁達芝" "竹注介具失" "ゅ修究答養" "志抜航層深" "億録赤想消" "色貸販編仕" "左態花栄ザ" "ぬ展警型誰" "根様独止堂" "図挙険ゼ波" "之末ぼ街免" "州払乗庫状" "例満津準遊" "字材過諸単" /* 右手(内枠)→右手(外枠) */ "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "佐法数郎談" "接備最急験" "記朝知ワ送" "モ資士費ィ" "無石屋解募" "美題井洋実" "宿制集安画" "セ運ツ特谷" "神び打勤ャ" "優公品語演" "昔短岩巨敗" "遠ォ将ぞ塚" "序振練念働" "耳授版効視" "示即難普辺" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "む南原駅物" "ケ式戦関男" "話座線ダ橋" "べ民ソ点遇" "期ゾ歳強係" "要設水藤有" "連鉄教力ベ" "デ現エ他度" "車成天世文" "主映書可へ" "ホ共ブ平楽" "私ゴ来信午" "村ガ製校ご" "ノ完重約各" "近外米ョ光" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "●●●●●" "洗羽個医静" "響忘討史環" "司迎華許補" "復並浦ユ冷" "担陸巻競護" "支協用表正" "先多商ハ交" "調混ポ決ミ" "組選党択体" "銀以ヌ営治" "ヤ心界意今" "再ネ〜口台" "団計夫食総" "戸ひょ価与" "身ピ勝反ズ" ; /* ascii コードの 0x21 から 0x7e までに対応する全角文字 */ static unsigned char zenkaku_table[] = " !”#$%&’()*+,−./" "0123456789:;<=>?" "@ABCDEFGHIJKLMNO" "PQRSTUVWXYZ[¥]^_" "‘abcdefghijklmno" "pqrstuvwxyz{|} ̄" ; /****************************************************************************** 【関数名】 tcode 【機 能】 二つのキーを取得し、Tコードによって全角文字一つを返す。ただし、 さらに多くのストロークによる入力モードのルーチンを呼ぶ場合もある。 【引 数】 再帰の深さ。 【返り値】 全角文字 正規の入力 (unsigned) -1 モード変更が行なわれた場合 コントロールコード どこかのストロークでそれが入力された場合 「〓」(ゲタ) tcode_jf() で、ない組み合わせを入力した場合 スペース tcode_fj() で、その読みの全角文字がなかった か、キャンセルされた場合 【注 意】 tcode() は(場合によって)tcode_jf(), tcode_fj() を呼ぶ。 tcode_jf(), tcode_fj() は tcode() を呼ぶ。 再帰の深さの上限は ******************************************************************************/ static unsigned int tcode(int depth) { unsigned char* geta = (unsigned char*) "〓"; const int DEPTH_LIM = 8; /* jf, fj の再帰の深さの上限 */ int c1, c2, a, b, n; do { if ((c1 = input()) == -1 || iscntrl(c1)) { /* 第1ストローク */ return (unsigned) c1; } if ((c2 = input()) == -1 || iscntrl(c2)) { /* 第2ストローク */ return (unsigned) c2; } if (depth >= DEPTH_LIM) { /* 再帰が深すぎる場合 */ return (unsigned) *geta << 8 | *(geta+1); /* ; /* 「◆」が出力される */ } else { if ((c1 == 'j' || c1 == 'J') && (c2 == 'f' || c2 == 'F')) { return tcode_jf(depth); /* “合字”入力の場合 */ } if ((c1 == 'f' || c1 == 'F') && (c2 == 'j' || c2 == 'J')) { return tcode_fj(depth); /* 簡易かな漢字変換 */ } } if (c2 == ' ') { /* 第2ストロークがスペースの場合 */ c1 = mode2 == QWERTY ? c1 : dvorak(c1); n = c1 - 0x20; /* 第1ストロークを全角文字化して返す */ return (unsigned) zenkaku_table[2*n] << 8 | zenkaku_table[2*n+1]; } a = keycode[c1]; /* 第1ストロークのキーコード */ b = keycode[c2]; /* 第2ストロークのキーコード */ if ((a < 0) || (b < 0)) { /* Tコードで使わない文字を入力した場合 */ a = b = 0; } n = ((b & 0x20) >> 5) * 800 + ((a & 0x20) >> 5) * 400 + \ ((b & 0x18) >> 3) * 100 + ((a & 0x18) >> 3) * 25 + \ (b & 0x07) * 5 + (a & 0x07); return (unsigned)tcode_table[2*n] << 8 | tcode_table[2*n+1]; } while (1); } /* tcode */ /* tcode_jf 用の表 */ static unsigned char jf_table[] = #include "tcode_jf.tbl" ; /****************************************************************************** 【関数名】 tcode_jf() 【機 能】 全角文字2つを入力させ、表に従って全角文字1つを返す。 【引 数】 再帰の深さ。 【返り値】 全角文字 正規の入力 「〓」(ゲタ) ない組み合わせを入力した場合 (unsigned) -1 モード変更が行なわれた場合 コントロールコード どこかのストロークでそれが入力された場合 ******************************************************************************/ static unsigned int tcode_jf(int depth) { int i; unsigned int k1, k2; unsigned char* geta = (unsigned char*) "〓"; if ((k1 = tcode(depth+1)) == (unsigned) -1 || k1 <= 0xff && iscntrl(k1)) { return k1; } if ((k2 = tcode(depth+1)) == (unsigned) -1 || k2 <= 0xff && iscntrl(k2)) { return k2; } for (i=0; jf_table[i]; i+=6) { if ((k1 >> 8 & 0xff) == jf_table[i+2] && (k1 & 0xff) == jf_table[i+3] && (k2 >> 8 & 0xff) == jf_table[i+4] && (k2 & 0xff) == jf_table[i+5]) { return (unsigned) jf_table[i] << 8 | jf_table[i+1]; } } /* return (unsigned) ' '; */ /* こちらにすればゲタは出力されない */ return (unsigned) *geta << 8 | *(geta+1); } /* tcode_jf */ /* tcode_fj 用の表 */ unsigned char fj_table[] = #include "tcode_fj.tbl" ; /****************************************************************************** 【関数名】 tcode_fj 【機 能】 簡易かな漢字変換による入力。 【引 数】 再帰の深さ。 【返り値】 全角文字 それが選ばれた場合 (unsigned) -1 モード変更が行なわれた場合 コントロールコード どこかのストロークでそれが入力された場合 スペース その読みの全角文字がなかったか、キャンセル された場合 ******************************************************************************/ #define YOMILEN 7 /* 読みの長さはこの字数まで */ static unsigned int tcode_fj(int depth) { unsigned char* p; unsigned int k[YOMILEN+1]; int i, c; printf("|"); /* 読み入力モードにはいったことの表示 */ i = 0; while ((c = input()) != ' ') { /* ' ' は読み入力の終了の印 */ if (c == -1) { /* モード変更がなされた場合 */ erase(2*i+2); return c; /* 読みを消去して帰る */ } if (i == 0 && c == BS) { /* 一文字目で BS が押された場合 */ erase(2); return ' '; /* キャンセル扱い */ } if (i > 0 && c == BS) { /* それ以外で BS が入力された場合 */ i--; erase(2); continue; /* 一文字消去 */ } if (iscntrl(c)) { /* その他のコントロールコードは無視 */ continue; } ungetched = YES; ungetchedchar = c; /* そのキーを ungetch して…… */ k[i] = tcode(depth+1); /* tcode() を呼び、結果を k[i] に格納 */ if (k[i] == ' ') { /* キャンセルだった場合 */ continue; } else if (k[i] == (unsigned) -1 || k[i] <= 0xff && iscntrl(k[i])) { erase(2*i+2); return k[i]; /* モード変更・コントロールコード */ } if (i == YOMILEN) { /* 読みの長さがいっぱいの場合 */ continue; } putchar(k[i] >> 8 & 0xff); /* ユーザが入力した読みの一字を表示 */ putchar(k[i] & 0xff); i++; } k[i] = 0U; /* 読みの終端符号 */ erase(2*i+2); /* 読みを消去 */ /* 以下、表から読みを検索 */ p = fj_table; while (*p) { for (i=0; k[i]; i++) { if ((k[i] >> 8 & 0xff) != p[2*i] || (k[i] & 0xff) != p[2*i+1]) { break; /* 一致しなかったら break */ } } if (k[i] == 0U && p[2*i] == ' ') { /* ←読みが見つかったしるし */ return tcode_fj_sub(p+2*i+1); /* あとは別関数にまかせる */ } while (*p++ != '.') { /* 次の読みの先頭へ移動 */ ; } } return (unsigned) ' '; /* その読みは表になかった */ } /* tcode_fj */ /****************************************************************************** 【関数名】 tcode_fj_sub() 【機 能】 ユーザに候補全角文字群から一文字を選ばせる。 【引 数】 (ユーザの入力した読みに対応する)候補全角文字群の先頭アドレス。 【返り値】 全角文字 それが選ばれた場合 (unsigned) -1 モード変更が行なわれた場合 スペース どれも選ばれなかった場合 【注 意】 ここではコントロールコードの入力はできないようにした。もし許すと、 “キャンセル”といったつもりで BS を打って、その前の確定した一文字 を消してしまうことがありえるからである。 ******************************************************************************/ static unsigned int tcode_fj_sub(unsigned char* p) { unsigned char* q = p; int c, i, knum; while (1) { /* まずは候補漢字を表示する */ printf("%s", q == p ? "【" : "《"); /* 左端のカッコを表示 */ for (i=0; i<10; i++) { if (q[2*i] == '.') { /* 候補漢字の終わりならば */ break; /* for ループを抜ける */ } printf("%s%c%c", i==5 ? " " : "", q[2*i], q[2*i+1]); } knum = i; /* 表示された候補漢字の数 */ for ( ; i<10; i++) { printf("%s・", i==5 ? " " : ""); /* 残りは「・」を表示 */ } printf("%s", knum == 10 && *(q+20) != '.' ? "》" : "】"); /* 右端のカッコを表示 */ /* 以下でユーザが選択する */ while (1) { if ((c = input()) == -1) { /* iscntrl(c) はチェックせず */ erase(26); return c; } else if (c == 'a' || c == 'A') { /* 一文字目を選択 */ erase(26); return (unsigned) *q << 8 | *(q+1); } else if (c == 's' || c == 'S') { /* 二文字目を選択 */ if (knum >= 2) { erase(26); return (unsigned) *(q+2) << 8 | *(q+3); } } else if (c == 'd' || c == 'D') { /* 三文字目を選択 */ if (knum >= 3) { erase(26); return (unsigned) *(q+4) << 8 | *(q+5); } } else if (c == 'f' || c == 'F') { /* 四文字目を選択 */ if (knum >= 4) { erase(26); return (unsigned) *(q+6) << 8 | *(q+7); } } else if (c == 'g' || c == 'G') { /* 五文字目を選択 */ if (knum >= 5) { erase(26); return (unsigned) *(q+8) << 8 | *(q+9); } } else if (c == 'h' || c == 'H') { /* 六文字目を選択 */ if (knum >= 6) { erase(26); return (unsigned) *(q+10) << 8 | *(q+11); } } else if (c == 'j' || c == 'J') { /* 七文字目を選択 */ if (knum >= 7) { erase(26); return (unsigned) *(q+12) << 8 | *(q+13); } } else if (c == 'k' || c == 'K') { /* 八文字目を選択 */ if (knum >= 8) { erase(26); return (unsigned) *(q+14) << 8 | *(q+15); } } else if (c == 'l' || c == 'L') { /* 九文字目を選択 */ if (knum >= 9) { erase(26); return (unsigned) *(q+16) << 8 | *(q+17); } } else if (c == ';' || c == '+') { /* 十文字目を選択 */ if (knum >= 10) { erase(26); return (unsigned) *(q+18) << 8 | *(q+19); } } else if (c == 'e' || c == 'E') { /* 十文字だけ戻る */ if (q > p) { q -= 20; break; } } else if (c == 'i' || c == 'I') { /* 十文字だけ進む */ if (knum == 10 && *(q+20) != '.') { q += 20; break; } } else if (c == ' ') { /* ユーザが取りやめた場合 */ erase(26); return ' '; } } /* while */ erase(26); /* 次の候補漢字群を表示するために現在のを消す */ } /* while */ } /* tcode_fj_sub */ /****************************************************************************** 【関数名】 erase() 【機 能】 バックしながら文字を消去する。 【引 数】 何文字分バックするか。(全角文字は2字と数える。) 【返り値】 なし。 ******************************************************************************/ static void erase(int n) { while (n--) { printf("%c %c", BS, BS); } } /* erase */ #if 0 unsigned int tcode_fj_sub(unsigned char* p) { unsigned char* q = p; int i; do { int knum = 0; /* まずは候補漢字を表示する */ printf("【"); /* 左端のカッコを表示 */ printf("%s", q == p ? " " : "←"); /* 左端のカッコを表示 */ for (i=0; i<8; i++) { if (q[2*i] == '.') { /* 候補漢字の終わりならば */ break; /* for ループを抜ける */ } printf("%s%c%c", i==4 ? " " : "", q[2*i], q[2*i+1]); } knum = i; /* 表示された候補漢字の数 */ for ( ; i<8; i++) { printf("%s・", i==4 ? " " : ""); /* 残りは「・」を表示 */ } printf("%s", knum == 8 && *(q+16) != '.' ? "→" : " "); printf("】"); /* 右端のカッコを表示 */ /* 以下、ユーザが選択する */ do { int c; if ((c = input()) == -1 || iscntrl(c)) { erase(26); return c; } else if (c == 'a' || c == 'A') { /* 一文字目を選択 */ erase(26); return (unsigned) *q << 8 | *(q+1); } else if (c == 's' || c == 'S') { /* 二文字目を選択 */ if (knum >= 2) { erase(26); return (unsigned) *(q+2) << 8 | *(q+3); } } else if (c == 'd' || c == 'D') { /* 三文字目を選択 */ if (knum >= 3) { erase(26); return (unsigned) *(q+4) << 8 | *(q+5); } } else if (c == 'f' || c == 'F') { /* 四文字目を選択 */ if (knum >= 4) { erase(26); return (unsigned) *(q+6) << 8 | *(q+7); } } else if (c == 'j' || c == 'J') { /* 五文字目を選択 */ if (knum >= 5) { erase(26); return (unsigned) *(q+8) << 8 | *(q+9); } } else if (c == 'k' || c == 'K') { /* 六文字目を選択 */ if (knum >= 6) { erase(26); return (unsigned) *(q+10) << 8 | *(q+11); } } else if (c == 'l' || c == 'L') { /* 七文字目を選択 */ if (knum >= 7) { erase(26); return (unsigned) *(q+12) << 8 | *(q+13); } } else if (c == ';' || c == '+') { /* 八文字目を選択 */ if (knum >= 8) { erase(26); return (unsigned) *(q+14) << 8 | *(q+15); } } else if (c == 'e' || c == 'E') { /* 8文字だけ戻る */ if (q > p) { q -= 16; break; } } else if (c == 'i' || c == 'I') { /* 8文字だけ進む */ if (knum == 8 && *(q+16) != '.') { q += 16; break; } } else if (c == ' ') { /* 中止 */ erase(26); return -1; } } while (1); erase(26); /* 次の候補漢字を印字するため現在のを消す */ } while (1); } #endif #if 0 unsigned int tcode_fj_sub(unsigned char* p) { unsigned char* q = p; int i; do { int knum; for (i=0; i<8; i++) { if (q[2*i] == '.') { /* 候補漢字の終わりならば */ break; /* for ループを抜ける */ } } knum = i; /* まずは候補漢字を表示する */ printf("【"); /* 左端のカッコを表示 */ for (i=0; i<4; i++) { if (i < knum) { printf("%c%c", q[2*i], q[2*i+1]); } else { printf("・"); } } printf("%s", knum == 8 && *(q+16) != '.' ? "→" : " "); printf("%s", q == p ? " " : "←"); /* 左端のカッコを表示 */ for (i=4; i<8; i++) { if (i < knum) { printf("%c%c", q[2*i], q[2*i+1]); } else { printf("・"); } } printf("】"); /* 以下、ユーザが選択する */ do { int c; if ((c = input()) == -1 || iscntrl(c)) { erase(24); return c; } else if (c == 'a' || c == 'A') { /* 一文字目を選択 */ erase(24); return (unsigned) *q << 8 | *(q+1); } else if (c == 's' || c == 'S') { /* 二文字目を選択 */ if (knum >= 2) { erase(24); return (unsigned) *(q+2) << 8 | *(q+3); } } else if (c == 'd' || c == 'D') { /* 三文字目を選択 */ if (knum >= 3) { erase(24); return (unsigned) *(q+4) << 8 | *(q+5); } } else if (c == 'f' || c == 'F') { /* 四文字目を選択 */ if (knum >= 4) { erase(24); return (unsigned) *(q+6) << 8 | *(q+7); } } else if (c == 'j' || c == 'J') { /* 五文字目を選択 */ if (knum >= 5) { erase(24); return (unsigned) *(q+8) << 8 | *(q+9); } } else if (c == 'k' || c == 'K') { /* 六文字目を選択 */ if (knum >= 6) { erase(24); return (unsigned) *(q+10) << 8 | *(q+11); } } else if (c == 'l' || c == 'L') { /* 七文字目を選択 */ if (knum >= 7) { erase(24); return (unsigned) *(q+12) << 8 | *(q+13); } } else if (c == ';' || c == '+') { /* 八文字目を選択 */ if (knum >= 8) { erase(24); return (unsigned) *(q+14) << 8 | *(q+15); } } else if (c == 'h' || c == 'H') { /* 八文字だけ戻る */ if (q > p) { q -= 16; break; } } else if (c == 'g' || c == 'G') { /* 十文字だけ進む */ if (knum == 8 && *(q+16) != '.') { q += 16; break; } } else if (c == ' ') { /* 中止 */ erase(24); return -1; } } while (1); erase(24); /* 次の候補漢字を印字するため現在のを消す */ } while (1); } #endif /* 〓 */ /****************************************************************************** 【関数名】 【機 能】 【引 数】 【返り値】 【注 意】 ******************************************************************************/