にせねこメモ

はてなダイアリーがUTF-8じゃないので移ってきました。

静的なHTMLページをoEmbedで他サイトに埋め込み可能にする

YouTubeなどの動画サイトの動画や、ブログ記事の内容をブログカードとして埋め込むための規格の一つとして、oEmbedがある。はてなブログもoEmbedに対応している(埋め込む側・埋め込まれる側両方とも)。

仕様概要

oEmbedの仕様は https://oembed.com/ にある。

これを見ると、埋め込まれる側がoEmbedに対応するには、だいたい次のようになっている。

URL schemeはendpointと同じドメイン(サブドメインは違ってもよい)で、http/httpsも一致してる必要がある。

http://flickr.com/services/oembed?url=http%3A//flickr.com/photos/bees/2362225867/

のようにAPI endpointにURL schemeを渡すと、仕様に定義されているようなパラメータをもったJSONまたはXMLが返ってくる。JSONXMLのどちらを返すかは、クエリパラメータで指定することもできるし、別々のendpointを用意することもできる。

さて、これではURL schemeAPI endpointのペアを知らないとoEmbedを呼び出すことはできない。ここで、HTMLページにその情報を埋め込むことで発見できるようにしている。次の例が挙げられている。

<link rel="alternate" type="application/json+oembed"
  href="http://flickr.com/services/oembed?url=http%3A%2F%2Fflickr.com%2Fphotos%2Fbees%2F2362225867%2F&format=json"
  title="Bacon Lollys oEmbed Profile" />
<link rel="alternate" type="text/xml+oembed"
  href="http://flickr.com/services/oembed?url=http%3A%2F%2Fflickr.com%2Fphotos%2Fbees%2F2362225867%2F&format=xml"
  title="Bacon Lollys oEmbed Profile" />

静的Webページにも対応できるか

API endpointは入力されたURLに対応して動的に出力を返すことを前提としている。
しかし、適当にHTMLで書いたページを公開するのに動的なCGIを置くのも気が引けるので、ページ毎にendpointを用意したら、動的な仕組みを用意せずともoEmbed対応できるのでは? と考えて、やってみた。

以下の4ファイルは https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/ 以下にアップロードすることを前提としている。

index.html

<!DOCTYPE html>
<html>
<head>
<title>oEmbedのテスト</title>
<link rel="alternate" type="application/json+oembed"
  href="https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/oembed.json"
  title="oEmbed Profile of oEmbedのテスト"/>
<link rel="alternate" type="text/xml+oembed"
  href="https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/oembed.xml"
  title="oEmbed Profile of oEmbedのテスト"/>
</head>
<body>
このページを埋め込み可能にします。
</body>
</html>

クエリパラメータのurlは固定なので省いた。Vineなんかも似た様な感じで、動画毎にJSON/XMLファイルのURLを用意してクエリ文字列を使わずに対処してるっぽい。
参考: はてなブログの貼り付けにVineが対応していた - すなばいじり

oembed.json

{
    "author_name": "nixeneko",
    "html": "<div style=\"width:100%;height:120px;border:1px solid;font-weight:bold;overflow:hidden;background-color:white;\"><img src=\"https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/simarin.jpg\" width=120 height=120 style=\"float:left;margin-right:10px;\"/>ここをキャンプ地とする</div>",
    "url": "https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/index.html",
    "version": "1.0",
    "height": 120,
    "width": "100%",
    "description": "おい概要食わねぇか",
    "type": "rich",
    "title": "埋め込みどうでしょう"
}

JSONXMLの情報は、oEmbed公式の説明やはてなブログの設定などを参考に書いた。ブログなどではhtmlパラメータが埋め込まれて表示されるっぽい。
また、widthに100%と指定しているがこれは仕様としては正しくなく、ピクセル単位の数値にすべきであるが、はてなブログのoEmbed情報では100%となっている。

oembed.xml

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<oembed>
  <author_name>nixeneko</author_name>
  <description>おい概要食わねぇか</description>
  <height>120</height>
  <html>&lt;div style=&quot;width:100%;height:120px;border:1px solid;font-weight:bold;overflow:hidden;background-color:white;&quot;&gt;&lt;img src=&quot;https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/simarin.jpg&quot; width=120 height=120 style=&quot;float:left;margin-right:10px;&quot;/&gt;ここをキャンプ地とする&lt;/div&gt;</html>
  <title>埋め込みどうでしょう</title>
  <type>rich</type>
  <url>https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/index.html</url>
  <version>1.0</version>
  <width>100%</width>
</oembed>

.htaccess

AddType application/json .json
AddType text/xml .xml

HTTPレスポンスヘッダのContent-Typeを適切に設定する必要があり、JSONはapplication/jsonXMLtext/xmlにする。

テスト

はてなブログではURL記法で:embedを指定することで、oEmbed対応サイトを記事に埋め込むことができる。

[https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/index.html:embed]

と書くと、↓のようにoEmbedの埋め込みが表示される。

ここをキャンプ地とする
↑ここまで

いけた! htmlパラメータがそのまま埋め込まれているようである。

また、 http://iframely.com/debug などを使ってoEmbedが認識されているかを確かめてみることもできる。

備考

ブログなどでoEmbedを埋め込む側ではセキュリティ的にホワイトリスト方式をとっているものもあり、そこではこのような得体のしれないoEmbedは参照されないことになるかもしれない。

JSONを手で書くのは現実的ではないので、何らかの方法で自動生成した方がよさそう。

oEmbedの情報はキャッシュされるので、JSON/XMLに変更を加えても反映にしばらく時間がかかる可能性がある。テスト中はキャッシュの生存期間cache_age (秒数を指定)を小さく指定しておくといいかもしれないが、必ずしもcache_ageの値を使うとは限らないらしい。

(2018-03-22 追記)
今回は埋め込み用HTMLにiframeを使っていないが、oEmbedで埋め込めるようになっているページは、大抵はiframeを使って別のHTMLページを読み込ませるようになっている。このとき、iframeによって埋め込まれるページのレスポンスヘッダのContent-Security-Policyが他サイトへの埋め込みを許可するように適切に設定されていないと、読み込まれないことになる。

現在のUnicodeモンゴル文字の問題点と最近の動き

モンゴル文字は、主にモンゴル語表記のための文字*1である。縦書き専用の文字であり、日本語の場合とは反対に左から右へと行を進める。また、アラビア文字のように続け書きされ、文字が語のどの位置に来るかによって形が変わる。
モンゴル文字は現在も中国の内モンゴル自治区モンゴル語の表記に現役で使用されている。他方モンゴル国ではソ連の影響下でモンゴル語の表記をキリル文字に切り替えたので、モンゴル文字は学校で習いはするものの一般にあまり使われない。

Unicode 3.0からモンゴル文字がシベ文字・トド文字・満州文字と統合されて収録されているため、コンピュータでこの文字を入力するにあたっては、独自の符号化方式を作成するのでなければUnicodeを利用しようとするのが当然に思える。しかし、現状のUnicodeモンゴル文字は致命的な欠陥を抱えている。

このエントリでは、2017年ころからUnicode Technical Committee (UTC)で盛んに議論されているUnicodeモンゴル文字ブロックの問題点と、その改善に向けた動きを、現代モンゴル語の表記を基本として見ていく。

Unicodeのサイトに、モンゴル文字に関するUTC文書がまとめられている。この記事はその最近の文書の内容を元にしている。

致命的な欠陥: 相互運用性がない

Unicodeモンゴル文字の最大で致命的な問題点は、エンコーディングのレベルで相互運用性(interoperability)がないことである。平たく言い替えると、機種依存文字状態になっている。

喩えを用いるのは不適当かもしれないが、ラテン文字の符号化で考えると、

  • 大文字小文字は統合し同一コードポイントとする
  • 大文字小文字の区別のためのvariant selectorを用意し、文字に後置するかしないかによって大文字小文字を区別する
  • 一方、variant selectorを付けた場合と付けない場合のどちらが大文字でどちらが小文字かが未定義なため、両方式のフォントが共存していて、互いに互換性がない

といった状況である。


現状のエンコーディングでは、モンゴル文字の表示はフォント依存である。これは、Unicode公式で明文化されている規則だけではフォントを実装するには情報が足りず(underspecified)、各々のフォントベンダがそれぞれの解釈で実装を進めた結果、ベンダ間で実装が非互換となっている。あるフォントでは正しく表示されるUnicode文字列が、別のフォントでは正しく表示されないということが普通に起こっている。

一例として、「良い」という意味の単語(キリル文字表記はсайн)を挙げる。次図は、L2/17-334 On migration issues of the graphetic modelのAppendixからの引用である。
f:id:nixeneko:20180224162725p:plain
縦は3種類のコードポイントの並びを、横は8つのフォントベンダの実装を示す。黒い単語は正しく表示されているものを、グレーは単語が正しく表示されていないものを表す。フォントベンダは、左からMenksoft (中国)、Delehi (Almasとも, 中国)、IMUCS (中国)、Founder (中国)、Huaguang (中国)、Bolorsoft (モンゴル国)、Microsoft (米国)、Google (米国)である。

どのコードポイントの並びをとっても、全てのフォントで正しく表示できるものは存在しないことが分かる。

ここで挙げられている三種類のコードポイントの組み合わせについて、一体どれが正しいのかというと、Unicodeでは規定されていない。つまり、誰も「何をどう表示すれば正しく実装できたといえるのか」が分かっていないという状態である。


どうしてこうなった: 音声情報の符号化

モンゴル文字が元々複雑だからというのが一つの原因ではあるが、もう一つの原因は現状のUnicodeモンゴル文字が音声情報ベースの符号化であることである。


X3L2/96-054 Joint proposal draft on encoding Mongolian Character Setは1996年にモンゴル国と中国が共同で作成したモンゴル文字符号化の草案であるが、その中で、符号化の方針として次のような記述がある。

● To guarantee the information integrity(not to lose the information) , different characters of the same glyph are coded separately.
The main principle to abide by is “No Information loss”.

(略)
② The sound information of Mongolian is very important especially in data indexing and searching. In many cases, a letter is of different pronunciation and different meaning accordingly. It is rather necessary to encode them all . This will contribute greatly to the information processing of Mongolian script.

http://www.unicode.org/L2/L1996/96054-n1368-mongolian.pdf

という訳で、形が同じだが別の音を表すものであるなら別々の文字としてコード化すべき*2だと言い、音声情報を符号化することを強く推している。

その後の議論については読んでないので分からないが、現状のUnicodeモンゴル文字ブロックも基本的にこの方針でエンコードされている。
この音声情報を符号化することが混乱を引き起こしている。

音声情報ベースで符号化を行うと、ソートが簡単になる、また異音同綴語を区別できるなどの利点はあるが、レンダリングが複雑になり、文字の入力や照合に混乱をもたらすなどの欠点がある。

音声情報を符号化するというのは、モンゴル文字ラテン文字転写とだいたい一対一の対応がとれるということでもある。モンゴル文語の文法書においてはラテン文字転写で説明されていることも多い。
転写とは文字の音声的な特徴を写し取ったもので、形の情報を区別しないことがある。そのため、転写は、一部の文字についてはモンゴル文字で書き分けない文字を書き分けるし、別の文字についてはモンゴル文字で書き分ける文字を書き分けられないという特徴がある。これが転写ひいては符号化されたコードポイントとモンゴル文字の字形との間の対応のずれとなり、どうにか対応付けをするために複雑な仕組みを必要としている。

モンゴル文字の複雑さ

音声情報を符号化したために、モンゴル文字の形状の複雑さはシステムやフォント側が引き受けることとなった。

モンゴル文字がどのように複雑だったり、混乱を招いているのかを見ていく。

母音調和による字形変化

モンゴル文字は、語の中のどの位置にくるかによって、また母音調和等によって形が変化する。

モンゴル語における母音調和とは、男性母音(a, o, u)と女性母音(e, ö, ü)の2つの母音系列が、原則一語中で混ぜて使われないというものである。他に、どちらの系列とも共存できる中性母音(i)がある。
母音が男性母音または中性母音からなる単語を男性語、女性母音または中性母音からなる単語を女性語という。中性母音のみからなる単語は女性語となる。

子音によっては、男性語と女性語で別の形を使うものがあり、例えば、U+182D MONGOLIAN LETTER GAは、次のように7種類以上の字形に変化する(赤部分。実際には母音等の文字とリガチャになっているものもありフォントグリフとは一致していないので注意)。
f:id:nixeneko:20180302222513p:plain
このように同じコードポイントの文字を、システムとフォントによって適切な形で表示する必要があるのだが、その規則は明示されてない部分も多いため、手探りで実装することになる。

二重母音のi

母音のiは次のような形を取り得る。
f:id:nixeneko:20180303133752p:plain
語中のiは基本的に「すね」(左下に突き出る斜め線のこと; шилбэ 脛)が1本でかかれる。

一方で、本記事の冒頭で掲げた「良い」という意味の単語(キリル文字でсайн)は、「子音s + 二重母音ai + 子音n」という構成になっているのであるが、語中の二重母音の二番目のiは「すね」が2本となり、これを“i”で転写する方式と“yi”と転写する方式とがある*3。それぞれに従うと「良い」сайнの転写は順に“sain”, “sayin”となる。

他方、二重母音の2番目にくるiはすべて「すね」2本なのかというとそうではなく、数字の8(キリル文字でнайм)とその派生語については例外的にiは「すね」1本でかくため、「良い」сайнを“sain”とする場合、同じ“i”でも「すね」が1本のときと2本が存在することになる。
f:id:nixeneko:20180303151408p:plain
また、本来の文字yは基本的に「すね」の先が上に跳ね上がった形でかかれる。そのため、二重母音の「すね」2本のiを“yi”で転写するポッペ式における“sayiqan”という転写は、

  • сайхан「素晴らしい」(yはまっすぐな「すね」)
  • саяхан「つい先ほど」(yは曲がった「すね」)

のどちらの語をも表しうる*4
f:id:nixeneko:20180303151434p:plain
このように、同じ文字が単語ごとに正書法によって複数の形に書き分けられるため、文字の形を変更するvariation sequenceという仕組みが存在している。これは、形を変更したい文字にvariation selectorという専用の符号を後置することで、文字を望んだ形に変更するという仕組みである。しかし、どれを本則として、どれをバリエーションとするかについて定義が不十分であるため、混乱がある*5

まとめると、冒頭で掲げた「良い」(сайн)という単語は、

  1. 語頭・語中の二重母音aiを転写するのに“ai”と“ayi”のどちらを使うか*6。両方採用することも可能。
  2. “ayi”を採用する場合、「基本はyをまっすぐな『すね』で表示して、曲がった形にするためにvariation sequenceという仕組みを用いる」か、あるいはその逆か

という2つの分類で説明できる。
繰り返すがこれについてはどれが正しいかというものは規定されていないため、どの方式にも理があるが、互換性はない。

書き分けない文字に別々のコードポイントを当てる

他にも、同じ見た目の文字でも音が異なるならば別々にコード化するという方針により、語中のどの位置でも書き分けのないo, uに別々のコードポイントが与えられている。ö, üについても同様である。他にも書き分けのない文字はあるが省略する。
f:id:nixeneko:20180303171046p:plain
モンゴル語を理解する人は発音が分かるので、どちらを使えばいいか分かるのではないかという考えもあるかもしれない。しかし、モンゴル文字表記が作られてから時間が経っているため、綴りと発音が乖離しており、発音からo, uのどちらだとわかるとは限らない。また、モンゴル語ではアクセントの関係で、第一音節にある母音ははっきりと発音されるが、第二音節以降の短母音は弱化して曖昧に発音される。そのため、転写方法においても、モンゴル文字で形の区別のないo, uについて、oとuをすべて区別して書き分ける方法と、第一音節のみo, uを書き分け、第二音節以降はuで統一するという方式が併存している*7。転写方法も一様でないし、その転写とほぼ一対一で対応する音声情報ベースのエンコードにおいても表現が一様にならないのは当然という気もする。

結果として同じ見た目になるコードポイント列がたくさん存在し、入力する人にとっても優しくないし、検索を行うにしても、形が同じなのに引っかからないという事態が発生することになる*8
さらに、キーボードのキートップからは同じ形の文字の区別がよくわからないため、「正しい綴り」というものがもし存在したとしても、それを入力するのは難しい。結果的に人にも機械にとっても厳しい仕組みとなっているのが現状である。

現状の問題点まとめ

現状のエンコーディングモデルについて、L2/17-328 Script Ad Hoc Group Recommendations on Mongolian Text Modelでは次のような欠点が挙げられている。

  • モデルが非常に複雑であり、仕様が十分に定義されていない(undespecified)。結果としてテキスト表現が曖昧である(ambiguous)
  • フォントやレンダリングエンジンに非常に複雑な文脈依存ルール(contextual rule)を必要とするが、明確な仕様がない
  • そのルールでは求める表示にならない文字を直すために、大量のvariation sequencesを必要とする
  • フォントの実装や提供を行うことが非常に困難
  • 結果、異なる実装やフォントで事実上相互運用性がない
  • 相互運用性を“修正”するために、不安定な根拠の不安定なパッチ群を必要とする
  • 国際ドメイン名でサポートされることはない(同じ見た目を示す複数のコードポイント列が存在するため、セキュリティ上困難)
  • 標準的なユーザにとって、検索が非常に困難になる可能性がある(入力テキストが曖昧性をもつため)
  • 顕著なセキュリティ上の懸念がある
  • テキスト表現に含まれる音声情報はtext-to-speechにも言語分析にも実際効果的ではない

散々な言われようである。

改善の動き

さすがにこの現状ではまずいだろうと、Unicodeモンゴル文字改善のためのScript Ad Hoc Groupが作られ、改善に向けた動きが活発になっている。

L2/17-243 Script Ad Hoc report and recommendations on Mongolianにおいて、2種類の改善案が出されている。それぞれの特徴を挙げる。

1. 字形アプローチ(Graphetic approach)

  • 文字の形と振舞いを基準に、音でなく形をベースとして文字を特定する
  • あいまいさがなくなり、同じ見た目の語であればコード列が一通りに定まる。見たとおりに入力すればいい
  • 現状のモデルの根本的な再構成であり、非互換
  • 15程度の文字を新規に追加し、混乱の生じない文字については再利用する。既存の文字には変更を加えず、現状のモデルとの共存が可能
  • アラビア文字のようなcursive-joining modelでシンプルに実装できる
  • 現代モンゴル語の表記(Hudumという)にはvariation sequencesを必要としない(歴史的な文書や表記ミスを再現するためにvariation sequencesは必要ではある)
  • 音声情報を持たないため、適切な順番にソートすることが難しく、同綴異義語の区別ができない

2. 音声アプローチ(Phonetic approach)

  • 現状のモデルを全体としては維持する
  • 現在の中国標準規格と整合しやすい
  • 新規に文字は追加せず、現在のvariation selectorsの振舞を修正あるいは廃止して新しく追加するもので置き換えることによって、相互運用性を確保する
  • 現状のモデルの複雑さをほとんど引き継ぐ


字形アプローチについてはL2/17-335 [Draft] A graphetic approach for the Mongolian encoding modelで独立した草案が作成されている。
また、モンゴル文字は字形アプローチとし、モンゴル文字と統合されている他の文字(トド文字・シベ文字・満州文字)については大きく変更せず*9、全体の整合性を整えた案がL2/17-333 A mixed encoding scheme for the Mongolian blockである。

これから字形アプローチ策定者はフォントやシステム等の試験実装を作成し、それによってモンゴル文字の表現において問題があるかどうかを検査していくだろうということである。

各国の反応

さて、Script Ad Hoc Groupは字形アプローチを強く推しているのであるが、中国やモンゴル国はどのように思っているのだろうか。
2017年9月23-25日に中国のフフホトで開催されたWG2 ad hoc meeting on MongolianのレポートがL2/17-347 Mongolian Ad Hoc Report (Hohhot, Inner Mongolia)である。

この文書によると、The Mongolian Working Group (おそらく中国か?)はthe Phonetic modelを支持し、モンゴル国の代表たちもthe Phonetic modelを支持しているとのことである。Unicode Technical Committeeの代表たちはどちらのモデルがよいとは言わなかったが、モンゴル文字テキスト処理の現状を懸念していることを表明した。

どちらにせよ、現状のモデルには多数の問題があり、改善策としてどちらの方式がとられたとしても、長期目標としてはモンゴル文字テキストを交換可能かつ将来にわたってアクセス可能にすること(interchangeable and accessible for future generations)であると会議の出席者は合意している。また、この問題の解決に向けて情報(や知識)を共有したり、協働することに同意したとのことである。

中国・モンゴル国の両国ともに現状と地続きの音声アプローチの方を支持しているようであるが、最終的にどの方式が選ばれるにしろ、相互運用性が確保されることは期待できそうである。
標準化の会議が年一回なので、公式の規格となるのは早くても2019年のUnicode 12.0以降となる。動向に注目したい。

参考文献

モンゴル文字に関するUTCの文書
Unicodeモンゴル文字の字形(variants)について
Unicode 10.0の、現状のモンゴル文字ブロックについての説明

*1:「用字系(script)」と言った方が適切かもしれないが、記事内では基本的に「文字」で統一した。

*2:「“cake”のcと“nice”のcは発音違うから別のコード当てよう!」みたいな話で、書き分けがないのであれば同じ文字として統合する方が分かりやすいし、Unicodeの他の文字体系でもそのようになっている。

*3:「すね」2本の二重母音aiを“ai”とする方式と“ayi”とする方式がある。参考: Transliteration Schemes For Mongolian Vertical Script

*4:塩谷茂樹・中嶋善輝(2011)『大阪大学世界言語研究センター 世界の言語シリーズ3 モンゴル語』、大阪大学出版会。初版第1刷 p. 60.

*5:Variation sequenceはUnicodeのStandardizedVariants.txtである程度の標準化がなされているが、抜けがあったり、不十分であるため、ここにおいても改善の議論がある。

*6:“ayi”の方を採用するメリットとして、наймの「すね」1本のiと区別可能という面がある。

*7:第二音節以降を一律にuで転写する方式は「現代の代表的な文語辞典であるレッシング(F. D. Lessing)の辞書が採用する方式」で、一方「歴史的な経過と形態論的な配慮を紙してoとuを表記し分ける方式」は「提案者にちなんでポッペ・モスタールト(Poppe-Mostaert)方式と称され」ていて、両方式が併存しているとのことである。(河野六郎 編(2001)『言語学大辞典 別巻 世界文字辞典』、三省堂。pp. 1038-1044「蒙古文字」の項)

*8:もちろん、現状のエンコーディングで同一形状を判定できるようなルールを作る場合、そのルールはフォント依存となる。

*9:トド文字・シベ文字・満州文字モンゴル文字の派生であるが、モンゴル文字で書き分けないが異なる音を表すものについて、文字を変形したり、点等の記号を付したりして字形の区別をつくり、曖昧さをなくした(減らした)ものなので、音と文字がよく対応し、音声アプローチでも問題が少ない。

Python 3でpopcountを計算する

ある整数値が与えられたとき、それを二進数表記した時の1の個数(1になっているビットの数)を数えるのをpopcountと呼ぶらしい(population countの略)。これはハミング距離を計算するのに使え、2つの値のXORをとってpopcountを計算すればハミング距離となる。

Pythonには標準で用意されてないので、64ビット整数に対する演算を想定していくつかの実装を比べてみる。
Python 3系は整数に決まった上限がないので、64-bit unsigned int相当の \ 0\ \text{~}\ 2^{64}-1\ の範囲の整数値を入力として計算する。

TL;DR

  • bin(n).count("1")が簡潔でそこそこ速い
  • メモリを使ってよければ、事前計算した216要素の配列を引くのが標準機能だけでは最速に近いかもしれない
  • gmpy2ライブラリのgmpy2.popcount(n)を使うのが最速

速度の計測

Python 3でいくつかの実装の速さをみてみる。

環境

速度の計測にはrandom.getrandbitsで64ビットの乱数を取得してそれに関数を適用し、1000000回の処理時間をtimeitで測定した。

測定結果

関数 秒数
dummy 0.4457
popcnt0 9.9395
popcnt1 1.4312
popcnt2 1.7646
popcnt3 1.6916
popcnt4 1.6313
popcnt5 1.0738
popcnt6 0.4762

dummyは、何も計算せず定数を返す関数であり、乱数の取得や関数呼び出しにどの程度の時間がかかるかをみる為に用意した。

def dummy(n):
    return 0

popcnt0: 単純なループによるもの

工夫しないとこの程度の時間になるという、比較用のベースラインとして用意した。

def popcnt0(n):
    c = 0
    for i in range(64):
        c += (n >> i) & 1
    return c

これより遅い実装も可能で、再帰を使ったものは実行時間がこれの2倍程度になった。

2進数の文字列にして“1”の数を数える

標準ライブラリでシンプルに実装できるうえ、桁数の制限がない。

popcnt1: bin()を使うもの

def popcnt1(n):
    return bin(n).count("1")

標準機能だけでシンプルであり、速度的にもそんなに遅くないので、大抵はこれを使えば十分そうである。

popcnt2: "{:b}".format()を使うもの

def popcnt2(n):
    return "{:b}".format(n).count("1")

bin()を使った場合より遅かった。

popcnt3: ビット演算を使うもの

def popcnt3(n):
    c = (n & 0x5555555555555555) + ((n>>1) & 0x5555555555555555)
    c = (c & 0x3333333333333333) + ((c>>2) & 0x3333333333333333)
    c = (c & 0x0f0f0f0f0f0f0f0f) + ((c>>4) & 0x0f0f0f0f0f0f0f0f)
    c = (c & 0x00ff00ff00ff00ff) + ((c>>8) & 0x00ff00ff00ff00ff)
    c = (c & 0x0000ffff0000ffff) + ((c>>16) & 0x0000ffff0000ffff)
    c = (c & 0x00000000ffffffff) + ((c>>32) & 0x00000000ffffffff)
    return c

ビットマスク・ビットシフトと足し算を使って計算したもの。原理は次を参照。

事前に計算した配列を引くもの

8ビット、16ビット等適当に決めたビット数で表現できる任意の整数に対するpopcountを計算した配列を事前に用意しておき、実際にpopcountを計算する時には64ビット値を事前に決めたビット数ごとに分割し、配列から対応する計算済みの値を取り出して足し合わせる。

popcnt4: 2^8要素の配列を利用

POPCOUNT_TABLE8 = [0] * 2**8
for index in range(len(POPCOUNT_TABLE8)):
    POPCOUNT_TABLE8[index] = (index & 1) + POPCOUNT_TABLE8[index >> 1]

def popcnt4(v):
    return (POPCOUNT_TABLE8[ v        & 0xff] +
            POPCOUNT_TABLE8[(v >> 8)  & 0xff] +
            POPCOUNT_TABLE8[(v >> 16) & 0xff] +
            POPCOUNT_TABLE8[(v >> 24) & 0xff] +
            POPCOUNT_TABLE8[(v >> 32) & 0xff] +
            POPCOUNT_TABLE8[(v >> 40) & 0xff] +
            POPCOUNT_TABLE8[(v >> 48) & 0xff] +
            POPCOUNT_TABLE8[ v >> 56        ])

この環境ではbin(n).count("1")のpopcnt1より遅いのでわざわざ使うものではなさそう。

popcnt5: 2^16要素の配列を利用

POPCOUNT_TABLE16 = [0] * 2**16
for index in range(len(POPCOUNT_TABLE16)):
    POPCOUNT_TABLE16[index] = (index & 1) + POPCOUNT_TABLE16[index >> 1]

def popcnt5(v):
    return (POPCOUNT_TABLE16[ v        & 0xffff] +
            POPCOUNT_TABLE16[(v >> 16) & 0xffff] +
            POPCOUNT_TABLE16[(v >> 32) & 0xffff] +
            POPCOUNT_TABLE16[(v >> 48)         ])

この環境では標準機能だけを利用した中では最速となったが、速度は環境に依存しそうではある。あと、2^16個の要素からなる配列をメモリに確保するのはあまりうれしくない。
また、ここではpopcountの計算だけを行っているが、他にもいろいろな処理をする場合には配列がキャッシュに乗りきらず速度は低下するのではないかと書いてる人もいた。

popcnt6: gmpy2ライブラリを使う

Cで実装された多倍長演算Pythonライブラリgmpy2を使うのが速そうである。ライブラリのコンパイル設定にもよるかもしれないが、gmpy2が利用しているライブラリであるGMPやMPIRはSSE4.2で追加されたPOPCNTというCPU命令を内部で使っているようだ。
GMPやMPIR自体が多倍長演算ライブラリなので、桁数の制限もなさそう。

インストール

Windowsではプリコンパイルされたものがあるのでそれを使うか、Anacondaを使用してる場合はAnaconda Promptからcondaコマンドで入れることができる。

conda install -c anaconda gmpy2

Unix/Linuxの人はInstallationを参照。Ubuntuではaptで入るらしい(python3-gmpy)。

コード

import gmpy2
popcnt6 = gmpy2.popcount

最速。定数を返すdummy関数の場合と実行時間が大して変わらず、popcountの計算にほとんど時間がかかっていないことがわかる。ライブラリが使える環境であればこれを利用するのが速い。

まとめ

標準機能だけを利用する場合、bin(n).count("1")が簡潔で速度も悪くなく、大抵はこれを使えば良さそう。桁数の制限もない。

標準機能だけの利用で最速なのは事前計算した2^16要素からなる配列を引くものであった。とはいっても環境によっては遅いかもしれないし、メモリを必要とするのであまりうれしくない。

外部ライブラリを使ってよいのであれば、gmpy2のgmpy2.popcountを使うのが一番速そう。


とはいえそこまで速度追い求める必要があるのならPython使わない気もするが…。

「フレンズの会」まとめ

2017年4月29日と6月3日に「フレンズの会」という、アニメ『けものフレンズ』の制作スタッフが集まり作品について話すトークイベントが行われた。基本的に2回とも同じ内容であり、6/3は再公演という体である。今更だけどメモをまとめておく。

メモから起こしているし時間も経っているため、あやふやな所もあると思うのでご容赦いただきたい。他の人がまとめているものがあると思うので比較しつつ読むとよいかもしれない。

以下、基本的に敬称略とした。

プロデューサーパート

プロデューサー・細谷(テレビ東京)、アニメーションプロデューサー・福原(ヤオヨロズ)

4/29

  • ニコニコ超会議けものフレンズのキャラ(のグッズを売ってるところがあった)
    • 2次創作推奨してるけどちょっと頒布のレベルを超えてるというか…
  • ヤオヨロズのやり方は何がなんだか分からない(細谷)
  • 3行位の各話のあらすじが去年の夏前に
    • 普通はシリーズ構成の人が全体の骨子をかき、シナリオライター・脚本の人がシリーズで4~5人、あと何度も見ていく
  • 「作り方違うっぽいんで大丈夫です」(と言っていた) (細谷)
  • 最初の方嫌いでした(細谷)
  • 最大の功績はあきらめたこと(細谷)
  • 委員会十何社、何でヒットしたか誰もわからない(福原)
  • 黙ってたことだけが仕事(細谷)
  • たつきを信じろ」が、委員会でも同じ感じ(福原)
  • ファミマプリント、サーバーが落ちた
  • 基本全部落ちてる
  • ラインスタンプ、使い勝手がよい
    • 6話までのファン投票
    • 『ゔっ』(バスにはねられるサーバル)は使い勝手が悪いからだめだとライン社に言われたが、通した
  • 5/26一挙配信 LV30館くらい
  • 舞台 結構前から決まってた

6/3

  • 三行のあらすじだけで10月、11月までひっぱった
  • 前特番のバラエティ(0話)に金田さんと小林さんを使いたかったので本編に入れてもらった(細谷)
    • 金田さんはトキを、小林さんはツチノコを知らなかった
  • 0話をいつにするか会議をしていた。初めにしてよかった(7話位に入れる案もあった, 制作側としては途中で挟まった方が楽)

ほか権利的な話、けものフレンズは二次創作を推奨してるけれど、商業みたいなのはちょっと…みたいな話。同人の範囲なら、とか

制作パート

美術監督・白水、作画監督・伊佐、監督・たつき、アニメーションプロデューサー・福原
1~4話の映像を流しながらコメンタリーという感じ。
2回の話をマージするのも難しそうだったので左右に並列させた。横ぶち抜きの見出しはシーンの目安だが厳密でない。

4/29の回6/3の回
  • 美術監督の役割は普通のアニメと同じ感じ
  • 作画監督の役割は普通のアニメの総作画監督作画監督の役割
  • コンテの描き方
    • Vコンにするか、コンテ作った後にVコンにするか
    • 5種類くらい2~3話まで試した
一話最初
  • サバンナの乾燥感を出すのが難しかった、かさかさしてる草の感じ(白水)
  • 一話、キャラクター紹介がいっぱい出てくるのではなく、かばんちゃんとサーバルちゃんしか出てこない、美術の重みが大きい(福原)
  • 空と草と遠くに山(白水)
    • どこを向いても草原しかない
  • (省力化のために)壁をどうにかして(作りたい)と冗談で言ってみた
  • シマウマには悪いことをした
  • 難所を通る
    • (調べても)平原しかない。「あるからもっと調べろ」と言われて、探したら雨季の時削られた川、湖(があった) (伊佐)
  • 伊佐が設定周りを一貫してやっていた(たつき)
    • (それによって)深みがでた(白水)
  • 美術、作監、設定にも強い。ボードの作成など途中でも情報共有ができた(福原)
    • 結構スイッチする
  • サバンナの乾燥感を出すのが難しい(白水)
  • カットごっそりなくなったりとか(福原)
  • ミライさんとか出るか出えへんかとか(たつき)
  • 何回か作り直した(伊佐)
  • サバンナは大体が美術(福原)
    • 何もない。草、山、空、木…(白水)
  • 場面設定上起伏がある地形について調べて見つからなかったが、たつき監督に「絶対あるからちゃんと調べて」と言われて調べ直したら、雨季と乾期があるところで、流木などで起伏があるところがあった(伊佐)
  • はじめ、1話乾期、2話雨季とかだったが、だるいから切った(たつき)
  • 引き(の画)が多い(キャラが小さい)。自然物が多い。パーク感を出す(たつき)
  • 1話は世界観が分かる映像を持ってこないといけない(福原)
  • CGで全身写すと大変(たつき)
  • やっとサバンナの書き方に慣れたらすぐ密林に(白水)
  • 設定は使い捨てじゃんじゃんいく(たつき)
テーブル
  • だんだん文明物が出てくる(たつき)
  • 最初はかばんちゃんに名前がなかった、主人公って呼んでいた(白水)
  • 11話くらい、主人公のままオーダーを出してた(たつき)
  • しんざきさんとトークイベントしたい(福原)
  • テーブルなどの人工物を匂わす程度に出して行く(たつき)
  • バオバブの木のシーン…ストーリーが改変になって追加で作ったカット、没になった後に作り出した(伊佐)
  • 原作が無い作品なので、一回、結構つくって、半分くらいつくって、だいたいこんな感じの作品だねって感じで(たつき)
水場のシーン
  • 湿気…最初の乾燥感と差を出す(伊佐)
  • サバンナの水場の感じが難しい、さいしょ岩清水、日本庭園っぽくなった(白水)
  • つかみかけたところでさよなら、ストックができない(白水)
  • 最初の方話は聞いてた、ラフを用意してたが、どんどん変わるので軌道修正(伊佐)
  • ゲストキャラを使えるかどうかわからない、探り探りやっていた(たつき)
    • 4~5話でだいぶ確定
    • モデルとして使えるキャラで、その地域にでてくるキャラ(たつき)
  • サバンナ、雨季も出してもよかった(たつき)
  • ボード段階では雨季も描いてた(白水)
  • 2話は雨季の予定だったがジャングルと被る(たつき)
  • よくあるCGアニメはメインとなるステージつくっとけば、そこでしゃべってれば新しいモデルを用意しなくていい(福原)
  • モデルのリスト3~40体出すってことに「死ぬのか」って(福原)
  • 1話1体じゃしょっぱい(たつき)
  • お客さん目線のたつきと作る方のたつきといる(福原)
  • 動物の特徴を盛り込むってのに苦労した(伊佐)
  • サバンナの水場なので、どれくらい水々しくしたらいいか、日本の岩清水のようになってもいけない(白水)
  • (美術を描いてて)ジャパリパークがどれくらいの広さなのか分からなかった(白水)
  • (福原に見たことある景色なのか聞かれて)ちょいちょいどこかで見たとこあるな感がある(たつき)
  • 日本ではないので乾燥感をつけて差別化(たつき)
  • 硬い感じの葉、ブラシを作成して描いた、イネ科など(白水)
  • 調べるとイネ科だけでたくさんある(伊佐)
  • (映像をちょっと巻き戻して)見たこともない顔があった(たつき)
    • (ネットとかでよく見るサーバルちゃんのまぬけな顔)中割だった
ゲート
  • 1話、テイクが多かった(たつき)
  • 1話は結構作り直した(伊佐)
  • 没カットが雑誌に出てた
  • 雑誌の取材用に没カットに手を加えて嘘カットを作った(対セルリアン)
  • 劇伴は、ナチュラルな世界だけどセルリアンだけ異質感、デジタルな感じ
  • 最初強いなあと思ったけど、何回もかかるんで
  • カバの髪の毛は監督がつくった
  • 目の種類は意識して多くつくった、ハンコ絵になりにくい様に(たつき)
別れのシーン
  • 1話の脚本とシリーズ構成の相似性(福原)
  • 一話をまず上げて、全体と並行して構成と脚本同時にできたので、2~10話で全体で細かいところを回収していった(たつき)
  • 結構隠してる。後から気づいたり、人から教えられて知ることが多い(伊佐)
  • 全部を共有してるわけではない(白水)
  • 少しずつ小出しにされた(伊佐)
  • わかってかいちゃうとだめということもある、顔とかで分かるとだめ(たつき)
    • 声優とか顕著(福原)
  • アニメーターがキャラに感情を載せすぎるとだめなときがある(たつき)
  • 最初2話分を一話に圧縮(たつき)
  • 紙飛行機をスタッフの人にヨレヨレにつくってもらったが、ヨレヨレ感が足りなかったのでもっとヨレヨレにした(伊佐)
  • ヨレヨレにするのはCGでは難しい。「下手にすんのが下手」(たつき)
  • (再会のシーン) (この木実際にあるの?に対し)ユーフォルビアという木(白水)
  • 雨季エリアの設定、ゲートでサバンナから雨季に(白水)
  • ゲートは国境のイメージ(伊佐)
    • 日本人としては土の上に境目があるのはぐっとくる(たつき)
  • 一話最後鳥とかが飛んでいく(福原)
    • 精一杯の言い訳を……鳥もいることをできるだけ早くに示そうとした(たつき)
  • アフリカの夕焼けのイメージ
  • 色の設定、色の感覚は監督が一番強いので何度もダメ出しをされた(白水)
  • (作ってるので)見るのあんまり慣れてない、ラッシュチェックでおなか痛い(たつき)
  • (クリエイターは永遠に作り続けるので)完成しないよね、締め切りってものがなかったら納品されないな(福原)
再会
  • ここでミライさんが(福原)
  • 10話かの犯人もここでいれていくっていう(たつき)
  • かばんちゃん、初めは名前が決まってなくて、主人公って呼んでいた。後半になってもかばんちゃんでなく主人公と呼ばれていた(白水)
  • 委員会で「かばんちゃん」って言う名前だと伝えたとき、みんな「はて?」って感じだった(福原)
OP
  • あまり記憶に残ってない、一ヶ月ぎりぎりでここで作らなきゃってときは、まじか(伊佐)
  • 1話狩りごっこ、OP、最後11,12話の勝負、どれか詰めたらどれか減る(たつき)
  • 一話けっこう頭から、その時点では12話まで作業工程は見えてた(たつき)
  • 全体にフラットに(たつき)
  • アニメーター、美術の時間感覚で全体見てると気が狂いますよね(たつき)
  • カットが1話300超えないように(たつき)
  • アニメ背景美術、一日に20~30枚かかないと(白水)
  • 勝負カットは1日1枚とか(白水)
  • カメラワークで大きく振るやつはほとんど映らないので書き込まない(白水)
  • (ボスとサーバル何かを持ってかばんに近づくシーンで)これは一体なんだったんでしょうか(たつき)
  • 昆布ってかかれてる(福原)
  • 一応答えはある(たつき)
  • 後半OP変えた時もぎりぎりまでまってもらった(福原)
  • 主人公の方しか喋らない。ラッキービーストの向きを修正させられた。あまりやるとサーバルいじめに加勢してるようで(伊佐)
2話 ジャングル
  • 1,2話で水場から見下ろすサバンナ全景、背景が主役(白水)
  • 広さ、どこまでがパークなのかつかめなかった。最初「こんなに大きく描いていいのかな」と戸惑いながら(白水)
  • 最初知らされてなかった(伊佐)
  • (監督は)ダミーを仕掛けてくる。最初、西ノ島を調べさせられた(伊佐)
  • サーバル・かばん二人との情報量を現場で合わせたい(たつき)
    • 「罠にはめてやろう」
    • なるべく美味しく食べてやろう
  • ジャングルの植物…身近な植物ではだめ、日本の森になる(白水)
    • シダなど
  • 2話でフォトショのブラシを10種類ほど作った(白水)
  • 普通のアニメのバンク、使いまわしがあまりない(福原)
  • 動物だし動かして相談しながらやってた
  • 調べることも多かった(福原)
  • エンターテイメントなので、最終的に(たつき)
  • 「塩をなめるか調べろ」(と監督に言われ)海外サイトで見つけた(アクシスジカ) (伊佐)
  • 動画は必ず一回見る(たつき)
  • ジャングル…11話で後ろにバスが走る
  • ジャングルの美術ちょーヤじゃない?(福原)
  • ちょーヤ……苦しみました(白水)
  • でも一話でブラシもさよなら(福原)
  • シダの葉っぱは再利用できないので、ここだけでしか使えない(白水)
  • ジャパリまん初登場(たつき)
  • 撮影の旭プロダクションの方で木漏れ日を綺麗に入れてもらって質が上がった
  • 最後はみんな愛で動いてた(福原)
  • 美術は全然バンク作ってないよね(福原)
  • バンクが全然できない(白水)
  • ボス、だんだんここら辺からギャグキャラに
川のシーン
  • 川、岸、増水とかで道が途絶えた設定(伊佐)
  • カワウソ、はじめおらんかった(たつき)
    • レア1、アプリ版で人気なかった(福原)
  • ここ一回全部すてた(はじめサル系だった) (たつき)
  • 石で遊ぶ
    • 石を見てない(伊佐)
    • このシーンの間の感じ、たつきくんの笑いの間はあんな感じ(福原)
  • ジャガーめっちゃいい人(たつき)
  • その場であるもので船をつくる、歩道で(伊佐)
  • 船の設定とかなんやかんやしてた(たつき)
  • ウォーキングコースとは変わるけどジャングルだし(白水)
  • どのような形にするか?作った感がでると文明レベルが上がってよくない(伊佐)
  • かばんちゃんが物を加工しはじめるのでそっちに割り当てたい(たつき)
  • 橋の浸水例などを調べて設定をつくった(伊佐)
    • 自然の摂理
  • コツメカワウソはゲームでは☆1で、ハズレ感(福原)
  • お手玉、あれをみて衝撃を受けて入れた(たつき)
  • 水場、普通の川と違ってねっとりしている。波にはこだわった(伊佐)
    • 撮影さんとの合わせ技
    • 美術で反射まで描いたり
    • 5話湖面のキラキラのエフェクト
Bパート
  • バス、最後にまで出る。リテイク。パークにある感じ、アトラクション感。プラモデルとか(伊佐)
    • 構想段階から(テイクが)4,50近い
  • 川の、主塔という吊橋のパーツ、設定を考えたのは監督のアイデア(白水)
  • (橋のパーツが)何でわかるんですか?(伊佐)
  • お客さんがネットで見つけてきたり(白水)
  • 6割くらいはもともとの知識、3~4割はけもの合わせで調べた(たつき)
  • 普段から天井ダクトがむき出しになった写真を撮っていた
  • 廃墟とか好き、軍艦島(たつき)
  • サーバルがバスをもって跳ぶシーン。マックスの馬鹿として早めに提示しておこう、3話崖から落ちても行ける、限度(たつき)
    • ものさし(福原)
  • 知能的にはカワウソが低い(福原)
  • 後半、文明レベルが上がるので、前半が野生っぽい(たつき)
  • バスはなかなかOKが出なかった(伊佐)
    • 前後に分けようとしたのは途中から(白水)
  • シリーズ構成のメモ出てきてちょっと怖かった、気触れてる感じが(たつき)
  • コツメカワウソははじめサル系だった
  • サルが木からブランブランして登場するアニメーションを作ってたが消えた(伊佐)
  • 動物ものは類人猿出ないなあ(制作時にズートピア公開) (福原)
  • 見たいもの作って評価されたのが(たつき)
  • たつき監督の知識の広がり
  • 浅くひっかけとく感じ(たつき)
  • アクシスジカが土なめるとこ
    • 海外の動画サイトで塩舐めてるのを見つけた(伊佐)
    • エンタメなので、本当か嘘かでは、嘘でも面白ければいいけど、できるだけ調べたい(たつき)
ED
  • 廃墟。明暗の暗部分。アニメのふり幅の下部分(たつき)
  • 実は立体的に動かしている。写真に見える美術(白水)
  • 美術をやらないといけない、モデルを作ってBOOK貼り付け(たつき)
  • 立体的な動かし方(の度合い)を段々上げていく(たつき)
  • 観覧車がラストカット最終回に繋がる(福原)
  • 一枚写真ではなく、書き足したり、モデルを別に作ったりした(たつき)
次回予告
  • 音を聞いて初めて内容を知る(たつき)
3話
  • (ラッキービーストの)「まかせて」、一周してから見ると面白い
  • ロープウェー、監督が「登り切ったところで最後下がるはずだ」と(伊佐)
  • たつき監督が「きっとこうだ」と言って、調べるとそう、というパターン(福原)
  • 平野から縦に(福原)
  • (3話)前半と後半で少しだけジャングルが再利用できる(白水)
  • ゴンドラは色々調べた(伊佐)
    • 実際に行ってみた
トキ
  • トキ、(金田さんが)すごいたくさん歌ってくれた(たつき)
    • 隙間を作っておいた(たつき)
    • 録り直し4つ5つ(セルフリテイク) (たつき)
  • 2話からOPにキャラクタがどんどん増えていく
  • トキの羽は監督がつけた(白水)
  • アニメーターとして触ってるところもまばらにある(たつき)
  • 3人ともまたがる領域の部分が多い(福原)
  • 飛ばす上下動が間違うと危ない動きになる(たつき)
  • 3DCGは歴史の蓄積がないので(手探り) (たつき)
  • フルCGのセルルックで1クール30分をやったのはポリゴンピクチュアズサンジゲンヤオヨロズくらいでは(福原)
  • 崖、何個かカットなくなった(たつき)
  • プレスコとアフレコ(のやり方を)この辺りまで(擦り合わせていた) (たつき)
  • プレ:アコが6:4、4:6とか、アフレコ寄りのプレスコ(たつき)
  • アルパカが出てきた後がつらい、できるだけ空に居てほしかった。空は素材兼用してカロリーを(削減した) (白水)
  • 熱心にやってもらって2テイク目くらいでいい感じだったが、3回4回やっていただいた(たつき)
  • 前半のキャラ変なやつ多い(福原)
    • ちょっと強め置いてるとこがありますね(たつき)
  • この辺りから元が動物であることを匂わせていく。細谷Pが「崖登るもんだな」と(福原)
  • ここまでは(ジャパリまんは)ピンク色(福原)
    • 前ブルーハワイ味とか……(福原)
    • 青色6号でしょ(たつき)
  • 日付の関係でトキ→かばんではなく、録るのが逆の順になってしまった(たつき)
  • ロープウェイ、途中で支柱の上に乗るシーンがあると聞いていた(伊佐)
  • 監督が(ロープウェイの到着地点が)一度上がって下がると言い張った(伊佐)
ジャパリカフェ
  • 元ネタはシャッツキステ
  • この店で脚本を書いてた(2, 3話) (たつき)
  • 池袋、ホワイトボードのペン立ての裏に書いて帰ってきた(たつき)
  • マルイ、なくなった時用にポストカードを持って行った、持って行った時には何にもなかった(たつき)
  • マチュピチュっぽい感じ
  • 3話、設定美術の仕事多かった(たつき)
  • 筋書き読んで実際に行ってみたいとわくわくしていた(伊佐)
  • 紅茶の淹れ方を監督がシャッツキステメイドさんに聞いていた(伊佐)
    • 最初コーヒーだった、コーヒーの木について調べた(伊佐)
  • アニメオリジナルなので、表面に映った物の後ろで捨ててるものも多い(福原)
  • ゴンドラも設定の方でどうやって動かすかという、これも監督が足漕ぎであるはずだと(伊佐)
  • 遊園地感を出していく(たつき)
  • トキの目のハイライト、絵を描く人は気づいていた(福原)
  • 吉崎先生が後ろで仕込んどるんで見のがしがないか恐い(たつき)
  • たまたまシャッツキステで脚本書いてて、その後コラボが決まって、「見張られてる…」(たつき)
  • コーヒーから紅茶に変えた。コーヒーは喉にはあんまよくない(たつき)
  • シャッツキステで紅茶の淹れ方を取材してた(伊佐)
  • 卓上メニューはたしかシャッツキステそのまま(白水)
  • 自然物がサブの時はいいけどメインとなると難しそう
  • 自然物の方がごまかしがきく、ブラシでざっくり。ただ、いつまでたっても決まらないので、人工物の方が決めやすい(白水)
  • テーブルは3Dモデル? (福原)
  • ベースは3Dモデル、2D美術でかなり書き足している(白水)
    • (3Dモデルを)レイアウトとして
  • (トキの歌)さっきよりちょっと上手くなってる、でも下手に(たつき)
バス~ED~アラフェネ
  • バス、手で描くと死人が出る(たつき)
  • 「ゔっ」お客さん笑ってる
  • 酷いアニメです、これ狂ってますね(たつき)
  • あんたのアニメだよ(福原)
  • 吉崎さん、すごく感想を送ってくる(たつき)
  • アラフェネ、2話はなかった(福原)
    • 2人に対する贖罪(たつき)
    • おさらいができる感じ(白水)
    • 前のキャラクターが一度きりでなく、もう一度見れるのでうれしい(伊佐)
  • 最終話までなくならない電池。科学力(たつき)
  • 普通に考えて先頭に電池あったら危ない(福原)
  • 3話で頑丈さのマックスを示しとこうかなって(言い訳しとこうかなと) (たつき)
  • 監督の提示してくるワードからさぐりさぐりで作ってみる。「ここは一体どこなんだ?」(白水)
  • 声優さんにほどよく知ってもらう(たつき)
  • 出てきたとき、発見があったことを(演技に)乗せてもらえる(たつき)
  • Bパート、細かいところで動きのダメ出しが何回も(伊佐)
  • 監督と相談できるので、見栄えを考えた上で物を置ける(伊佐)
  • ただ今回ちょっとしんどすぎた(たつき)
  • 芯が決まってからは人が増えても大丈夫(たつき)
  • その前は人が増えても(だめ) (たつき)
  • 普通テレビシリーズ12話全部を(一人で)演出することはない(福原)
  • 気ぃ狂いますのでやらん方がいいですよ(たつき)
4話、砂漠
  • ここら辺で気づいた、「まかせて」を被せていけるんじゃないかと(たつき)
  • CGでガイドを作ってそれをなぞる(感じで作っている)? (福原)
    • まちまち
  • CGだと結局手を入れてなじませないといけない(伊佐)
  • パースから出してもらって一から描く、草原とかは描いた方が早い(白水)
  • 監督の方で素体つくってそれを元にモデルを作る(伊佐)
  • 作ったモデルをレンダリングすると1時間とか(伊佐)
    • 監督のだと早い、自分たちが作ると1時間くらいはかかる(伊佐)
  • (レンダリングの速さについて)考えてます、そこで短縮しないと3話位落ちしてまう(たつき)
  • (レンダリング中に食事する)レンダ飯、レンダリング時間短いとできない(福原)
  • マシン2台用意してレンダリング中に作業(たつき)
  • 8人くらいでやるのは? (福原)
    • 恐怖、50~100人用意してどうにか(たつき)
  • 「木陰のまま走れる感じ」サーバルちゃんが自分の知識で話してる感じがある(伊佐)
  • セリフはかなり考える(たつき)
    • 文字見た時のやつ「かばんちゃん何に言い出すの?」ねちっこく考えて(たつき)
  • 完全に知らないってことの説明がないが、察するに十分のやり取りがある(福原)
  • 「かばんちゃんは人間だから文字が読めるんだね!」という説明だと、工数の省略ができるが、不粋、下品(福原)
  • キャラに入り込むと雰囲気が出る、自然にするために工数が3倍とかになったり(たつき)
  • (動物紹介コーナーの)スナネコの落描き、岩と砂だけだとあまりにも寂しい(白水)
    • 勝手に描いた? (福原)
    • こっちで描いてそのまま通った(白水)
  • 後半は(スタッフ間で)ピント合ってくるのでそのままスルーって感じ(たつき)
  • マッドマックスっぽいよね(福原)
  • スナネコ、地がキャラらしくて、演技すると外れる(たつき)
  • サーバルの尾崎さんも
  • (指示について)共通言語が多いので猫らしさ、キャラらしさ、愛らしさがコンパクトに伝わる
  • Vコン先行で伝わりやすくしてるものの(福原)
  • ピント合わない人だと(難しい) (たつき)
  • サーバルらしい台詞、らしさ
  • キャラとか整合性あっていい(福原)
  • 台詞とからしさからずれないようにとか(たつき)
  • ジャパリまんの袋はファミチキの袋が(モデル) (伊佐)
    • 会社近くにファミマあるからね(福原)
  • 廃墟っぽくて好き(たつき)
  • バイパスって響きが怖い(伊佐)
地下迷宮
  • ツチノコ、このエリアにいて良い動物だから
  • ゲームにも出てきた(たつき)
  • 実在するかわからない奴が人間、こっちの歴史を語ってる(伊佐)
  • 3話~5話くらいまでに世界観を示す(たつき)
  • 人間が「あいつ絶滅してたっけ?」って感じのことを言う感じで人間に向かって言わせたかった
  • 迷路…ポートピア連続殺人事件
  • 最初ここ描いてて何で溶岩があるかわからなかった(白水)
    • ここに溶岩描いてって言われるだけ? (福原)
    • そう(白水)
    • たつき流監督術(福原)
  • 楽しみを残したまま作るのは面白い、騙されてくれたり(たつき)
  • 楽しんで作ってたり、ライブ感
  • 行き当たりばったりででなく詰め込めるものを詰め込んだ感じ(たつき)
  • (アニメでジャパリコインって呼ばれてるものが)ジャパリコインじゃないって(福原)
    • らしさをとった、2種*1あると混乱する(たつき)
  • ハンドルを1回もラッキービーストは触ってない(たつき)
    • ちょいちょいニャンってやるよね(福原)
  • この辺とかジャガーの下りとか順繰りには作りづらい(たつき)
  • ばらばらに走るところなどVコンでないと伝わりづらい(たつき)
  • 蛇の尻尾なので、しなりとか動きは頑張ってる(伊佐)
  • 急にテンションが上がる感じ、声をつけたときにギャップがあり修正が(大変) (伊佐)
  • なぜ溶岩があるか知らされてなかった(白水)
  • 3話4話くらいでパークの裏側を気にする、(ツチノコは)視聴者と同じ立場(たつき)
  • 遊園地とかの巨大迷路をモデルとした(たつき)
  • このときはパーク全体の地図はできてなかった? (福原)
  • この後何が出てくるって情報はあったが、地図としてはなかった(白水)
洞窟の外
  • 実際にパークがあってそれをアニメにしてる感じがある
  • ツチノコ、オタクっぽくていい。短いにしては支離滅裂、三つくらいの役職(たつき)
  • 上手い声優は根元を押さえた上で外される(外した演技をする) (たつき)
  • 撮影結構粘らせてもらえる、ラスト1日でいろいろいじったり(たつき)
  • 洞窟の外結構粒子見れるんですね(福原)
    • 埃のきらめきなどを足す(たつき)
  • これ録ってる時、声優さんもわかってない感じ(たつき)
    • 委員会でも(福原)
  • 昔何かあったんだなーって感じをこの時間軸で(伝える)の、綱渡り的な感じがあった(たつき)
  • アラフェネ、ことごとくアクシデントにあうのが可愛らしい(伊佐)
  • つちのこ館、すごい喜んでた。お客さんが増えた(福原)
  • 外で明るいからミライさんが見えてないってことだよね(福原)
    • 明るいところで映すようにはしてましたね(たつき)
  • ツチノコが人類のことを話してるのが面白くてですね(伊佐)
    • 存在していない動物が人類のことを話してる(福原)
  • よく声優さんの声がぴったりはまったね(福原)
    • 微妙にプレスコ部分もあって、あまりにひどいところはアニメーションの方を作り直しに近いところでしたこともあった(たつき)

*1:アニメ版でジャパリコインと呼ばれるものはNEXONアプリ版のジャパリゴールドのデザインで、ジャパリコインは別のデザインとなっているらしい。参考: https://dic.nicovideo.jp/a/%E3%82%B8%E3%83%A3%E3%83%91%E3%83%AA%E3%82%B3%E3%82%A4%E3%83%B3#h2-2

AutoHotkeyで入力キーボートレイアウトの切替を行う

Windowsでは複数の入力言語やキーボードレイアウト(IMEを含む)を設定できる。日本語IMEは日本語入力のオンオフを切り替えられるのでそれだけを利用している場合には触れることは少ないかもしれないが、Google日本語入力ATOKのような別のIMEを併用したり、中国語、タイ語など他の言語のIMEやキーボードを使う場合、切替が必要となる。

この切替は「Alt+Shift」(入力言語の切替)、「Ctrl+Shift」(同言語でのキーボードレイアウトの切替)、あるいはWindows 8以降では「Windowsロゴキー+Space」(入力言語・キーボードレイアウトの切替)のショートカットキーで行うことができる。また、設定で特定のキーボードレイアウトへ切り替えるショートカットを指定することができるが、設定できるキーの組合せに制限があったり、うまく設定が反映されなかったりすることがあるので、AutoHotkeyでキーボードレイアウトの切替を定義できれば便利だろう。


AutoHotkeyはSendMessage命令を利用してWindows APIのウィンドウメッセージを投げることができる。これで望む入力言語・キーボードに対応するinput locale identifier (入力ロケール識別子)を指定してWM_INPUTLANGCHANGEREQUESTを投げると、入力言語・キーボードを切り替えることができる。
したがって、このinput locale identifierを適切に取得すれば、指定したキーボードレイアウトを切り替えるホットキーが定義できる。これを取得するために、Windows APIのLoadKeyboardLayout関数やGetKeyboardLayout関数を利用することができる。

検証環境

Windows デスクトップ アプリケーションのいくつかで動作を確認したが、動かないアプリケーションもあるかもしれない。

方法1: LoadKeyboardLayout関数を使う場合

LoadKeyboardLayout関数のsyntaxは次のようになっている。

HKL WINAPI LoadKeyboardLayout(
  _In_ LPCTSTR pwszKLID,
  _In_ UINT    Flags
);

LoadKeyboardLayoutの引数のpwszKLIDは「input locale identifierの名前」であり、16進数の数字8文字のからなる文字列で、レジストリ

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Keyboard Layouts

の下にある項目のものである。ここから、利用したいキーボードを表す8桁の16進数字をメモしておく。

なお、既定のキーボードについては次のページからも参照できる。


目的のキーボードを探すのに役立つ情報として、pwszKLIDの下4ケタはlanguage identifierである。language identifierは次のページから参照できる。

また、上4桁については、その言語のデフォルトキーボードは0000となるようである。ある言語のキーボードレイアウトにいくつか種類がある場合、0001, 0002, と上4桁の番号が順番に増えたりするらしい。一方でMSKLCなどでキーボードレイアウトを自作した場合などは上4桁がa000などとなる場合もある。

実装例

ここでは、例として「日本語・Microsoft IME」と「ロシア語 (タイプライター)」に切り替えるホットキーを設定してみる。
まず、pwszKLIDとして与えるべきものは

キーボード pwszKLID
日本語・Microsoft IME 00000411
ロシア語 (タイプライター) 00010419

である。

これらを引数に指定してLoadKeyboardLayout関数を呼び出してinput locale identifierを取得し、取得したinput locale identifierを指定してPostMessageでWM_INPUTLANGCHANGEREQUEST (0x50)メッセージをアクティブウィンドウに投げれば切り替えができる。

F11で日本語・Microsoft IME、F12でロシア語 (タイプライター)に切り替えるAutoHotkeyスクリプトは次のように書ける。

F11::
  ;日本語・MS-IMEへの切替
  ja := DllCall("LoadKeyboardLayout", "Str", "00000411", "Int", 1)
  PostMessage 0x50, 0, ja,, A  ;WM_INPUTLANGCHANGEREQUEST
Return

F12::
  ;ロシア語 (タイプライター)への切替
  ru := DllCall("LoadKeyboardLayout", "Str", "00010419", "Int", 1)
  PostMessage 0x50, 0, ru,, A  ;WM_INPUTLANGCHANGEREQUEST
Return

方法2: GetKeyboardLayout関数を使う場合

いちいちレジストリエディタ開いてinput locale identifierの名前を調べるのは面倒である。どうせ切り替えるキーボードは普段使っているものなので、現在使用しているキーボードから直接input locale identifierを取得してしまえばよい。


GetKeyboardLayout関数は現在選択されているinput locale identifierを返す。
しかし、LoadKeyboardLayoutの場合と異なり、32ビットのinput locale identifierのMSB (最上位ビット)が1の場合でも正整数が返ってくる。要するに32ビット符号なし整数扱いになっているようだ。
一方でPostMessegeでWM_INPUTLANGCHANGEREQUESTを投げる時に指定するinput locale identifierは符号あり整数にする必要があるようで、GetKeyboardLayout関数が返した数値をそのまま用いると、32ビットアプリでは動くが、64ビットアプリでは動作しないようである。
そのため、自分で変換する必要がある。


まず、次のようなスクリプトを使って、使っている入力言語・キーボードレイアウトのinput locale identifierを取得する。
結果はキー入力として出力されるので、テキストエディタなどを開いて調べたいキーボードレイアウトに切り替えた状態でF10を押す。

F10::
  SetFormat, Integer, H
  WinGet, WinID,, A
  ThreadID:=DllCall("GetWindowThreadProcessId", "UInt", WinID, "UInt", 0)
  InputLocaleID:=DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")
  Send, %InputLocaleID%
Return


すると、次のようなinput locale identifierが取得できる。

キーボード input locale id
日本語・Microsoft IME 0x4110411
ロシア語 (タイプライター) 0xF0080419

日本語・Microsoft IMEの場合は32ビットのMSBが0であるため問題ないが、ロシア語 (タイプライター)の場合はMSBが1なため負数で表す必要がある。

次のWebサービスのようなものを用いて、32ビット16進数表記を符号あり10進整数に変換する。

すると、0xF0080419は-267910119であることがわかる。これをWM_INPUTLANGCHANGEREQUESTメッセージのlParamに指定する。


F11で日本語・Microsoft IME、F12でロシア語 (タイプライター)に切り替えるAutoHotkeyスクリプトは次の様になる。

F11::
  ;日本語・MS-IMEへの切替
  PostMessage 0x50, 0, 0x4110411,, A  ;WM_INPUTLANGCHANGEREQUEST
Return

F12::
  ;ロシア語 (タイプライター)への切替
  PostMessage 0x50, 0, -267910119,, A  ;WM_INPUTLANGCHANGEREQUEST
Return

文字のデザインに筆記具が与える影響

Type& 2015「ロゴの多言語化:デバナガリとアラビア文字

2015年11月21日にType& 2015の「[3]ロゴの多言語化:デバナガリとアラビア文字」を聴講した。これは、まずデーヴァナーガリー及びアラビア文字の特徴についてそれぞれタイプデザイナーであるVaibhav Singh氏およびNadine Chahine氏から簡単に紹介がなされ、さらにラテン文字のロゴと各スクリプト*1版作成の実例が紹介された。その後、実在の日本の会社のロゴタイプを題材に、実際に両氏が各スクリプト版を試作したというものであった。


この後半のローカライズロゴ試作においてお題に使われたうちの一つがWonders! by Panasonicのロゴであった。
ここで注目したいのが感嘆符「!」で、上の縦棒部分の下端がカーブして切り取られ、左側にとがっている。一方で、試作されたデーヴァナーガリー及びアラビア文字版ロゴではそれが左右逆になっていた。図解すると次のようである*2
f:id:nixeneko:20151124001702p:plain
アラビア文字ラテン文字とは逆に右から左へと書き、疑問符などの記号も左右反転させて使う(“؟”)ので、デザインが左右反転しているのも納得できるが、一方でラテン文字同様左から右へ書くデーヴァナーガリーでもデザインが反転しているというのは不思議である。
このことは公演中にデーヴァナーガリー版ロゴについて小林章氏がVaibhav Singh氏に質問していたことなのだが、Vaibhav Singh氏はその理由について「その方が自然だから」と返答していた。

筆記具が影響した?

ここからは私の仮説であるが、伝統的に文字を書くのに使われていた筆記具が影響しているのではないかと思う。各スクリプトが伝統的にどのような筆記具で書かれていたかをみていくことで確認してみたい。

ラテン文字

ラテン文字は長らく羽ペンで筆記されてきた伝統をもつ。次の動画で羽ペンの作り方や筆記のやり方が解説されている。現在のラテン文字セリフ書体のデザインは羽ペンで書かれた文字の形を元にしているという。
www.youtube.com
羽ペンは平らなニブ(ペン先)をもち、縦方向に動かすと太く、横方向に動かすと細く線がかける。
現在の欧文カリグラフィーで使われるペンにも同様に平たいニブをもつものがあるが、ニブ(ペン先)を上に向けて外側からみたときに、傾きがなく横まっすぐになっているか、あるいはゆるやかに右肩上がりになっている*3かのどちらかのようである。
ペンを当てるときはペン先が水平から反時計回りに角度がついた状態で書かれることが多いようだ。これは、oなどの円形の文字の左上と右下が細くなり、反対に左下と右上が太くなることに影響している。
f:id:nixeneko:20180113164152p:plain
(フォントはTimes New Roman)

アラビア文字

イスラム世界ではアラビア文字による書道が発達している。アラビア書道用のペンは葦ペン等の平らなニブをもつ筆記具が用いられる。ペン先は斜めにカットされていて、ニブを上に向けて外側からみたときに右肩上がりになる場合が多いようだ。アラビア文字を書く場合はペン先の角度が直角に近く、ペンを横に向けてに持つ感じになる。次の動画でペンの持ち方が解説されている。
www.youtube.com

アラビア文字フォントでも、ペン先を傾ける方向はラテン文字と同様反時計回りでありながら、角度はかなり急峻になっているのがみてとれる。
f:id:nixeneko:20180113171052p:plain
(フォントはTimes New Roman)

デーヴァナーガリー

デーヴァナーガリーは伝統的に葦ペンでかかれる。

次の動画では、デーヴァナーガリー用のカリグラフィペンは、ペン先が欧文カリグラフィー用とは逆の傾きをもち、右肩下がりになっているという説明がある。
www.youtube.com
実際に文字を書いているところや書かれた文字をみると、ペン先の当て方がラテン文字アラビア文字とは傾きが逆で右肩下がりになっている。
www.youtube.com
次の動画では基本的なストロークを紹介しているが、ここで書かれている円は右上と左下が細く、左上と右下が太くなっている。
www.youtube.com

全体として、ニブの当て方が逆であることから、ラテン文字アラビア文字とは線の方向と太さの関係が逆になっていることがみてとれる。線の端についても、左上から右下に傾いていることがわかり、これもラテン文字と逆である。
f:id:nixeneko:20180113172941p:plain
(フォントはAdobe Devanagari)

まとめ

カリグラフィ用のペンのニブの形状(傾き)の違いと、ニブをどの向きで紙に当てるかについてを次図にまとめた。
f:id:nixeneko:20180113173314p:plain

ここで、なぜアラビア文字デーヴァナーガリーで試作ロゴの感嘆符「!」の向きが一致したのかを検討してみたい。

アラビア文字で感嘆符が反転したのは書字方向が反対になるのに合わせたということだろう。

一方で、デーヴァナーガリーは、伝統的にラテン文字とは逆方向の右肩下がりにペン先を当てるため、線の端は右肩下がりになるのが自然であり、線の端が右肩上がりになる要素は不自然であると考えられる。そのためラテン文字と書字方向は同じだが、「!」の縦線が右肩下がりになる形を採用し、デーヴァナーガリーのエレメントに合わせたのではないか。


結果としてアラビア文字デーヴァナーガリーで「!」の形が一緒になったものの、どうして元のラテン文字のロゴから左右反転したような形を採用したのか、その理由は2つのスクリプトで異なっているようにも感じられる。
文字のデザインはそのスクリプトが書かれていた筆記具に影響されるというのは正しそうではあるが、必ずしもそれだけでデザインが決定される訳ではなく、他の要因との複合で最終的な形が作られるのだろう。

*1:この「スクリプト」は、ラテン文字アラビア文字デーヴァナーガリーなどの文字体系のことを指す。用字系、書字系などとも。script.

*2:蛇足ではあるが、“Wonders!”の“s”に当たる部分を、デーヴァナーガリーではs, アラビア文字ではzに相当する文字で転写しているのも面白い。

*3:ペン先に角度がついているものをobliqueという。Difference between an italic, an oblique, and a stub? | Classic Fountain Pensによると、usually about 15 degreesとのこと。

キーボードの言語によってDvorakJの有効無効を切り替える

随分前に、DvorakJを利用して英字入力はDvorakにし、日本語入力はJapanist 2003を利用して親指シフト(NICOLA)をエミュレーション利用していた。一方で、ロシア語やタイ語等を入力する要求がでてきて、DvorakJはこの様な日本語以外のキーボード言語の入力時に無効にする設定ができず、まともに入力ができないため、Dvorak配列を使用するの自体をやめてしまっていた。

やりたいこと

キーボードの配列を次のようにしたい。

  • 日本語入力時(キーボード言語が日本語かつIMEオン): 親指シフト(NICOLA)
  • 英字入力時(キーボード言語が日本語かつIMEオフ): Dvorak
  • 他言語入力時(キーボード言語が日本語以外): Qwerty相当 (キーボードの入力そのまま)


これは、2回の場合分けによって表現できる。

  1. キーボード言語による場合分け(日本語か?)
    • 日本語でない→キー変換を行わない
    • 日本語である→2へ
  2. IMEのオンオフによる場合分け
    • オン→日本語入力用配列
    • オフ→直接入力用配列


ここで、現行のDvorakJ (2014-06-07版)ではIMEのオンオフの検出で日本語入力時と直接入力時で別々の配列を適用することができる(つまり、2.は実装されている)が、一方で日本語以外の言語に切り替えたときも直接入力用の配列が適用されてしまって、日本語以外の言語を入力することができない。
なので、うまいことキーボードの言語が日本語であるかどうかで場合分けを行い、日本語である場合にだけキーリマップを適用する様にしたい。

方針

DvorakJはAutoHotkey_L用のスクリプトが公開されているので、それを改変し、条件分岐部分を追加すればいいのではないかと思う。

AutoHotkeyで現在のキーボード言語を取得するには次のページのようにするといいらしい。

ここに挙げられたコードを引用する。ただし、このコードはコンソールでは使えないとのことである。

F11::
  SetFormat, Integer, H
  WinGet, WinID,, A
  ThreadID:=DllCall("GetWindowThreadProcessId", "UInt", WinID, "UInt", 0)
  InputLocaleID:=DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")
  MsgBox, %InputLocaleID%
Return

要するにInputLocaleIDが現在のキーボードを識別するIDのようである。

WinAPIのGetKeyboardLayoutの項によると、

The return value is the input locale identifier for the thread. The low word contains a Language Identifier for the input language and the high word contains a device handle to the physical layout of the keyboard.

GetKeyboardLayout function (Windows)

だそうで、下位2バイトは入力言語のlanguage code、上位2バイトはキーボードレイアウトへのデバイスハンドルらしい。

最新のWindows 10 (バージョン1709)において、実際に取得したInputLocaleIDは次のようになっている。

言語 キーボード InputLocaleID
日本語 Microsoft IME 0x4110411
タイ語 タイ語 Kedmanee 0x41E041E
ロシア語 ロシア語 0x4190419
ロシア語 ロシア語 - ニーモニック 0xF0330419
ロシア語 ロシア語 (タイプライター) 0xF0080419
モンゴル語 伝統的なモンゴル文字 0xF0B20850

その言語の標準的なキーボード配列においては上4桁(2バイト)は下4桁と同じになっているように見える。
キーボードによって条件を変化させるのであれば全体を比較すればよいし、言語によって変化させるのであれば下2バイトだけ比較すればよいことになる。

Language Codeについては、AutoHotkeyのドキュメントにも次の様な記術があるが、

WindowsのLanguage Codeの一覧は次のページから参照することができる。


DvorakJのソースをみてみたところ、DvorakJ全体を一時停止するキーショートカットが設定できるので、これに使われてるロジックを利用して、キーボードが日本語以外に切り替わった場合に一時停止するようにし、反対に日本語に切り替わった場合には一時停止を解除するようにしてみる。

環境

改変

DvorakJのAutoHotkey_Lスクリプト版の src/init/set_various_timers.ahk を開き、27行目付近の

	;;; IME の状態を定期的に調べる
	SetTimer, IME_GET, %IMEms%

の下に

	SetTimer, Keyboard_GET, %IMEms%

を挿入し、更に末尾に

;; キーボードの言語を一定間隔毎に取得し、日本語以外だったら動作を停止する。
;; 日本語だったら動作を再開する。
Keyboard_GET:
  SetFormat, Integer, H
  WinGet, WinID,, A
  ThreadID:=DllCall("GetWindowThreadProcessId", "UInt", WinID, "UInt", 0)
  InputLocaleID:=DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")
  If ( InputLocaleID & 0xFFFF = 0x411 ){ ;Japanese
    If ( A_IsSuspended ){
      toggle_status_of_dvorakj(False)
    }
  } Else { ;otherwise
    If ( !(A_IsSuspended) ){
      toggle_status_of_dvorakj(True)
    }
  }
return

を追加した。

要するに、一定時間ごと(今回はIMEの状態を定期的に調べる間隔(IMEms)を流用した)に現在のキーボードの入力言語を取得し、

  1. 入力言語が日本語であり、かつ、DvorakJが無効である(Suspendされている)場合は、Suspendを解除する
  2. 入力言語が日本語でない、かつ、DvorakJが有効である(Suspendされてない)場合は、Suspendする

という処理をもともとのソースコードに追加している。

感想・課題

しばらく使ってみたが、親指シフト回りがあまり快適でなかったのでやめてしまった。DvorakJ自体を利用するのが久しぶりであるのに加え、親指シフトのエミュレーション用として利用したことがなかったため、問題の切り分けができていない。そのためはっきりしたことが言えないので今後も検証が必要である。

  • 親指シフトのエミュレーションの同時押しの検出がやまぶきRより精度が低い感じがする。そのため、入力ミスが多発した。
    • 急いで入力すると「にゅうりょく」が「にけをりょく」や「にゅうりいる」になったり。やまぶきRでも時々なるけれど…。
    • やまぶきRと同様の設定にしてるつもりであるが、設定によって改善が可能かもしれない。要検証。
  • ウィンドウを切り替えたときや別の入力フィールドに移ったときなどにうまく入力ができなくなる場合があった。
    • 改変部分が原因かもしれないが、素のDvorakJを最近使ってなかったので比較ができない。
    • やまぶきRでもなったことがあるように思うので一概に何ともわからない。別のウィンドウ切り替えた後で戻すと復活したりする。
  • DvorakJに用意されていた一時停止機能を勝手に利用しているため、一時停止してもキーボードが日本語であればすぐ再開されてしまい、一時停止機能が使えない状態になっている。
  • 本当にこんな改変で大丈夫なのか……?


頂いた情報によると、DvorakJとやまぶきRではいろいろと同時押しエミュレーションのロジックが異なるので入力感は同じにならないとのこと。


なかなか難しい。