5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

自作エディタをつくるAdvent Calendar 2016

Day 13

コンソールで動くエディタを作る(13日目) キーバインドについて

Last updated at Posted at 2016-12-13

本稿は自作エディタをつくる Advent Calendar 2016の13日目です、レポジトリはこちら

文字を挿入後にカーソルを1つ後ろにずらす

12日目の積み残しです。ずらしました。

カーソル位置をチェックする

現状の動作だと、カーソルをマイナス3文字目とかに動かせてしまうので、簡単にセグフォが起こせてしまいます。
12日目の保持しているカーソルの位置と、実際のカーソル位置がズレたほうが使いやすそう問題は、後で考えることにして
いったんセグフォが起きない位置にしかカーソルを動かせないようにします。

ちょっと困ったのはunsigned intの挙動です。

unsigned int x = 0; x--;は、コンパイルが通るし、これだけではランタイムエラーにならないです。

unsigned int x = 0; x--;if(x<0) {x=0;}は、コンパイルで怒られます。

エラー内容はcomparison of unsigned expression < 0 is always false 0未満にはならないよ、ですかね。

ちょっと著者がunsignedに求めていたものと違うのですが、言われるとそうだよねって感じです。

今回はカーソル位置はたまたま1始まりなのでx<1にしましたが、設計時点で色々考えればよかった気がします。

教訓として、unsignedを使う時はエラーケースをどこにしまうか考えてからにしよう!って思いました。

余談として、charをunsignedにするとprintfのときは便利ですが、signedのほうがstrcpy等が使いやすいので、指定してあればどちらでも良いのかもしれません。

全体的に、ちょっと型に理解が浅かったですね。

話を元に戻して、カーソル位置について

  • 行の先頭より左に行けなくする
  • ファイルの先頭より上に行けなくする

は自明ですが、

  • 行の末尾より右に行けなくする

は12日目の保持しているカーソルの位置と、実際のカーソル位置がズレたほうが使いやすそう問題があります

  • ファイルの末尾より下に行けなくする

は、その通りでもいいし、空行を追加して下に行けるようにしてほしい派もいる気がします。

けっこうカーソル移動は奥が深いですね。好みの問題の気がするので、とりあえず実装が楽な方に倒します。

これでセグフォは起きなくなりました。

制御文字を入力する(十字キー)

9日目の十字キーの謎より、十字キー文字コードは分かっているため(mac+bash環境調べ)

up    = 0x1B,0x5B,0x41
down  = 0x1B,0x5B,0x42
right = 0x1B,0x5B,0x43
left  = 0x1B,0x5B,0x44

こんな感じで0x1B、0x5Bを特殊な状態として扱うことで、十字キーを入力できるようにしました。

snipet.c
if(key[0] == 0x1B && flag == NOT_CTRL) {
  flag = ALLOW_1;
} else if (key[0] == 0x5B && flag == ALLOW_1) {
  flag = ALLOW_2;
} else if (flag == ALLOW_2) {
  if(key[0] == 0x41) cmd.command_key = UP;
  if(key[0] == 0x42) cmd.command_key = DOWN;
  if(key[0] == 0x43) cmd.command_key = RIGHT;
  if(key[0] == 0x44) cmd.command_key = LEFT;
  flag = NOT_CTRL;
} else {
  flag = NOT_CTRL;
  cmd.command_key = INSERT;
}

無事に動作したので、u/d/l/rキーの割り当ては無くします。
終了は、後述するCtrl+Qにしました。

制御文字を入力する(それ以外のキー)

ついでに、削除キー等の文字コードもprintfで調べます。
コメントは、どういう操作を割り当てたいかの希望です。

Backspace = 0x7F //文字削除
Esc = 0x1B //終了
Alt + LEFT = 0x1B,0x62 //行先頭へ
Alt + RIGHT = 0x1B,0x66 //行末尾へ
Alt + S = 0xC3 // 保存
Alt + Q = 0xC5 // 終了
Ctrl + S = 0x13 // 保存
Ctrl + Q = 0x11 // 終了
Shift + LEFT = 0x1B,0x5B,0x31,0x3B,0x32,0x44 //範囲選択
Shift + RIGHT = 0x1B,0x5B,0x31,0x3B,0x32,0x44 //範囲選択
Shift + UP / DOWN = 判別不能(Shiftを押さない時と同じ文字コードになる)
ALT + UP / DOWN = 判別不能(Shiftを押さない時と同じ文字コードになる)
Ctrl + 十字キー = 測定不能(Macのスクリーン移動に操作を取られる)
Cmd + 各種キー = 測定不能(Macの固有機能に操作を取られる)

後半の測定不能は、3日目の懸念事項だったものですが、Ctrl+十字キーも無理だとは・・・。
ちょっとショックです。

Escキーって、0x1Bなんですね。

後続に文字が来るかどうかは、現状の実装(getchar)だとわからないので、
十字キー(例:上キーは0x1B,0x5B,0x41)の先頭の0x1Bか、Escキーかはその時点で判断できません。
今の所困らないですが、Escキー単押しに機能を割り振るのは難しそうです。

先人(vi/emacs)の知恵を知る

そもそも、Alt+SはMacだとßを打つためのキーバインドなので、奪って機能を割り振ってしまうとßを打ちたい人が困ります。
じゃあCmdキーは・・・、となるとMac固有の機能と衝突するため割り振れません。
となると、Ctrl+何かEsc押した後に何か、あたりが候補に挙がって・・・(๑•̀ㅁ•́๑)✧ ハッ!

まるで vi / emacs のキーバインドですね。(nanoもですね。)
あの変則的なキーバインドに不満を感じたのがエディタを作る動機の1つだったのですが、
どうやら似たキーバインドにたどり着きそうです。なるほど、こういう理由から、キーバインドが生まれたのですかね。

自分のエディタに対して、先人の知恵をなぞるか、新たな形を模索するか考えた方が良さそうです。
ctrl+十字キーさえ打てれば、ctrlで揃えるのもありかなと思ったのですが、ちょっと考えます。

今日のまとめ

  • カーソル位置をチェックするようにしました
  • vi/emacs/nanoの工夫を垣間見ました

長くなってきたので、文字を削除するは明日に回します。

vi/emacsの変則的なキーバインドに不満を感じたのがエディタを作る動機の1つだったのですが、
どうやら似たキーバインドにたどり着きそうです

釈迦の掌の上で回ってる気分ですね・・・。なるほどなぁ。

前回分のコメント(自動テストに関して)ありがとうございます。
まだ参照先を読みきれてないですが、単体テストはそろそろ入れないとつらいところ。

5
2
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?