たのしい人生

お絵かき / Kindle 視点で iPad Pro 2020 (Gen. 4) 12.9 inch レビューと iPad Pro 2017 (Gen. 2) からの乗り換えや Apple Pencil 2 と保護ケース・シートの話

TL;DR

iPad Pro 2017 (Gen. 2) から 10.5 inch から iPad Pro 2020 (Gen. 4) 12.9 inch に乗り換えました。世代や画面サイズの変化についてレビューします。結論から言うと Apple Pencil 2 がめちゃくちゃによいし、それを活用できるようにすると最高。

iPad Pro 2020 12.9 inch を買いました

もともと iPad Pro 2017 10.5 inch をお絵かきするぞ!と思って購入し初代 Apple Pencil を iPad Pro に挿して充電する日々を送っていたのですが、Apple Pencil 2 の本体に磁力固定・無接点給電が羨ましすぎて 2020 の発表と同時に即購入しました。そんな iPad Pro 2020 12.9 inch を 2 ヶ月弱使ってみてのレビューをお届けします。

f:id:biacco42:20200510164136j:plainf:id:biacco42:20200510165228j:plain

お絵かきなら 10.5 inch でも 12.9 inch でも実は大差ない

私は結構画面に寄って描いてしまいがちなので、体感としては 10.5 inch でも 12.9 inch でもそれほど絵の描きやすさは変わらない印象でした。ただ、同じ視界いっぱいにキャンバスを映す場合、12.9 inch だと相対的に顔を離して絵を描くことができるので、そういう意味で目に優しいのは 12.9 inch のほうかもしれません。

f:id:biacco42:20200510165856j:plainf:id:biacco42:20200510165405j:plain
10.5 inch と 12.9 inch のサイズ感の比較。10.5 inch はベゼルが広いためもう一回り画面が小さい。

画面の大きさで絵の描きやすさが変わってしまうか気にしている人に関しては「正直どっちでも描けるよ (たぶん)」といった感じなので、画面サイズに関しては他の理由で決めても構わないと思います。

f:id:biacco42:20200510170010j:plainf:id:biacco42:20200510170006j:plain
デスクに置いてみた感じ。iPad Pro 2020 (と 2018) はベゼルが細いので思ったより小さく感じる。

Kindle でマンガ読むなら 12.9 inch の横持ち見開き表示は 10.5 inch よりかなりいい

Kindle でマンガを読むならできるだけタブレットで、それも横画面で見開きに表示にするのが製本版のマンガ体験に近く非常におすすめなのですが、特に iPad Pro に関しては断然 12.9 inch モデルがおすすめです。

f:id:biacco42:20200510173123j:plain

写真はつくみず先生の少女終末旅行① [つくみず (2014) 少女終末旅行① 新潮社] なのですが、10.5 inch モデルだと原本よりひと回り小さくなってしまいます。もちろん元の本のサイズにもよるのですが、12.9 inch の方が体験としては「マンガ的」なので、Kindle でマンガを読もうと思っている場合は個人的には 12.9 inch モデルのほうがおすすめです。

10.5 inch と 12.9 inch で重さは結構変わるので気になる人はそこは注意

上記 Kindle の項では 12.9 inch がおすすめと書きましたが、10.5 inch と 12.9 inch の重量は無視できない差があります。iPad Pro 2020 の 11 inch モデルは 471 g、12.9 inch モデルは 641 g で、12.9 inch モデルだと重さおよそ1.4 倍弱、スマホ 1 台分程度重くなります。

私の持っている iPad Pro 2017 10.5 inch は 469 g で 11 inch モデルとほぼ同じ重さなのですが、12.9 inch の iPad Pro と持ち比べると明確に重さの違いが感じられます。重量が気になる方はこの点は注意したほうがいいでしょう。11 inch モデルと 12.9 inch モデルの隠れた最大の違いと言っても過言ではないです。

Apple Pencil 2 はめちゃくちゃ進化してるのでコレのために買ってもいい

ここからが本題で、iPad Pro をお絵かきデバイスたらしめている Apple Pencil についてです。

もともと所有していた iPad Pro 2017 は初代 Apple Pencil で、初代の時点でもなめらかな書き味に感動したのですがいくつか問題点がありました。対して iPad Pro 2018 (Gen. 3) 以降で採用されている Apple Pencil 2 はそのほとんどの問題が解決しており、Apple Pencil 2 のためだけに iPad Pro 2020 を買ってもいいぐらいです。

感度が改善されている

初代 Apple Pencil は画面に触れる前、空中に浮いた状態でも線の入力がされてしまう「負の感圧」が結構あったのですが、Apple Pencil 2 ではこれが改善されています。ほぼチューニング無しで画面に触れるぐらいから入力が始まるので、より自然に描けます。

f:id:biacco42:20200510183637j:plain

また、感圧の分解能も初代 Apple Pencil より高くなっているらしいのですが、正直そこは私の能力ではあまりわかりませんでした。また「ペン先のブレ」は初代 Apple Pencil / Apple Pencil 2 共に Wacom の液晶タブレット等に比べると大きいように感じるので、究極を求めるなら気になるかもしれません。

充電が iPad にくっつけるだけ

説明不要です。これが最高に便利すぎます。初代 Apple Pencil を使っているときは、朝オフィスでおもむろに iPad Pro に初代 Apple Pencil を刺して充電するのが日課だったのですが、Apple Pencil 2 では iPad Pro 本体にくっつけておくだけで常にフル充電、使いたいときにサッと使えます。

iPad Pro をお絵かきの道具や手書きメモとして使うのであればこの「いつでも使える確信がある」というのは非常に重要です。精神的なめんどくささがあると絶対に使わなくなります。

f:id:biacco42:20200510180812j:plain
新旧 Apple Pencil 充電の姿

転がらないデザイン

地味にこれがめちゃくちゃ嬉しいのですが、Apple Pencil 2 では円柱のいち部分だけが平面になったデザインをしています。

f:id:biacco42:20200510181606j:plain
基本的に円柱だが一部だけ平面になっている (かしこい!)

初代 Apple Pencil は完全な円柱だったため少しでも平面が出ていない机などに置くとコロコロコロ…と転がっていってしまう不安定さが非常にストレスでした。Apple Pencil はそれ単体で 1 万円程度するため、机の上から落としたりするのがめちゃくちゃ怖いんですよね。なので Apple Pencil 2 のデザインは非常にありがたいです。

また表面仕上も変わって、初代のツルツルな質感から Apple Pencil 2 ではサラサラマットな仕上げに変更されました。これは好みもあるでしょうが、悪くないです。

ダブルタップによるツール切り替え

Apple Pencil 2 ではペンのダブルタップによるツール切り替えができるようになりました。標準ではペンなどの書き込み系ツールと消しゴムが交互に切り替わるようになっています。これがかなり便利で、絵を描きながらツールパレットに意識を移動することなく消しゴムツールに持ち替えて修正することができるようになりました。うれしい。

注意点としては、「ダブルタップ」というとついついスマホタブレットのようなタッチパネルを想像してしまいますが、Apple Pencil 2 のダブルタップ検出はおそらく加速度ベースで、指を「トントン」とする衝撃を計測しています。そのためダブルタップする場所は意味ありげな平面部分でなくても、先端寄りなら本体のどこでも大丈夫です。

重心位置が少し下がった?

微妙な違いですが、初代 Apple Pencil はやや重心位置が高く指先でペンを動かすとペンの後ろ側の重心にやや振り回される印象がありました。Apple Pencil 2 では初代より長さが少し短くなり、重心位置が下がっているようです。重量は変わっていないらしいのですが、使ってみると Apple Pencil 2 の方がやや軽快に使えます。

f:id:biacco42:20200510184201j:plain
ほんのちょっぴり短くなった Apple Pencil 2

Apple Pencil 2 の磁力で本体固定・充電は最高だけど縦持ちすると手に干渉する

ここまで Apple Pencil 2 の魅力を書いてきたのですが、欠点もあります。結構致命的なのが、Apple Pencil 2 を iPad Pro 本体につけた状態で縦持ちすると、微妙に手とぶつかってしまう問題です。

f:id:biacco42:20200510195634j:plain:w400

とくにソフトウェアキーボードで入力しようとすると Apple Pencil 2 が外れかけることもしばしばあります。机の上からならまだしも、手の高さから、たとえばアスファルトApple Pencil 2 を落としてしまうのはあまり想像したくありません。一方で、Apple Pencil 2 を iPad Pro 本体にくっつけておくのは充電の機能も兼ねているため、Apple Pencil 2 だけペンケースに入れるといった運用は本来の利便性を損ねてしまうほか、サッとメモをとる、絵を描くといったことができなくなってしまうので致命傷です。

前述の通り、少しでもめんどくさい要素があると人間は利用しなくなるものです。できるだけハードルを下げておく必要があります。

ペン収納つきの 3rd party 製保護ケースが必須

Apple 公式の iPad Pro 2020 の保護カバーは側面を保護してくれないほか、Apple Pencil 2 もむき出しのため、上記の「縦持ちすると Apple Pencil 2 が手と干渉して落ちそう」問題が発生します。そこで個人的におすすめなのは、Apple Pencil 2 の収納スペース付き保護ケースです。

今までの写真でも写っていましたが、私は iPad Pro 2017 のときから Apple Pencil 収納機能付き保護ケースを利用していました。初代 Apple Pencil は充電を本体に挿して行わなければならないものの、こういったケースを用いることで常に iPad Pro と Apple Pencil が同時にあるので「絵を描きたい!」と思ったときに Apple Pencil を探すところから始める、みたいなことが必要なく、これが結構体験がよかったです。

検索すると iPad Pro 2020 向けにも Apple Pencil 2 の収納スペース付きの保護ケースがあります。しかも Apple Pencil 2 なら保護ケースに収納しているだけで充電もしてくれます。完璧です。

私はこちらを購入しました。

f:id:biacco42:20200510191330p:plainf:id:biacco42:20200510191347p:plainf:id:biacco42:20200510191356p:plain

f:id:biacco42:20200510191407p:plain

Apple 公式の保護カバーと違い側面も保護してくれる他、Apple Pencil 2 の収納スペースもあるため縦持ちしても Apple Pencil 2 に手を引っ掛けて落としてしまう心配がありません。これで初代 Apple Pencil の問題点をほぼすべてクリアした最強お絵かき・手書きメモ環境になりました。

こちらのケースに関しては Apple 公式のものに近いサラッとした手触りで、カバーの開け閉めによる iPad のウェイク・スリープ機能やスタンド機能にも対応しています。また、側面まで保護するタイプのケースだと電源ボタンや音量ボタンがケースに隠れてしまうことになるのですが、このケースはこのボタン部分の作りが非常によく、力を入れなくても押せて、ボタン本来のクリック感まで感じられる作りになっています。正直感心しました。おすすめです。

お絵描きするならペーパーライクフィルムはあったほうがいい

Apple Pencil と iPad でお絵かきをするのであればペーパーライクフィルムはつけたほうがよいと思われます。私も最初は「画面がギラついて画質が劣化するんじゃないか」等の懸念があって貼っていなかったのですが、一度覚悟を決めてペーパーライクフィルムを貼ってみたら思ったより画質劣化が小さく「なんでもっと早く貼らなかったんだ」と思ったぐらいです。

iPad 標準のガラス面に Apple Pencil のプラスチックなティップだとどうしても「カツカツ」「ツルツル」と滑ってしまう感覚で、紙にペンでかくのとは体験が大きく異なってしまうのですが、ペーパーライクフィルムを貼ることで完璧とは言わないもののそれなりに紙に近い感覚でかけるようになります。ペンが滑ってしまうことがなく動かしたいところに動かして止めたいところで止められるようになるので、手書きメモならともかく絵を描く場合はペーパーライクフィルムを貼ることをおすすめします。

私は、iPad お絵かきパーソンの間で定評のある下記の商品を購入しました。

iPad Pro は画面が大きく、保護フィルムを貼るのも一苦労です。実際このフィルムを貼る際も正直苦戦はして、貼った直後はどうしても少しの気泡が入ってしまい失敗したかなと思ったのですが、1 日程度で気づかないうちにきれいに気泡が消えました。最近の材料技術・ミクロな加工技術はすごいですね…

f:id:biacco42:20200510193405j:plain:w400

使い始めた直後は結構抵抗感が強いのですが、ある程度使うとちょうどいい感じの滑りになります。実際にこのフィルムと iPad Pro 2020 で最近描いたのがこんな感じです。

ラフスケッチ20200503www.pixiv.net

へるへる helltaker 六道冥www.pixiv.net

f:id:biacco42:20210117014131p:plain
描きかけ

まとめ

めちゃめちゃ長くなってしまいましたが、お絵かき / Kindleバイスとしての iPad Pro 2020 12.9 inch モデルのレビューはこんな感じになります。iPad Pro と Apple Pencil のおかげでお絵かきが始められたので、iPad Pro と Apple Pencil は実質無料です。ちょっとしたメモも iPad でとっているため手放せないデバイスになりました。おすすめです。

おしまい。

最新 Apple iPad Pro (11インチ, Wi-Fi, 256GB) - シルバー (第2世代)

最新 Apple iPad Pro (11インチ, Wi-Fi, 256GB) - シルバー (第2世代)

  • 発売日: 2020/03/25
  • メディア: Personal Computers

Apple Pencil(第2世代)

Apple Pencil(第2世代)

  • 発売日: 2018/11/07
  • メディア: Personal Computers

Self-Made Keyboards in Japan こと自作キーボード Discord サーバーでアクセスコントロールとその bot による自動化を導入した話

TL;DR

リモートワーク / WFH や STAY HOME 等でネットワークを介したコミュニケーション手段が非常に求められている中、Discord サーバー運用のノウハウとして カテゴリやチャネルのアクセスコントロールの仕方と bot による自動化 についてまとめます。

Self-Made Keyboards in Japan Discord サーバー

2 年半ほど前から Self-Made Keyboards in Japan という自作キーボードコミュニティのサーバーを Discord で運用しています。

biacco42.hatenablog.com

大変ありがたいことに非常に多くの方に利用していただいており、メンバーはそろそろ 3000 人になろうかというところです。感謝🙏

今春、サーバーメンバーが多くなってきたこともあり、より一層コミュニティとしての機能を拡充したいという思いから、キーボードに直接は関係ないチャネル群とそれをまとめるカテゴリを導入しました。一方で「キーボードサーバー」としての混乱をきたさないことも期待されており、今回カテゴリ単位での可視性・アクセスコントロールを導入しました。

その手順と自動化手法、オマケとして導入経緯や判断について簡単に紹介します。

チャネル・カテゴリ単位でのアクセスコントロール

Discord のチャネルやカテゴリに対するアクセスコントロールの設定法は既存のチャットアプリなどと比べるとやや特殊に見えるかもしれません。

Slack ではプライベートチャネルは「プライベートチャネルを作って」「そこに招待された人だけが見える」という比較的オールドスクールな手法によっています。対して Discord ではこのようなアクセスコントロールをするために role という概念を用います。一見複雑ですが、きめ細やかな権限管理が柔軟にしやすく非常に便利です。

role

Dircord における role というのは、簡単に言うとユーザーにつくラベルです。そしてチャネルやカテゴリに対して、その role というラベルごとに 読み書き等の権限を管理することができます。個人ではなく role に対して権限管理を行うため

  • 個人単位での権限管理が不要で
  • 権限設定の複雑化・意図しない権限付与バグを防ぎやすく
  • 権限のオンオフを role というテンプレート付与剥奪で冪等にできる (←自動化しやすい)

というメリットがあります。

f:id:biacco42:20200509183219p:plain:w300

Biacco42 というアカウントには managers Nitro Booster enable-other-category という role が付与されていることが確認できます。

チャネル / カテゴリを不可視にする

Discord の role による権限管理は非常に柔軟で様々なことができるのですが、基本的に必要なのは 読み書き権限のコントロール かと思います。

Discord では

サーバー全体での role による権限管理 → カテゴリの権限管理 → チャネルの権限管理

のように階層化された権限管理モデルが採用されています。より狭い範囲での権限設定が優先され、変更しないものに関しては上位の権限設定が継承されます。

これを利用して「カテゴリ A の中では role α だけが書き込むことができる」「チャネル B は role β しか見れないし書き込めないプライベートチャネル」というような管理が可能になります。

f:id:biacco42:20200509184510p:plain

f:id:biacco42:20200509185020p:plain

例えば上記画像は、管理者アカウントによる bot の動作テスト用のチャネルの権限設定の一部で、 everyone role の Read Message 権限が剥奪され、 managers role が付与されている人たちのみこのチャネルを見ることができるようになっています。真ん中のグレーの斜め線は上位からの権限の引き継ぎを表しています。

まとめると、カテゴリやチャネルに

  • everyone など全員が該当する role で読み書き権限を制約
  • 許可したい role ごとに読み書き権限を設定

でプライベートチャネルをつくることができます。

role 付与の自動化

会議体のようなある程度固定した組織運用をする場合は上記のカテゴリ / チャネルの権限設定をして管理者権限でユーザーごとに role を付与すればよいのですが、Self-Made Keyboards in Japan のような多人数のオープンコミュニティではそれを人力で管理するのはだいぶ無理があります。また、厳密なアクセスコントロールが必要なわけではなく、「単純に興味がなくて表示を減らしたい」「一部チャネルについては別途規約に同意してほしい」などといった場合には、ユーザーが制限された範囲内で自由に role を付け外しできる方が好ましいです。

ここからは、そういった role 付与の自動化について説明します。

role 付与を管理する bot を導入する

こういったチャットサービスの自動化といえば bot の導入が手軽です。ですが bot を別途サーバーなどでホストするのはインフラ的にも運用的にもコストが重いです。今回のような role 付与をするぐらいであれば botホスティングを含んだサービスを利用することで導入・運用コストを大幅に引き下げることができます。

今回は Dyno というサービスを利用する方法を紹介します。今やろうとしている role の付与程度なら無料プランで利用できる大変太っ腹なサービスです。

dyno.gg

f:id:biacco42:20200509192506p:plain

Dyno のサイトにアクセスして右上の Add To Server を押して、自身の Discord アカウントに紐付いた サーバー管理権限のある サーバーに bot を追加します。その際 bot に付与する権限を確認されます。

f:id:biacco42:20200509194644p:plain:w300

Administrator や Manage Server 等の強い権限はその権限を必要とする機能を利用しなのであれば外しておいたほうが安全です。今回は role の付与とテキストコマンドの削除等だけできればいいのでかなりの権限を制約しておきました。接続が完了すると Discord サーバーの方に bot が参加して、Dyno のページに自動的に遷移します。

Dyno には非常にたくさんの機能があるのですが、不用意に発動されると困るため今回利用する Custom Command 以外は Module / Command ですべて無効にしておきました。利用したい場合は適宜有効化してください。

f:id:biacco42:20200509195301p:plain

めちゃくちゃたくさんの機能があります。

role を付与する Custom Command を設定する

Dyno には標準で role {user} {role} というコマンドがあるのですが、これを誰でも使えるようにしてしまうと好き勝手に role が振れるようになってしまい大変危険です。そのため Custom Command という機能を利用してこの role コマンドを安全にラップします。

Custom Command は bot が読み取ることができるチャネルで {prefix 文字列}{Command 文字列} と入力すると Response が実行されるものです。prefix 文字列はデフォルトで ? ですが変更することが可能です。

Dyno の管理画面の Custom Command のページを開き Add Command でコマンド追加画面を開きます。

f:id:biacco42:20200509200507p:plain

Command 欄には受け付けるコマンドの文字列を、Response には実行する機能やテキストチャネルに書き込む文字列を記述します。今回の設定では、 #enable-other-category チャネルでのみ ?i-agree-to-the-terms-of-use を入力すると enable-other-category role がオン・オフできるようになっています。

上記画像では

  • Command を i-agree-to-the-terms-of-use
  • Response を {require:#enable-other-category}{!role {user} enable-other-category}

設定しました。前述の通り、なにも制限しなければ bot が読み取り可能なすべてのチャネルでこのコマンドが発行されてしまうため、require によってこのコマンドが利用可能なチャネルを #enable-other-category のみに制約しています。 {!{既存コマンド}} で既存のコマンドを呼び出すことができ、{user} などの事前適宜 Variable によって値を埋めることができるので、 role コマンドをこの Custom Command を発行したユーザー {user}enable-other-category を引数として呼び出しすとことで role の付与のオン・オフを制御します。

このように Custom Command で既存コマンドをラップすることで、動作を制限して安全に任意のユーザーに利用してもらうことが可能になります。

利用できるコマンドはこれ以外にもたくさんあります。詳細については Dyno のドキュメントを確認してみてください。

dyno.gg

このようにして、Dyno を利用することで bot サーバーをホスティングすることなく Discord の role 付与を安全に行うことができます。

以上で role 付与、カテゴリ / チャネルのアクセスコントロールの自動化は完了です。お疲れさまでした。

余談

今回、Self-Made Keyboards in Japan Discord サーバーでは、自作キーボードサーバーというトピックサーバーならではの問題として、オフトピックな話題を「コミュニティ」としてどう扱うかという観点で、OTHER カテゴリというカテゴリを導入し、上記の可視性のコントロールを設定しました。

人間、多様な側面を持っているものですから、キーボードのことで意気投合した人々と、キーボードを離れて単に雑談をしたり他の趣味を共有したりといったコミュニケーションを取りたい、人間関係を構築したい、というのは自然な欲求かと思っています。また、そういった刺激が新たな創発の原動力になりうるとも思っています。一方で、Self-Made Keyboards in Japan はキーボードをメイントピックとしたサーバーなので、そういったチャットはノイズという捉え方も可能です。

それらどちらか一方を取るのではなく、個人の自由と裁量に任せてサーバーが運用できたらという思いで今回のような施策を実施しました。他のサーバーでも似たような問題に悩んでいる管理者の方がいるのではないかと思い、今回この記事を書きました。そのような悩めるサーバー管理者の一助になれば幸いです。

おしまい。

自作キーボード入門用語集 2020

この記事では、自作キーボードを構成する要素とよく聞かれる用語を列挙しながら、2020年に自作キーボードに入門するための基礎知識をできるだけ網羅的に紹介します。

  • 外出自粛もあってお家でできる趣味や娯楽を求められている方
  • 新年度・新生活も 1 ヶ月が経ち会社や学校に馴染んで新しいことを始めようという方
  • 自作キーボードって言葉を最近よく聞くな~と言う方
  • 自作キーボードをはじめようと思っている方
  • 自作キーボードのより深い情報を知りたい方

向けに、今自作キーボードの何が「アツい」のか旬のトレンドも交えつつ、自作キーボードでよく聞かれる用語に簡単な文脈と説明を与えることを目標としています。

目次

以下では、知識が広げられるようポイントとなる用語に Google での検索リンク をつけました。また、その用語の 深度 を ♨ マークの数 (1 ~ 3) で表示しています。♨ が 1 個のものは入門する際に知っているといい用語、♨ が 2 個ないし 3 個のものはより深い高度な用語・トピックになっています。♨ が 2 個以上のものについてはよくわからなければ読み飛ばしてもらって大丈夫です。そもそも量が多いので、全てを理解しようとしなくて大丈夫です。

この記事だけではすべての項目について詳細に解説をつけることはできないですが、自作キーボードについてより深く知りたいとき、わからない用語や概念が出てきたときに、調べるためのきっかけや相互の関連性を整理するための道標として役立てていただければ幸いです。

自作キーボードの構成

まずは自作キーボードの一般的な構成要素から紹介していきます。以下の図は自作キーボードの主要なパーツを表した図で、キーボードによって多少の違いはあるものの、基本的にはどのキーボードでもほぼこういった構成になっています。

f:id:biacco42:20200503204306p:plain
キーボードを構成する基本 5 パーツとキーボードキット。どのようなキーボードでも基本はこういった要素の組み合わせになっています。

特にこの中でも、プレート・基板・ケースの3つをまとめてキーボードキットとして取り扱う事が多く、この記事では ♨キーボードキット♨♨プレート♨♨基板 (PCB)♨ケース♨キースイッチ♨キーキャップ の6種について、それぞれの概要や関連用語、カスタマイズのトレンドを紹介していきます。

キーボードキット

♨キーボードキット は、大きく 2 つのカテゴリに分けられます。一つは、日本でよく見られる電子工作キットに近いスタイルの ♨自作キーボードキット で、もう一つは海外で主流となっている、金属筐体など比較的工業生産的な半完成品のパーツを組み合わせて作る ♨♨カスタムキーボード です。

自作キーボードキット

おそらく、読者の方々が思う自作キーボードのイメージは ♨自作キーボードキット の方で、2016 年頃から日本国内で主流のスタイルとなっています。個人製作のものが多いため、アクリルなどの比較的安価かつ加工がしやすい材料を用いていることが多いです。各製作者から、様々な形状や機能を備えた多様な自作キーボードが次々に登場していることが大きな特徴です。

f:id:biacco42:20200504231944p:plain
Googleで「自作キーボード」で検索すれば個性豊かな様々な形状のキーボードが見つかります。

カスタムキーボード

海外キーボードコミュニティ (♨♨reddit♨♨r/MechanicalKeyboards♨♨geekhack♨♨keebtalk ) などで支持が厚いのが ♨♨カスタムキーボード (Custom Keyboard) です。左右分離型など個性的な形状が多い自作キーボードキットに対して、一般的なキーボードの形状を出発点に、よりよい キーボード体験 を求めるムーブメントです。打鍵感や打鍵音、デザイン、設計者のブランドなどを重視して、アルミや真鍮といった金属を加工した高級なものから、カスタマイズ性とコスパに優れた標準的な設計のものまで幅が広いのが特徴となっています。

打鍵音の心地よさからカスタムキーボードの打鍵動画の人気も高く、そういった動画を多数投稿している ♨♨Taeha Types (Nathan Kim)YouTube チャンネルなどが存在しています。

f:id:biacco42:20200504234222p:plain
多数のカスタムキーボードの組み立て・打鍵動画を投稿している Taeha Types の YouTube チャンネル。自作キーボードキットと異なり、カスタムキーボードはオーソドックスなキー配置のものが大多数を占めています。

www.youtube.com

これらのキーボードキットに共通する主要なパラメータに ♨物理キー配列 が挙げられます。物理キー配列は文字通りキーの物理的な並べ方のことで、キー数による分類、♨左右分離型♨一体型 といったキーボードの形状による分類、♨Row Staggered (一般的なキーボードのように行がずれる配列) のようなキースイッチのレイアウトを示す分類、の 3 つに大別できます。

キー数

自作キーボードではキー数についても従来の常識にとらわれず自由に設計できます。フルキーボード等と呼ばれる US 104 キーボードのキー数である 104 キーを 100 % として、パーセンテージでおおよそのキー数を表現することが慣例となっています。例えば、32キーの ♨Treadstone32 であれば ♨30 % キーボード、といった具合です。また、テンキー部分をなくしたものを ♨♨TKL (TenKey Less)Windowsキーに相当する位置のキーをなくしたものを ♨♨WKL (Win Key Less) と呼ぶなど、特殊な呼び方も存在しています。

形状

特徴的な外見で日本で一躍人気を博したのが ♨左右分離型 です。市販品の左右分離型キーボードもなくはないですがまだまだ珍しいため、左右分離型のキーボードといえば自作キーボード、という向きもあるかと思います。両腕を広げ、胸を開いた自然な姿勢で打鍵できることがメリットとされています。

f:id:biacco42:20200505172304j:plain
左右分割型の Ergo42 Towel。キーキャップは MDA BigBang。

逆に「普通のキーボード」となるのが ♨一体型 です。左右分離型の特徴やメリットを考えると、自作でわざわざ一体型を作るにはメリットは一見なさそうに思えますが、膝の上に置いて使えることや、デスク上を従来のキーボードと同じようにレイアウトできるなどの理由から根強い人気があります。

f:id:biacco42:20200505172007j:plain
一体型である GH60 の互換基板 DZ60 と互換アルミ削り出しケース。キーキャップは JTK Purple on White。

キースイッチのレイアウト

キースイッチのレイアウトでは、通常のキーボードのように行方向 (Row) にずれる様に (Staggered) キーを並べた ♨Row Staggered、人間の手の形に配慮して列方向 (Column) にキーをずらした ♨Column Staggered、縦横をずらさず碁盤の目状にキーを配置した ♨Ortholinear (格子配列)、指の動きに着目して行方向にキーをずらした ♨♨Irregular Row Staggered♨♨Symmetric StaggeredMicrosoft Ergonomic Keyboard に似たレイアウトで近年注目の ♨♨Alice配列 と言われるものなどがあります。

f:id:biacco42:20200505182918p:plain
キーボードのキー数、形状、キー配置とその表現の例。

プレート

キースイッチを固定・安定させるためのパーツが ♨♨プレート で、♨♨マウントプレート と呼ばれることも多いです。打鍵感や打鍵音に影響するパーツで、現状では柔らかいほうが打鍵感が優しく、好まれる傾向にあるようです。

材質としてはアルミや真鍮といった金属の他、アクリルやポリカーボネート、基板の材質である繊維強化プラスチック (FR4) などもよく用いられています。柔らかな打鍵感を高めるために、プレートにスリットを入れたり、部分的にプレートのない部分を作ったり、そもそもプレートを入れない場合もあります。

タクタイルやリニアといったスイッチの特性によって相性のいいプレートが異なるとも言われており、キーボードキットによっては複数の選択肢が用意されていることもあるので、マウントプレートのオプションがあるか確認してみるといいでしょう。

f:id:biacco42:20200505185029j:plain
真鍮製のプレートにスイッチをはめた図。適度な強度と柔らかさでマウントプレートに用いられている場合がある。

基板(PCB)

キースイッチの入力状態を読み取るための回路を印刷した板が ♨♨基板 (PCB) です。スイッチと ♨♨マイコン、USB ポートと ♨♨マイコン をつなぐ回路や LED 用の回路が印刷されており、これに各種電子部品をはんだ付けをします。基板自体のカスタマイズ性はほとんどありませんが、同一の形状の基板でも事前に電子部品がはんだ付けしてある ♨はんだ付け不要のキット も最近では出回っているので、はんだ付けに不安がある場合そういった点に着目して選んでみてもいいかもしれません。

f:id:biacco42:20200505190410j:plain
自作キーボード入門用の 4 キーマクロパッド meishi2 の基板。これに電子部品をはんだ付けしていく。

yushakobo.jp

ケース

♨ケース はキーボードの回路を保護する他、外見としての美しさや打鍵感・打鍵音に影響する重要なパーツです。日本では、簡易的ながら比較的安価で実用十分なアクリル製の ♨♨サンドイッチケース が多くなっています。カスタムキーボードではアルミ削り出しで作られた ♨♨トップマウントケース や、最近採用例が増えている ♨♨♨ガスケットマウントケース、その他にもポリカーボネートや木を削り出したケース、最近では3Dプリントケースなど、非常に多様な形状・材質のものがあります。

f:id:biacco42:20200505210955j:plain
日本の自作キーボードキットに多いアクリルサンドイッチケース。安価でシンプルだが、設計次第では打鍵感も悪くなく個人でも製造可能なため、日本の自作キーボードキットではよく用いられています。

f:id:biacco42:20200505211117j:plain
アルミ削り出しケース。アルミケースは質感がよく加工性もいいためこちらもよくケースに用いられています。

基本的には、重く剛性の高いケースほど打鍵時の不要な振動が抑えられて好まれる傾向で、カスタムキーボードでは ♨♨真鍮の重り がわざわざ追加されていることも多いです。最近ではアクリルや繊維強化プラスチック(FR4)など比較的軽量な ♨♨サンドイッチケース♨♨鉛板 を貼るなどのカスタマイズも登場しています。

また、基本的にはキーボードのケースはキーボードキットに固有ですが ♨♨GH60 と呼ばれるキーボード基板とその互換基板 (♨DZ60 など) は交換用のケースが数多く出回っており、手軽にドレスアップすることが可能になっています。

f:id:biacco42:20200505214159p:plain
GH60 とその互換基板は安価かつ交換用のケースが豊富で、簡単にドレスアップできるのが魅力。

Casekbdfans.com

キースイッチ

自作キーボードにおいて打鍵感を左右する非常に重要なパーツが ♨キースイッチ です。もともと「赤軸」など軸の色で種類が呼び分けられていたことから ♨軸 とも呼ばれます。現在主流となっているのは、メカニカルキースイッチのデファクトスタンダードとなっている ♨Cherry MX シリーズの互換製品と、薄型スイッチである ♨Kailh Low Profileスイッチ、通称 Choc スイッチです。

カニカルキースイッチといえば、長らく Cherry MX の赤・茶・青・黒の打鍵感の異なる 4 種類の軸が主流でしたが、最近では中国メーカーを中心に Cherry MX 互換のキースイッチだけでも 100 種類近いものが販売されており、以前とは状況が大きく異なってきています。ここでは、これだけ多くのスイッチを分類するためのパラメータである、♨♨キーの感触 (フォースカーブ)♨荷重♨静音♨♨♨なめらかさ の 4 つについて簡単に紹介していきます。

キーの感触(フォースカーブ)

キースイッチの主要なパラメータとしてキーの感触があり、大きく ♨リニア♨タクタイルクリッキー の 3 種類に分けることができます。

♨リニア はスイッチを押し込む際に引っかかりがなく、他にないなめらかな打鍵感が特徴となっています。名前の通りスイッチを押し込む際の ♨荷重 (スイッチを押すのに必要な力) の変化が一定で、入力される点 (♨♨作動点) での荷重変化がなくフィードバックがない、他のスイッチにはないメカニカルキーボード特有の感触となっています。Cherry MX でいうと赤軸や黒軸が相当します。

対して ♨タクタイル は作動点付近で荷重が一旦重くなった後一気に軽くなって「スコン」と落ちるような感触 (バンプ) が特徴的なスイッチです。打鍵時に明確に押したことがわかるフィードバックがあり、とっつきやすいスイッチになっています。Cherry MX でいうと茶軸が相当します。

♨クリッキー はタクタイル同様にバンプを持ち、バンプを超えると同時にカチッというクリック音が鳴ることが特徴のキースイッチです。キーの感触だけでなく、音によるフィードバックもあるため「入力している感」が強くたのしいスイッチですが、かなりうるさいためオフィスや学校などで使用する際には周りの人にも気を配ったほうがいいでしょう。

これらの感触について定量的に表現したものが「フォースカーブ」で、キースイッチによってはデータが公開されています。横軸はスイッチを押し込んだ距離、縦軸は押し返してくる力 = 荷重です。キースイッチのフォースカーブには向きがあり、右向き矢印が押し込むとき、左向き矢印が離すときを表しています。下のグラフを見ると、リニアの変化の少ない押し心地やタクタイルの「バンプ」を目に見ることができるかと思います。

f:id:biacco42:20200505222240p:plain
リニア、タクタイル、クリッキーそれぞれのフォースカーブ。横軸はスイッチを押し込んだ距離、縦軸は押し返してくる力 = 荷重を表しています。

荷重

キースイッチが入力される ♨♨作動点、または ♨♨底打ち に必要な押し込む力が ♨荷重 で、通常 g (グラム) ないし cN (センチニュートン) で表されます (ものすごく大雑把に言えば g と cN はだいたい同じと思っていいです (あくまでだいたいです))。荷重はキーの感触とは独立で、リニアでもタクタイルでもクリッキーでも、軽いスイッチから重いスイッチまで様々なバリエーションが存在し、「リニアの60g」「タクタイルの45g」のように表現します。荷重は主にスイッチ内のスプリングの強さで決まり、作動点で 45 g 程度、底打ちで 60 g 程度が標準的とされているようです。海外では比較的重め (作動点で 45 ~ 60 g 程度) のものが好まれる傾向にありますが、日本国内では 45 g より軽い 35 g や、人によっては 25 g など非常に軽量なスイッチを好む人もいます。

最近ではこのスプリングにも様々な種類が登場し、スプリング単体での購入も可能となってきました。押し込む距離が長くなると荷重が大きくなる ♨♨♨プログレッシブスプリング や、押し始めから底打ちまで荷重変化が少ない ♨♨♨スロースプリング など、新しい選択肢が増えてきています。

f:id:biacco42:20200505223054j:plain
最近ではキースイッチの交換用スプリングも比較的容易に入手可能になりました。写真は底打ち 62 g のスロースプリングで、押下開始時点から荷重負荷が大きく、底打ちまでの荷重変化が小さいため安定した打鍵感になりやすいです。

静音

通常のメカニカルスイッチはプラスチック部品がぶつかるため少なからず「カチャカチャ」といった音が出ます。それに対して、プラスチックがぶつかる部分にゴムなどを配置した ♨静音スイッチ というバリエーションが存在する場合があります。音が気になる場合には検討してみるとよいでしょう。ただし、ゴムパーツによって底打ちの打鍵感などに影響があるため、実際に触ってみて検討をしたほうがいいかもしれません。クリッキースイッチはもともと意図的に音を出しているため、静音スイッチというものはありません。

なめらかさ

これらのキースイッチに関する最新の、そして最も注目されている要素がなめらかさです。近年非常に多くのスイッチがリリースされている理由の一つが、このなめらかさの追求と言っても過言ではありません。一見どれも同じように見える Cherry MX 互換スイッチですが、メーカーによって設計や部品選定の違い、製造時期による品質のばらつきなどによって打鍵感に差がでてきます。一般に、摩擦感や引っ掛かりのないなめらかな打鍵感がよいとされており、悪い打鍵感のことを「このスイッチはガサガサする」などと表現することがあります。最高の打鍵感を求めて日々なめらかなキースイッチが研究されていますが、なめらかさはスイッチの種別だけでなく複数のパラメーターが絡み合っているため簡単には説明できないことも多いです。

最近では ♨♨♨金型の状態♨♨♨プラスチック素材♨♨潤滑 (ルブ)♨♨♨スイッチパーツの組み合わせ (キメラ)♨♨ガタツキを減らすフィルムの追加 (スイッチフィルム) など、スイッチのなめらかさとそのカスタマイズについて日夜議論がなされています。

なめらかなスイッチとして評価が高いものを一部例示しておくと、比較的高価なスイッチを製造販売する ♨♨ZealPC♨Tealios や、♨Gateron♨Ink シリーズなどが挙げられます。また、最近ではキースイッチを分解して潤滑剤を塗布することで動作をなめらかにする ♨♨潤滑 (ルブ) も非常に人気が高まっており、以前は入手困難だった潤滑剤や、ルブのためにキースイッチを開けるための ♨♨スイッチオープナー♨♨ルブステーション など、ルブに関する様々な製品が登場してきています。

f:id:biacco42:20200505224354j:plain
キースイッチの潤滑 (ルブ) は最近環境が充実してきており Krytox 205 や Tribosys 3203 といった高性能な潤滑剤が入手できるようになってきています。

キーキャップ

キーボードの顔とも言える存在が ♨キーキャップ です。自作キーボードでよく用いられる Cherry MX 互換スイッチはキーキャップを取り付けるための軸部分が共通になっており、多くの個性的なキーキャップを取り付けられます。キーキャップはキーボードの見た目を大きく変えることもさることながら、指が直接触れる場所でもあるため打鍵感にも大きな影響がある重要なパーツとなっています。

キーキャップの材質としては、♨ABS 樹脂♨PBT 樹脂 がよく使われます。ABS 樹脂は発色が鮮やかで加工性がよく二色成形に向くなど見た目に優れた性質を持ちますが、耐久性が低く摩耗してテカテカになりやすい欠点があります。PBT 樹脂は逆に高い耐久性・耐摩耗性をもち美観が保たれやすいですが、加工性が低く高価格になりがちなところがあります。それぞれ手触りや打鍵音に影響し、ABS はツルツルした手触りのものが多く軽めの打鍵音で、PBT はサラサラとしたマットな手触りのものが多く「コトコト」といったやや落ち着いた打鍵音になりやすいのが特徴です。

また、形状として ♨♨DSA♨♨DCS♨♨SA♨♨Cherry♨♨OEM♨♨XDA♨♨MDA♨♨KAT♨♨KAM … などなど、♨プロファイル と呼ばれる多くの分類があります。行ごとに階段のような段差のあるもの (♨ステップスカルプチャ Step Sculpture)、指が触れる面が円筒状にへこんでいるもの (♨シリンドリカル Cylindrical) や球形にへこんでいるもの (♨スフェリカル Spherical)、キートップの面積の広さ、キーキャップの高さなどに特徴があり、それぞれのプロファイルが各々に特色を打ち出しています。指の触覚は想像以上に正確なので、同じキーボード、キースイッチだとしても、プロファイルを変えることで様々な変化が楽しめるポイントです。

f:id:biacco42:20200508003809p:plain
キーキャップの形状による分類。DSA や XDA といったフラットなプロファイルは場所を選ばないため変則的なキー配置になりがちな自作キーボードキットでも扱いやすいです。一方でステップスカルプチャを持つキーキャップにも根強い人気があり、打鍵音を重視する場合には背の高い SA プロファイルのキーキャップなども好まれます。

これらのキーキャップは現在、通常の販売のほか ♨♨Group Buy と呼ばれる共同購入で期間限定・数量限定で生産されることが多く、好みのデザインのものを逃してしまうと入手不可能になってしまう場合もあり注意が必要です。Group Buy を通して高品質なキーキャップを製造しているメーカーとしては ♨♨GMK♨♨Signature Plastics (SP) が、Group Buy の ♨♨プロキシ販売サイト (代理販売) としては ♨♨zFrontier♨遊舎工房 が、Group Buy の企画・告知環境としては ♨♨geekhack 等のコミュニティサイトがそれぞれ有名です。

まとめ

自作キーボードを構成する要素とよく聞かれる用語を、その構成をなぞりながら駆け足で紹介しました。近年盛り上がっているトピックも盛り込んだため、一読しただけではすべての情報を追いかけることは難しいと思いますが、ぜひ自分が気になるトピックを見つけて、2020 年の自作キーボード入門のきっかけ、また新たな領域の開拓の道標として活用していただければ幸いです。

おしまい。

Windows 環境で Blue Yeti のマイクのモニタ (入力フィードバック) が聞こえない場合の設定 / モニタをオフにする方法

問題 - モニタ音声 (フィードバック音声) が聞こえない

USB 接続で高音質な音声入出力が可能な Blue Yeti Microphone。3.5 mm のステレオミニジャックがついており、PC 等の出力デバイスの音を聞きながら 遅延ゼロで入力音声をミックスしてモニタリングできる機能 が非常に便利な使い勝手のいいマイクで、podcast をオンラインで収録したり YouTube 配信したりゲームのボイスチャットに利用したりされています。

↓後継機種

Blue Yeti で検索すると一般的にこの 入力音声をモニタリングする機能はオフにできない と書いてあります。ですが、Windows で場合によってはこのモニタリング音声が聞こえない場合があります。ヘッドホンをした状態で自分の声がフィードバックされないとしゃべるのが非常に困難で問題になります。

解決法 (or Blue Yeti のモニタ音声をオン / オフにする方法)

ポイントは 録音デバイスではなく再生デバイスのプロパティを操作すること です。録音デバイスの入力レベルを操作しても モニタの音量は変更できません。

f:id:biacco42:20200420010838p:plain
1. タスクトレイのサウンドインジケータを右クリックしてサウンドの設定を開く

f:id:biacco42:20200420011001p:plain
2. サウンド コントロール パネル を開く

f:id:biacco42:20200420011347p:plain
3. 再生デバイス Yeti Stereo Microphone のプロパティを開く

f:id:biacco42:20200420011611p:plain
4. レベルタブを開くとマイクの項目があるのでここでモニタの音量調節が可能

以上です。お疲れさまでした。

型クラスの原点 How to make ad-hoc polymorphism less ad hoc を読んだ話

以下の記事は 2018 年 2 月 に Qiita に投稿した記事の移植です

pixivFANBOX にも投稿しています。ご支援頂ける場合はよろしくお願いいたします。

www.pixiv.net


オレオレ型クラスの話をやめろ。原典に当たれ。ということで、Haskell に型クラスの導入を提案した論文とされる Philip Wadler. How to make ad-hoc polymorphism less ad hoc を読んだのでそれをまとめる話です。

型クラス導入の目的

2 つの多相

多相にはアドホック多相、パラメトリック多相の 2 つの種類がある。

アドホック多相

アドホック多相は、ある関数が受け入れる型によって 型に応じた振る舞いをするような多相 。典型的なのは関数や演算子オーバーロード

3 * 3
3.14 * 3.14

同じ演算子 * だけど、整数型と浮動小数点数型どちらでも使えています。

パラメトリック多相

名前の通り、型を表すパラメータを取ることによって 型によらない共通の振る舞いをする多相 。典型的なのは length 関数。

 length :: [a] -> Int

配列であれば中の型に関係なく使うことができる。

Hindley/Milner 型システムと多相

パラメトリック多相については Hindley/Milner 型システムがよく扱えるということで広く用いられていたけど、アドホック多相については良い手法がなかった(ためアドホック多相が導入されていなかった)。

この論文では、型クラスってものを導入して Hindley/Milner 型システムを拡張することでオーバーロード = アドホック多相ができるようにするよ。

アドホック多相の制約

算術演算の場合

整数型と浮動小数点数型にオーバーロードされた乗算演算子 * を考える。この演算子 *アドホック多相にできるけど、それを利用した関数はアドホック多相にできない。

-- これはできない
square x = x * x

square 3
square 3.14

関数自体を Int -> IntFloat -> Floatオーバーロードさせることもできるけど

squares (x, y, z) = (square x, square y, square z)

みたいな関数を考えるとき、組み合わせが爆発する。

同値評価の場合

同値性を評価する場合にも同じような問題がある。

-- これはできない
member [] y = False
member (x:xs) y = (x == y) \/ member xs y

member [1, 2, 3] 2
member "Haskell" 'k'

そこで同値性についてはパラメトリック多相で対応するアプローチが試された。

(==) :: a -> a -> Bool
member :: [a] -> a -> Bool

ただ、この方法だと関数型や抽象データ型などの同値評価ができない型を渡しても静的に型エラーを起こすことができず、実行時に評価しようとしてエラーすることになってしまった。

そこで同値評価できる型だけに同値性評価できるように制約を書ける方法が Standard ML で導入された。

(==) :: a(==) -> a(==) -> Bool
member :: [a(==)] -> a(==) -> Bool

この方法では、関数型や抽象データ型などを member 関数に渡すと型エラーにすることができるようになったけれど、Standard ML では参照型の同値性評価は他の型の同値性評価と異なるように設計されていたので、同値性評価する型の峻別のためにランタイムシステムを構築する必要が出てきてしまった。

これに対してオブジェクト指向では、データに対して実装を与えるメソッドのポインタの集合 = 辞書 を持っているので、同値性評価関数に渡ってくる引数のいずれかの辞書に含まれる同値性評価のメソッドを用いて評価することができる。

このメソッドの集合をデータと一緒に渡すのがいい感じだから、型クラスでもこのアイディアが背景としてあるよ。

型クラスの導入例

まず、型クラスを実際に導入したコード例を示す。

class Num a where
    (+), (*) :: a -> a -> a
    negate   :: a -> a

instance Num Int where
    (+)    = addInt
    (*)    = mulInt
    negate = negInt

instance Num Float where
    (+)    = addFloat
    (*)    = mulFloat
    negate = negFloat

square            :: Num a => a -> a
square x          = x * x

squares           :: Num a, Num b, Num c => (a, b, c) -> (a, b, c)
squares (x, y, z) = (square x, square y, square z)

型クラスの定義

このコードで型クラス Numclass キーワードによって定義されている。Num 型クラスは (+)(*)negate が定義されている型 a が所属している。

続いて、instance として型 a を具体化した実装を与えている。これらは Num の要求する関数を実装しているか型検査される。たとえば

addInt :: Int -> Int -> Int

が検査される。

型クラス制約の利用

型クラスの導入によって、前述の squaresquares が実装できた!

ここで square の型は Num a => a -> a となっているが、Num a => によって型 aNum が実装されていることが要求されている。この square は次のように利用できる。

square 3
square 3.14

そしてもちろん

square 'x'

Num Charinstance が存在しないからコンパイル時に静的に型エラーにできる!

アドホック多相が実現できていることが確認できる。

型クラスの 変換

実際にはこの型クラスの仕組は、コンパイル時に型クラスを用いない形に変換されて Hindley/Milner 型システムで扱えるようになる。つまりは型クラスはある種の糖衣構文になっている。

上記のコード例を型クラスを用いない形に変換したものが下記のコード。

data NumD a = NumDict (a -> a -> a) (a -> a -> a) (a -> a)
add (NumDict a m n) = a
mul (NumDict a m n) = m
neg (NumDict a m n) = n

numDInt     :: NumD Int
numDint     =  NumDict addInt mulInt negInt

numDFloat   :: NumD Float
numDFloat   =  NumDict addFloat mulFloat negFloat

square'          :: NumD a -> a -> a
square' numDa x  =  mul numDa x x

squares'  :: (NumD a, NumD b, NumD c) -> (a, b, c) -> (a, b, c)
squares' (numDa, numDb, numDc) (x, y, z)
          =  (square' numDa x, square' numDb y, square' numDc z)

class 宣言の代わりに、class で定義されていた関数の型を持つデータ型の辞書 NumDict とそれらのメソッドにアクセスするための関数が定義されている。1

instance で宣言されていた部分は、上記の NumD a 型のデータ型の値として変換される。

numDInt     :: NumD Int
numDInt     =  NumDict addInt mulInt negInt

やってることは単純で、NumDict 値コンストラクタで値を埋めているだけ。Float も同じ。こうやって作った辞書をもとに演算は以下のように書き換えられる。

x + y     -->  add numD x y
x * y     -->  mul numD x y
negate x  -->  neg numD x

ここで引数に渡っている numD は適当な演算の入った辞書。

ここからが型クラスのマジックで、適当な演算の入った辞書が型によって自動的に挿入される!

3 * 3       -->  mul numDInt 3 3
3.14 * 3.14 -->  mul numDFloat 3.14 3.14

これによって型によって処理を切り替えるというアドホック多相が実現された。

square'          :: NumD a -> a -> a
square' numDa x  =  mul numDa x x

square 3     -->  square' numDInt 3
square 3.14  -->  square' numDFloat 3.14

力尽きたので Eq 型クラスからの話(型クラスの継承等)については割愛。変換のルール自体は上記に示されたもの。あとで書くかもしれない。

まとめ

というわけで、型クラスはオブジェクト指向でない静的型付け言語、特に Hindley/Milner 型システムを持った言語において、Hindley/Milner 型システムを用いてアドホック多相を実現する手法として導入されました。その型クラスのお手本になったのは実はオブジェクト指向言語のサブタイピング多相であり、オブジェクト指向における関数ポインタの辞書を文字通り Haskell におけるデータ型の辞書として読み替えて この辞書を型に応じて挿入する というものでした。

型クラスの原典に当たって、これで一安心ですね。

実は、全く同様の実装が Scala で借用されており、Haskell における型クラスが脱糖されたような状態で書けるようになっています。また、最近登場した Swift や Rust でも型クラスと似たようなことができるようになっています。おもしろいですね。

おしまい

参考

Philip Wadler. How to make ad-hoc polymorphism less ad hoc Instances and Dictionaries - School of Haskell


  1. 現在の GHC の実装ではレコードによって一括定義するようにしているらしい data NumD a = NumDict {add :: a -> a -> a, mul :: a -> a -> a, negate :: a -> a} みたいな

【Haskell や圏論が出てこない】Scala で型クラスを完全に理解した話

以下の記事は 2018 年 2 月 に Qiita に投稿した記事の移植です

pixivFANBOX にも投稿しています。ご支援頂ける場合はよろしくお願いいたします。

www.pixiv.net


TL;DR

結論から。

型クラスはちょっとすごいオーバーロード であり 型に対して静的にメソッドを挿入する方法 です。

この記事は

  • Haskell圏論等の難しそうな知識・議論なしで型クラス概念を具体的に理解する
  • 型クラスが実は単なるすごいオーバーロードで、ちょっとした便利なものだと実感できる
  • 型クラスとインターフェイスの違い論争で消耗しなくなる
  • 型クラスを知っているとなにがオトクなのかわかる
  • Haskell 等の高度な抽象化の恩恵を Java 的な慣れ親しんだシンタックスで書ける Scala は便利でたのしいと感じる

ことを目的としています。

対象読者

  • 関数型とか型クラスとかモナドとかよく聞くけど全然わからない…でも理解したい気持ちはある
  • 型クラスの概念はいろいろ読んでなんとなく分かるけど説明が Haskell ばかりで実感がわかない
  • 型クラスがなんなのかはぶっちゃけどうでもいいが、便利なのかどうか、どう便利なのかを知りたい

Scala 自体はわからなくても大丈夫です。

まえおき

最近またにわかに 型クラス が話題になっていました。

モナド圏論同様、Haskell の神秘じみた概念の一つして定期的に話題になっていて、なんだかすごくてかっこよさそうなんだけれど、そもそも Haskell をよく知らないし、理論色の強い解説が多くなかなかスッキリ消化できない方が多いのではないかと思います。私もその一人です。Haskell とかさっぱりです。

しかし 型クラスが本当に素晴らしいものなら Haskell を使わなくても素晴らしいといえるはず ということで、この記事では Pure Scala で型クラスを具体的に理解することを目指します。

"型クラス" とはなにか

最初に、型クラスそのものではなく、"型クラスという誤解を招きやすい名称" について整理したいと思います。JavaC++ 等にはじまる多くのオブジェクト指向言語では クラス は特別なキーワードとして扱われてきました。そして、それは と呼ばれる概念とほぼ一対一対応しています。

この慣習がまず 型クラス という言葉をわかりづらくしてしまっているように思います。そこで一旦、OOPL での型やクラスという概念を忘れて、本来的な言葉の定義を考え直してみます。

けい【型】[漢字項目]の意味 - goo国語辞書 - goo辞書 1. 同形のものをいくつも作るとき元になるもの。いがた。「原型・紙型・母型」 2. 基準となる形。タイプ。「型式/定型・典型・模型・類型」

となっており、鋳型等、同じ形をしたものを作るもの・その枠といった意味です。もうちょっとプログラム的に言えば 一定の決まったデータ構造の約束 と言えそうです。

一方 クラス

Weblio - class (共通の性質を有する)部類、種類、(学校の)クラス、学級、組、(クラスの)授業(時間)、(編物教室などの)講習、クラスの生徒たち、同期卒業生、同年兵

となっており、共通の性質をもった集まり であると言えそうです。

つまり、型クラスとは型のクラス = 似たような性質を持った型の集まり、というふうに読み取ることができ、これは実際型クラスをよく説明する表現になっています。

型クラス = 共通の性質を持った型の集まり

というわけで前置きが長くなりましたが、言葉の意味を明らめたところで実際に型クラスとはどういうもので、型クラスが一体何を実現してくれるのか見ていきたいと思います。

型クラスを見て体験する

まずは、型クラスがどんなコードの見た目をしていて何ができるのかを確認してみます。Scala のコードですが、Scala を知らない人でも雰囲気がつかめれば大丈夫ですので、細かいシンタックスは気にせず見てみてください。

まずは、以下のような仕様の実装について考えます。

sum という List を受け取ってその合計を返す関数を定義したいとします。この際、sum が引数に受け取る型は、ただ 1 つの List[Int] などではなく、合計という概念が適用できる型 を幅広く受け取れるようにしたいでしょう。このように多くの型を受け取れることを「多相」と呼びます。

言い換えると、合計という概念が適用できるある型 A を要素に持つ List[A] を引数に取る多相なメソッド sum を作りたい、です。ここで、型 A は拡張できない or 拡張したくない既存の型とします。

ここでいったん合計という概念の詳細は考えずに、まずは IntString の2つに対応してみましょう。自然に実装できるでしょうか?

sum メソッドのナイーブな実装

def sum(xs: List[Int]): Int = xs match {
  case Nil => 0
  case head :: tail => head + sum(tail)
}

def sum(xs: List[String]): String = xs match {
  case Nil => ""
  case head :: tail => head + sum(tail)
}

sum(List(1, 2, 3))        // => 6
sum(List("a", "b", "c"))  // => "abc"
sum(List(true, false))    // Kaboom! Can't compile

型クラスがでてくるかと思いきや拍子抜けしたかもしれませんが、実はオーバーロード / アドホック多相で上記の仕様を満たすことができます。簡単にコードの説明をすると

  1. 引数の List を match (switch のようなものです) で Nil と それ以外で場合分け
  2. Nil だったら受け付ける型のデフォルト値を返す
  3. List が要素を持つならその先頭の値 head と List の残りの要素 tail の総和を足す

ということをやっています。

オーバーロードの引数の型として、合計という概念が適用できる型を列挙し、それぞれの実装を与えることで自然に型にそった処理を実現できています。

この実装によって明らかになった性質がいくつかあります。

  • 合計という概念が適用できる型を明に列挙することで、それ以外の型で利用しようとした場合は静的にコンパイルエラーにすることができる
  • オーバーロードの制約となる型は既存の型であり、既存の型を修正したり拡張したりせずに新たに振る舞いを追加できる
  • 合計というセマンティクスは共通だが、型ごとに実装は異なる

同時に、この実装にはいくつか問題を指摘することができるかと思います。

まず、sum(xs: List[Int]): Intsum(xs: List[String]): String でほとんど実装が重複してしまっています。DRY じゃないですね。

また、今の sumIntString のみにしか対応できていません。もちろんこれら以外の合計が適用できる型には対応できていないですし、仮に多くの型のオーバーロードを用意したとしても、 sum の利用者が追加する独自の型に対応することはできません。つまり、拡張性・再利用性が無い状態になってしまっています。

これらの問題を解決して拡張性を得るためには、合計という概念が適用できる型 をきちんと取り扱う必要がありそうです。

そこで少し今の sum の実装を見直してみます。問題点として挙げた 実装の重複 という観点から、IntString で共通な部分と異なる部分を抽出してみます。

共通な部分は

  • リストの要素の たぐり方
  • リストが Nil だったときには、引数の型のデフォルト値を返す
  • 引数の型同士の加法を利用した合計の実装

異なる部分は

  • IntString それぞれのデフォルト値
  • IntString それぞれの加法の具体的な実装

です。

ここから List に内包される 合計という概念が適用できる型 の条件として 加算が定義できる型 であることが言えそうです。このような加算が定義できる型を Addable な型と呼ぶことにしましょう。そうすると、sum メソッドは Addable な性質を定義できる型の集合 を要素として持つ List を受け入れたいと言えます。

それができる すごいオーバーロード型クラス ということになります。

早速上記の仕様の型クラスでの実装をみてみましょう。

sum メソッドの型クラスでの実装

def sum[A](xs: List[A])(implicit addable: Addable[A]): A = xs match {
  case Nil => addable.unit
  case head :: tail => addable.add(head, sum(tail))
}

trait Addable[A] {
  val unit: A
  def add(x: A, y: A): A
}

implicit object AddableInt extends Addable[Int] {
  override val unit: Int = 0
  override def add(x: Int, y: Int): Int = x + y
}

implicit object AddableString extends Addable[String] {
  override val unit: String = ""
  override def add(x: String, y: String): String = x + y
}

sum(List(1, 2, 3))        // => 6
sum(List("a", "b", "c"))  // => "abc"
sum(List(true, false))    // Kaboom! Can't compile

Scala を知らない方は traitobjectimplicit 等の見慣れないキーワードが出てきてちょっと混乱するかもしれませんが、落ち着いてオーバーロードの実装と見比べてみると概形が見えてくるのではないかと思います。Scala の説明もしながら、順を追って見ていきます。

まず sum メソッドの実装を 1 ヶ所に集中するために、型パラメータ A を導入しました。

def sum[A](xs: List[A])(implicit addable: Addable[A]): A = xs match {
  case Nil => addable.unit
  case head :: tail => addable.add(head, sum(tail))
}

早速いくつか Scala 特有の記法があるため簡単に補足します。 def はメソッドを定義するキーワードで、def hoge(): Piyo のような形で使います。最後の Piyo が戻り値の型です。Scala ではメソッドのパラメータを複数の パラメータリスト として記述することができます。なので () が 2 つありますが、単に引数が並んでいるだけだと思ってもらって大丈夫です1。2 個目のパラメータリストにあるキーワード implicit は型クラスを実現する重要な機能で、オーバーロードと同様に 型情報を元にコンパイラが暗黙的に挿入すべき値を解決します。つまり、Addable[A] の型を見て自動的にその型に適合した addable が挿入されます。型によって実際に呼び出すメソッドが決まるオーバーロードそっくりですね。

ここで、あらためて sum の型 A に関する実装について、共通の部分と異なる部分を再確認してみます。

共通な部分は

  • リストの要素の たぐり方
  • リストが Nil だったときには型 A のデフォルト値を返す
  • A 同士の加法を利用した合計の実装

異なる部分は

  • A のデフォルト値
  • A の加法の実装

です。

sum[A](xs: List[A])(implicit addable: Addable[A]): A メソッドには共通の List のたぐり方が実装されています。対して型 A に共通の振る舞いが sum の次の Addable[A] に定義されています。

trait Addable[A] {
  val unit: A
  def add(x: A, y: A): A
}

trait というのは実装の持てる interface のようなものです。ここには見ての通り、ある型 A のデフォルト値が unit という変数で表され、加法が add(x: A, y: A): A というシグネチャで宣言されています。ここで宣言した Addable = 加算が定義できる 性質が、合計という概念を適用できる型の条件でした。

さて、ここまでで sum に共通な要素を記述することができました。ここからはオーバーロード同様に、合計という概念が適用できる型それぞれについて Addable の実装を与えていきましょう。

implicit object AddableInt extends Addable[Int] {
  override val unit: Int = 0
  override def add(x: Int, y: Int): Int = x + y
}

implicit object AddableString extends Addable[String] {
  override val unit: String = ""
  override def add(x: String, y: String): String = x + y
}

またしても implicit キーワードが出てきましたが、ここまでくればもう分かる通り、この implicitsum メソッドの引数における implicit とこの実装を紐付けるための目印になっています。オーバーロードでは、共通のメソッド名で異なる引数型であれば自動的にオーバーロードであることがコンパイラに伝わりますが、implicit を利用する場合にはコンパイラに明示的に教えてあげる必要があります。

object というのは シングルトンオブジェクト のことで、Scala では言語組み込みの仕様になっています。object は定義と同時に型の名前でアクセスできる static なクラスのようなものだと思ってください。このシングルトンオブジェクトで、IntString それぞれの型に固有の処理を実装として与えています。

さて、一通り眺めてきましたが、いまここを読んでいる方は上記のシングルトンオブジェクトの実装がオーバーロードのように見えてきているのではないでしょうか?もう一度、実際に並べて比べてみます。

オーバーロードと型クラスの比較

オーバーロード

def sum(xs: List[Int]): Int = xs match {
  case Nil => 0
  case head :: tail => head + sum(tail)
}

def sum(xs: List[String]): String = xs match {
  case Nil => ""
  case head :: tail => head + sum(tail)
}

型クラス

def sum[A](xs: List[A])(implicit addable: Addable[A]): A = xs match {
  case Nil => addable.unit
  case head :: tail => addable.add(head, sum(tail))
}

trait Addable[A] {
  val unit: A
  def add(x: A, y: A): A
}

implicit object AddableInt extends Addable[Int] {
  override val unit: Int = 0
  override def add(x: Int, y: Int): Int = x + y
}

implicit object AddableString extends Addable[String] {
  override val unit: String = ""
  override def add(x: String, y: String): String = x + y
}

型クラスのほうがちょっと実装が長くなってしまっていますが、オーバーロードの実装で問題の一つだった重複した実装が、ジェネリックsum メソッドによって一本化できています。

さらに、オーバーロードのもう一つの問題点だった拡張性についても、型クラスでは改善しています。今、合計という概念が適用できる型として Double を発見し、Double についても sum メソッドが利用したくなったとします。この時、sum の実装については手を加えずに、sum を拡張することができます。

implicit object AddableDouble extends Addable[Double] {
  override val unit: Double = 0.0
  override def add(x: Double, y: Double): Double = x + y
}

sum(List(1.0, 2.0, 3.0)) // => 6.0

さらにさらに、自作の有理数を扱う Rational クラスをつくったとしましょう。Rational クラスには Rational 同士を加算する add メソッドが定義されているとします。この時、sum の実装については手を加えずに

implicit object AddableRational extends Addable[Rational] {
  override val unit: Rational = Rational(0, 1)
  override def add(x: Rational, y: Rational): Rational = x.add(y)
}

sum(List(Rational(1, 2), Rational(1, 3), Rational(1, 4))) // => 13/12

気持ちよくなってきた。

というわけで型クラスを見てきましたが、もう型クラスについては怖くなくて、オーバーロードのようにすっかり手に馴染むようになってきたのではないでしょうか?

型クラスとは

ここで、型クラスの性質をまとめてみます。

  • あるジェネリックなメソッドが 受け入れられる型の集まり を型クラスの実装として明に列挙することで、それ以外の型では静的にコンパイルエラーにすることができる(型クラス制約)
  • 型クラス制約を与える型は既存の型でよく、既存の型を修正したり拡張したりせずに新たに振る舞いを追加できる
  • 型クラス制約を受ける型の振る舞いは共通だが、型ごとに実装は異なる
  • 既存の型クラスに適合させたい型が増えた場合には、その型クラスの実装を提供するだけでよい(たとえば sum メソッドに手を入れる必要がない)

これは前述のオーバーロードの満たす性質と近く、より抽象的な / 拡張に対して開いたものになっています。特に、ライブラリ実装者が型クラスを用いることで、利用者はライブラリによってなされた実装に対して手を加えることなくそれを拡張することができます。

実際、今回扱った sum メソッドでは DoubleRational といったすでに存在する一般の型について、sum メソッドだけでなく型そのものについても直接変更を加えず、後付で Addable な性質を実装することができました。

これらが、型クラスが便利で、コードをより抽象的で整理されたものにしてくれるといわれる所以ではないかと思います。

そもそも実は、型クラスという仕組み自体が この記事で名前の出せないあの言語 で一般性の高いアドホック多相 / オーバーロードを実現するための仕組みとして導入されました。これについては別記事で扱っていますが、型クラスがちょっとすごいオーバーロード というのは言い過ぎではないはずです。

型クラスがわかってきたところで、よくある 型クラスとインターフェースの違い について考えてみます。

型クラスとインターフェースとの違い

型クラスは、ある型に対するメソッドの存在を約束するという点でインターフェースと似ており、よく比較されています。実際、Scala の型クラスの実装でも trait Addable[A] のようなかたちで、trait による抽象化が行われていました。

では、インターフェース(トレイト)と型クラスではなにが違うのか、sumAddable の実装についてインターフェースを用いたサブタイプ多相による実装を考えてみます。

Addable[A] インターフェースを継承したクラスの値を扱う sum

trait Addable[A] {
  val value: A
  def add(x: Addable[A]): Addable[A]
}

class AddableInt(override val value: Int) extends Addable[Int] {
  override def add(x: Addable[Int]): Addable[Int] = new AddableInt(value + x.value)
}

def sum[T](xs: List[Addable[T]]): Addable[T] = xs match {
  case Nil => null
  case head :: Nil => head
  case head :: tail => head.add(sum(tail))
}

sum(List(1, 2, 3).map{ new AddableInt(_) }).value // => 6

渡された List が空の場合はデフォルト値が取得できないので null を返してしまったり、そういう設計のため addsum の引数・戻り型が A でなく Addable[A] になってしまっていたり、 List[Int] を包み直したりなかなか難儀な感じになってしまいましたが、ほぼ似たような実装ができています。が、型に紐づく処理を挿入するためだけにすべての値をインターフェースに適合した型にラップしており無駄が多いし素直じゃないですね。

Java だとこういうときは ストラテジーパターン が自然かもしれません。

AddStrategy[A] インターフェースをストラテジーとする sum

def sum[A](xs: List[A])(addStrategy: AddStrategy[A]): A = xs match {
  case Nil => addStrategy.unit
  case head :: tail => addStrategy.add(head, sum(tail))
}

trait AddStrategy[A] {
  val unit: A
  def add(x: A, y: A): A
}

object AddStrategyInt extends AddStrategy[Int] {
  override val unit: Int = 0
  override def add(x: Int, y: Int): Int = x + y
}

sum(List(1, 2, 3))(AddStrategyInt) // => 6

もうおわかりだと思いますが、これはほぼ完全に型クラスによる実装と同じです。implicit による自動挿入だけがない状態になっています。

インターフェース・サブタイピング、Scala でできないこと

インターフェースの実装でできていなこと、ひいては Scala でできないことは、結局のところジェネリックなメソッドの型パラメータ A からスタティックなメソッドが呼べないことです。(既存の型 A に対して unit 等の拡張ができないというのもありますが...2)

// これはできない
def sum[A](xs: List[A]): A = xs match {
  case Nil => A.unit
  case head :: tail => A.add(head, sum(tail))
}

Scala は pure な OOP を標榜しており、method は常にそれの所属するインスタンスを必要としますScalastatic キーワードがなく、実質的な static として機能するのがシングルトンオブジェクトである object であることからも、Scala がメソッドの呼び出しに常にインスタンスを必要とするオブジェクト指向を目指していることがわかります。

そこで、型に紐付いた static なメソッドを呼び出すためのプレースホルダimplicit object だったわけです。上記の A と下記の addable: Addable[A] が対応していることがわかるかと思います。

// 型クラスによる A の addable への置き換え
def sum[A](xs: List[A])(implicit addable: Addable[A]): A = xs match {
  case Nil => addable.unit
  case head :: tail => addable.add(head, sum(tail))
}

型クラスとインターフェースの違いまとめ

まとめると、インターフェースと型クラスは似ているようですが、そもそも目的の違うもので比べるものではない ということです。

インターフェースはそれを継承したものにその 実装を強制する仕組み です。この仕組自体は型クラスの実装でも用いられていました。

一方型クラスは、その約束された実装を 型情報に基づいて自動的に挿入する 仕組みでした。型クラスを実現するためには挿入する実装を約束するために、インターフェースが必要 でした。

型クラスとインターフェースは似たような性質を見かけ上持っているため比較されたりしていますが、そもそも対置して比較できるものではなく、むしろ型クラスがインターフェースに依存している、協調的な関係になっています。

インターフェースでの実装でも示した通り、インターフェース自体は様々な使い方ができ、ポイントだったのは 型に対する実装をデータ型と同じ場所に置くか、違う場所に置いて適宜挿入するか ということでした。

この、型に対する実装をインターフェースで約束して、データ型と違う場所に置いて自動的に挿入してくれる仕組みこそが型クラスの正体でした。

その点でも、型クラスが アドホック多相・オーバーロードのための仕組み = 型情報に基づいて自動的に実装を挿入する仕組み であるということが納得できるかと思います。

長々とやってきましたが、最後に型クラスを知っているとなにが嬉しいかを紹介して終わりにしようと思います。

おまけ - なぜ型クラスとインターフェースが混同されてしまったか

おそらく、型クラスの原点である Haskell において、型クラスがインターフェースの仕組みを暗黙に内包していることが原因ではないかと思います。

前述の通り、型クラスは仕組み上、実装の約束をするためのインターフェースを必ず必要とします。しかし、Haskellオブジェクト指向な言語ではないため、そもそもインターフェースというオブジェクト指向の仕組みを持ちませんでした。継承とかないですからね。

そのため、型クラス導入の際に、型クラスを実現するキーワード class が実質的にインターフェースの部分を担うことになりました。

このことが型クラスとインターフェースが混同されて議論される原因の一端ではないかと思っています。おまけおわり。

型クラスを理解すると嬉しいこと

型クラスを理解しているとなにが嬉しいでしょうか。個人的には、ライブラリやフレームワーク等の抽象的なコードを書く側でない限り 型クラスによる実装を書く機会はめったにない と思います。

では、型クラスの知識はムダなのかというとそんなことはありません。ライブラリを作成する際はもちろん、 ライブラリを利用する・コードを読む際にとても役立ちます

Scala のライブラリでは、標準ライブラリも含めて型クラスによる実装が様々なところに見つけられます。Scala のコレクションのように 高階型 を伴う実装や Json パーサー等の型によって異なる実装を挿入したい場合において型クラスは非常によく用いられているため、それらを利用する際に型クラスの知識があると シグネチャから実装の意図が容易に汲み取れます

たとえば、ScalaJson パーサーの 1 つである play-jsonJson.fromJson メソッドのシグネチャを見てみます。

def fromJson[T](json: JsValue)(implicit fjs: Reads[T]): JsResult[T]

型クラスの知識があると、ドキュメントがなくても Reads[T] 型の意図するところ、求められる実装がこのシグネチャからわかるのではないでしょうか?実際にこのメソッドを使うコードを示します。

case class Cat(name: String, age: Int)
object Cat {
  implicit val jsonReads: Reads[Cat] = Json.reads[Cat] // 型クラスの実装の提供
}

val json = Json.parse(
  """{
    "name" : "Tama",
    "age" : 4
  }"""
)

val cat = Json.fromJson[Cat](json)  // ここに implicit に jsonReads が渡されている
// --> val cat = Json.fromJson[Cat](json)(jsonReads) と同じ

Json.reads[Cat] は実はマクロで、Cat 型の実装から JsonCat 型にパースする Reads[Cat]インスタンスを生成してくれます。Cat 型に特殊化した実装を型クラスのインスタンスとして提供しているわけですね。

このように、ユーザー側で定義した型について、型クラスを利用することで型固有の処理をあとから利用者が差し込めるようになっています。型の定義場所にその型のパーサを implicit に提供することで、実際に Json をパースするところでは型に固有のパーサーを意識しなくて済むようになっています。

というわけで、型クラスを知っていると利用者としてもメリットが有ることがわかったかと思います。自分で積極的に使わなくても、コードを読む際に重宝するという点で、Scala におけるデザインパターンの一つとして捉えても差し支えないでしょう。

どうでしょうか?型クラスがどんなものか具体的に理解できたでしょうか。

本当に型クラスの指すものがこれであっているのか気になる、型クラスの定義自体を知りたい、という場合は型クラスの原点 How to make ad-hoc polymorphism less ad hoc を読んだ話も参照してみてください。

型クラス完全に理解した。

補足1 - sum メソッドと fold

今回の sum メソッドの実装は、デフォルト値と加算という処理を使って List の値を走査して単一の戻り値を作っていました。これについて、関数型と呼ばれる言語を扱ったことがある人は fold が思いついたのではないかと思います。まさに foldsum のようなリスト構造をたぐる処理の一般的表現になっています(より一般性があるのは foldLeft / foldRight ですがここでは簡単のため fold とします)。

def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1

Scala のコレクションの根幹になっている GenTraversableOnce[+A] にこの定義がありますが、これはデフォルト値 z と、 A1 型の 2 つの値を取って A1 型の値を返す関数オブジェクトを引数にとっており、それぞれが Addableunitadd に相当してることがわかると思います。fold を使って sum と同様の実装を与えてみます。

List(1, 2, 3).fold(0){ (acc, i) => acc + i }
List(1, 2, 3).fold(0){_ + _}
List(1, 2, 3).fold(AddableInt.unit){ AddableInt.add }

2 行目は省略記法で、1 行目と意味するところは同じです。fold では型クラスやオーバーロードよりさらに柔軟に、利用するその場で処理を記述できるようになっています。これは関数を一級市民として扱うことで、関数型という型 の宣言ができるようになり、それがインターフェースとして機能しているわかりやすい例だと思います。3 行目はわかりやすさのため、という名の悪ふざけです。

fold に対して型クラスが優れている点は、型に応じて自動的に処理が挿入される点ですが、概ねの場合はこういった関数オブジェクトを渡すことでなんとかなるのではないかと実は思っています。実際、ここで挿入される関数オブジェクトは List(1, 2, 3) から推論される型 Int により (Int, Int) => Int であることが静的に解決されるので、型的に安全になっています。

補足2 - Context bound な型クラス制約の書き方

Scala の型クラスについてはもうちょっとオシャレに書く方法が用意されています。Context bound というやつです。

def sum[A: Addable](xs: List[A]): A = xs match {
  case Nil => implicitly[Addable[A]].unit
  case head :: tail => implicitly[Addable[A]].add(head, sum(tail))
}

引数として渡されていた (implicit addable: Addable[A]) をなくして、implicitly[Addable[A]] というかたちで Addable[A] の実態を参照できるようになりました。おしゃれではあるのですが、見た目が直感的じゃないので賛否両論かもしれません。

参考

Martin Odersky. Poor man's Type Classes Philip Wadler. How to make ad-hoc polymorphism less ad hoc JSON automated mapping


  1. カリー化などで調べると説明があるかと思います

  2. implicit を用いた暗黙の型変換(Pimp my liblary パターンとも呼ばれるらしい)で既存型に対して拡張は可能ですが、わかりづらさ等の理由で最近はあまり推奨されていないようです。

Scala の implicit parameter のスコープと左辺値型推論で困った話

以下の記事は 2016 年 7 月 に Qiita に投稿した記事の移植です

pixivFANBOX にも投稿しています。ご支援頂ける場合はよろしくお願いいたします。

www.pixiv.net


Scala の特徴的言語仕様の一つであり、憎まれたり便利だったりする implicit の小ネタです。いろいろ検証過程を書いてるので、結論だけ知りたい人は最後を見てね。

便利な implicit parameter

implicit には何種類かあるのはご存知という前提で。implicit parameter 便利ですよね。

implicit val g = "Hello "

def hoge(name: String)(implicit greet: String) {
  println(greet + name)
}

hoge("Biacco") // 2番めのパラメタ群については implicit に渡される

ただ、この implicit が解決されるスコープと型推論が組み合わさるとややこしいことになるようです。

implicit parameter の解決スコープと型推論がうまく動かない例

今回ハマったのはこれ。

object Main extends App{
    import Hoge._
    val h = new Hoge
    h.hoge
}

class Hoge {
    def hoge(implicit s: String) { println(s) }
}

object Hoge {
    implicit val hs = "hoge!"
}

一見動きそう。でもコンパイルすると

error: could not find implicit value for parameter s: String

なるほどわからん

検証1: スコープを確認する

スコープに正しく入ってないのかな?と思って以下を試す。

object Main extends App{
    import Hoge._
    val h = new Hoge
    h.hoge(hs) // 明示的に hs を渡してみた
}

class Hoge {
    def hoge(implicit s: String) { println(s) }
}

object Hoge {
    implicit val hs = "hoge!"
}

動くんですよねこれが。コンパイル通ります。おっかしいな〜〜〜〜〜〜〜〜〜〜

検証2: ローカルスコープにおいてみる

というわけで、スコープに存在しないわけではないというのがわかった。じゃあ間違いなくアクセスできるということで試しにローカルスコープにおいてみる。

object Main extends App{
    import Hoge._
    
    implicit val hs = "hoge!"
    
    val h = new Hoge
    h.hoge
}

class Hoge {
    def hoge(implicit s: String) { println(s) }
}

object Hoge {
}

これもOK. この辺でかんべんしてくれという気持ちになり始める。

問題の定義: implicit な変数がスコープ内にいるにもかかわらず implicit parameter で解決されない

というわけで、現在の問題は

  • implicit な変数はスコープ内にいる
  • implicit parameter がそれを解決できない
  • implicit な変数はローカルスコープではなく import のスコープにいる

になります。一応 暗黙のパラメータ解決優先順位 なんかを見てみるものの、import した場合は Prefix なしの状態で参照できることとなっているが、 import Hoge._ しているのでそこも問題なさそうである。

解決法

まぁ、タイトルにもしているのでお気づきかと思いますが、この問題は implicit parameter と左辺値型推論が組み合わさると発生するようです。なので明示的に型注釈を与えてみます。

object Main extends App{
    import Hoge._
    
    val h = new Hoge
    h.hoge
}

class Hoge {
    def hoge(implicit s: String) { println(s) }
}

object Hoge {
    implicit val hs: String = "hoge!" // implicit な変数に型注釈をつける
}

と、コンパイルできるようになりました!出力もちゃんと hoge! になる。なんだったんだこれ...

解決した後に見つけたんですが OE さんがもう書いてた。死にたい。

Scala コミュニティでは定期的に話題になる問題のようです。きびしい。

コミケ C97 サークル「たのしい人生」のお知らせと今年の振り返りの話

この記事はキーボード Advent Calendar 2019、23 日目の記事です。

adventar.org

22 日目は ai03 さんの「海外コミュニティでの活動から学んだこと」でした。

docs.google.com

24 日目は foostan さんの「Let's Split Rebuild Log」です。

fstn.hateblo.jp

コミケ C97 告知

最初にコミケ告知です!サークルスペースは 4 日目 南ホール ラ13a です。クレジットカード決済対応予定です!

びあっこ @Biacco42

biacco42.booth.pm

KbD C96 August 2019 特集「遊舎工房インタビュー」「キーボードカスタマイズ最前線」

実店舗の遊舎工房成立の経緯とこれからを語っていただいたり、2019 年になって大幅に変わった自作キーボードのトレンド、カスタマイズの最新情報、そのなかでもアルチザンキーキャップワークショップ主催のお二人へのロングインタビューなど、2019 年の自作キーボードシーンを記録するコレクションとしてどうぞ。電子版もありますが、製本版に関しては在庫分で終了予定です。

既刊 KbD C95 も持っていく予定です。こっちも歴史やキーボードキットの情報の一覧など、資料性が強いかもしれない。

biacco42.booth.pm

せきごん @_gonnoc
I2C 接続可能なマウス IC 評価用モジュール。下の写真は作例。

f:id:biacco42:20191226013933j:plain
マウスIC評価用モジュール

f:id:biacco42:20191226014020j:plain
作例 (I2C 接続可能)

いつの間にかモジュール化されてましたすごい。

Kugel-1

booth.pm

言わずとしれた自作トラックボール付キーボードキット。

ゆーち @F_YUUCHI
Lily58 Lite

f:id:biacco42:20191226014755j:plain
Lily58 Lite

Columnar Staggered の定番 Lily58 の初心者向けに改良されたバージョン。組み立てやすくなっているとのこと。10,000 円予定。

というわけで、サークル「たのしい人生」はコミケ C97 4日目 (12/31) 南ラ13a でお待ちしています!

告知終わり。

今年の振り返り

ここからは、今年は目標としていたところと、期せずしてできたことがあったので、それらを軸に簡単に振り返ろうと思います。

目標:人を頼る・チーム作業をする・人と仕事をする

私はどうにも人を頼るのが苦手で、できることならスタンドプレーでやっていたいというタイプなのですが、歳を重ねるにつけていろいろと制約を感じたり、一人でいつまでやり続けられるのかという不安も出てきていました。

現職の仕事も 1 案件 1 エンジニアみたいなのが基本なので、ともかくチームでの作業やコミュニケーション、頼り頼られるみたいな人間的生き方からあまりにも離れすぎていたため、ちょっとまずいかな、と。こういう思考になるのは歳なんですかね。

ということで「人を頼る」「チーム作業をする」「人と仕事をする」というのをふんわり目標にしていました。目標というかほとんど焦燥感と言ってもいいかなと思います。

この観点・目標については今年はかなりがんばれたし、蒔いた種から収穫できたかなと思っていて、結構満足しています。具体的な話を 3 つほど。

ほぼ週刊キーボードニュース

実際には去年から種を蒔いていたほぼ週刊キーボードニュースですが、おかげさまで「ほぼ毎週」、 1 年間走り抜けることができました。

www.youtube.com

ともかく「人と協力し」「スケジュールを守りながら」「継続する」と、私の苦手なもの三段重ねの、今思えば随分攻めたプロジェクトでした。でも、兎にも角にもこれを実現してやりきれたのは、私を叱咤し諦めず一緒に創り上げてくれたぺかそ氏のおかげです。本当によく見捨てられなかったなと思います。

キーボードニュースに関しては、間違いなく私一人では絶対にこんなに良い結果にはならなかったし、そもそも継続も実現もできなかったと思うので、「人を頼って」「チーム作業をして」一人ではできないものづくりができたので、これは本当によかったなと思っています。

分業やマネジメントの仕方についても、二人で手探りながら少しずつ進めてこれました。ぺかそ氏が何事もプロフェッショナルなので、コミュニケーションも円滑で、チーム作業でありながらやりたいことなんかをサクサク実現できたりして、とても心地よい経験でした。チームとしてちょっと都合が良く回りすぎた (たぶんぺかそ氏が回してくれていた、が正確なのですが…) フシもあるので、来年はもうちょっと分業・マネジメントの仕組についても勉強・実践していきたいところです。

来月にはほぼ週刊キーボードニュースも放送開始 1 周年になります。まだまだやりたいことあるので、来年はもっとリスナーの方々とも関わりながら、楽しんでいただける放送を一緒に創り上げられたら幸いだなと思っています。

サークル「たのしい人生」

もうちょっとゆるい形で「人を頼る」ために、お声がけをさせてもらって、個人サークルだった「たのしい人生」が複数人の参加するサークルになりました。響きだけならめちゃめちゃリア充っぽい…。

上の告知でも書いたとおり、せきごんさん、ゆーちくんと 3 人で少しずつ活動させてもらっています。

ほぼ週刊キーボードニュースのように、1 つのものをガッツリ複数人で作る、というのはこれはこれで特殊スキルなので非常におもしろいんですが、やはりコミットの責任が伴います。なので、もうすこし軽く「人を頼る」ために、それぞれが作ったものを持ち寄るという形でのサークル活動をはじめてみました。

自作キーボード界隈では有名な「沼人の会」もそれぞれがそれぞれの成果物を持ち寄るという点で似ているのですが、いい意味で沼人の会は非常に進捗圧が高い空間のようなので、たのしい人生の方はもうちょっとほんわかした、自作キーボードの「きらら枠」になったらいいかなという感じで、おかげさまで非常に頼りまくってしまっています。

ともかく今まで、成果を出し続けること以外で人と関わることができない人間だったので (文字にするとひどすぎる)、今こうして見捨てられずに一緒にいてくれることに感謝しかないです。来年は少し自分も還元できるものを還元しつつ、まだまだ頼ってたのしいサークル活動ができれば…と目論んでいます。

ハロー、自作キーボードワールド

ここまでは「人に頼る」「チーム作業をする」など基本的には、協力する人間を作る、というテーマだったのですが、もう一つ、少し緊張感を足す目的で考えていたのが「人と仕事をする」でした。というわけで、つい先日始まった ITmedia さんでの連載「ハロー、自作キーボードワールド」です。

www.itmedia.co.jp

最近だと、連載とは別で新型 HHKB こと HHKB HYBRID のレビュー記事なんかも書かせていただきました。

www.itmedia.co.jp

これらは、明確に仕事として連載を請け負うということで、ある種の「契約という形での人との関わり方」「人と仕事をする」という目標がラッキーなことに実現させていただけたお話になります。締め切りや受け入れ品質のチェックなど、ある程度責任を負って、プロとして人となにかを作り上げる、という経験を今絶賛させていただいてます (編集井上さん、記事遅れていてすいません)。

上のような書き方だとちょっと敵対的に見えてしまうかもしれませんが、実際には編集の方に非常に支えられた状態で作業をさせていただいていて、いい人間・いい仕事をする方が社会にはちゃんといるんだ、と感動しています。

他にも蒔いてる種がちょっとだけあるのですが、それはもうすぐお披露目されると思うので、お楽しみということで。

というわけで、自分なりに目的意識を持って、人と関わる、人と一緒につくる、ということをやってきたつもりの 2019 年でした。とは言うものの、忙しかったり疲れたり、必ずしも常に気を配って過ごせていたわけではなかったのですが、結果としては「目的として意識してよかったな」と思える大満足な結果になったかと思います。

ただ、これはどれも関わってくれた、支えてくれた人たちのおかげで、当然一人で達成できるタイプの目標ではなかったので、迷惑をかけたことも多かったと思います。ですが、過度に自らを律しすぎず、「お互い様」精神で迷惑をかけることも、かけられることも自然と受け入れられるようになれたのなら、少しは成長できたのかな、と感じます。周りから見たら迷惑なおっさんが発生しただけにみえる…と今気づいてしまいましたが、そこは一旦目をつぶっておこうと思います。

できたこと・やれたこと

完全に期せずしてできたこと・やれたことといえば、ずっとコンプレックスだったお絵かきを始めることができました。

一端のオタクなので、やはり絵を描くということにはちょっとした神聖性を感じずにはいられないのですが、どうにもセンスが無いというか、人生で幾度となく挑戦しては挫折して、「自分には絵のセンスがないんだ」と自分を納得させてきました。ですがここ数年、ありがたいことに絵を描く友人・機会に恵まれ、「iPad Pro がお絵かきデバイスとしていいらしい」なんて話も重なって、昨年末から iPad Pro お絵かきマンとしてデビューしました。

挫折した、なんて言っていますが、今までどう描いていいかまったくもって見当もつかず、ほとんど手を動かすこともかなわないまま、ただちょっと描いては諦めていただけだったのですが、信頼できる友人に絵を見てもらい、レクチャーをしてもらうことできっかけを掴んで、絵を描き始めることができました。

なんだかんだ言ってこれも人の縁のおかげということで、なんだか今年は特別な年だったんだなぁ、と振り返ってみてひしひしと感じています。人脈が大事!という人間は信用できないですが、刺激を受けられるよい友人の存在は代えがたいですね。

ちゃんと仕上げたのは 6 枚ぐらいしかないんですが、自慢します。

f:id:biacco42:20191226032248p:plain:w420
びあっこちゃん

まともに描いた絵としてはこれが初です。ほぼ週刊キーボードニュースのリリース期限が迫っていた 1 月、必死で描いたのを覚えています。よく絵もかけないのに VTuber にいきなりなろうとしたなと、我ながら驚きます。

f:id:biacco42:20191226034045p:plain:w420
現場ぺかそちゃん

なんか突然描いてみたくて描いた。当時は本当に全然描き方がわからなくて、これ描くのに 4 時間ぐらいかけたんじゃないかと思います。アホでは?

落書き20190701www.pixiv.net

習作。このころから本格的に、神絵師に 囲んで棒で叩かれながら 優しく指導していただきながら練習をはじめました。これは好きな作家さん (ぎゃりん先生) の絵をトレース、模写練習をした後、手に感覚が残っているうちになぐり描きしたものです。当時は顔のパーツや輪郭などを完全に感覚というか何も理解せずに描いていたので、今見るとよく描けたなって感じがします。

びあっこちゃん 201908www.pixiv.net

「いや、びあっこちゃん描けよ」というあまりにもまっとうな指摘を受けて描きました。背景もちゃんと描いたえらい。まだこのころは骨格等の意識が曖昧だったはず。よく描けたな (2)。

立花先生が無限にかわいいwww.pixiv.net

ダンベル何キロ持てる?ブームで、同作品より立花先生。キーボード然り、愛はやっぱり原動力ですね。

健屋花那「それなー」www.pixiv.net

VTuber 事務所のにじさんじより、健屋花那。これはきちんと骨格等を意識して描きました。ポージングなんかも、骨格表現の練習としてつけたフシがあります。この絵はなんと健屋本人に使ってもらうことができました!生きていてよかった…

という感じで、今年は新しいこと、それも苦手意識を持っていた絵を描くことを始められました。絵を描く世界は過当競争で、とても自分がなにか意味のあることをできるとは思えないですし、「そんなことしてる時間でもっと価値のあることを…」という指摘も尤もなんですが、キーボードも絵も「自分が欲しい物」が市場にない以上自分で作るしかない、そして少なくとも絶対自分は得をするので、自分のためにやり続けようと思います。

まとめ

というわけで、後半は完全に自己満でしたが、振り返ってみると基本的に今年もキーボードを中心に生活が回っていたんだなぁ、という感じの 1 年でした。ずっと言及を避けていましたが、modulo! ほそぼそ試作開発を続けています!ちょっとどころじゃなく遅れていて申し訳ないですが、2020 年は modulo year にする (なる) ので、よろしくお願いします!

では、また来年。自作キーボードのたのしみが、より多くの方に広がって社会の総幸福が増えますように。

この記事は Ergo42 Towel (Gateron Silent Red Stock / Big Bang / Eucalyn 改配列) で書きました。 (7125文字 / 3 時間)

meishi2 keyboard ビルドガイド

meishi2 - The updated micro macro keyboard をご購入、もしくはリポジトリから製造いただきありがとうございます。この記事では、meishi2 keyboard の組み立て方を簡単に紹介します。

必要なパーツ

項目 数量
meishi2 PCB 1
Pro Micro 1
ダイオード(1N4148) 4
リセット用タクトスイッチ(5 mm ピッチ 2 本足) 1
クッションラバーシール 4
キースイッチ (Cherry MX 互換 / Kailh Choc) 4
キーキャップ 4

※キースイッチとキーキャップは別売りです

(オプション) 組み立てに必要・あると便利な道具

温度調節機能が便利(ない安物は温度が高すぎてはんだづけが難しいし基板焼いちゃいやすい)。加温も早くてよいです。

コテ台も安いのもあるんだけど、熱いものを扱うのでちゃんと固定できる・保護できるものがおすすめ。これはコテ先クリーナーもついていて、スポンジに水をつけるタイプと比べてもめちゃめちゃ扱いやすいので総合的にお得だと思います。

はんだ吸取り器があったほうがよい場合も多いんだけれど、自作キーボード、多分そんなにはんだをミスったりするような複雑な部分もないし、とりあえずはこれだけあれば十分。

バイスの余った脚を切るのに必要。

これぐらいあればこのキーボードを作る分には十分だと思います。

はんだづけ

はんだづけは、合金であるはんだ線を高温で溶かして、2 つの金属接点を電気的に接続して固定する方法です。はんだは接着剤ではなく、きちんと加熱して接点同士を合金として接合しないと正しく動作しないです。 というと難しそうですが、 はんだは温度が高い方に流れる という基本ルールさえ押さえれば基本は大丈夫です。

はんだづけする際は、上記の はんだは温度が高い方に流れる の原則に沿って、まずは繋ぎたいパッド (写真の丸い輪っか状の銀色の部分) と端子 (写真のコンスルーの金色の棒) をはんだごてのコテ先で加熱します。このとき、母材 (繋ぎたいパッドと端子) を温めるのが目的なので、まだはんだ線は 溶かしません 。3 ~ 5 秒程度、十分に母材を温めてから、はんだ線をコテ先につけてはんだを溶かして流します。この時、母材が十分に温まっていれば、自然とはんだが母材に吸い付くように流れます。富士山型になる程度、軽くはんだを流し込んだら、はんだ線を離し、その後にはんだごてを離します。

1. まず母材を温める

2. はんだ線をつけてはんだを流す

組み立て

基本的には、すべてのパーツを正しく配置して、はんだづけしてキーキャップ・脚シールをつけるだけです。はんだづけの基本は背の低いパーツから、なのでその順番で付けていきます。パーツはロゴマークがついている側につけていきます。

完成図

ダイオード

ダイオードの向き

ダイオードという部品は基本的には一方向にだけ電流を流す整流用に使われます。なので、どちらに電流を流すかという 向き の概念があります。この向きを間違えると正しく動作しません。

写真のダイオードの右側、黒い線が入っている側が カソード、逆に入っていない側が アノード といい、アノード側からカソード側に向けて電流が流れます。

キーボードに固定する際には、この黒線の入ったカソード側を、基板の白線のある側、四角いパッド側に向けてセットしてください。

ダイオードを差し込むときは、ダイオードの根元付近でリード (銀色の線の部分) を折り曲げて、スルーホール (銀色の穴) に通してください。通した後、軽くハの字型にリードを広げると固定されてはんだづけがしやすくなります。

タクトスイッチ

続いて、タクトスイッチをはんだづけします。タクトスイッチには向きがないので、スルーホールに通してはんだづけをするだけでオッケーです。

Pro Micro

Pro Micro の固定方向

上記写真のように、ロゴマークが入っている面を上にして、Pro Micro の USB 端子が基板の外に向くように設置します。

ピンヘッダの接続

通常のピンヘッダを用いてはんだづけで基板と接続する方法と、コンスルーと呼ばれる抜き差し可能なピンヘッダを用いて基板と接続する方法の 2 種類があります。付属するピンヘッダによってそれぞれ以下の章を参照してください。

通常のピンヘッダ

写真のように Pro Micro の部品実装面が上になるようにピンヘッダをはんだづけします。ピンヘッダをはんだづけする際は、基板にピンヘッダをテープ等で仮止めして作業すると Pro Micro に対してピンヘッダが斜めにならずに固定しやすいです。

裏面も同様にはんだづけします。

コンスル

コンスルーの固定方向

遊舎工房で販売されている meishi2 キットには、コンスルーという基板にはんだづけしなくても抜き差しが可能になるパーツが付属しています。 (Update) 2022 年現在コンスルーの入手が非常に困難になっており、コンスルーは付属しなくなっています。 コンスルーがある場合は Pro Micro にコンスルーをはんだづけします。コンスルーを Pro Micro の部品実装面と逆側になるようにはんだづけします。

コンスルーには向きがあり、金色の軸が側面から見える側 (窓側) が同じ向きになるように、また窓が端子に近い側を Pro Micro 側になるように揃えます。

キースイッチの固定

この基板は Cherry MX / Kailh Low Profile 両対応仕様です。3 pin 仕様のキースイッチ (固定用の脚が出ていないもの) だと多少の遊びがあり斜めにキーを固定できてしまいます。そのため、5 pin 仕様のキースイッチ、もしくは、はんだづけする際に、セロハンテープ等でスイッチの向きを固定してはんだづけすることをおすすめします。

5 pin 仕様のキースイッチ

完成状態

表面

裏面

ファームウェア書き込み

組み立てが完了したらファームウェアをビルドして書き込みます。meishi2 keyboard では QMK Firmware が利用できます。

QMK Firmware

ここでは詳細は省きつつ、ファームウェアをビルドしてインストールする手順と、キーマップの変更方法を「黒い画面」を使わない方法と、CUI で行う方法の 2 つで簡単に紹介します。

従来のファームウェアビルド・書き込み方法は後半の章に移動しました

2021/11/18 Remap のファームウェア書き込み機能とキーマップ書き換え機能に対応しました! Google Chrome 等の対応ブラウザでファームウェアの書き込み・キーマップの変更が可能です!🎉

Remap meishi2 カタログページ

meishi2 を PC に接続した状態で、Remap カタログページの FIRMWARE タブ → FLASHファームウェアを書き込むことが出来ます。

FLASH ボタンを押したあと書き込み方法のダイアログが表示されるので、Firmwaremeishi2_via for meishi2、Bootloader が caterina になっているのを確認して FLASH を押します。

FLASH を押すと Google Chrome 上で serial port を選ぶダイアログが表示されます。

そうしたら meishi2 のリセットボタンを押してください。

リセットボタンを押してブートローダーが書き込みモードになると Google Chrome の serial port ダイアログに Arduino Micro (やそれに類する名前) があるはずなのでそれを選択し Connect を押します。

書き込みが正常に完了したら、USB を抜き差しすると PC に meishi2 キーボードとして認識されます。

(2023 9/11 追記) Remap が QMK 0.22 系に対応し、0.18 系のキーマップ書き換え対応は https://qmk018.remap-keys.app になりました。現在 Remap にホストされている Ergo42 / meishi2 のファームウェアは 0.18 系なので、キーマップの書き換えは https://qmk018.remap-keys.app を利用してください。

近いうちに 0.22 系のファームウェアを Remap にアップロード予定です。

お疲れ様でした

ここまで来たらあなたも立派な自作キーボーダーです。おそらくここまでたどり着けたなら、他のより高度な自作キーボードについてももう自分で作ることができるようになっていると思います。

しかしここで触れた内容は自作キーボードのほんの一部に過ぎません。キーキャップやキースイッチにこだわるのも楽しいですし、QMK firmware にはここでは紹介しきれなかったたくさんの機能があります。ぜひ、このキーボードをそういった次のキーボード道の道標として利用していただければ幸いです。

ようこそ自作キーボード沼へ!

Help

組み立ての際に困ることやトラブル等あるかと思います。その際には Twitter@Biacco42 にリプライを飛ばしていただくか、Self Made Keyboard in Japan Discord server で相談していただければ対応します。特に Self Made Keyboard in Japan Discord server には私以外にも自作キーボードを製作している方がたくさんいるので、より多くのアドバイスを得られるかと思います。大変気楽なコミュニティですので、ぜひこちらの利用も検討してください。

おわり

従来のファームウェアビルド方法と書き換え方法は以下の章を参照してください。

従来のファームウェアビルド・書き込み方法

「黒い画面」を使わずにビルド・書き込み

なんと 2019 年にもなると、黒い画面を使わなくてもファームウェアをビルド・書き込みできるようになりました🎉

手順が、以下の動画で紹介されているので参考にしてみてください。動画中で Ergo42 としているところを meishi2 に読み替えるだけでオッケー (なはず) です。

また、サリチル酸さんの入門記事もまとまっていておすすめ です。


基礎からわかる!自キ入門講座 第12回「ファームウェアのカスタマイズ」

CUI でビルド・書き込み

QMK firmware documentation でデフォルトで紹介されている方法はこちらになります。CUI に慣れている人は、マクロ機能等自由な拡張ができる他、内部で何が起こっているかわかりやすくなるので、やってみるのも一興です。

ファームウェアの実装とビルドの詳細については QMK firmware documentation のドキュメントを参照してください。

環境構築

Git

まず Git が必要です。Windows / Mac / Linux 環境でそれぞれにインストール方法が異なるため、それぞれのプラットフォームの Git をインストールしてください。

Mac でかつ brew がインストールされていれば (brew についてはここでは説明しません)

$ brew install git

DebianLinux であれば

$ sudo apt install git

等でインストールできます。とりあえずファームウェアのビルドの目的だけであればこれで大丈夫です。

Git が準備できたら、ソースをダウンロードします。

ソースコードをダウンロードしたいディレクトリに移動して

$ git clone https://github.com/qmk/qmk_firmware.git

ソースコードを取得できます。

Build 環境

Mac / Linux の場合

QMK のプロジェクトルート配下の util/qmk_install.sh を実行することで、ビルドに必要な依存が解決されます。

$ ./util/qmk_install.sh

Linux の場合だと特権を要求されるので、

$ sudo ./util/qmk_install.sh

としてください。

Windows の場合

こちらの QMK-MSYSを使ってWindows上に最速でqmk環境を構築する を参照して環境構築をしてください。

ファームウェアのビルドと書き込み

組み立てた meishi2 キーボードを USB ケーブルで PC に接続しておいてください。

ビルド環境が構築できたら、ファームウェアをビルドします。

$ make biacco42/meishi2:default:avrdude

でビルドとインストールをいっぺんにできます。途中リセットしろよという旨のメッセージが出るので、そこでリセットボタンを 1 回または 2 回連続で押します(ブートローダーによって挙動が異なるようです)。リセットを検出すると自動的に書き込みが始まります。

Linux 環境の場合は書き込みに特権が必要かもしれないので、権限不足で書き込めなかった場合は

$ sudo make biacco42/meishi2:default:avrdude

としてください。

動作の確認

正常にファームウェアが書き込めたら、キーボードとして認識されて動作するはずです。default キーマップでは左から順に Ctrl-z Ctrl-x Ctrl-c Ctrl-v の配置になっています。動作が確認できたら meishi2 キーボードの完成です!お疲れ様でした。コピペがはかどりますね。

ファームウェアの改造

以上の工程でキーボードは完成しましたが、せっかくの自作キーボードですからコピペ以外にも使えるようにしたくなります。そのためにはファームウェアの改造が必要になります。その方法を簡単に紹介します。

meishi2 キーボードのキーマップを変更するには、キーマップが記述されている <QMK firmware root>/keyboards/biacco42/meishi2/keymaps/default/keymap.c を編集します。また、新たに名前をつけてキーマップを作成したい場合は default ディレクトリをコピーして適当に名前を変えて keymap.c を編集してください。その際ビルドコマンドは

$ make biacco42/meishi2:<your keymap directory name>

になります。

keymap.c で実際にキーマップが定義されているのは

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = KEYMAP( /* Base */
  LCTL(KC_Z),  LCTL(KC_X),  LCTL(KC_C), LCTL(KC_V) \
),
};

の部分、特に LCTL(KC_Z), LCTL(KC_X), LCTL(KC_C), LCTL(KC_V) の部分になります。これが左から順番にキーの割当を表しています。簡単ですね。

このキーマップに指定するキーの一覧については QMK firmware documentation の Keycodes Overview に一覧があります。初期状態だと、LCTL(KC_Z) のような形で、Ctrl と Z の同時押しを表現しています。 LCTL を外せば単なる Z キーになりますし、MEH(kc) とすれば Ctrl+Alt+Shift+kc が一発で入力できます。その他にもメディアキー(音量操作等)や電源キー(KC_SYSTEM_POWER)等の便利キー系もあるので、いろいろ試してみてください。

また、ここでは説明しませんが、マクロ機能もあり、あるキーが押されたら一定の複雑なキーコードや文字列を送信することもできます。5000 兆円欲しい!キーボードとか。

Maker Faire Tokyo 2019 に Self-Made Keyboards in Japan が出展します!

今年も Maker Faire Tokyo が 2019 8/3 ~ 8/4 に開催され、Self-Made Keyboards in Japan Discord 有志メンバーが今年も出展申し込みしています!

2018 年は自作キーボードが大きく羽ばたいた 1 年でしたが、2019 年、より裾野を広げ、多様性を増し、よりパワーアップした自作キーボードの世界を展示予定です。

f:id:biacco42:20190508020540j:plain

今後の展示当落情報・展示内容等はこの記事を随時更新して提供する予定です。おたのしみに!

f:id:biacco42:20181225003000j:plain

Amazon.co.jpアソシエイト