みずぴー日記

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

💖アイドルとして勤務する -理論と実践- #imas_hack

speakerdeck.com

IM@S Engineer Talks - connpassで話した。

あいさつとアジェンダ

f:id:mzp:20180712104110j:plain

こんにちは。mzpです。

f:id:mzp:20180712104115j:plain

本日はアイドルアバターで勤務する話をする。

背景: リモートワークの欠点

f:id:mzp:20180712104120j:plain

ボクの“副業”先はリモートワークを推奨している。これには雨の日は出社が面倒くさいと思う人が多かった、名古屋だけではエンジニアを集めれなかった、など様々な事情がある。

チームメンバーの半数は遠隔地に住んでいるため、リモートワークを前提とした働き方が必要となる。

f:id:mzp:20180712104123j:plain

リモートワークはいくつかの利点があるが、欠点もある。 今回は「自室から勤務する」という欠点にスポットをあてる。

f:id:mzp:20180712104126j:plain

カメラに写る範囲に変なものを置けない。 私はリモートワークをする直前に、カメラに写る範囲から物をどかすという作業をしている。

よく写るように、部屋の照明をだいぶ明るくする必要がある。 まぶしい。

f:id:mzp:20180712104131j:plain

この問題は弊社固有ではないらしく、同じくリモートワークを推進するソニックガーデン社ではこのような解決案が提案されている。(テレビ会議を劇的に円滑にする簡単なノウハウ | Social Change!)

このようにカメラのうつる範囲にオフィス風のポスターをはることで、自宅にいながらオフィスで勤務しているかのようにみせることができる。

f:id:mzp:20180712104135j:plain

こういった問題があるため、社内でVR勤務を求める声があがりはじめた。 これは全社集会で「10年後なにをやっていたいか」という話をした結果だが「アバター勤務」がやりたいことにあげられている。

f:id:mzp:20180712104139j:plain

よりよい未来は自分で作っていかなければならないので、アイドルアバターによるリモートワークを開始した。

デモ

f:id:mzp:20180712104142j:plain

デモです。

アバター勤務の利点

f:id:mzp:20180712104145j:plain

これでオンラインミーティングに参加するとこのようになる。 これは今週あった朝会の様子である。

これを今年の4月から続けている。

f:id:mzp:20180712104149j:plain

背景を気にしないくてよくなる。

iPhone Xの顔認識は可視光を利用していないため、部屋の明さを気にする必要もない。

f:id:mzp:20180712104152j:plain

自分の表情が反映されるので、積極的に笑顔になろうとする意識が働く。 姿勢もよくしたほうがいい。

f:id:mzp:20180712104156j:plain

かわいい表情を維持するために表情に気をつかうようになる。

f:id:mzp:20180712104200j:plain

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

f:id:mzp:20180712104204j:plain

自分が微笑むとアイドルも微笑み返してくれる。脳にいい。

だんだんと自分がかわいい気がしてくる。むしろ自分がアイドルだ。

社内の反応

f:id:mzp:20180712104208j:plain

同僚の反応はこのようなものだった。 だいたいみんな戸惑いつつTwitterでしゃべっていた。 Slackは静かだった。

f:id:mzp:20180712104211j:plain

一方で弊社の代表がわりといい話をしていた。

「チームメンバーとして見た目は関係ない、性別、年齢も関係ない。みながベストな格好で勤務してほしい」

f:id:mzp:20180712104214j:plain

ただ、Slackアイコンを変えたほうが反響が大きくておもしろかった。「Slackコールがアイドルからの電話になる」

社外の反応

f:id:mzp:20180712104218j:plain

いくつかブログに書いたところ、社外からもいくつかの反応をもらった。

f:id:mzp:20180712104222j:plain

「mzpさんってあの美少女の人ですか」「はいそうです」という会話をしたことである。 まさか、美少女ですかと確認されて、肯定することが生じるとは思っていなかった。

f:id:mzp:20180712104225j:plain

あと「今後、アバター勤務が一般化したとして、そのときは同調圧力が働いて無難なアバターになるのでは。美少女などが使えるのは先行者だけだ」という考察がよかった。 説得力がある。

仕組み

f:id:mzp:20180712104228j:plain

今日はエンジニアトークなので、ここからは仕組みの話をする

f:id:mzp:20180712104232j:plain

コンセプトとしては気軽につかえるアバターシステム。 リモートワークしながら使えるのが前提となるので、専用のコントローラやセンサーを使ったものは避けた。 理想は通常のカメラと同様に使えるアバターシステムである。

f:id:mzp:20180712104235j:plain

このシステムは、主に4つの部分で構成されている。 - 人間の顔をiPhoneのセンサーで認識する - 認識した結果をアイドルに変換するiPhoneアプリ - iPhoneの画面をmacOSでキャプチャする - キャプチャした結果をオンラインミーティングアプリに接続する これらを1つづつ説明していく。

iPhone Xによる顔認識

f:id:mzp:20180712104239j:plain

最初はiPhoneによる顔認識について話す。

f:id:mzp:20180712104242j:plain

iPhone XにはFace IDのために顔の形状を認識するためのセンサーが搭載されている。これは30,000以上の赤外線ドットを顔に照射することで、顔の形状を読み取る。

f:id:mzp:20180712104245j:plain

ARKitを用いることで、このセンサー類で検知した顔の向きや表情を取得できる。本当にさまざまな表情が取得できるので眉毛のうごきだけとっても左右上下の動きをとれることになってる。 ただ、ボクはそこまで自在に眉が動かせないのでデバッグできない。

f:id:mzp:20180712104249j:plain

常にカメラで顔を写すためにスタンドが必要である。 今回はライトニングドックを用いた(iPhone Lightning Dock - ホワイト - Apple(日本))。

アイドルへの変換

f:id:mzp:20180712104252j:plain

次はアイドルへの変換について話す

f:id:mzp:20180712104256j:plain

ここではiPhoneのセンサーで検知した顔の向きや表情をアバターに反映させる。開発にはUnityを用いた。

f:id:mzp:20180712104300j:plain

顔の向きの反映は座標系を間違えなければそれほど難しくはない。hただ失敗すると顔が異常な方向を向いてしまうので怖い。

f:id:mzp:20180712104304j:plain

表情の反映はいくつかの工夫が必要である。 ARKitは顔の各パーツの動きを取得しているが、アバターはモーフという単位で表情を管理している。 このギャップを埋める必要がある。

f:id:mzp:20180712104308j:plain

たとえば眉毛の上下運動を左右のまばたきと対応づける。 顎の位置を口の大きさに対応づけるといった工夫をしている。 また、表情はオーバーなほうが伝わりやすいので一部は係数をおおきめにかけている。

f:id:mzp:20180712104312j:plain

我々は目をとじるとなにも見えなくなるので、まばたきがうまく反映できているかのデバッグはむつかしい。 結果、ウインクの練習が必須となる。

f:id:mzp:20180712104315j:plain

アイドルは基本笑顔だが、我々の基本は無表情なので対応が難しい。 今回は無表情は笑顔、笑顔は歯をみせる笑顔に対応づけた。

f:id:mzp:20180712104319j:plain

眉毛をさげるといった3次元の存在である我々には難しい表情はショートカットを設ける。 ここでは口をすぼめると困った顔になるというショートカット表情を導入している。

f:id:mzp:20180712104323j:plain

しかしそこまで多彩な表情ができるわけではないので「泣き顔」「怒っている顔」などは割愛した。 仕事している上でそんなに利用しないだろうという判断のものだが、笑顔と困っている顔に制限されたアバターで勤務するのはだいぶディストピアっぽい。

f:id:mzp:20180712104326j:plain

Tスタンスではなくかわいいポーズが必要となる。 いろいろ見た中で、照れ - ニコニコ静画 (イラスト)のポーズのうちミクの後ろに腕をまわしているポーズがかわいかったので採用した。

f:id:mzp:20180712104329j:plain

そのまま適用するとこうなる。 とてもかわいいが、上半身と首をひねっているため長時間は厳しい。

f:id:mzp:20180712104418j:plain

つらいとTwitterにつぶやくと、弊社人事よりかわいいは我慢だというコメントを貰う。

f:id:mzp:20180712104421j:plain

そうはいっても首をいためそうだったので、ポーズは修正した。 このように胴体の角度をなくし、楽に維持できるようにした。

iPhoneのキャプチャ

f:id:mzp:20180712104426j:plain

次はiPhoneの画面をキャプチャする仕組みである。

f:id:mzp:20180712104434j:plain

ここはゲーム実況配信のためにさまざまな知見が蓄積されている。 HDMI出力をキャプチャする、AirPlay互換サーバーを使うなど様々な方法がある。

f:id:mzp:20180712104438j:plain

今回はmacOSを使うのでQuickTime Playerによるキャプチャを用いた。

f:id:mzp:20180712104442j:plain

キャプチャの技術的詳細は、ばんじゅんさんがPhotoStudioPlayerを作る過程で検討しているのでそちらを参照してほしい(デレステフォトスタジオのリアルタイム透過プレイヤーをつくった - ツバメになったバリスタ)。

オンラインミーティングへの参加

f:id:mzp:20180712104445j:plain

最後にオンラインミーティングへの参加である。

f:id:mzp:20180712104449j:plain

キャプチャした内容を仮想カメラとして認識させるにはCamTwistを用いた。

f:id:mzp:20180712104456j:plain

特定のアプリのみをキャプチャできるので、それでQuickTimeを選択した。

f:id:mzp:20180712104459j:plain

あとはオンラインミーティングアプリでCamTwistによって作られた仮想カメラを選択すれば、ミーティングに参加できる。 どのアプリを使うかは会社の都合によって変わるところだが、今回はzoomを用いた。

まとめ

f:id:mzp:20180712104505j:plain

まとめると、次の流れでアイドルアバターによるリモートワークを実現している。

  • iPhone X + ARKitで表情をキャプチャする
  • Unityで作成したアプリで表情をアイドルにマップする
  • macOSiPhone画面をカメラとして認識させ、オンラインミーティングに参加する

さあ、みなさんもアイドルとしてリモートワークしましょう。

自撮り機能

f:id:mzp:20180712104508j:plain

このアプリにはリモートワーク用以外にもいくつかの機能を搭載している。まずはスクリーンショット保存機能。

f:id:mzp:20180712104512j:plain

デバッグの途中でだんだんと卯月の自取り画像を作るのがたのしくなってきたのでつけた。 よりリアリティをだすためにあえてシャッター音をつけている。

撮影ボタンなどもなるべくカメラアプリに見えるよう工夫した。

f:id:mzp:20180712104515j:plain

カメラロールがこのような状態になる。 かわいい。

f:id:mzp:20180712104519j:plain

正面より斜めのほうがいいと発見した。

f:id:mzp:20180712104522j:plain

見おろす感じもいい。

f:id:mzp:20180712104526j:plain

上からみおろすのもよい。

f:id:mzp:20180712104530j:plain

シャフトアニメにありがちなポーズ、通称シャフ度をしようとしたがうまくいかなかった。

f:id:mzp:20180712104534j:plain

笑顔とウインクと顔の角度を工夫したやつです。 これがいちばんうまく撮れたと思う。

ブルーバックスクリーン

f:id:mzp:20180712104538j:plain

背景をブルーバックスクリーンにする機能もある。

f:id:mzp:20180712104542j:plain

まるでデレステのフォトスタジオみたいですね。 ということは、さきほどばんじゅんさんの発表であったPhotoStudioPlayerとくみあせると、デスクトップ上にアイドルを呼べる。

f:id:mzp:20180712104546j:plain

このためにカメラ位置の調整機能もつけているので、こうすると全身を写せる。まるでデスクトップに住んでいるようになりますね。

f:id:mzp:20180712104551j:plain

Twitterでは「伺かだ....」というコメントを何件かもらいましたがみなさんしっていますか。ボクは謎のダメージを受ける。はてブコメントではひたすら「\e」と書かれた。

あんまり続けると老人会になるのでこれくらいにしておく。

今後の課題

f:id:mzp:20180712104555j:plain

目線制御をいれたい。 iPhoneのカメラをみることなくiPhoneの画面を見る技術が必要になる気がしてる。

iOS12のARKit2では単純に顔認識の向上らしいので、さらなる精度向上が見込める。 さらに舌認識がついたので対応したいが、仕事中に舌を出すシチュエーションが思いつかないので、あまり使い道はないかもしれない。

顔しか認識しないため、あまり複雑なポーズができない。 せめて手を動かしたい。OpenPoseなど姿勢推定アルゴリズムと組合せることで、手を認識できるようになるかもしれない。

専用のコントローラを用いて腕の制御をする方式も考えられるがリモートワーク支援という文脈からはずれてしまう上、手軽さがなくなってしまうので悩み所である。

類似ツール

f:id:mzp:20180712104601j:plain

最後に類似ツールがいくつかあるので紹介する。

f:id:mzp:20180712104604j:plain

FaceRig

f:id:mzp:20180712104608j:plain

パペ文字

f:id:mzp:20180712104613j:plain

iOS12のFaceTime。 今年のWWDCで発表された新機能。もともとメッセージアプリでは絵文字に表情をつけて送信するアニモジという機能があったが、これが通話に拡張された。 キーノートを現地で聞いていたが、これを見た瞬間、時代が追いついてきた!と思った。

まとめ

f:id:mzp:20180712104618j:plainf:id:mzp:20180712104621j:plain

🏭工場日記

工場実習日記の名前はシモーヌ・ヴェイユの工場日記に由来する。 この本には第二次世界大戦以前の工場で勤務した経験が綴られている。 著者の観察力が非常に高く、工場での労働について鋭い記述が多い。

工場日記 (ちくま学芸文庫)

工場日記 (ちくま学芸文庫)

🐾経緯・来歴

シモーヌ・ヴェイユは哲学者である。

哲学には詳しくないが、本の序文やWikipediaにある記述を要約すると次のような経緯で工場で働くことに決めたらしい。

幼ないころから優秀で、パリ高等師範学校を卒業したのち高等中学校の教授となる。 これがどれくらいの難しさなのかがいまひとつ分からないが、"教授資格者"の手当が存在しているかとや、現代のパリ高等師範学校の記述)を読む限りでは相当な難関であると想像できる。

そのなかで社会主義と出会い、その中で語られる労働者の生活を実際に体感したいと熱望するようになった。 そこで教職をしばらく休み、いくつかの工場で働きはじめた。

そのときの体験は、日記や断片的なメモ、友人にあてた手紙などに残されている。 これをまとめたものが工場日記である。

🤕消耗していく様子

さすがに工場での労働はつらかったらしく、どんどん消耗していく様子が見てとれる。 働くのがつらい、というのが何度も書いてある。

働いて食べるということは、多かれ少なかれ、苦しいことではないだろうか。

一歩一歩がわたしには苦痛だった(精神的に。 帰るときには、苦痛は肉体的になる)

朝の四時半に、眠りたいというつよい欲望がおこってきた。しかし、もう起きねばならなかった。 平日休みをとればいいという誘惑をしりぞける。

地下鉄で、若い女が「もう、がんばれそうにないわ」。 ——— わたしもだ・・・・・・。

一歩一歩歩くということに、確かな意思の力が要る。 帰宅してみれば、それでもたいへん元気になった。

一たん機械の前へ立ったら、一日八時間は、自分のたましいを殺し、思考を殺し、感情を殺し、すべてを殺さなければならない。

🤔思考の放棄

工場で淡々と同じ作業を繰り返すためには、余計なことを考えないことがコツである。 それが合わなかったらしくそれに対する悔しさも繰り返し登場する。

(昼休みに)「プリジュニク(大衆向けデパート)」で食事、くつろぐ。 工場へもどるまでの、しばらくの楽しい時間、技師たち、職工たち・・・・・・。 機械の前へもどると、また奴隷になったように思う。

こういう生活がもたらすもっともつよい誘惑に、わたしもまた、ほとんどうちかつことができないようになあった。 それは、もはや考えることをしないという誘惑である。 それだけが苦しまずにすむ、ただ一つの、唯一の方法なのだ。 ただ土曜日の午後と日曜日にだけ、わたしにも思い出や、思考の断片がもどってくる。 このわたしもまた、考える存在であったことを思いだす。

(考えるのをやめるのは) スピードをあげるための要件だ。ものを考えるのをやめなければならないということの屈辱感を、心の底から感じる。

ひまな時間は、一応理論的には、一日八時間労働なので、かなりあるはずですが、実際には、疲労のためにないのも同じことです。

考えないために給料が支払われている傾向がありそうです。

🔥周囲への評価

作業を意味を考えずに仕事している同僚たちが気にくわなかったらしく、辛辣なことを書いている。

数学の勉強をしなかったら、機械は、労働者にとって一つの神秘的存在になる。

仲間たちは、自分たちが奴隷であることを、十分に理解していないからなのだ。

決して苦しんだことのない人間の単純さ。

専門家は堕落をまねく。

🎓要求の高さ

来歴によるものだと思うが、周囲に要求する水準が高い。さらに本人は高いことを自覚してない様子なのがおもしろい。

かれは、ラテン語を二年間、ギリシア語を一年間、英語を少し勉強したことがあるそうだ。 (こういうことを、かれはなんのてらいもなく自慢する)。

(昔の教え子への手紙で) 教科書や講義の批判をするのです。 やってみると、おどろくほどたくさんな誤った理論が横行していることがわかるでしょう。 こういう遊びは非常に有益です。

その他

💻デスクトップマスコット

f:id:mzp:20180620232647p:plain

美少女として勤務するで作ったアバター表示アプリと、デレステフォトスタジオのリアルタイム透過プレイヤーをつくったのクロマキーフィルターつきiPhoneキャプチャを組合せることでデスクトップマスコットになった。

👚ポーズ

デスクトップマスコットになるには全身を写す必要があるので、Tスタンスではなくかわいいポーズが必要となる。

いろいろ見た中で、以下のポーズのうちミクの後ろに腕をまわしているポーズがかわいかったので採用した。

seiga.nicovideo.jp

そのまま適用するとこうなる。

f:id:mzp:20180620233126p:plain

とてもかわいいが、上半身と首をひねっているため長時間は厳しい。 多少、ポーズは修正した。修正はVmd2XMLを利用した。

f:id:mzp:20180620233935p:plain

かわいいには我慢がつきものらしい。

🏟背景色

クロマキー合成をするために背景を単色に切り替えれるようにした。 これはカメラのSkybox設定をいじって実現した。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChangeBackground : MonoBehaviour {
    private int count = 0;

    public void OnClick() {
        count = (count + 1) % 4;

        switch(count) {
            case 0:
                Camera.main.clearFlags = CameraClearFlags.Skybox;
                Camera.main.backgroundColor = new Color(49/255.0f, 77/255.0f, 121/255.0f);
                break;
            case 1:
                Camera.main.clearFlags = CameraClearFlags.SolidColor;
                Camera.main.backgroundColor = new Color(0.15f, 0.48f, 1);
                break;
            case 2:
                Camera.main.clearFlags = CameraClearFlags.SolidColor;
                Camera.main.backgroundColor = new Color(1, 3/255.0f, 102/255.0f);
                break;
            case 3:
                Camera.main.clearFlags = CameraClearFlags.SolidColor;
                Camera.main.backgroundColor = new Color(251/255.0f, 179/255.0f, 2/255.0f);
                break;
            default:
                break;
        }
    }
}

そのままMastodonでtootしたらコマ割りされたみたいになってよかった。アニメのアイキャッチ画像っぽい。

f:id:mzp:20180630154431p:plain

📷カメラ位置の調整

全身がはいるようにカメラ位置をずらした。 こうしてみると、引きで写すとかわいい衣装がよく見えて、いいのかもしれない。

f:id:mzp:20180620234751p:plain

その他

💎RubyKaigi 2018

RubyKaigi 2018に参加した。 RubyKaigi(仙台)、WWDC(サンノゼ)、出張(東京)というかなり強い日程になっていたがなんとか落ち着いた。

f:id:mzp:20180530121726j:plain

🎤セッション

Rubyの型に興味があったので、型の話を中心に聞いた。

ASTのまわりの発表がいくつかあったので聞いた。 やっぱり型と文法には興味ひかれる。

TRICK 2018 (FINAL)は見たかったが移動と被ってしまって見られなかった。 残念。

✨ブース

開始直後にEightのTシャツを貰いにいったら写真を撮られた。美少女として勤務するで笑顔の練習をしたので、なんとか笑えた。

定期的にコーヒーが提供されててうれしかった。

f:id:mzp:20180531123956j:plain

お弁当おいしい。 牛タンを食べにいくタイミングがなかったが、お弁当で食べれた。

f:id:mzp:20180531120035j:plain

⌨️SKK

SKKこと仙台高等工業学校の跡地も見にいった。

f:id:mzp:20180530141855j:plain

日本語入力のSKKとの関係は微妙で、関係は明言されていないが無関係のはずがないくらいの感じになっている。Wikipediaでは以下のように断言を避けている。

また、東北大学の教授により開発されていたわけであるが、新制東北大学の工学部の母体のひとつ仙台高等工業学校の略称もSKKである。

SKK - Wikipedia

それはそれとして、校歌が刻まれた石碑があってよかった。

f:id:mzp:20180530142550j:plain

校歌だけあって、言葉が格調高くていい。「SKKのわかき子」「SKKの名を揚げよ」が心に染みる。

f:id:mzp:20180530142702j:plain

f:id:mzp:20180530142656j:plain

f:id:mzp:20180530142708j:plain

そのあと年表を見たら「SKKの名は消えた」と書いてあって、アッとなった。

f:id:mzp:20180530142757j:plain

🦀瑞鳳

瑞鳳のバイキングがやばいと聞いていたのでRubyKaigiの前日に泊まった。

togetter.com

同僚2人と泊まったが部屋が異様にひろくてびびる。

f:id:mzp:20180530171157j:plain

部屋の玄関が広すぎる。

f:id:mzp:20180530171137j:plain

聞いていたとおり夕食が豪華。好きなだけ蟹が食べれる。

f:id:mzp:20180530192411j:plain

肉もある。

f:id:mzp:20180530192442j:plain

温泉も広くて最高だった。

🍽食事

移動に追われたせいで街中で買い食いしたくらいしか仙台っぽいものを食べていない。

仙台にしかないという土鍋チーズこってりの天下一品。

f:id:mzp:20180530131756j:plain

ひょうたん揚げ。 かまぼこで作ったアメリカンドッグみたいな味がする。

f:id:mzp:20180530133853j:plain

たいやき。

f:id:mzp:20180530150412j:plain

⏰時短勤務

勤務時間を7時間/日とする時短勤務をはじめて1年半ほどが経過した。

かなりよいのでまとめておく。 年収の向上と同程度の価値があると感じている。

f:id:mzp:20180530215053p:plain

🏢業務

業務内容は大きな変化なく、支障なくできている(と思う)。 いくつかの要因がありそうだが、よく分からない。

  • 8時間勤務のうち最後の1時間は疲労していることが多い。疲労していて生産性が悪い時間がなくなっているだけなので、影響は少ない。
  • フレックス勤務なのでまとめて働きたい日は残業して、他の日に早く帰るなどの調整をしている。
  • もともと全員の出勤時間・退勤時間はばらばらなので、自分が早く帰っても周囲の負荷が少ない。

🍻ハッピーアワー

たまたま無職・休職中の知り合いが多かったのでハッピーアワーに飲みに行っていた。なぜか寿司の写真が多い。

f:id:mzp:20180129183425j:plain

f:id:mzp:20170601201940j:plain

f:id:mzp:20180321194532j:plain

大半が職を得てしまったので今後は難しいかもしれない。大半の友人はフルタイムで勤務しているので、ご飯の約束をすると、どこかで時間を潰す必要が生じる。

🚶‍♂️通勤

自由になる時間が増えたので、これまで電車で移動していた区間を徒歩にするなどしてゆっくり通勤するようにした。

最初のうちは新鮮でよかったが、だんだん飽きてきた。 それでも気分転換になるので、たまにやっている。

通勤途中にある神社がひょうたん推しでおもしろかった。

f:id:mzp:20180530215014p:plain

♨️スーパー銭湯

時間に余裕ができたので、スーパー銭湯にたまに行くようになった。

気分転換と疲労回復を狙っているが、継続的に成果を出し続けるたったひとつの冴えたやりかた - Misoca開発者ブログにあるように温泉の近くに住んだほうが効率がよい気がする。

👜リモートワーク

旅先でリモートワークをし、仕事後に観光するのを何度かやった。 これは時短勤務ととても相性がよい。

旭川の街中を散歩しているときの様子。

f:id:mzp:20170612180456j:plain

松江の宍道湖から見た夕日はよかった。仕事終わりが日没ぎりぎりになってしまったので、あわてて走った。

f:id:mzp:20180208084312j:plain

雪がやばいということに目をつむれば、玉造温泉はすごく雰囲気がよかった。

f:id:mzp:20180208233742j:plain

✨個人活動

技術書典参加などは、自由になる時間が増えたおかげである。

執筆の負荷がだいぶ軽減されたと思う。いきなり2冊出せたのも執筆時間が確保できたのが大きい。

f:id:mzp:20180422102943j:plain

🎬映画を見る

会社帰りに映画を見にいきやすくなるかと思ったが、これはうまく行かなかった。

これは「開始時間が固定なので早く仕事が終わっても早く見れるわけではない」「そんなに映画が好きではない」などの理由が大きい。結局、家でNetflixを見ている。

💖美少女として勤務する

パペ文字による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に接続してビルドしはじめた。 あとからビルドを始めたのに、先にビルドが終わったのでびびった。