Squeak5.0で日本語表示をするシリーズ: とりあえずJapaneseEnvironmentを直してStrikeFontで日本語を表示できるようにする

おそらくここらへんは将来的にはなくなる予定の仕組みなのかもしれないのですが、とりあえず淡々と直していきましょう。いったん TrueType のことは忘れて StrikeFont(ビットマップフォント)で日本語を表示できるようにします。


まず最初に、既定のフォントをインストールします。(要ネット接続)

(Locale isoLanguage: 'ja') languageEnvironment installFont


うまくインストールできれば、表示フォントに Accuny あるいは DefaultMultiFont を指定した状態で次のコードを print it すると、「あ」が表示されるはずです。

Character leadingChar: JapaneseEnvironment leadingChar code: 12354 

http://squab.no-ip.com/collab/uploads/Sq5JapaneseEnvFix01.png


念のため、Accunyフォントの fontArray を調べるとサイズが 6(JapaneseEnvironment leadingChar + 1)に増えて、その 6 番目めに日本語フォントが新しく入っているのが確認できます。

(TextStyle named: 'Accuny') defaultFont fontArray
"=> {a StrikeFont(Accuny11 12) . nil . nil . nil . nil . a StrikeFont(Japanese10 12)} "


ここで、なぜか無くなっている StrikeFontSet>>#copy を追加しておきます。

| urlStr |
urlStr := 'http://squeak-ja.sourceforge.jp/patches/PatchesJa20111005-4.2.sar'.
SARInstaller new fileInFrom: urlStr asUrl retrieveContents contents asByteArray readStream


以下のスクリプトでデフォルトのフォントを日本語表示可能な Accuny に変えることができます。

| style normalFont windows |
style := TextStyle named: #DefaultMultiStyle.
style defaultFontIndex: 3.
normalFont := style defaultFont.
smallFont := style fontAt: style defaultFontIndex - 2.
Preferences class selectors
   select: [:sel | (sel beginsWith: 'set') and: [sel endsWith: 'FontTo:']]
   thenDo: [:sel | Preferences perform: sel with: normalFont].
Preferences setPaintBoxButtonFontTo: smallFont.
Preferences setBalloonHelpFontTo: smallFont.
BalloonMorph setBalloonFontTo: smallFont.
windows := SystemWindow
   windowsIn: ActiveWorld
   satisfying: [:sw | sw model isKindOf: Workspace].
windows do: [:ws |
   (ws findA: PluggableTextMorph) ifNotNil: [:morph |  morph font: normalFont]]

次に Locale を日本語に変更して、IME からの入力やコピー&ペースト、ファイルの入出力に適切なエンコーディングが使われるようにするしくみ使えるようにします。

Locale currentPlatform: (Locale isoLanguage: 'ja')


しかし、これをするとととたんにいろいろとおかしなことが起こり始めるので、わかる範囲で直していきましょう。コピー&ペーストなどもできなくなることがあるので、適宜 Locale currentPlatform: (Locale isoLanguage: 'en') で元にもどしながら操作するのがよいと思います。なお、以下は Windows 環境での作業ですので、他の OS 向けには適宜読み替えて(あるいは試行錯誤してみて)ください。


▼ LanguageEnvironment class>>#isAlphaNumeric: の追加

この状態で IME から「あ」などと入力してみて最初に気づくのは MessageNotUnderstood: JapaneseEnvironment class>>isAlphaNumeric: エラーです。

http://squab.no-ip.com/collab/uploads/Sq5JapaneseEnvFix02.png


とりあえず、JapaneseEnvironment class のスーパークラスの LangageEnvironment class に、すでにある #is〜: メソッド群を参考に self charsetClass に委譲する #isAlphaNumeric: メソッドを新しく追加します。

どのように定義してもよいのですが、ここでは次のようにします。まず、 #isDigit: を implementors of it (alt/cmd + m) するなどして定義を呼び出します。

http://squab.no-ip.com/collab/uploads/Sq5JapaneseEnvFix03.png


ここで最初の Digit を選択して AlphaNumeric をタイプするなどして置き換え、続けて alt/cmd + j (again) して次のも同様に置き換えます。

http://squab.no-ip.com/collab/uploads/Sq5JapaneseEnvFix04.png
http://squab.no-ip.com/collab/uploads/Sq5JapaneseEnvFix05.png


置き換えたら accept (alt/cmd + s) します。すると、#isAlphaNumeric: の定義はいったん消えて元の #isDigit: の定義に戻ってしまいますが、これは当該ウインドウが #isDigit: の implementors of it で開かれたからで、LanguageEnvironment を brorse it (alt/cmd + b) してブラウザをクラスメソッド一覧に切り替えるか、isAlphaNumric: についてあらためて implementors of it (alt/cmd + m) してやれば、#isAlphaNumric: がきちんと定義されているのが確認できるはずです。

これで、もしノーティファイアがそのままなら Proceed して消せますし、以後、IME 経由での日本語の入力時に同様のノーティファイアが現われることもないはずです。


▼スクロールホイールの操作が反応しなくなっているのを直す

手元の Win環境では、Locale を ja に切り替えると、ブラウザなどでスクロールをしようとしてスクロールホイールを回しても、ペインの中がフラッシュするだけでうまく動作しないようです。これは JapaneseEnvrironment class>>#inputInterpreterClass で Win 向けなどに指定されている UTF32JPInputInterpreter で、スクロールホイールのイベントうまく取得できていないのが原因のようです。そこで、次の赤字の部分を付け足して accept (alt/cmd + s) します。

UTF32JPInputInterpreter >> nextCharFrom: sensor firstEvt: evtBuf
    | keyValue mark |
    keyValue := evtBuf at: 6.
    keyValue = 0
        ifTrue: [keyValue := evtBuf at: 3].
    mark := self japaneseSpecialMark: keyValue.
    mark notNil
        ifTrue: [^ mark].
    keyValue < 256
        ifTrue: [^ (Character value: keyValue) squeakToIso].
    ^ Character leadingChar: JapaneseEnvironment leadingChar code: keyValue


▼コピー&ペーストがうまくいかないのを直す

JapaneseEnvironment >> clipboardInterpreterClass
    | platformName osVersion |
    platformName := Smalltalk platformName.
    osVersion := Smalltalk osVersion.
    (platformName = 'Win32'
            and: [osVersion = 'CE'])
        ifTrue: [^ NoConversionClipboardInterpreter].
    platformName = 'Win32'
        ifTrue: [^ UTF8ClipboardInterpreter].
        ifTrue: [^ WinShiftJISClipboardInterpreter].
    platformName = 'Mac OS'
        ifTrue: [^ MacShiftJISClipboardInterpreter].
    ^ platformName = 'unix'
        ifTrue: [(ShiftJISTextConverter encodingNames includes: X11Encoding getEncoding)
                ifTrue: [MacShiftJISClipboardInterpreter]
                ifFalse: [UnixJPClipboardInterpreter]]
        ifFalse: [NoConversionClipboardInterpreter]


この修正のあと、JapaneseEnvironment clearDefault してあげます。


▼ファイルの出力エンコードを UTF8 にする

JapaneseEnvironment >> systemConverterClass
    | platformName osVersion encoding |
    platformName := Smalltalk platformName.
    osVersion := Smalltalk osVersion.
    platformName = 'Win32'
    (platformName = 'Win32'
            and: [osVersion = 'CE'])
        ifTrue: [^ UTF8TextConverter].
    platformName = 'ZaurusOS'
    (#('Win32' 'ZaurusOS' ) includes: platformName)
        ifTrue: [^ ShiftJISTextConverter].
    platformName = 'Mac OS'
        ifTrue: [^ ('10*' match: osVersion)
                ifTrue: [UTF8TextConverter]
                ifFalse: [ShiftJISTextConverter]].
    platformName = 'unix'
        ifTrue: [encoding := X11Encoding encoding.
            encoding
                ifNil: [^ EUCJPTextConverter].
            encoding = 'utf-8'
                ifTrue: [^ UTF8TextConverter].
            (encoding = 'shiftjis'
                    or: [encoding = 'sjis'])
                ifTrue: [^ ShiftJISTextConverter].
            ^ EUCJPTextConverter].
    ^ MacRomanTextConverter

やはり修正の後、JapaneseEnvironment clearDefault してあげます。


あと、個人的な好みですが、(FileDirectory oldFileNamed: 'text.txt') edit を do it (alt/cmd + d) して FileList をエディタモードで開いたときなどに便利なように、拡張子が .txt ならデフォルトで UTF8 で開くようにも細工してしまいます。

FileList >> defaultEncoderFor: aFileName
    "This method just illustrates the stupidest possible implementation of
    encoder selection."
    | l |
    l := aFileName asLowercase.
    "((l endsWith: FileStream multiCs) or: [
    l endsWith: FileStream multiSt]) ifTrue: [
    ^ UTF8TextConverter new.
    ]
    "
    ((l endsWith: FileStream cs)
            or: [l endsWith: FileStream st])
        ifTrue: [^ MacRomanTextConverter new].
    (l endsWith: '.txt')
        ifTrue: [^ UTF8TextConverter new].
    ^ Latin1TextConverter new



こうやっていろいろと日本語の入出力が可能になるように直しているうちに、最初に適用した StrikeFontSet>>#copy を含め、umejavaさんのパッチ群に同じものがあることに今更ですがようやく気がついてきたので、まずはこのパッチ群をそのまま使わせていただいて、それを基に手を加えていった方がよさそうな気がしてきました。ということで、いつになるかわかりませんが次回は、試しに4.4J向けのパッチ群を5.0に導入したらどうなるかトライしてみようかと思います。