             怪ドキュメント 「skkinput 狂想曲」

0. 概要

   これを読めば skkinput の構造が分かるかもしれない…。「これを読んで分か
る人は読まなくても大丈夫だ」という定理はまだ証明されていないので、読んで
無駄じゃないかもしれません。(^^)

(登場人物)
たたり      ：skkinput の開発に日夜戦い続ける学生。研究活動はどうしたとい
              うツッコミが彼の当面の最大の敵である。
ファリー    ：謎の妖精。どうやら開発を手伝ってくれるらしい。
ロクサブロー：謎のソフトウェアエンジニア。神出鬼没。
若葉        ：skkinput の開発に付き合ってくれる仲間の一人。詳細は…某デー
              タベースで…。
師匠        ：我が敬愛する師匠。あらゆるコードの生成の中でもっともスパゲッ
              ティソースの生成を得手とする…というのは嘘である。
モアイ      ：謎の物体。大魔王と同一の存在であるという説あり。
徹夜の女神  ：？

1. イントロダクション

た「skkinput もリリースまであと間近だ…」
た「そう言えば、ここの辺りのコードはまだ実装されていなかったっけ…」
た「おや？ こんな時間にメールが…『これから停電します。WS の電源を落とし
    ておいて下さい』？！」
た「まずい…まず過ぎる…変更点を…」
  (ブチン！ 電気が消え、部屋は真っ暗になる)
た「(終わった…。終わってしまった…。これでファイルシステムまで壊れてい
    た日には何も残らない…)」
た「(長かったようで短かったコードの寿命。もう安らかに眠ってくれと言うしか
    無いのか…)」
フ「あいたたたたた…！」
た「？」
フ「痛いって言ってんの！ どきなさいっつーの！」
た「！」
フ「全く…。キーボードの上に頭置くの止めてくれる？」
   (WorkStation のキーボードの上に変なものが立っている)
た「ぬ、ぬいぐるみ…。ぬいぐるみがしゃべっている…。これがコーディングの
    し過ぎによる幻覚っていう奴なのか…はじめて見る…」
   (ぱちん！ 平手打ちの音)
フ「ちょっと！ 何が幻覚ですって！ こっちは危うく死にかけたんですからね！」
た「痛い？ 夢じゃない？！」
フ「ふーん。あんた見なれない格好ね…。名前は何って言うの？」
た「たたりだけど…」
フ「やっぱし変な名前。そうそう、あたしは妖精のファリー」
た「それはともかく…一体この変でわけわかめなこの状況は一体…」
フ「変でわけわかめなのはあんたの方なの！ あたし達が見えないのはあんた達
    が変なことばっかりしてるからなのよ！」
た「う…」
フ「ほら…そこの Netscape！ どこの Web Page を見ていたのかしらねぇ…」
た「電源の落ちた WS をどうやって操作しているんだ、お前は…」
フ「そんなの簡単じゃない。テレパシー通信よ」
た「そんなものを使うなーーーーー！！！！」
ロ「おやおや、おやおや。これはちょっと遅かったですか…」
フ「ちょっと、ロクサブロー！ 遅いわよ！ 御陰でえらい目にあったじゃない
    の！」
ロ「それはそれはすみません。おや、この人がリリースの迷い人ですか」
た「？！」
ロ「いえ。昨夜の停電案内から、この WS の前に座っている人間のコードが炸裂す
    ることが分かったのです」
フ「ふーん。あんた、たたりが暴走するのが分かってたんだ…」
た「分かってたんなら、前もって忠告してくれ！！！！！」
ロ「く…首を締めないで下さい…」
ロ「と、ともかく、バックアップも取れてないようですし、あきらめて一からコー
    ドを書くのが一番よろしいでしょう。それでは…私はこれで…」
た「それで帰るつもりなのか…(-_-)」
ロ「いやですね。ただの冗談ですよ。そのためにファリーをここに呼んでおいたん
    じゃないですか」
フ「どうして、それであたしが呼ばれなくちゃならないのよ！」
ロ「この哀れな人のプログラムを復旧し、無事リリースしてあげるためです」
フ「どうして、あたしがそんなこと！ あんたがやれば良いじゃない」
ロ「ソフトウェアエンジニアたる私は色々と忙しいのですよ。あなた、暇でしょ
    う？」
フ「ロクサブロー！ あんた、喧嘩売ってるの？」
た「ちょっと待った！ もしかして、コードを復旧してリリースできるのか？」
ロ「それはそこの妖精ファリー次第ですよ」
た「ファリー！」
フ「分かった、分かったわよ。だから、そんな目で見るのは止めてよ」
た「助かったぜ、ファリー！ じゃあ、早速さっきまでのコードを…」
フ「ちょっと、そんなこと、あたしに出来るわけないじゃない」
た「それじゃあ、お前、全然役立たずじゃないか…」
フ「殴るわよ！」
ロ「まあまあ…」
た「頼む。もう、あんたしか頼りに出来ない…」
ロ「この地の何処か、バックアップテープというものが…」
た「それで restore しろとでも？ (-_-)」
ロ「何を隠そう、今隠そう…ここにそのバックアップテープが…」
た「(-_-#)」
ロ「本当はこれを鍋に入れてから旨味、胡椒、デミグラスソースを加えて３日は煮
    こまないといけないところなのですが…」
た「な…何故そんな必要が…」
ロ「…出来たものが、こちらにあります」
た「あるんやないかい！」
ロ「これをテープストリーマに入れると、見事壊れます」
た「壊してどうする！」
ロ「これはこれはすみません。ソフトウェアエンジニアたるものセキュリティホー
    ルには常に気をつかうべきかと…」
た「何の関係があるんだ、一体…(-_-#)」
フ「ああ、もう！ 話が先に進まないじゃない！ どうすんのよ！」
ロ「この地の何処か…この壊れたテープストリーマの代わりに、このテープの表面
    を撫でるだけでコードを取り出すことの出来るアイテムが存在すると聞き及び
    ます。README と man page をもって、そのアイテムを用いる時、見事リリース
    は叶うでしょう」
た・フ「(壊したのはお前だろうが…)」
た「いや…その無事な方のテープだけでも置いていってくれれば…」
ロ「それでは私はこれで」
た「おい…」
フ「そうそう、まず、研究室を出てドキュメント作成を手伝ってくれる仲間を集める
    ことをおすすめします」
フ「何か嫌な予感…。仲間がいないと書けないような代物なの？」
ロ「書いた本人だけでは、何が分からなくて何が分かることなのか区別ができま
    せんから」
た「成程。一理あるな…じゃなくて！」
ロ「それでは私はこれで…」
た「…あのテープさえあれば隣の研究室で restore すれば仕舞いじゃないのか…」
フ「駄目よ、あのテープもデミグラスソース漬けの運命なんだから」
た「………どういう人間なんだ、一体」

フ「で、仲間集めはどうするの？」
た「そうだな…。その辺で出逢った人に声をかけてみるか」
フ「ずいぶん…適当なのね…」

た「しかし、仲間になってくれる人を探すといってもこの時間に何処を探せば…」
少女「あの…少々よろしいでしょうか」
た「？ どうぞ」
少「このソフトなんですけど、どうやって使えばよろしいんでしょうか？」
フ「…でも、これってメニューに書いてある通りに操作すれば良いだけなんじゃ…」
少「それがどこをどう触ってもこうなってしまうんです」
フ「…すっごい機械音痴」
少「ぐさっ」
た「おい！」
フ「ああ、御免、御免。ええと、そうね…やりたいことはこの紙に書かれている
    わけね…」
た「どれどれ…」
フ「ああ、これなら…」
少「御存知なんですか？」
フ「ええ…ここをこうやって、次にこうやって…そいでこうすればこうなる
    から…この繰り返しで大丈夫よ」 
た「(やけに指示代名詞が多いのは作者の実力の無さか…)」
少「ええと…はい。分かりました」
少「ああ。こんな親切な方にめぐり逢えるなんて、私なんて幸せ者なのでしょう」
フ「いやぁねぇ。大袈裟よ」
少「あ、申し遅れましたが…私、紅 若葉と申します」
フ「私は妖精のファリー」
た「俺はたたり」
若「私で何か力になれることがあれば、何でもおっしゃって下さい」
フ「別にいいわよ」
若「いえ。兄も受けた御恩は命にかえても御返しするようそう申しております」
フ「命にかえてもって…大袈裟ね。本当気持だけで十分よ」
若「そ、そうですか。それでは重ね重ね大変有難うございました」
フ「いえいえ」
若「それでは、私はこれで…」
フ「あ！ 違うわよ！ いきなりそこを触っちゃ駄目だってば」
若「えっと…す、すみません…」
た「今のはちょっと凄かったな…」
フ「大丈夫なのかしら…」

た「こんなところに人がいるんだろうか…」
フ「何だか暗いところねぇ…」
フ「！ でたぁ〜〜〜〜〜〜！！」
青年「でたぁ〜〜〜〜〜〜！！」
た「………」
青「しまった！ 部屋にいればこんなところで大魔王に遭遇することもなかっ
    たというのに」
た「いや、その…」
青「ここは三十六計逃げるにしかず！ では、さらばじゃ！」
た「なるほど…師匠はホテルモードなわけか…」

   (ドシン！ 何かにぶつかる音)
た「あいてて…すみません。前を見てませんでした」
青年「なんだと！ 貴様はこのわたしにぶつかっておきながら、前を見ていな
    かっただけという許し難い言い訳で逃げるつもりなのか！」
た「だから、すみません…」
青「いや、許せんな」
フ「…あんた、モアイじゃない！」
た「(こら、ファリー…。知らないふりをしてれば、いつかは向こうから去っ
    てってくれるのに、何を認知してるんだ…)」
フ「(そんなこと言ったって…だいたい、そういう発想ってのは後向きよ)」
モ「このわたしを前に内緒話か！ いい度胸だな」
た「…。というわけで、さようなら〜(全力ダッシュ)」
モ「あ、待て逃げるな！…」
た「待てと言われて待つわけがない！」
モ「貴様、次に会った時には覚悟しているがいい」
た「忘れる！ さよならぁ〜」

フ「で、一体誰を仲間にするわけ？」
た「何で3人しかいないんだぁ〜〜〜！！！ これじゃ、選択肢が無いじゃな
    いかぁ〜〜〜！」
フ「ま、しょうがないか。じゃあ、頼みに行くわよ…」

フ「あの娘だったら、多分まだこのあたりにいるんじゃない？」
フ「でも、あの娘、仲間にして役に立つの？」
た「そういえば、すごい機械音痴だったな…でも、礼儀正しかったし」
フ「あのね…。あ、いた…」
若「あ、あなた方は…。私に何か御用でしょうか？」
た「かくかくしかじかで君に仲間になってもらいたいんだ！ って、かくか
    くしかじかって何や〜！」
若「私を御仲間に？」
た「ああ」
若「私で良ければ喜んで」
フ「言っておくけどきついわよ」
た「おい、ファリー？」
フ「バグがうようよあるようなコードと戦うんだからね。もしかしたら、と
    んでも無く辛かったり、面倒だったり、下手したら夢の中まで出てくる
    かもしれないわよ」
若「いえ。それでこそ先程受けた御恩を御返し出来るというものです」
フ「しまった…やびへびだった…」
若「では、私少し作業が残ってますので、30分程御待ち下さい」
フ「あ…」
た「おい…」
  (しかし、彼女の作業が 30 分で終わるはずもなかったのであった…)

師「出たぁ〜！」
た「はいはい。じゃあ、手伝ってもらいましょうか」
フ「あの…『かくかくしかじかで…』は要らないわけ？」
た「言っても『出たぁ〜！』以外は言わないから大丈夫」
フ「そういう問題なわけ？」
師「所詮大魔王の前にはたった一人の人間の力なぞ塵芥のようなものだと言
    うのか！」
フ「何か言ってるみたいだけど？」
た「いつものことだから気にしなくても大丈夫さ」

フ「あんなの仲間にするの？」
た「俺の意志じゃない！」
フ「じゃあ、何なのよ」
た「意志だよ、大いなるな」
フ「何それ？」
た「いや…その…」
モ「ふっ、見付けたぞ！ さぁ、先程の続きを始めようじゃないか！」
た「…………」
    (その後、モアイは何を言っても部屋まで付いてくるのであった)

た「若葉、師匠、モアイ… skkinput の開発につきあってくれる仲間達だ」
若「若葉と申します。よろしく御願い致します」
モ「わたしだ！！！」
師「全く何でこんなことになったのかな…」
た「さて、仲間も集まったことだし、パーティーの名前を決めなきゃな」
若「うーん。どのようなのがぴったりくるでしょうか？」
モ「ワシに決めさせるのじゃ！！！」
た「あー、ここは開発者の権限で、俺が決める！」
師「じゃあ、早く決めて下さいよ」
た「うーん。よし、決めた！ このパーティーの名前は…」
フ「限りなくローセンスだわ…」
た「って最後まで言ってないぞ…(-_-)」
た「(気をとりなおして)必殺デバグ人だ！」
   (一同、硬直する…)
モ「何だこの名称は全く…(ぶつ、ぶつ)」
師「で、のさばるバグは許さないんですか？」
フ「ま…まあ…本人が気に入っているというんだから…」
た「何と言われようと、俺は気に入っているんだ。これで行くぞ」

ロ「おやおや、何とか仲間集めは完了したようですね」
フ「まあね。でも役に立ちそうなのがいないんだわ、これが」
モ「それはワシを除いての話だな！」
ロ「まあまあ…見れば、なかなか面白そうなメンバーが集まっているじゃない
    ですか」
若「御褒めにあずかりまして、光栄です」
師「褒められているわきゃないでしょうが！」
た「俺は楽しいコーディング＆ドキュメンテーションを目指していたからな…」
た「それで、俺達は一体これからどうすればいいんだ？」

ロ「そうですね。まずは用語の定義をされるのがよろしいでしょう」
た「そうか…やはり、何を書くにも用語の定義が出来ていなければ話にならない
    か…」
ロ「全てはその後ですね」

(謎の声)「はははははははは！！！！ そうは行かんぞ！」

た「何だ！」
フ「何よ、何よ！…って何を奇妙な声を上げてるのよ、モアイ！」
モ「くくくくく…そうそう簡単にリリースされてしまっては面白くないではな
    いか！ ここは一つ私が徹底的に邪魔してあげよう！」

(ナレーション)「いきなりの仲間の離反にたたりはどう立ち向かうというのか！
    以下、次号…」

フ「…って全然、ソースコードの解説になっていないわよ！ どうすんのよ、
    たたり！」
た「どうするって…」
フ「もう、はっきりしないわね！ 解説する気があるの？ どうなの？」
た「勿論あるさ。だけど、あれを止められるのか？」
モ「がははははははは………！！！」
フ「う…ちょっと無理かも…」
た「だろ？ 取り敢えず、ほっておいて先に進むか…そうすれば解説できるか
    な…」
た「よし…必殺デバグ人、出発だ！」
師「やっと出発ですか。いつまでこんな茶番をしているのかと思いましたよ」
若「こういう時って、ファンファーレが欲しいですよね」
フ「ああ…この名前、やっぱりセンス悪いわ…」

ロ「突然の停電に振り回されてめぐりあった彼ら…はてさて、一体、どんなプロ
    グラムが出来上がることやら」

2. 用語説明

た「で…一体何を説明すればいいんだ？」
楊「…まだ考えてなかったのですか…」
フ「…これ以上、登場人物増やすの止めてくれない？ あたしの出番が減るじゃ
    ない」
た「誰に話しているんだ…お前は…」
ロ「おやおや、まだ始められてないのですか」
フ「ロクサブロー！」
た「どうして、ここに？ さっき帰ったばかりじゃなかったのか？」
ロ「いえいえ、みなさんがあまりにのんびりしているようですので、一つ忠告を
    と思いまして」
フ「って何よ？」
ロ「無事に復旧できる可能性があるのはこの停電の最中だけなのですよ」
フ「どうして、そんな大事なこと黙ってるのよ！」
モ「それは面白い話を聞かせてもらった！ おおいに活用せねばな！」
た「お前…もう帰れ…」
ロ「おやおや、話しませんでしたか？」
フ「聞いてないわよ！ …たたり、何でもいいからさっさと始めなさい！」
若「あ…そんな無理に急がなくても…」

・変換サーバ
    日本語入力の機能を提供するサーバ。プロトコルとしては、XIM(X11R6),
  Ximp, Kinput, Kinput2, jinput などが存在する。

・変換クライアント
    XIM(X11R6),Ximp, Kinput2 プロトコルなどを利用して変換サーバに日本
  語入力のサービスを要求するクライアント。

・フロントエンドメソッド
    変換サーバへとキーイベントを直接に送り届ける方法。変換クライアント
  を経由しない。(参考:Ximp3_3.doc)

・バックエンド
    変換クライアントを通って、キーイベントが届けられる方法。必ず変換クライ
  アントをイベントが経由するためキーイベントの同期の問題が発生しない。

・Kinput2 Protocol
    Makoto Ishisone 様が提唱したプロトコル。kinput2 で用いられている。

  Kinput2 Protocol をサポートした変換クライアントとしては、kterm や tgif
  などが挙げられる。

・X Input Method Protocol
    X Window System の標準の多国語入力のためのプロトコルである。X11R5, 
  X11R6 標準の2種類がある。skkinput では X11R6 標準の X Input Method
  プロトコルをサポートしている。

・Ximp Protocol
   X11R5 当時に存在した X Server の多国語入力のためのプロトコル。
 (X11R5 標準のプロトコルは Xsi プロトコルであり、Xwnmo はこのプロトコ
  ルをサポートしている。普通は Xsi プロトコルをサポートしたサーバを作
  ることが多い。)

・OverTheSpot/OffTheSpot/Root Window Style
    変換サーバが変換クライアントへ日本語入力サービスを行う時にどのような
  形式で日本語入力の方法を提案するか。
    OverTheSpot Window Style の場合には変換クライアントの日本語を入力しよ
  うとしている位置にウィンドウを配置し、その場所で日本語入力を行わせる。
  (実際に変換クライアントの中で日本語入力を行っているように扱うことが
   できるのが OnTheSpot である。OverTheSpot は変換クライアントの上に変
   換サーバが日本語入力窓を作るだけである)
    OffTheSpot Window Style では変換クライアントの指定した領域(Window)で
  日本語入力を行う。MSDOS で動いていた ATOK7 などを考えると分かり易い。
  例えば、画面の一番下に日本語を入力する行ができる。
    Root Window Style では Root Window に新しく Window を作って、その
  Window で日本語を入力することになる。

・一行入力方式/その場入力方式
    変換サーバが変換クライアントへ日本語入力サービスを行う時にどのような
  形式で日本語入力の方法を提案するか。
    一行入力方式は、一行エディタの形で日本語を入力し明示的に送信キーを押
  すことにより日本語を変換クライアントへと入力することができる。
    その場入力方式は、確定した順に勝手に変換クライアントへと日本語を送る
  入力方式である。

3. 実行の流れ…概略

3.1 ソースの司る機能…

た「どのソースが何をしているか…多少は考えて書いたから、その説明をしよう」
フ「ちょっとは考えてるんだ。意外ねぇ」
た「(きちんと綺麗に行かなかったという事実の前には何も言えないか…)」

main.c:
  main 関数が存在。skkinput の初期化や終了処理を行うよう手配する。イベント
ループもこの中に存在する。各種プロトコルに対応するウィジェットを作成するの
もこの中である。

Kinput.c:
  Kinput/Kinput2 Protocol の変換サーバとしての処理を行う。中身は 
KinputWidget を define している。

SeparateWin.c:
  Root Window Style を実現する。SeparateWinWidget を define している。

OverWin.c:
  OverTheSpot Window Style を実現する。OverthespotWinWidget を define 
している。

OffWin.c:
  OffTheSpot Window Style を実現する。OffthespotWinWidget を define 
している。 

cstyle.c:
  OverTheSpot/OffTheSpot/Root Window Style に共通の処理がここにはき出
されている。キー入力後の処理を行っている。 

skksoc.c:
  Socket を利用して、skkserv と TCP/IP 通信を行う。

skksvect.c:
  skkserv からの変換結果及びユーザ辞書の探索結果を候補ごとに分けて管理する
ために用いられる関数が入っている。

skkldic.c:
  ユーザ辞書の探索や更新、record ファイルの更新を司る。

skkldrec.c:
  変換結果を記憶している。例えば、「わかば」を変換した結果「若葉」を選
んだ場合には、「わかば/若葉」の組み合わせが記憶されている。この結果は、
ユーザ辞書の登録の順序や completion、purge などに利用される。辞書のセー
ブを行うとクリアされる。

skkconfig.c:
  dot.skkinput を解析して、skkinput がどういう動作をすべきか決定する。
(グローバル変数に適切な値を入れる)

parseStr.c:
  dot.skkinput の解析の途中で呼ばれる。"" で囲まれた部分の解釈を行う。
また、XIM プロトコルの変換開始キーを調べるために呼ばれる。

keymap.c:
  どのキーが押された時にどの機能を実行すべきかを司る。キーを押された時に
テーブルを引いて、そのキーに割り当てられている機能番号を返すことが主たる
機能。

ctext.c:
  内部漢字コードの文字列を Compound Text の文字列に変換することを司る。
Kinput/Kinput2/XIM のいずれも変換クライアントへは Compound Text の形で
日本語を送ることになっている。Compound Text 自体は日本語(JISX0208など)
以外にも中国語、韓国語…を扱うことができる。Compound Text の詳細は、X
Window System のソースについている ctext.PS を参照のこと。

skkel.c:
  skk らしい動作をするためのメイン。skk.el に相当する機能がこの中で実現
されている。従って、j-henkan とか j-start-henkan という skk.el の中で定
義されていた lisp の関数が同じように定義されている。
  各キーに割り当てられた機能番号はこの関数のどれを実行するかを意味してい
る。

skkmarker.c:
  emacs の buffer emulation のために marker を emulation する。marker 
の作成、marker の移動、marker の削除などを行う。

skkmbuf.c:
  minibuffer を emulation する。minibuffer も通常の buffer も同じように
管理されているが、どの buffer の子供であるか等初期化を行う必要があるた
め。また、j-read-string などの関数もここで実現されている。

draw.c:
  OverTheSpot/OffTheSpot/Root Style Window のいずれもが利用する描画関
数などをここにはき出している。

MyDispatch.c:
  X event を監視し、適切な Widget へ X event を投げる(XSendEventする)
操作を行う。

MyError.c:
  X error event を無効化したり有効にしたりする。また、debug のためには
どの場所で X error event が発生したのかを知りたい時があり、その時に
X error event handler を奪って無限ループにするなどの処理を行う。

lispparse.c:
  skkinput-lisp の字句/文法解析を行う。

lispeval.c:
  skkinput-lisp を実行する。

HistMgr.c:
  一行入力方式の場合に以前に入力した文字列を記憶するのに用いられる。また、
以前かなモードであったか英数字入力モードであったか等を覚え管理する。変
換クライアントの Window ID に対して、これらの情報を残している。

FontMgr.c:
  skkinput が利用しているフォントを管理する。skkinput が利用可能なフォン
トであるかどうかを判断したり、不要になったフォントを解放したりする。

kanji.c:
  skkinput の内部コードと JIS や EUC, MS漢字コードとの変換や比較、内部
コードの文字列操作(strlen, strcpy, strcmp に相当する関数)が用意されて
いる。

Canvas.c:
  skkinput の buffer に書かれた文字を表示するのに用いられる。

WmcloseShell.c:
  Root Window Style の Window を作る時に利用される。Window Manager からの
WM_CLOSE メッセージを受けとれるようになっている。

CliMsg.c:
  X Client Message Event を受けると、callback を呼ぶだけの Widget の定
義。X Client Message Event を監視するのが目的。各種プロトコルにおいて
メッセージは X Client Message Event で送られるのが主であるから、
(XtAddEventHandler を使うべきだったかも)

Ximp.c:
  Ximp プロトコルの変換サーバとして機能するための処理を行う。
XimpWidget を作る。

Xim.c:
  X11R6 標準の X Input Method プロトコルの変換サーバとして機能するため
の処理を行う。XimWidget を作る。

im*.c:
  X11R6 標準の X Input Method プロトコルの変換サーバとして機能するため
の処理を行う。Xim.c から呼び出され、各種メッセージに対して様々な処理を
行う。これは基本的に kinput2 のソースから借りてある。skkinput と合わせ
るためにところどころいじってあるが。

XimOutBuf.c:
  X11R6 標準の X Input Method Protocol で変換クライアントからの接続要
求を受けた時、変換クライアントへ送るメッセージバッファを管理する。

3.2 実行の流れ…概略

若「次は、実行の流れですよね」
た「そうだな…。先に説明したソースの間での処理の流れは…かなりおおまかだけ
    ど次のようになっている」

   main.c ---> skkconfig.c ( <---> parseStr.c, keymap.c ) 
         
          ---> Kinput.c ---> Xim.c ---> Ximp.c --->「X event 待ち」
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
          各種プロトコルを司る Widget の初期化、realize。

   X event が来た場合には、
          ---> MyDispatch.c ---> Kinput.c, Xim.c, Ximp.c
                                 OverWin.c, OffWin.c, SeparateWin.c
                            ^^^^
                          X event が適当な Widget へ dispatch される。

          ---> main.c (再度、X event 待ち)

   signal( C-c など )が来た場合には、

          ---> main.c ---> skkldic.c (辞書のセーブ) (<---> skkldrec.c)
          ---> 終了

   変換サーバ宛に key press event が来た場合など、

          ---> main.c ---> OverWin.c ---> cstyle.c ( <---> keymap.c )
                    (XtDispatch)
          ---> skkel.c
          ---> skksoc.c, skksvect.c, skkmbuf.c など
              (変換動作があれば、soc や vect へ。minibuffer が作られれば
               skkmbuf へ)
          ---> cstyle.c
          ---> draw.c

た「skkinput は C で書かれているから当然 main から実行される
    わけだが…その main から呼び出される処理の流れは次のようになってい
    る」

      (1) 初期設定ファイルの解析
      (2) オプションの解析
      (3) 各種プロトコルを取り扱う Widget の作成。
      (4) イベント待ちループ。

フ「ふーん。そうなんだ。で、(1) の中はどうなってるの？」
た「具体的には、dot.skkinput の解析ということになっている」
    (勿論、config file を変更したいという人もいるだろうから、(2) の中
    のオプションの解析の一部は (1) に先立って行われることになっている) 
た「dot.skkinput の記述方法については、README.jis が参考になると思う」
フ「つまり、dot.skkinput を読み込んで字句解析・文法解析してから、大域
    変数に値を入れているわけね」
た「そういうことになるかな。字句解析・構文解析といっても簡単なものだけ
    ど…その辺のことは、skkconfig.c と parseStr.c で行われているんだ。

    (main.c)main() --> (skkconfig.c)skkinput_readConfigFile()

                  <--> (parseStr.c) 

た「字句解析な具体的な動作は、strncmp で行頭からキーとなる文字列が存在
    するかどうか調べ、一致した場合にはその引数の型に応じた処理が呼び出
    さることになる。parseStr.c が呼び出されるのは、文字列を見付けた場
    合だ」
フ「ふーん。そうなの」
モ「甘い！甘い！ そんな適当な文章で理解しろだと？！ 貴様、このワシをな
    めておるのか！！！！」
た「あまり細かい動作にまで触れても…誰も必要としないと思うが」
モ「それが俗人のあさはかさというものだ！」
フ「あんなのほっておいて先に行こうよ、たたり」
若「あ…そんなに急がなくても…」
た「と…ともかく、parse 部分の動作をまとめると…

    { "キーワード:", 動作 }, ... , { "キーワード:", 動作 },

    という配列を作っておいて、ファイルを一行ずつ読み込む。一行の先頭が
    キーワードに一致した場合には、動作を抜き出してそれに応じた処理をす
    る。大域変数に値を入れるという点ではどれも同じ処理だな」
若「そうなんですか…それは知りませんでした」
た「あまり凝っても仕方ないって思ってね…」
師「もっと変な作りかと思いましたよ(まあ、十分変だけど)」
た「もっと変って…一体俺に何を期待しているんだ…」
師「変！」
た「…………」
若「えっと…」
フ「フォロウのしようの無いこと言わないでよ！ ああもう、まったく」
た「(気を取り直して)と…大体、こんなもので良いと思うが？ みんな、どう
    だ？」
若「はい」
師「まあ…」
フ「分かったわ」
モ「ワシにはちっとも分からんぞ！ きちんとした説明をせんからだ！ やり直
    しを要求する！！」
フ「ほっておきましょう…まだまだ先は長いんだからね」
た「そうだな…」
モ「こら！ ワシを無視するな！」

た「次に行われるのは各種プロトコルを管理する Widget の作成だ」
若「Widget って何でしょうか？」
た「…実は俺も良く分かってない。オブジェクト指向の言語のオブジェクトに
    相当するものだと思っているんだが…。ウィンドウプログラミングにはオ
    ブジェクト指向が有効な場合が多いらしい。ボタンの挙動とかね」
若「えと……はい」
フ「こんな説明で何を分かれってのよ！」
た「まあ… Widget を読む時には、ClassRec を読み…
    
KinputClassRec kinputClassRec = {
    { /* core fields */
    /* superclass		*/	&widgetClassRec,
    /* class_name		*/	"Kinput",
    /* size			*/	sizeof( KinputRec ),
    /* class_initialize		*/	NULL,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize		*/	KIP_Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	KIP_Realize,
    /* actions			*/	kip_actions_table,
    /* num_actions		*/	XtNumber( kip_actions_table ),
    /* resources		*/	kip_resources,
    /* num_resources		*/	XtNumber( kip_resources ),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	FALSE,
    /* destroy			*/	KIP_Destroy,
    /* resize			*/	NULL,
    /* expose			*/	NULL,
    /* set_values		*/	KIP_SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus		*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* tm_table			*/	default_kip_translations,
    /* query_geometry		*/	XtInheritQueryGeometry,
    }
};

    そこにある、initialize, realize, setvalues, destroy, expose を順に
    見るといいよ。こればっかりはオブジェクト指向を良く知らない俺には説
    明できそうにない…(大体の説明は以下の通りだが…)」

   superclass … KinputClass の親が何であるか。親の性質(能力？)を継承
                 する。例えば、親が CompositeWidgetClass なら子供 
                 Widget (Managedな)を複数持つことができる
   class_name … Class の名前
   initialize … Create された時に一度だけ実行される関数。
   realize    … Realize された時に実行される関数。Window を作ったりす
                 る。 
   actions    … X Event に対する挙動振舞い(Action)をここに記述する。
   resource   … リソース…例えば Window の大きさや位置、背景色といっ
                 たものをここに記述する。
   destroy    … Destroy された時じ実行される関数。ここで Widget が内
                 部で確保していたメモリを解放するとかそういう作業を行
                 う。  
   expose     … Exposure Event が来た時の処理を行う関数を登録。
   set_values … XtSetValues でリソースに値が設定された時に呼び出され
                 る関数。オブジェクト指向のカプセル化が実現されている？
   get_values … XtGetValues でリソースの値が参照された時に呼び出され
                 る関数。
   tm_table   … action の登録に使う。

フ「無用な混乱を与えるよりはそれなりの書物を読むべしって忠告する方を選
    ぶわけね」
た「そうだけど」
フ「まっ、それでもいっか。たたりに任せておいたら不安だものね…」
た「(ひどい言われようもあったもんだな…)ともあれ、initialize は 
    CreateWidget した段階で、realize は XtRealize した段階で、
    setvalues は XtSetvalues を使った段階で呼ばれることになる。expose 
    は再描画イベントが来た場合に画面の書き直しをする処理が入るんだ」
フ「ふーん。あんまし参考になんないけど…」
モ「全くだ！」
師「これが説明なのか！ こんなものが説明だというのか！！ こんな説明で満
    足なのか！！！」
た「…………。先行くよ…」
モ「むっ！ この卑怯者めが！ 早く戻って来て続きを…おーい」

た「main では XtCreateWidget を利用して KinputWidget と XimpWidget と
    XimWidget が作られている。これらは、toplevel widget の子供になって
    いる」
た「しかし、create しただけでは実体は存在しない。realize しなければなら
    ないんだ。realize することにより各種変換クライアントからのメッセージ
    をさばくことができるようになる。ただし、親 Widget が realize されれば
    子供も realize されるようにできているので、main では、toplevel widget
    しか realize してはいないんだ」

  (詳細は X Toolkit Programming 本を参照して下さい。私の理解が間違って
   いる可能性があります。ソースから理解しましたので…)

た「各種プロトコルの widget の中身については後で説明することにして、(4) 
    だな」
若「そうですね」
た「通常 X Tool Kit の Event 待ちループは XtAppMain を使えば一発なのだが」
た「これだと変換クライアントが終了した時のイベントを監視することができない」
フ「本当にそうなの？ (疑いの眼差し)」
た「と思ったんだが…他に方法はあるのかもしれない。
    変換クライアントで何とかして欲しいと思ったこともあったんだが、Destroy 
    すると変換サーバに落ちるよというメッセージを送る暇はないようだし」
た「今は変換クライアントに対して、XSelectInput を用いて WindowDestroyEvent
    を拾うようにしている。だから、

    while(1){
      XtAppNextEvent( 引数… ) ;
      自前のイベント処理関数() ;
    }

    という形になっている。XtAppMain は XtAppNextEvent と XtDispatchEvent 
    の組み合わせになっているそうだから、XtDispatchEvent をする前に、
    WindowDestroyEvent かどうかを見るとかすれば良い」

た「このイベント処理関数では、どのウィンドウに来たイベントをどのウィンドウ
    に送りつけるかを処理できるようになっている。
    XEvent の window を書換えてから、XSendEvent で送りつけるようにしてい
    るんだ。
    別に他のウィンドウに送る必要がなければ、XtDispatchEvent で widget に
    イベントを渡すようにしている」
た「その管理は…次のようなデータ構造で行っている」

struct my_eventtable {
  Window src_window ;
  ^^^^^^^^^^^^^^^^^^^ こちらのウィンドウに来たイベントを
  Window dest_window ;
  ^^^^^^^^^^^^^^^^^^^^ こちらのウィンドウへと投げるようにしている。
  long event_mask ;
  ^^^^^^^^^^^^^^^^^ これは既にどのようなイベントを拾うようにしているのか
                    を覚えるために使っている。XSelectInput では以前の mask
                    に追加するということができないためだ。
  int number_of_eventtypes ;
  int event_type[ MAX_EVENTTYPES ] ;
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^どのイベントだったら投げ直すようにする
                    かが入っている。キーと Destroy 程度しか見ないので、配列
                    に入れている。
  struct my_eventtable *next ;
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^リスト構造だ、と。
} ;

た「Window Destroy Event は例外で、この場合は各種プロトコルの Widget に
    XtSetValues でイベントを渡して、該当するウィンドウが変換クライアント
    だったら、サービスを停止するようにしている」
フ「Window ID だけ変更して dispatch したら危なそうだから？」
た「そういうことになるな」

た「これでメインのしていることの大体の骨組みは分かったと思う。一般の X
    Tool Kit を使うアプリケーションと同様に Toplevel Widget を作り、その
    子供に必要な Window を出してくれる Widget を作り、イベントループには
    いっているんだ」
若「…はい」
た「イベントループの処理が少し違うが、その程度だと思う。細かいところでは
    SIGSTOP などが来た場合にどうするかとかそういう処理が残っているが…」
師「不要と！」
た「いや…あまり本質じゃないから…」
師「大魔王たる実力があれば説明なぞ不要とおっしゃられるわけですな…」
た「………だから、何なんだそれは…」
若「え？ 大魔王様を御存知無いんですか？」
た「………もういい………」

た「次は、key event の流れだ。
    フロントエンドなので、skkinput 自身が直接 key event を受けとることがで
    きるようになっている。
    例えば、Root Window に key event が来た場合には、SeparateWinWidget の
    KeyEventHandler に key event が流れることになる。

      SeparateWin.c (KeyEventHandler) ---> cstyle.c ---> skkel.c

    その後は、keymap.c でキーに何のファンクションが割り当てられているのか
    を見て、cstyle.c でファンクションの呼び出しを行っている」
師「キーマップはどうなってるんですか？」
た「XLookupString を使って、KeyPressEvent を押された文字に変換して、

        XLookupString( xevent, string, STRINGBUFSIZE, &key, NULL ) 
                       ↓
        struct skkinputKeyTable {
            int function[ NUMBER_OF_KEYS ] ;
            struct skkinputKeyTable *next[ NUMBER_OF_KEYS ] ;
        } keymap ;
        keymap->function[ string[ 0 ] ] からキーに割り当てられている機
    能番号を得ている。NUMBER_OF_KEYS を超えるキーに関しては、"invalid
    char" という関数が割り当てられているものとしている。
    この "invalid char" の場合には変換クライアントへ KeyPressEvent を送り
    返す処理しか行わない」
師「二文字以上の場合には？」
た「そちらは keymap->next をたどることになる。たどった先で function を
    再度見るんだ」
師「じゃあ、長いキーを一つ登録しただけで、やたらめったらメモリを食うわ
    けですね？」
た「いや…そんなに沢山登録することは無いと思ったんでね」
師「まさに大魔王理論！」
た「どこの理論だ！」

た「で、実際にキーに対する機能が実行されるところに入るわけだが…」
フ「何よ、歯切れ悪いわね」
た「…全部流れを追って説明するのは困難だと思ってね」
フ「全部の系列について説明するつもりなの？」
た「無理だと思う」
ロ「おやおや、お困りのようですね」
フ「ロクサブロー！」
フ「あんた、一体何処から湧いて来るのよ…」
ロ「それは企業秘密です」
フ「……」
ロ「成程、ありとあらゆる局面で実行の流れを追いかけるのが難しい、と」
た「そうなんだ…」
モ「愚か者のたどる末路だ！」
フ「モアイ、あんたねえ…そんな出典の分からない変な台詞ばっかり多用しないで
    よ…読んで分かる人が少なくなるじゃない」
モ「ワシは知らんな」
ロ「まあまあ。データ構造の説明だけでもされては如何でしょう」
た「データ構造か…」
ロ「そうすれば、実際にコードを読むことがあるとすれば…解析の手助けになる
    ことでしょう」
た「成程…」

若「で、どうなさるのですか？」
た「まずは漢字コードの取り扱いから入ろうと思う」
若「そうですね。それがよろしいです」

た「漢字コードといっても…JIS,EUC,SJIS…UNICODE…挙げていけばきりがな
    い」
師「アレフじゃないでしょう、有限じゃないですか」
た「全部扱えるようにして、嬉しがると思うか？」
師「ああ嬉しい。さあ、実装しましょう！」
た「………。さて…JIS の中を見ても、JISX0201-1976, JISX0208-1983, 
    JISX0212-1990 なんていうコードが存在する」

(JIS規格)

JIS X 0201 情報交換用符号 
    1バイト文字に関する規格

JIS X 0208 情報交換用漢字符号 
    2バイト文字に関する規格
    JIS C6226-1978（いわゆる旧JIS），JIS X 0208-1983,1990（いわゆる新JIS） 

JIS X 0212 情報交換用漢字符号 
    補助漢字に関する規格 

JIS X 0202 情報交換用符号の拡張法 (ISO 2022) 

JIS X 0221-1995 国際符号化文字集合 (UCS) -- 
    第1部 体系および基本多言語面 (ISO/IEC 10646-1 :1993)
    (これの16ビットコードが Unicode) 

JIS X 0211-1994 符号化文字集合用制御機能 (ISO/IEC 6429:1992) 

た「一つのコードで全ての漢字を扱うことができれば便利なんだけど…それは
    とても出来そうにない」
モ「その考え方は unicode だな？」
た「まあ、そういうことになるか」
師「じゃあ、新しいコードを作りましょう！」
た「作ってもフォントが無いぞ…しかも、他のコードへ変換することも考えな
   ければ。特に Compound Text に変換できないと意味がない」
師「大丈夫、大丈夫。大魔王の実力をもってすれば…」
た「だから誰が大魔王じゃ！」
若「それで…どのようにされるのですか？」
た「内部コードとしては、次のように実装している」

   struct myChar {
      char charset ;
      unsigned short chara ;
   } ;

た「文字コードと文字集合の両方を指定することで、どの文字かを指定するよ
    うにしている。文字集合には…」

   ISO8859-1 から ISO8859-9
   JISX0201-1976, JISX0208-1978, JISX0208-1983, JISX0212-1990

た「を指定できるようにしてある」
若「でも…それじゃあ…」
た「そうだね。ASCII コードだと言いたい時に ISO8859-1 の左半面を使うよ
    うにしてはいるけど、ISO8859-2 の左半面を使われるかもしれないし、
    JISX0201-1976 の左半面を使われるかもしれない…」
た「だから、ISO8859-? もしくは JISX0201-1976 の左半面は全て同じコード
    であるとして扱っている。表示の時はそれぞれのフォントを使うようにし
    ているが」
た「ここのあたりの操作は kanji.h, kanji.c にまとめて入っているよ」

た「次は Emacs の Buffer Emulation に使っている構造体の説明をしようと
    思う」 
た「skkinput は Emacs の Buffer を Emulation を行っている」
フ「確か… skk らしさは emacs から切離せないのか…とか何とか言ってたもん
    ね」
た「でも、RJJ は別に emacs らしいというわけでもない」
フ「skkinput は skk.el を見て、skk らしさを追及しようと試みたってこと？」
た「そうなるな」
フ「ふーん。で？」
た「で…まずは emacs の使っている marker に類するものを用意している。
    別にマーカと言っても大したことをしているわけではなくて、

    struct Marker {
       int *pos ;
       int cf ;
    } ;

    のような単純な構造体で表わされている」    
フ「*pos っていうのは？」
た「*pos には文字列の先頭からの文字数が入っている。マークされている場
    所が入っている」
フ「cf は？」
た「カーソルフラグだ。マークされている位置に文字が挿入された場合に、*pos
    が変化するべきか今迄の値を維持すべきかを決定する。カーソルだったら、
    カーソル位置に文字が入るとカーソルは一つ移動しなければならないだろ」
フ「で、マーカって何に使ってるのよ」
た「例えば、変換開始位置(henkan_start_point)、送り仮名開始位置、仮名入力
    開始位置、カーソル位置を操作するのに使っている。

    int cur_pos = 3 ;
           ↓
    "あいうえお"

    と "え" の位置にカーソルがあったとすれば、"う" が消されるとカーソルは
    前に移動しなければならない。そういう文字列の中の場所を指しているもの
    が文字列操作によって変化しなければならない時にマーカで管理するように
    しているんだ。
    (文字列操作の例、delete-region や insert-character など)

    cur_pos = 2
         ↓
    "あいえお"」

フ「肝心のバッファの方は？」
た「次のようになってる」

----- ここから ----- ここから ----- ここから ----- ここから -----
struct SKKInputNode {
  /*
   * 入力の管理に用いられる部分。
   */
  /* 送信用の文字列を格納するバッファ。*/
  struct myChar textbuffer[ TEXTBUFSIZE ] ;
  struct myChar mtextbuffer[ TEXTBUFSIZE ] ;
  /* 変換のための j-prefix … これが rom-kana-rule-list による状態遷 *
   * 移における状態の表現になる。以前、この配列を作った時には管理でき*
   * なくてやられてしまったけれど…今度はどうかな? */
  struct myChar j_prefix[ TEXTBUFSIZE ] ;
  /* 変換対象となる文字列を保管するバッファなのである。*/
  struct myChar j_henkan_key[ TEXTBUFSIZE ] ;
  struct myChar j_henkan_key2[ TEXTBUFSIZE ] ;
  struct myChar j_search_key[ TEXTBUFSIZE ] ;
  struct myChar j_num_list[ TEXTBUFSIZE ] ;
  /* カーソルの座標。*/
  int cur_pos, cur_pos2, cur_pos3, cur_pos4 ;
  int cur_pos_backup ;
  /* カーソルの移動可能な最小の値。*/
  int cur_pos_top ;
  /* マーク位置。*/
  int mark_pos ;
  /* カーソルがあるか否か。基本的にカーソルがある場所がキーを受けと *
   * ることが出来る。*/
  int cur_exist ;
  /* 変換モードに移行しているかどうか。*/
  int j_henkan_mode ;
  /* 変換中か否か( つまりは、▼かどうか。)。*/
  int j_henkan_on ;
  /* 仮名入力中か否か。*/
  int j_kana_mode ;
  /* 送り仮名の入力中か否か。*/
  int j_okurigana_mode ;
  /* 仮名か片仮名か。*/
  int j_katakana_mode ;
  /* 仮名入力の開始位置。*/
  int j_kana_start_point ;
  /* 変換文字列の開始位置。*/
  int j_henkan_start_point ;
  /* 変換文字列の終了位置。*/
  int j_henkan_end_point ;
  /* 送り仮名の開始位置。*/
  int j_okurigana_start_point ;
  int j_okurigana_offset ;
  /* 送り仮名。*/
  struct myChar j_okuri_chara ;
  /* abbrev-mode かどうか。*/
  int j_abbrev ;
  /* 全角入力モードかどうか。*/
  int j_zenkaku ;
  /* 仮名入力モードかどうか。*/
  int j_mode ;
  
  /* 確定までに変換した回数。*/
  int j_henkan_count ;
  /* 変換動作候補列挙中か？ */
  int j_henkan_show_candidate_mode ;
  /* ミニバッファが何のために作られたのかという情報が入る。*/
  int j_minibuff_usage ;
  /* 直接文字入力モードであったことが記されている。*/
  int j_input_by_code_or_menu_mode ;
  int j_input_by_code_or_menu_point ;
  int j_input_by_code_current_code ;
  int j_input_by_code_current_charset ;
  /*
   * Elisp にあるマーカーのための設定。
   */
  /* 現在のマーカーの位置。*/
  struct Marker markers[ MAXMARKERNUM ] ;
  /* マーカーの使用状況。*/
  int marker_usage ;

  /* search に利用。*/
  SkkinpSearchVector *j_henkan_vector_top ;
  VectorIndex *j_henkan_vector_index_top, *j_current_henkan_vector_index ;
  int j_henkan_vector_index_length ;

  /* completion に利用。*/
  SkkinpSearchVector *j_completion_vector_top ;
  VectorIndex *j_completion_vector_index_top,
    *j_current_completion_vector_index ;
  int j_completion_mode ;

  /* mini-buffer に利用。*/
  struct SKKInputNode *minibuffer ;
  struct SKKInputNode *parentbuffer ;
} ;
----- ここまで ----- ここまで ----- ここまで ----- ここまで -----

フ「でかいわねえ」
モ「全くだ！ この程度にこんなに使うとわ！」
カ「たたりくん、修行が足りないわよ」
フ「…そういう新キャラをまた出す…ネタが無いんでしょ」
フ「でも、こんなの見せられたっていきなりは分かんないわよ！」
た「一つずつ説明するよ…」
た「textbuffer はバッファに入力されている文字列を管理している。内部キャ
    ラを使っているので、struct myChar の配列になっている」
た「mtextbuffer というのはそのバッファのミニバッファに表示されるべき文
    字列が入っている。ミニバッファで入力を行ったりせずにただメッセージ
    を表示するだけなら、こちらを使うようにしている。例えば、"Quit" と
    か "C-x" などを表示する、変換候補を表示する…などだ」
た「cur_pos, ... はカーソルの位置だ。全部マーカとして登録されている」
フ「どうしてこんなに沢山あるのよ！」
た「カーソル以外のマーカをカーソルと交換して動かすという処理をする時に
    利用しているんだ」
フ「カーソル以外って何よ？」
た「j_kana_start_point, ... だよ」
フ「ふーん。やっぱし、良く分かんないわね」
た「cur_pos_top はカーソル位置の最小値が入ることになっている。カーソル
    の値はこれ以上小さくなることはない。beginning-of-line でカーソルが
    飛ぶ位置だと言ってもいい」
た「mark_pos はユーザが設定できるマークだ。範囲削除や範囲コピーに使っ
    たりするマークだ。これもマーカとして登録されている」
た「cur_exist がカーソルがあるか否か。一度に操作できるバッファは一つだ
    から、結局はどこかのバッファにしかカーソルは存在しないことになる。 
    だから、ここが True ならそのバッファにカーソルが存在して、何らかの
    操作(入力)が可能となる」
た「markers は先に説明したマーカを管理するのに使う配列、marker_usage 
    は何個マーカが使われたかを覚えている」
た「minibuffer は…そのバッファの子供があるかどうか、子供のバッファの
    ポインタとなっている。このポインタが NULL ではないのは、ミニバッファ
    で入力操作を行いたい時…例えば単語登録の作業…だ」
た「parentbuffer はそのバッファの親だ。親が存在するということは自分自
    身が誰かのミニバッファだということを意味している。自分自身の果たす
    べき役割(単語の登録作業が行われたのなら、入力された単語を親に渡す
    必要がある)を果たす際に…親の情報が必要になる」
た「ぜぇ…はぁ…。勢いよくじゃべり過ぎた…」
若「あの…たたりさん、お疲れのようでしたので、お茶をお持ちしました」
た「ああ、ありがとう、若葉」

4. 変換サーバになるには？

た「変換サーバになる…といっても、変換クライアントが変換サーバの存在を
    見付けられないようではどうしようもない」
モ「別にいいではないか。街の真中で変換サーバだと叫ぶがいい」
師「あ…それはいいですね。たたりさん、やって下さいよ」
た「だから…それでどうしろと？」
モ「するのはワシではない！」
た「………。そういうわけで、X Server 上では変換サーバは Xatom を使って
    変換クライアントに自分の存在を伝えるようになっている」
師「どういうわけなんですか？ 是非に説明して下さいよ」
フ「私も知りたいわ。説明しなさいよ、たたり」
た「お…俺は…どうしてこんな奴らと一緒にコードを書いているんだ…」
若「たたりさん、しっかりして下さい」
た「あ…ああ…それで…
    各種プロトコルの Widget は初期化された段階で、Xatom のオーナになる
    ようになっている。例えば、_JAPANESE_CONVERSION のオーナになれるの
    は、Kinput2 Server だけだ。他に _JAPANESE_CONVERSION のオーナになっ
    ているものがあると、それから所有権を奪うことになる。奪われた時の処
    理も必要だ。」
フ「XInternAtom( "_JAPANESE_COVERSION", False ) で作った、
    _JAPANESE_CONVERSION という Xatom の所有者を調べることによってクラ
    イアントは変換サーバの存在を知ることができるというわけね」
た「まさにその通りだ」

た「その後は、Client Message Event を用いて Window 間でメッセージを送
    りあうことになる。どんなメッセージが来たらどんな処理をするべきかは
    各種プロトコルによって定められているんだ」
フ「例えば？」
た「Kinput2 Protocol では CONVERSION_REQUEST, CONVERSION_END_REQUEST,
    COPNVERSION_ATTRIBUTE_NOTIFY というメッセージが使われる。

    変換クライアント --------------------> 変換サーバ
                      CONVERSION_REQUEST 

                      接続要求：
                         XCientMessageEvent *xev
                         xev->data.l[0] == _JAPANESE_CONVERSION
                         xev->data.l[1] == 変換クライアントの WINDOW ID
                         xev->data.l[4] == 変換クライアントの属性
                                           Kinput2 Protocol で利用。
                                           変換クライアントがどんな存
                                           在かを入れておく。

    変換クライアント <-------------------- 変換サーバ
                       CONVERSION_NOTIFY

                         いわゆる ACK

                         XCientMessageEvent *xev
                         xev->data.l[0] == _JAPANESE_CONVERSION
                         xev->data.l[1] == Compound Text かな？
                         xev->data.l[2] == 変換クライアントの property
                         xev->data.l[3] == 変換サーバの WINDOW ID

    となっている。data.l[1] の _JAPANESE_CONVERSION の部分にはどのよう
    な変換サーバであるのかが書かれることになっている。skkinput の場合
    には日本語入力しか想定していないから、_JAPANESE_CONVERSION 以外が
    来ることはない」
フ「こんな面倒な処理だったら、変換クライアント書くのも一苦労じゃない！」
た「kinput2 の作者が用意してくれている convlib.c というのを使えば、ここの
    通信部分のコード生成はかなり容易になるよ。
    GPL に準拠しているし、使ってみるのがいいんじゃないか」

4.2 xim protocol って？

た「mit/doc/Ximp/Ximp3_3.doc を見るのが一番なんだけどね」
た「Ximp プロトコルも Kinput2 プロトコル同様に、ある ATOM の owner になる
    ことでサーバとして名乗りをあげることができる」

4.3 ximp protocol とは？

5. そして…将来の展望なぞ…

フ「ふーん。…って、たたり！ 若葉がいないわよ！」
た「な、何！ 一体、何処に行ったんだ…」
フ「まあ、そう心配することはないかも。若葉もあれで一応…」
た「何を言ってるんだ！ 若葉はああ見えても、世間ずれしていて何処か抜け
    てて、しかも方向音痴なんだぞ！」
フ「あんた…容赦無く言うわね…」
師「まさに大魔王！ 大魔王復活の時は来たれり…」
た「(無視して)…ともかく早く探さなれば…」
若「たたりさん」
た「(しまった、さっきの聞かれたかな…)わ、若葉」
若「たたりさん、この方達、とっても困ってらっしゃるんです」
た「は？ どうされたんですか？」
謎の学生1「(名前も無しかい…)いやね、さっき Netscape で OverTheSpot の
    Window Style で日本語入力しようとしたんだけど、skkinput が動かないん
    だ」
た「うぐ…」
謎の学生2「いやあ、Windows'95 に SKK-IME っていうのが欲しいなあ。日本語
    入れるの SKK に慣れ過ぎちゃって、他のが使い難くて仕方がないんだ」
た「うぐうぐ…」
若「何とか力になってあげられないでしょうか。きっと、たたりさんなら何とか
    出来るって思うんです」
た「いや…あの…その…」
若「駄目…ですか？」
た「まあ…その…」
若「私、御迷惑でしたか？」
た「いや、そうじゃなくて…。
    Netscape に kinput2(OverTheSpot Window Style)で日本語を入れることが
    可能な環境が手に入らないんだ…。Ximp で動作する他のアプリケーションも
    なかなか手に入らなくて…。何とかしようとは思ってるんだけどね…。

    SKK-IME の方は…Windows'95 の MSDN の壁が超えられないんだ。それに
    VC++ はまだ勉強中だし。他にやるって宣言している人がいることだし…まあ
    様子見かな、と…」
若「たたりさん…」
た「若葉…」
若「分かりました…なさるつもりはないのですね」
た「…どうしてそうなる…」
モ「くくくくく、それは私がそう説明したからだ！ この男は周囲を騙して逃げる
    のが得意だとな！」
若「そうなのですか？」
た「うがああああああああーーー！！ あー、もう誰か何とかしてくれーーー！」
   (イベント失敗の音が鳴る…)

6. これがエンディング…

(突然の声)「そうですか、あなたのコーディングの姿勢を見せて頂きました」
た「！？」
   (見ると謎の女性が立っている)
ロ「あなたが…？」
フ「勝手に分かってるんじゃないわよ、ロクサブロー！」
ロ「この方が…ソースの復旧とリリースの大御所であらせられる徹夜の女神様
    です」
ロ「この方は徹夜した人の前にしか現われないのですよ」
徹夜の女神(以下、神)「私は女神。徹夜の女神…人に仕様変更を強いる者…リ
    リースの判定をせし者…」
た「俺は…あなたがこの壊れたバックアップテープからコードを復旧させてくれ
    る人だと聞いてここまで来たんだ。リリースの迷いを断ち切ってくれる人だ
    とも聞いた」
フ「そうよ。そのために辛く苦しいドキュメンテーションを乗り越えて来たんだ
    から」
師「ホントに辛く苦しかったんですか？ (--;」
神「頼まれれば判定しましょう…。ですが…」
た「？」
神「直るかもしれない、リリースできるかもしれない、そういう期待が大きい程
    駄目になった時のショックは大きいものです」
た「…それは…分かっている…」
神「それでは判定してみましょう…」
神「その前に…あなたは本当にリリースしたいと思ってらっしゃるのですか？ 
    今一つ強い思いが伝わって来ないのですが」
た「…いいんだ。ここまで実装できたら。自分で決めたから、それでいいんだ」
神「ではテープとドキュメントをこちらへ。その後、全ては決まっていることで
    でしょう」
た「よし…」
た「ロクサブロー、ファリー、若葉、師匠…今迄ドキュメンテーションにつきあっ
    てくれて本当に有難う」
ロ「いえいえ。なかなか面白かったですよ」
フ「またリリースに迷ったら案内してあげるわ」
若「あの…本当に御世話になりました」
師「もうこんな面倒は御免ですよ。ああでも大魔王には逆らえないんだろうな…」
た「(誰が大魔王だ…何が大魔王なんだ…一体…)それじゃ、みんな元気で！」

た「って…？」
神「SKK-IME も駄目だし、Netscape 対応も不完全と…駄目ですね、これは(つまり
    キャラクタイベント全滅、と)」
た「おい…全然当初の開発意図と関係ないところで判定するんじゃない…」
神「それにこのキれたコメントの数々。怪文書。何処をどう見ても世間に広まるに
    ふさわしい代物じゃありません」
た「こらこら…そういう主観的な判断で良いのか…」
神「というわけで、さようならーーーー」
た「こらこら、待てい！ せめてバックアップテープだけでも何とかしろーー！」

フ「…駄目だったみたいね」
た「何故だー！ 何故なんだーー！ 俺の日頃の行いはそんなに悪いというのか！」
師「悪い、悪い。もう最悪」
た「うぐ…。神様、カムバーック！ って、あんなのが戻って来ても役には立たん
    けど…」

た「こうして目的が無くなってしまった以上、必殺デバグ人は自然解散となった」
た「みんなは自分の研究室に戻ってまた自分の仕事へと戻っていった…」

   師匠は近々まわってくる研究会の準備に忙しい毎日をおくっているそうだ。

師「ああ…形態素解析が…」
師「こんな忙しい時期にメールが…『わたしだ！！！』」
師「やめてくれーーー！」

   モアイ氏は…彼のことをコメントするのは避けよう。だが、またとんでもない
メールを師匠へと送りつけることに違いない。

   そして…俺は…

た「あーバグった！ 何故だ、何故これで動かないんだーー！」
た「分からん。げ…こっちまで動かなくなってるぞ…。日付を戻すか…あー拡張
    した部分を書き直しか…」
た「ここの仕様はどうすれば美しいんだ…？」
た「何時になったら完全版ができるんだろう…」

た「こうして俺のコーディング＆ドキュメンテーションは終わりを告げた」
た「だが、これで仕様のすべてが実現されたわけではない…。
    この世界に SKK を愛する人達がいる限り…彼等独自の仕様というものが存在
    するのだから…」
た「仕様と仕様が響き合い、奏で出す旋律。それは SKK を愛する人達がいる限
    りきっと途絶えることはないだろう」

                                                              (完)

尚、このドキュメントに登場する一切の人物・団体は架空のものであり、実在の人
物・団体と一切関係ありません。

また、このドキュメントは未完成であり、完成する予定日は未定です。
