Linux版Scratch1.4で日本語入力

Linux版のScratch1.4で日本語入力日本語入力をできるようにした時のメモです。Ubuntu12とRaspberry Piで動く[Raspbian](http://www.raspbian.org/)で動くことを確認しています。※RaspbianについてはQEMU上で検証なので実機では検証していないのですが、実機でもできたというような話は聞いています。

## どうやって実現する？
Scratchはソースコードは[Scratch 1.4 Source Code](https://wiki.scratch.mit.edu/wiki/Scratch_1.4_Source_Code)で公開されていますがScratchという名前やロゴが使えなかったり、Scratchのサイトにアップロードできないなどの条件がありますので、今回はScratch自体に変更を加えるのではなくVMの方に変更を加えてみようと思います。

以前どこかのMLでScratchはutf32を期待しているというのを読んだ事がありますので、Scratchの期待するutf32をVMがScratchに渡してあげるように変更してみます。

## Scratchの設定と起動
まずはScratchをインストールします。

```console
$ sudo apt-get install scratch
```

素のままではIMEが起動すらしませんので、Scratchの起動ファイル中の`VMOPTIONS`に`-compositioninput`を追加します。

```console
$ sudo vi /usr/bin/scratch
```
```diff
@@ -7,7 +7,7 @@
 VM_VERSION=`find /usr/lib/squeak/ -name "squeakvm" -type f|cut -f5 -d"/"`
 SQ_DIR=/usr/lib/squeak/$VM_VERSION
 VM="$SQ_DIR/squeakvm"
-VMOPTIONS="-encoding UTF-8 -vm-display-x11 -plugins /usr/lib/scratch/plugins/:$SQ_DIR/"
+VMOPTIONS="-encoding UTF-8 -vm-display-x11 -plugins /usr/lib/scratch/plugins/:$SQ_DIR/ -compositioninput"
 IMAGE="/usr/share/scratch/Scratch.image"
 IMOPTIONS=""
 DOCUMENT=""
```

Scratchはを起動してみます。`-compositioninput`オプションを指定したことによってIMEが使えるようになっていますので試しに「あいうえお」と日本語を入力してみます。

![16-06-30 scratch.png](https://qiita-image-store.s3.amazonaws.com/0/128670/0019d9a7-a27e-0c4e-316c-435a2d2e0de2.png)

めでたく？化け文字が入力できました！「0081」「0082」あたりからutf8らしい事が分かります。ここでutf8ぽい雰囲気が確認できないと大変そうだったんですが、ちょっとひと安心です。

## VMの変更
まずはVMのコンパイルに必要なパッケージをインストールします。

```console
$ sudo apt-get install cmake g++ xorg-dev
```

つづけてVMのソースコードをダウンロードするために今使っているVMのバージョンを調べます。バージョンを調べるには`ls -Al /usr/lib/squeak/`を実行します。私の環境では4.4.7-2357である事が分かります。

```console
$ ls -Al /usr/lib/squeak/
total 4
drwxr-xr-x 2 root root 4096  6月  8 21:26 4.4.7-2357
```

https://packages.debian.org/ja/wheezy/squeak-vm や http://ftp.de.debian.org/debian/pool/main/s/squeak-vm/ あたりから近いバージョンを探します。今回は同じバージョンがありましたので`squeak-vm_4.4.7.2357.orig.tar.gz`をダウンロードしますが、もし同じバージョンがない場合は近いものをダウンロードして試してみるという事になります。

解凍します。

```console
$ tar xvfz squeak-vm_4.4.7.2357.orig.tar.gz
```

ソースコードを変更します。検証コードという事で力技で書いたので長いコードになってしまいましたが、中身はutf8をutf32に変換するだけのものです。探せば普通に関数とかあるのかもしれません…

```console
$ cd squeak-vm-4.4.7.2357.orig
$ vi unix/vm-display-X11/sqUnixX11.c
```

```diff:unix/vm-display-X11/sqUnixX11.c
@@ -1699,29 +1699,64 @@ static unsigned char *lookupKeys(int (*l
 
 static int recordPendingKeys(void)
 {
-  if (inputCount > 0)
-    {
-      int i= iebOut - iebIn;
-      for (i= (i > 0 ? i : IEB_SIZE + i) / 4; i > 0; -- i)
-	{
-# if defined(DEBUG_XIM)
-	  fprintf(stderr, "%3d pending key %2d=0x%02x\n", inputCount, i, *pendingKey);
-# endif
-	  recordKeyboardEvent(*pendingKey, EventKeyDown, modifierState, 0);
-	  recordKeyboardEvent(*pendingKey, EventKeyChar, modifierState, 0);
-	  recordKeystroke(*pendingKey);  /* DEPRECATED */
-	  ++pendingKey;
-	  if (--inputCount == 0) break;
-	}
-      return 1;
-    }
-  /* inputBuf is allocated by lookupKeys */
-  if (inputBuf != inputString)
-    {
+  if (inputCount <= 0) {
+    if (inputBuf != inputString) {
       free(inputBuf);
       inputBuf= inputString;
     }
-  return 0;
+    return 0;
+  }
+
+  int utf32 = 0;
+  while (inputCount > 0) {
+	//110x xxxx 10xx xxxx
+	if(inputCount >= 2 &&
+	   pendingKey[0] >= 0xc0 && pendingKey[0] <= 0xdf && 
+	   pendingKey[1] >= 0x80 && pendingKey[1] <= 0xbf)
+		{
+		utf32 = ((pendingKey[0] & 0x1f) << 6) | 
+			 (pendingKey[1] & 0x3f);
+	        recordKeyboardEvent(0, EventKeyDown, modifierState, utf32);
+	        recordKeyboardEvent(0, EventKeyChar, modifierState, utf32);
+		pendingKey+=2;
+		inputCount-=2;
+	//1110 xxxx 10xx xxxx 10xx xxxx
+	} else if(inputCount >= 3 &&
+		  pendingKey[0] >= 0xe0 && pendingKey[0] <= 0xef && 
+		  pendingKey[1] >= 0x80 && pendingKey[1] <= 0xbf && 
+		  pendingKey[2] >= 0x80 && pendingKey[2] <= 0xbf)
+		{
+		utf32 = ((pendingKey[0]  & 0x0f) << 12) | 
+			((pendingKey[1] & 0x3f) << 6) | 
+			 (pendingKey[2] & 0x3f);
+	        recordKeyboardEvent(0, EventKeyDown, modifierState, utf32);
+	        recordKeyboardEvent(0, EventKeyChar, modifierState, utf32);
+		pendingKey+=3;
+		inputCount-=3;
+	//1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
+	} else if(inputCount >= 4 &&
+		  pendingKey[0] >= 0xf0 && pendingKey[0] <= 0xf7 && 
+		  pendingKey[1] >= 0x80 && pendingKey[1] <= 0xbf && 
+		  pendingKey[2] >= 0x80 && pendingKey[2] <= 0xbf && 
+		  pendingKey[3] >= 0x80 && pendingKey[3] <= 0xbf)
+		{
+		utf32 =	((pendingKey[0] & 0x07) << 18) | 
+			((pendingKey[1] & 0x3f) << 12) |
+			((pendingKey[2] & 0x3f) << 6) |
+			 (pendingKey[3] & 0x3f);
+	        recordKeyboardEvent(0, EventKeyDown, modifierState, utf32);
+	        recordKeyboardEvent(0, EventKeyChar, modifierState, utf32);
+		pendingKey+=4;
+		inputCount-=4;
+	} else {
+	        recordKeyboardEvent(*pendingKey, EventKeyDown, modifierState, 0);
+	        recordKeyboardEvent(*pendingKey, EventKeyChar, modifierState, 0);
+	        recordKeystroke(*pendingKey); /* DEPRECATED */
+		pendingKey++;
+		inputCount--;
+	}
+  }
+  return 1;
 }
 
 static int xkeysym2ucs4(KeySym keysym);
```

コンパイルします。PCがゆっくり目なので、今回はvm-display-X11のみをコンパイルしてインストールしてみます。インストールはちょっと強引かもしれませんが既存のso.vm-display-X11を新しいso.vm-display-X11に差し替える事で行います。

```console
$ mkdir bld
$ cd bld
$ ../unix/cmake/configure
$ make vm-display-X11
$ sudo mv /usr/lib/squeak/4.4.7-2357/so.vm-display-X11 /usr/lib/squeak/4.4.7-2357/so.vm-display-X11.orig
$ sudo cp vm-display-X11/so.vm-display-X11 /usr/lib/squeak/4.4.7-2357/
```

オリジナルのso.vm-display-X11と新しいfileso.vm-display-X11を比較するとかなり大きくなってしまいましたが、とりあえずは気にしないでおきます。

```console
$ ls -Al /usr/lib/squeak/4.4.7-2357/so.vm-display-X11*
-rwxr-xr-x 1 root root 279934  7月  2 12:26 so.vm-display-X11
-rw-r--r-- 1 root root  96860  4月 25  2012 so.vm-display-X11.orig
```

Scratchを起動して日本語が入力できることを確認します。