みずぴー日記

人間の再起動ボタンはハワイのビーチにある

💖美少女として勤務する

パペ文字によるVR出社 を継続している。 楽しい。

f:id:mzp:20180516212627j:plain

🌟アバターの変更

パペ文字に搭載されているモデル以外の美少女にもなりたくなったので、Unityでアバター表示アプリを作成した。

モデルは物述有栖を利用している。 かわいいのと、ライセンスが明確なのがよい。

f:id:mzp:20180516212722j:plain

実装は以下のページが参考になった。

📸自撮りボタンの追加

Unity+iOSでカメラロールにスクショを保存するまで - Qiitaを使って、スクリーンショットを手軽に撮れるようにした。

f:id:mzp:20180516214118p:plain:w300

カメラロールがどんどんかわいくなっていく。

f:id:mzp:20180516214418p:plain

🛠ライトニングドック

常に顔を映せるようにライトニングドックを購入した。 便利なの自宅用とオフィス用を買った。

f:id:mzp:20180516124820j:plain

iPhoneが常に起動しつづけることになるので、だいぶ発熱する。

☺️表情

夕方になると表情が死んでくることを発見した。目が閉じ気味になって、口が開き気味になる。かわいさが半減してしまうので、積極的にほほえむように気をつけはじめた。

f:id:mzp:20180516215553p:plain:w300

でもあくびしててもかわいい。

f:id:mzp:20180516215839p:plain:w300

🙊周囲の様子

mstdn.jp

mstdn.jp

mstdn.jp

🙅‍♀️zoom.us への接続の改良(失敗)

デレステフォトスタジオのリアルタイム透過プレイヤーをつくった - ツバメになったバリスタを応用して、zoom.us への接続を改良しようとしたが

Zoom APIを用いて、iPhone画面を直接配信できるようにしようとしたが、変更できる範囲が少なくどうしようもなかった。

☕️ JavaScriptと入力メソッド

AquaSKK 4.5.0ではEscキーの扱いを改善した。 この修正のためにWebKitにおけるキーイベント配信の仕組みを追ったので、まとめる。

💡入力メソッドごとの差異

上記Tweetにあるように、テキストを入力中にEscを押した際にJavaScriptで発火するイベントが入力メソッドごとに違う。

macOS標準の日本語入力やGoogle日本語入力ではキーコードが229のイベントが発生するが、AquaSKKではキーコードが27のイベントが発生していた。 このイベントが違うと入力メソッドを扱うJavaScriptコードが複雑化するので修正した。

🔑キーコード 229

キーコード229はUI Eventsで次のように定義されている。

If an Input Method Editor is processing key input and the event is keydown, return 229.

(訳: 入力メソッドがキー入力を処理しておりイベントが keydown の場合は、キーコードは229となる)

🌐WebKit

W3Cが定めているキーコードなのでブラウザ内部の処理が関係するのだろうと想定して、WebKitのコードを調べた。

WebKitはアプリケーションのUIを実現するUIプロセスとタブごとに作られるWebプロセスが協調して動作している。 キー入力の処理もこの2つのプロセスが関連している。

f:id:mzp:20180514223203p:plain

UIプロセス

// Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm

void WebViewImpl::keyDown(NSEvent *event)
{
    // (snip)

    // 入力メソッドに処理を転送する
    interpretKeyEvent(event, [weakThis = createWeakPtr(), capturedEvent = retainPtr(event)](BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
        ASSERT(!handledByInputMethod || commands.isEmpty());

        // キーイベントに入力メソッドが処理したかどうか(handledByInputMethod)を付与して、Webプロセスに転送する
        if (weakThis)
            weakThis->m_page->handleKeyboardEvent(NativeWebKeyboardEvent(capturedEvent.get(), handledByInputMethod, weakThis->m_isTextInsertionReplacingSoftSpace, commands));
    });
}

void WebViewImpl::interpretKeyEvent(NSEvent *event, void(^completionHandler)(BOOL handled, const Vector<WebCore::KeypressCommand>& commands))
{
    // (snip)

    // Cocoaが提供するAPIを使ってイベントを入力メソッドに転送する
    [inputContext() handleEventByInputMethod:event completionHandler:[weakThis = createWeakPtr(), capturedEvent = retainPtr(event), capturedBlock = makeBlockPtr(completionHandler)](BOOL handled) {
        if (!weakThis) {
            capturedBlock(NO, { });
            return;
        }

        LOG(TextInput, "... handleEventByInputMethod%s handled", handled ? "" : " not");
        if (handled) {
            capturedBlock(YES, { });
            return;
        }

        auto commands = weakThis->collectKeyboardLayoutCommandsForEvent(capturedEvent.get());
        capturedBlock(NO, commands);
    }];
}

入力メソッドにキー入力を転送するのに非公開のAPIを利用している。愉快。公開されているAPIと違い、処理結果をコールバックで受けとれるようになっている。

// FIXME: Move to an SPI header.
@interface NSTextInputContext (WKNSTextInputContextDetails)
- (void)handleEvent:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler;
- (void)handleEventByInputMethod:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler;
- (BOOL)handleEventByKeyboardLayout:(NSEvent *)event;
@end

Webプロセス

WebプロセスではUIプロセスで付けられたマークをもとに、元のキーイベントを配信するかキーコード229のイベントを配信するかを決めている。

// Soruce/WebCore/page/EventHandler.cpp

// Match key code of composition keydown event on windows.
// IE sends VK_PROCESSKEY which has value 229;
const int CompositionEventKeyCode = 229;


bool EventHandler::internalKeyEvent(const PlatformKeyboardEvent& initialKeyEvent)
{
    // (snip)
    
    // キー入力が入力メソッドで処理ずみかどうかを判定する
    bool handledByInputMethod = keydown->defaultHandled();
    
    if (handledByInputMethod) {     
        // 入力メソッドで処理済みだったらキーコードを229に入れ替える
        keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
        keydown = KeyboardEvent::create(keyDownEvent, &m_frame.windowProxy());
        keydown->setTarget(element);
        keydown->setDefaultHandled();
    }

    // (snip)
    // キーイベントを配信する
    element->dispatchEvent(keydown);

    if (handledByInputMethod)
        return true;

    // 入力メソッドで処理されていないなら処理を継続する
    // (snip)
}

🙊余談

  • JSに配信されるイベントを見るにはKeyboard Event Viewerが便利。
  • WebKitを処理を追うときはXcodeでブレイクポイントを設定して追った。 Debugging WebKitが参考になる。
  • WebKitのビルドに時間がかかってつらかったので、途中で会社のiMacProに接続してビルドしはじめた。 あとからビルドを始めたのに、先にビルドが終わったのでびびった。

🌕月を売った男

人月の神話では、理想のチーム形態として、R.A.ハインライン月を売った男の文章が引用されている。

引用されている文章(要約)

プロジェクトのリーダーが雑務に追われることを嘆くところから引用ははじまる。

コスターは両手で顔をおおってしまったが、やがて顔を上げる。「わかってます。なんとかしなければいけないとわかっているんです --- しかし、わたしが何か技術的な問題と取り組んでいると、阿呆なとんちきがやれ輸送の問題だ、やれ電話だなんだかんだと、つまらんことでわたしに決定を求めてくるんです。 すみません、ハリマンさん。自分ではやれると思っていたんですが」

出資者がその事態を改善するために業務を調整する。

ハリマンはうんとやさしくいった。 「(略) わたしが4、5日そのデスクにがんばって、きみがそんなつまらんことから守ってもらえるような体制をととのえよう。 わたしが求めているきみの頭脳は、反動ベクトルとか燃料効率、設計荷重などということを考える頭脳で運送契約なんかを考える頭じゃないからな」

さらに今後の業務を調整するアシスタントもつける。

「ボブ、ジョック・バークリュウイーを紹介しよう。彼はいま、きみの奴隷だ。 きみは主任技師で最高のだれにも制約されない責任者のままだよ。 ジョックはいわば、ほかの仕事を引き受ける摂政殿下だな。 これから、きみは全然何にもわずらわされることはないよ --- ただ、月ロケットを作る細部の問題は別だがね」

おもしろい点

たしかに理想的なチームのように思える。 この「月を売った男」は1950年でた小説なので、60年以上前に描写されたチームが理想的に思えるのはおもしろい。

さらにおもしろいことに「月を売った男」は絶版しているが、人月の神話は新装版が入手可能である。 引用の中に生きつづけるSF小説、ロマンがあってよい。

手元にある「月を売った男」と「人月の神話」

引用されている文章がよかったのでAmazonマーケットプレイスで購入した本。

f:id:mzp:20180510224310j:plain

「いまだ色あせない」と書こうかと思ったが、本はだいぶ変色していた。「近ごろは、技術的な仕事もあまりできてないな?」「やろうとはしているんです」のやりとりもだいぶいい。

f:id:mzp:20180510224433j:plain

✏️#技術書典 に本を出すまで

技術書典4で頒布した同人誌ができるまでの流れを記録する。

✨書きはじめたきっかけ

@が技術書典3に出展してて楽しそうだったので、自分もやってみたくなった。

前々から入力メソッドの作り方を調べ直そうと思ってたので、それを題材に選んだ。 AquaSKKをメンテナンスに必要な部分は知っているが、Swiftから使うとどうなるかなどは未知の部分なのでそこを埋めたかった。

ただ調べるにつれて、ほぼ資料がないことが分かってきたので、すこしでも資料を増やすためにこの本を出さなければならない、という使命感で書いていた。

📚本のスタンス

「資料を増やしたい」というのが目的にはいっているので、同人誌を読まないと得られない情報というのを極力減らしたかった。

なので、このブログに同等の内容を載せるようにした。 入力メソッドで検索すると同人誌と同等の内容が書いてある。だいたい1エントリが1章に対応するはずだが、構成の都合で変更した部分もある。

f:id:mzp:20180425072321p:plain

多くの人にはなじみがない分野だろうと思ったので、イラストを多めにしたかった。

かわいい女の子のイラストにしたかったが、すべてイラストレーターさんにお願いする予算はないのであきらめた。かわり謎の生命体を自分で描いた。

f:id:mzp:20180425072134p:plain

📅本ができるまで

調査開始

🍣入力メソッドが最初に調べたことなので、技術書典3の直後くらいから調べはじめていた。 RubyKaigi 2017に移動する新幹線の中で調べていた記憶がある。

このころはScrivenerに調べた結果を書き溜めている。このころは本文中に絵文字を使っているが、組版でこれがネックになる。

f:id:mzp:20180425072749p:plain

執筆開始

技術書典にサークル申し込みしたあとからRe:VIEWで書き始めた。落選したときのことはあんまり考えてなかった。

f:id:mzp:20180425073337p:plain

レポジトリは、ちょうどローンチされた直後のKeybaseの暗号化gitを利用した。 GitHubでない強い理由はないが、新しいものを使ってみたかった。

推敲

1月末に当選したことが分かったので、本格的に推敲しはじめた。最初はPDFとiPadでやっていたが、文字サイズが妥当かどうかわからなくなったので、紙とペンに切り替えた。

f:id:mzp:20180424215928j:plain

印刷して推敲するの、結局4回ほど繰り返した。

f:id:mzp:20180424215915j:plain

途中、温泉で推敲するという文豪ごっこをやったが、温泉に入るだけで終わった。

f:id:mzp:20180211164843p:plain

イラスト・図

できるかぎりイラスト・図を増やしたかったのでProcreateで描いた。

f:id:mzp:20180425075231p:plain

文字はApple Pencilを使ってもうまく書けなかったので、Sketchを使って入れた。

f:id:mzp:20180425075533p:plain

書体の変更

たまたま入った本屋でデザインのひきだしのバックナンバーを大量に手にいれてしまった。

これでブックデザインに凝りたい気持ちが高まってしまって困った。 とりあえずAdobe Typekitに加入して見出しや本文の書体を変えた。

見出しはかわいらしさをだすために視覚デザイン研究所のメガ丸にした。 本文書体は、一〇〇年目の書体づくりを読んで以来ファンなので、秀英明朝にした。

f:id:mzp:20180425074658p:plain

この書体変更のためにRe:VIEWが使うTeXエンジンをLuaLaTeXにいれかえた。 わりと大変だった。

入稿

栄光が同人の日キャンペーンで30%オフをしていたので、これを利用した。

f:id:mzp:20180425075748p:plain

だいぶ余裕をもって書き上げたはずだが、入稿するときにPDFをアプロードし忘れるなど、だいぶスリリングだった。

2冊目

3月末ぐらいで書くものがなくなって暇になった。 サークルスペースにも余裕あるしな、と思って2冊目を書きはじめた。 この話は工場実習日記 ふりかえりに書いた。

当時のことをがっとノートに書いてから書きはじめたので、すごい雑な図が手元にある。

f:id:mzp:20180424230107j:plain

完成

どきどきしながら技術書典の会場にいったら届いてて安心した。 よかった。

🎉🎉 #技術書典 参加

技術書典4にサークルとして参加した。楽しかった。

f:id:mzp:20180424071843p:plain

📖頒布した本の電子版

Booth.pm に電子版を置いた。

📦ブースの様子

f:id:mzp:20180422102943j:plain

到着するまで、本がちゃんと届いているか、印刷されているかが心配だったか、まったく問題なかった。

決済用のQRコードと表紙が印刷されたポップが準備されててありがたかった。

会社の会議室で設営の練習をしておいてよかった。

💨当日の様子

SKKユーザー、入力メソッド作ろうとしてる・作っている人がわりと来てくれて嬉しかった。 一日であれだけど数のSKKユーザーと会うのははじめての体験でよかった。

サークルスペースが通りやすいところにあったせいか、いろんな人が見本誌を手に取ってくれた。 誰もいないタイミングはほぼなかった。黒曜堂の@に店番を手伝ってもらえなかったら詰んでた。

暇なタイミングでboothに電子版を出す準備するつもりだったが、そんな余裕はまったくなかった。 PCのバッテリー持つかなーと心配していたが、完全に杞憂だった。

💸頒布冊数

手元に在庫をほぼ残さず、頒布できた。

  • 日本語入力を作るときに必要だった本: 143冊(書籍版: 100冊、DLカード: 43枚)
  • 工場実習日記: 98冊

工場実習日記は進捗大陸にも置かせてもらっていたので、そちらでも70冊ほど頒布した。

被サークルチェック数は、最終的に190だった。 来てくれた人はちゃんとチェックをつけてくれてるように思う。

👣サークル巡り

ほとんど自サークルに居たが、たまに抜けだして他のサークルを見にいった。

事前にサークルチェックをしたものの「まあ、自分の欲しい本だし、ぶらぶらしてれば見つかるでしょ」と思いながら歩いてたため、完全に破滅した。 人が多くて特定のサークルを目指して歩かないと辿りつけなかった。 たぶん事前にチェックしたサークルの半数くらいにしか辿りつけていない。

他の参加者の様子を見ていると、サークル配置図を印刷したものを持ってきてる人が多かった。 賢いと思う。

💕その他感想

  • 見本誌は「はじめに」を熟読してる人が多かった。 目次を読む派なので意外。 次は「はじめに」をもっとちゃんと書こう。
  • DLカードのほうが人気かと思ったが、書籍版のほうが人気だった。
  • 本のタイトルはTwitter検索しやしいもののほうがよさそう。工場実習日記は技術書典4の工場実習日記 - Togetterというまとめが作れて楽しそう。

📘 #技術書典 の本に書かなかった話

何度か書いているが技術書典 4のい15で入力メソッドについて解説した本を頒布する。

f:id:mzp:20180421131444j:plain

この本では、話題が脇道にそれるのを避けるために、いくつかの話題を排除した。せっかくなのでここに記録しておく。 ただ、いくつか根拠があやふやのものもあるので注意してほしい。

アイヌ語の入力メソッド

アイヌ語はもともと文字を持っていなかったが、カナ表記を用いた表記方法が存在する。 そのためにコㇿポックㇽのㇿやㇽといった小書きカナが存在する。他にもラテン文字による転写もあるが、ここでは扱わない。

この小書きカナを入力するための入力メソッドがアイヌ語入力メソッドである。

カタカナを入力するという点では日本語入力と共通しているが、実装は共通化されておらず、漢字入力の機能もない。扱う言語もjaではなくainとして登録されており、別ものである。

f:id:mzp:20180421132820p:plain

入力メソッドと教育

入力メソッドと教育

日本語入力にローマ字入力とかな入力があるように、中国入力にも拼音入力と注音入力といった複数の入力方法がある。

日本語入力ではローマ字入力の利用が主流だが、中国では地域によって違う。 台湾では注音入力、中国本土では拼音入力が主に用いられている。これは教育の違いに由来するものらしい。

文字を書くというのは教育と深い関係があることが再認識できて興味深い。

入力メソッドと信仰

国際SILは非営利のキリスト教信仰に基づく少数言語のための組織である。(とWikipediaに書いてあった)

国際SILはKeymanという入力メソッドをリリースしている。 これは次のような特徴を持つ。

おそらくありとあらゆる環境で、すべての人が母語を入力できるようにするのが目標なのだろう。

国際SILの目的のひとつは「少数言語の発展を援助する」なので、このために開発を続けているのだろう。自らの信じることのためにひたすら入力メソッドを開発する行為、これはまさしく信仰である。

漢字とは何か

漢字は古代中国で誕生したのち、日本、韓国、ベトナムといった国々に伝来した。

その後、その国の事情にあわせていくつかの文字が追加・転用された。例えば、峠・畑・辻といった日本にのみ存在する国字と呼ばれる文字も存在している。

同様に、現代中国、韓国、ベトナムには他の国にない漢字を元にした文字が存在している。

  • 簡体字(Han)。本当に国字と呼ばれているかは調べきれていない。 現代の中国語表記に用いられるやつ。
  • 和製漢字(Kanji)。日本で作られた漢字。畑とかが有名だと思う。書籍によって日本漢字、国字などと呼ばれていて、どれが正式がよくわからない。
  • ハンチャ(Hang)。韓国で使われる漢字(朝鮮における漢字)。書籍によって朝鮮だったり韓国だったりする。
  • チュノム(Chunom)・ハンノム(HanNom)ベトナムで用いられる文字。 元々の漢字とあわせて使う場合はハンノムになる。

このような状況のため「漢字」と言った際に、どの範囲を指すか不明瞭である。

すべての総称として「漢字」を使う場合もあれば、ベトナム語のように中国由来の文字のチュハン、漢字を応用して作った文字をチュノムというように区別する場合もある。

「漢字と、漢字から派生した文字」という表現もできなくはないが、そうなるとひらがな・カタカナも含まれてしまう。 これは一般には適切ではない。

Unicodeではこのような「漢字」はCJK unified ideographsとなっており「中国、日本、韓国で用いられる表意文字」とされており、厳密な定義を避けてるように見えて興味深い。

中国語の入力メソッド

中国語の入力方法は多数存在する。 macOSに標準搭載されているものだけでも5種類存在する。

f:id:mzp:20180421132519p:plain

これに加えて、中国語の文字体系も1つではなく、簡体字繁体字がある。

これら多数の入力方式を実現するために、中国語入力は以下のような仕組みになっている。

  • 拼音入力、注音入力といった入力方式の違いは、入力モードとして実装する
  • 簡体字繁体字は別の入力メソッドとして実装する
  • 簡体字繁体字の共通部分は内部的なフレームワーク(動的リンクライブラリ)として抽出する

f:id:mzp:20180421132719p:plain

これは他の入力メソッドには見られない仕組みなのでおもしろい。

設定画面のキーボードレイアウト表示

入力ソースの設定画面にはキーボードレイアウトが表示する領域がある。奇妙なことに日本語入力はローマ字入力がかな入力かによって表示がかわる。

f:id:mzp:20180421133404p:plain

入力メソッドとキーボードレイアウトの対応は、システム環境設定の設定ペイン*1にハードコードされている。

000000000000a81b        pushq   %rbp
000000000000a81c        movq    %rsp, %rbp
000000000000a81f        subq    $0x130, %rsp
000000000000a826        movq    0xa823(%rip), %rax ## literal pool symbol address: ___stack_chk_guard
000000000000a82d        movq    (%rax), %rax
000000000000a830        movq    %rax, -0x8(%rbp)
000000000000a834        leaq    0xc125(%rip), %rax ## Objc cfstring ref: @"com.apple.inputmethod.SCIM.WBX"
000000000000a83b        movq    %rax, %xmm0
000000000000a840        leaq    0xbf59(%rip), %rax ## Objc cfstring ref: @"com.apple.inputmethod.SCIM.WBH"
000000000000a847        movq    %rax, %xmm1
000000000000a84c        punpcklqdq      %xmm0, %xmm1
000000000000a850        leaq    -0x130(%rbp), %rcx
000000000000a857        movdqa  %xmm1, (%rcx)
000000000000a85b        leaq    0xc11e(%rip), %rax ## Objc cfstring ref: @"com.apple.keylayout.WubixingKeyboard"
000000000000a862        movq    %rax, %xmm1
000000000000a867        leaq    0xc0d2(%rip), %rax ## Objc cfstring ref: @"com.apple.keylayout.WubihuaKeyboard"
000000000000a86e        movq    %rax, %xmm0
000000000000a873        movdqa  %xmm0, %xmm2
000000000000a877        punpcklqdq      %xmm1, %xmm2
000000000000a87b        leaq    -0xa0(%rbp), %rdx
000000000000a882        movdqa  %xmm2, (%rdx)

そのためこの機能は、外部の入力メソッドからは利用できない。この話はInputMethodKitの非公開機能にも書いし、Radar済みである。

入力モードの使い方

「入力モード」の使い方は言語によって違う。

ベトナム語入力ではTelex,VNIといった入力方式を切り替える。 これは日本語入力で言うところのローマ字入力、かな入力といった違いに相当する。

f:id:mzp:20180424064042p:plain

一方、日本語では「ひらがな」「カタカナ」といった文字の種類の違いを選択する。

f:id:mzp:20180424064150p:plain

なぜこの違いが生じたのかは分からない。 たぶん歴史的なものだろう。

絵文字の可能性

f:id:mzp:20180424063827p:plain

中国語入力・日本語入力が特殊な位置付けになっているのは、漢字の種類が膨大であることが原因の1つである。 Unicodeに収録された文字体系を見ても1万種類を越える文字を持つ言語は稀である。

ただし絵文字は漢字に匹敵する文字数を持つ可能性がある。 現時点で1000文字を越えており、今後も増える可能性がある。さらにSkin toneといった修飾子によって、バリエーションも増やせる。

そのため、絵文字の文字数が増えるにしたがい、入力メソッドのような仕組みが一般化していく可能性がある。

絵文字がある種のUnicodeバグを世界から一掃しつつある件について|Rui Ueyama|note に類似した話だと思う。

*1:/System/Library/PreferencePanes/Keyboard.prefPane/Contents/Resources/IntlKeyboard.prefPane

💕パペ文字によるVR出社

パペ文字zoomを組合せて、リモート勤務した。

📌きっかけ

10年後に会社がどうなっているかを話す会を実施した。 その中で「VR出社」を挙げている人が多かった。

f:id:mzp:20180419111550p:plain

10年後にやるなら今から慣れといたほうがいいなという気持ちになったので、試した。 たぶんみんなの言うアバターは美少女のことではない。

🎥構成

パペ文字からzoomへの配信はできない。たぶんzoomがReplayKitによる配信に対応してないせいだと思う。

そこで、次のような構成にした。

  1. iPhone X + パペ文字で美少女になる。
  2. QuickTimeiPhone Xの画面をキャプチャする。
  3. CamTwistでアプリケーションの画面をWebカメラとして認識させる。
  4. CamTwistカメラをzoomで利用する。

✨様子

💬 Slack

アバターにあわせてSlackのアイコンを変更した。

f:id:mzp:20180419112320j:plain

表情がぎこちないといわれる。

f:id:mzp:20180419141114p:plain

zoomのアバターを変えるより、Slackのアイコンを変更したほうが反響が大きい。

f:id:mzp:20180419141152p:plain

言葉遣いをかわいくしようという意識が働くが、勝手が分からない。

💓その他の反応