プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

プログラマのためのVerilog入門

 ここのところしばらくVerilogをやっていました。というわけで、まとめていこうと思います。

 といっても、基本的な文法の話はしません。プログラミングをこれまで基本としてやってた人が、ハードウェア記述言語を触るときに気をつけなくてはならないことを中心に記載していこうと思います。(というか、記事書けるほど文法詳しくない。)


記事の内容:



メインは最後の状態変数の話です。では興味のある方はどうぞ。



論理合成可能なVerilogとテストベンチのVerilogは違う

 C++開発でテストするなら、Assert文やCppUnitTestとかあたりを使いますかね。JavaならJUnitとか使いますよね。C++で開発したものをC++でテストする。Javaで開発したものをJavaでテストするということは特に違和感ないかとおもいます。

 Verilogでも同様で、Verilogで開発した論理合成可能な記述を、Verilogでテストします。

 我々ソフト畑の人間からすれば、C++,Javaで開発したものとテストコードにおいて、その文法的な書き方に区別はつけてないとおもいます。
(テストコードは開発コードに比べて雑とか、利用してるテストライブラリに併せて若干変則的な書き方をするなどの変化はあるでしょうが。)

 が、Verilogの場合、「論理合成可能」、つまり回路に変換可能という縛りが開発コードにはある一方、テストベンチ用の検証コードはその縛りがないので、文法レベルの書き方が増加します。まずはそのことを理解しておきましょう。


regとwireとlogicと

 Verilogが糞だなと思う理由の一つが「reg」「wire」「logic」という型の存在。方々でも言われておりますが、regとwireという型は単にシミュレータの実装上のもので、物理的な意味(配線型、メモリ型など)はありません

 たぶんですが、最初に論理回路シミュレータを作った人が、そういう二つの構造体を定義してデータ管理する実装をしたんでしょう。こんなイメージ↓の実装だったのではないかと。

typedef struct{
  char*  value;
  size_t size;
}wire;

typedef struct{
  char* current_value;
  char* next_value;
  size_t size;
}reg;

wire* wire_list;
reg*  reg_list;

void update()
{
  //always等のプログラム的な処理の実行
  calcReg();
  //assignの一発で決まる処理の実行
  calcWire();
  // regのnext_valueをcurrent_valueに代入
  updateReg();
}




 で、作ったシミュレータを動かすための文法作るときに、二つの構造体のどっちに割り振るべきか判断する処理を考えるのが面倒くさかったのでしょう。もしくは単に、C言語では型を書かないといけないので、何も考えずに癖でそれを持ってきただけかもしれません。あぁ、なんかこう考えると、親近感がすごくわいてきませんか?私はとても親近感がわきました。

 ということで、我々プログラム畑の人間からすれば、この背景を理解さえしていればregとwireに関しては、さほど躓いたり不思議に思うことはないと思います。単にシミュレーターというライブラリが宣言している構造体を宣言しているだけですから。



 で、文法上も分けてる理由がないとようやくSystemVerilogでregとwireがlogicという型でまとめられたわけです。





 これは単なる文句なんですが、もうこのlogicを作ろうという判断がまた糞ナンセンスですよね。logicとかいう型を作った人は「あくまでVerilogはシミュレータ用言語である」としか考えてないんじゃないでしょうか。だったらまだregとwireの方が愛嬌があります。

 作るべきだった型は「logic」ではなく、フリップフロップ型、ラッチ型、組み合わせ回路型などの物理型と検証型(今のlogic型)に分けるべきだと思います。なんか申し訳程度に「always_ff」と「always_comb」がありますが、なんで型じゃなくて記述方法で制限しようとすっかね?


 むろん、論理合成時の最適化や、エンジニアのコードの書き方が悪くて実際にフリップフロップに変換することができないとか、回路上にラッチができる可能性があるから型で制限しにくい!という意見もあるかもしれない。けど、それこそエンジニアの意向と異なるわけだからWarning、Error事項だよね?もし、最適化の結果それらが許される、とエンジニアが判断するなら、それ用の型に変更する(もしくはアノテーション的なものの付加で良いかもしれない)べきです。






状態遷移の考え方を変数中心にする

 特に最近はclojureやらなんやらイミュータブルな実装が流行で、私に限らず、「変」数ではなく、引数など「定」数でプログラムすることが多くなっていると思います。むろん、変数の値で状態遷移するプログラミングを全くしないわけじゃないですけど。

 しかし、Verilogを書く際には全く逆で、変数を中心に状態遷移するようにしないと、綺麗な実装ができません。しかもその状態遷移は、普段我々が全く意識していないレベルの状態遷移ですら、変数中心で状態遷移させる必要があります。一度理解すればなんてことはないんですが、私はこの発想が最初なかったんですよね。

 

 「処理A,Bをしたあと、処理Cをし、前の結果が真なら処理Dを、偽なら処理Eをする。」という内容を考えましょう。

 状態遷移はこうなっていますよね。


f:id:nodamushi:20160625022550p:plain



 まぁ、ここまでは特に問題ありません。言われりゃその通りだ。

 さて、ここで問題になるのは、AからB、BからCへのε遷移は実際に誰が遷移させるのかと言うことです。

 たとえば我々プログラマはこう書きますよね。

void main()
{
  A();
  B();
  if(C())
    D();
  else
    E();
}


 このとき、A(),B(),if(C())への遷移という概念はおそらく考えていないと思います。なぜなら、プログラムは上から下に実行されるものだからです。一方CからD,Eは、遷移を意識していると思います。(それが状態遷移と思っていなくても、分岐という形で意識していると思います。)

 この上から下に実行されるという時間の概念がε遷移の正体になります。


 しかし、Verilog(論理回路)ではこの上から下へと言う時間の概念を使うことはできないのです。

 むろん、回路Aの信号を回路Bに伝え、回路Bの信号を回路Cに伝え………っていうような逐次処理ができるなら、単に組み合わせ回路で表現できます。ですが、この間メモリ(フリップフロップ)の更新はできません。だって組み合わせ回路だから。

 途中、メモリの更新をどうしても挟まなくてはならない場合、クロックの単位で処理する回路を区切ることになります。あぁ、残念ながらこの時点で、上から下へという時間の概念がぶった切られました。なぜなら、それぞれの区切られた回路は並列に動くからです。

 従って、どの回路が有効なのかを決定する状態変数を管理する必要があります。擬似コードとしてはこんな感じでしょう。

int state;
void main()
{
  while(state!=5)//5で終了とする
  {
    // A,B,C,D,Eの関数それぞれが実際には一つ一つの回路になる
    // stateの値で有効な回路を選択する
    // C言語ライクに書くとA~Eのどれか一つしか起動しないが、実際には全部同時に並列実行されます。
    switch(state)
    {
      case 0:   A();   break;
      case 1:   B();   break;
      case 2:   C();   break;
      case 3:   D();   break;
      case 4:   E();   break;
    }
  }
}

 ん~、だいぶ普通のプログラミングから離れてきましたが、まだこれくらいは書くことあります。ユーザーからの入力による状態遷移が複雑すぎる場合は、こうやって管理すると見通しがよくなったりします。昔作ったTeXの処理系の中心部分はこんな設計でした。

 ところで、stateはだれが変更するんでしょうかね?

 いや、そりゃま、こうでしょ?と私が最初に普通に考えたものは以下のような内容でした。

int state;
//実際には各回路(関数)はそれぞれの処理をしますが、
//めんどうなので今はstate以外は省略しています。
void A(){state = 1;}
void B(){state = 2;}
void C(){state = 何らかの条件 ? 3 : 4;}
void D(){state = 5;}
void E(){state = 5;}

 オブジェクトではありませんが、Stateパターンの考え方を持ち込んでいますね。残念ながら、これを回路としては作れないんですよね。一つのフリップフロップに、5つの回路からの入力がある記述になっています。例えるなら、一つのUSB端子に複数のUSBデバイスを挿せないのと同じです。

 複数のUSBデバイスを挿せないなら、ハブを挟めば良いじゃない。というわけで、私が次に考えたのがこうです。

int state;
int state_a,state_b,state_c,state_d,state_e;
void state_update() //毎クロック勝手に動く
{
  state = state == 0? state_a://状態A
          state == 1? state_b://状態B
          state == 2? state_c://状態C
          state == 3? state_d://状態D
                      state_e;//状態E
}
void A(){state_a = 1;}
void B(){state_b = 2;}
void C(){state_c = 何らかの条件 ? 3 : 4;}
void D(){state_d = 5;}
void E(){state_e = 5;}

 あくまで間違いを選択する程度の能力。もちろん、これ動くんすよ。各変数を更新する回路(関数)は一つしかないので問題ありません。が、決してスマートではありません。

 さて、なぜ私があくまで間違い続けるのか?それは、各関数間の遷移、特に「CからD,Eへの遷移の責任が関数Cの戻り値にある」という発想から抜けられなかったからです。あと、こうしておくと、特定の関数からの状態遷移を後から変えるのが楽ですよね?


 ここで一気に、状態遷移に関して各関数が主体の構成から、状態変数が主体の構成に切り替えるパラダイムシフトが必要になります。つまりこうです。

int state;
int c_value;
void state_update() //毎クロック勝手に動く
{
  state += state==3||(state == 2 & c_value) ? 2: 1;// CからEに移動する場合とDでは2を加算
}
void A(){}
void B(){}
//* c_valueはCからD,Eどちらに移動するのかの条件となる値。
//  組み合わせ回路で出力します
void C(){c_value = 何らかの条件 ? 0: 1;}
void D(){}
void E(){}

 このように基本的には各関数状態変数の更新には何も関与せず、state_updateが常に全ての状態遷移の管理をします。

 まれにCの様に遷移条件を組み合わせ回路で出す奴もいますが、あくまで遷移条件だけです。遷移状態をはき出したりしません。


 このようにstate_updateが全て受け持つことで、構造が単純化されます。この例ではどの信号(変数)を選択するかを決めてたセレクタがなくなり、単純な加算機一つになりました。state ==3 || (state ==2 & cvalue)?の部分がセレクタに見えますが、その後ろにあるのは定数なので、ただの論理式です。

 まぁ、一方で、状態遷移の変更要求にたいする柔軟性は若干失われますが。(仕様変更で一つの状態遷移を追加するために、下手すると全部変更する羽目になったりする。たとえば上の例でAとBの間にXを挟んでくれという仕様が来たら………?Xを1とし、B以降の状態値を1増やすのか、それともA:0→X:5→B:1という遷移条件を増やすのか………)


 状態遷移………なかなか味わい深いですね。こんな本を買って今積んでいるところです。みなさんも興味があったら是非。

組込みエンジニアのための状態遷移設計手法―現場で使える状態遷移図・状態遷移表の記述テクニック― (MBD Lab Series)

組込みエンジニアのための状態遷移設計手法―現場で使える状態遷移図・状態遷移表の記述テクニック― (MBD Lab Series)

Firefox44.0で拡大時にIMEのポップアップ位置がずれる

自動でFirefox44.0に更新されたところ、以下のように、拡大しているときのテキストエリア入力でIMEのポップアップ位置がずれるという現象が発生しました。

Firefox47で修正されたことを確認しました。



環境依存のバグかはわかりませんが、プロファイルを作り直して、新しいプロファイルで実行しても同様に発生したので、アドオンが原因ではなさそうです。

(私が利用しているIMEはATOKです。32bit版、64bit版同様に発生しました。)

非拡大時にはこの現象は起こらないので、拡大時のIME表示位置計算が何かミスっているんだと思います。

f:id:nodamushi:20160129005153j:plain


Firefox43.0.4に戻したところ、この現象は消えたので、もし、同様の現象が発生し、困っている方がおられましたら、直るまでは前バージョンに戻しておくと良いと思います。(自動更新を切ることも忘れずに)

Firefox43.0.4(Win32)

Firefox43.0.4(Win64)


f:id:nodamushi:20160129005152p:plain


拡大機能なんてあまり誰も使わないのかねぇ?
目が悪い私は拡大しまくってるんだけど。



ところで、Firefoxの悪手のせいでKeysnailの寿命が近いという話は本当なんですかね……?


追記

会社のPCでも試したところ同様の現象が発生することを確認しました。

会社のIMEはマイクロソフト純正です

MarkdownビューワーをJavaFXで作ってみた

 Markdownを書くのに一番いい方法って何なんでしょうね?
 私はEclipse + GMF viewerを主に使っていたんですけど、このGMF viewerってディレクトリにhtmlファイル出力しちゃうのがすっごい気にくわないんだよねぇ。
 かといって、Firefoxとかでやるとしても、たとえKeySnailを入れてるとしても、EclipseとかEmacsのテキスト編集機能にはさすがにかなわないのよね。



 で、GitBucket作者のたけぞうさんがGitBucket用のMarkdownプロセッサ(markedj)をJava作って公開したという記事を見つけた。

 ほう、Javaとな。

 しかも、会社のGitサーバーに入れたのはGitBucketなので、私の利用環境との相性も良いじゃん。

 よし、markedjのビューワー作るか!JavaFXで!

というわけで、できた

以下からダウンロードできます。
Java8u40以上のJavaにちゃんとパス通ってればmarkedjviewer.jarをダブルクリックで起動するはず。
なお、Windows以外で動くかはわからんっ。前に作ったJarファイルの位置の検索がちょっとトリッキーなことしてるので、テストしたWindows以外で動くか謎。
markedjviewer


f:id:nodamushi:20151108202326p:plain

ソースコードはこちら
Git repository




使い方

 まぁ、ぶっちゃけほとんど機能なんてないので、説明するようなこともないんですが。。。

 起動するとこんな感じの画面です。
f:id:nodamushi:20151108204635p:plain

 上のバーのファイルボタンからMarkdownを開くなり、ドラッグアンドドロップをするなりで開くことができます。

 開いたら、………あとはスクロールするぐらいしか操作することはないですけどね。

 一応、現在の表示内容のHTMLを保存する機能(Ctrl+S)、画像等の変更を反映させるためのリロード(F5かCtrl+R)があります。
 メニューバーにあるコンフィグ(歯車のボタン)機能は張りぼてです。GUI作るのが面倒くさくなりました。




Emacsと組み合わせる

 このビューワーはMarkdownファイルを監視しているので、ファイル内容が変更されると、自動的に表示を更新してくれます
 本当は画像ファイルとかも監視したかったんだけど、WebViewが今何開いてるのかどうやって取得するのかわからなかった。まぁ、今後の課題と言うことで。

 さて、Emacsにはauto-save-buffers-enhanced.elという、ファイルを編集したら、自動的に保存を行ってくれる便利なプラグインがあります。


 ファイル更新監視 + 自動保存………もう、私が言いたいことはもうおわかりですね?
 つまり、Emacs+auto-save-buffers-enhanced.el+markedjviewerで結果を即座に確認しながら、書くことができるわけです!

 んほおおおおお、きもちいいいいのぉおおおおおお!!!

f:id:nodamushi:20151108202925p:plain

 あ、そうそう、表示領域を広くするために、ウィンドウがフォーカス持っていない場合はツールバーが消えるという地味な機能がついています。(上の画像ではビューワーにフォーカスがないので、黒いツールバーが表示されていない)




 というわけで、私にとっては結構便利なものがなんかできました。
 これで快適なMarkdown生活が送れます。



 

Javaでコマンドラインから受け取った引数処理するクラス作ってみた

 コマンドラインから受け取った引数を簡単に処理したいという話。
 
 結論から言えば、すでに作られているライブラリ使うといいよ!!!
 参考:Javaでコマンドライン引数を処理する


 
 まぁ~、車輪の再々再発明なんだけど、MITライセンスのライセンスすら嫌じゃん。URLとか、ライセンス書かないといけないし。ぶっちぇけここしか外部ライブラリ使ってないし、そのためにいちいちライブラリ情報書くのもなー。
 というわけで、著作権放棄のライセンス(CC0 1.0 Universal)で作ってみた。よっぽどライセンスが緩すぎるものしか使いたくねぇ!って人は選択肢になるかもしれないよ。


 nodamushi/NArguments · GitHub

 Java6対象。(ワークステーションのLinuxがJava6だったのよっ。)
 ただし、Pathを使ってるから、コンパイルするときは、JDK7以上にするか、Path関連全部削除するか。

 基本的な思想はたぶん、arg4jと同じ。(使ったことないけど)
 簡単な使い方はDemo.javaを見ればわかるかなーってくらい、単純。ドキュメントなんていらない。
 私しか使わねぇから、ドキュメントも用意するの面倒くさいとか、そういう理由では断じてない。私は嘘はつかないっ(`・д´・ )



public static void main(String[] args){
    final NArgument<Args> nArgument = new NArgument<Args>(new Args());
    nArgument.setIgnoreConvertException(false);
    try {
      nArgument.addArguments(args);
    } catch (final ConvertException e) {
      System.out.println("Parse error:"+e.getMessage());
      System.out.println(nArgument.getDescription());
      return;
    } catch (final ReflectionException e) {
      e.printStackTrace();
      return;
    }

    final Args a = nArgument.get();
    System.out.println(a);
    if(a.help){
      System.out.println();
      System.out.println(nArgument.getDescription());
    }

  }


 Argsってのは、自分で定義するデータ格納クラスです。こんな(↓)感じで定義。
 使える型はString以外に、intなどのprimitiveと、Path,File,Charsetが使えます。
 Argumentsで正規表現で受け取る受けとらないを選択できるのが地味に便利かなぁと思っています。


@Description(
    "demo arguments.\n"
    + "[-a String]* [(-b|--bbb|--bbbb)] [-c] [-d] [(-e|--encoding) File Encoding] "
    + "[-i Integer] [(-h|--help)] [-n Number] [InputFiles]+")
class Args{
  @Option(value="-a",description="multi string option")
  private List<String> strs;

  @Option(value="-b",alias={"--bbb","--bbbb"},description="flag option")
  private boolean flagB;

  @Option("-c")
  private boolean flagC;

  @Option("-d")
  private boolean flagD;

  @Option(value="-e",alias="--encoding",description="text file charset")
  private Charset charset;

  @Option(value="-i")
  private String integer;
  //setterがある場合はsetterを優先的に使う。たとえprivateであっても。
  //従って、integerはStringであるが、setterがintになっているので、int型のOptionと判定される
  private void setInteger(final int i){
    integer = "input integer value is '"+String.valueOf(i)+"'";
  }

  //@Optionはmethodにも付加可能
  public boolean help;
  @Option(value="-h",alias="--help",description="show this help")
  private void setHelp(final boolean b){
    help = b;
  }

  @Option("-n")
  private double number;

  @Arguments(match="\\.txt$")
  private List<Path> inputTextFiles;

  @Arguments
  private List<File> inputFiles;


  @Override
  public String toString(){
    final StringBuilder sb=new StringBuilder();
    sb.append("Options\n");
    sb.append("-a = ").append(strs).append("\n");
    sb.append("-b = ").append(flagB).append("\n");
    sb.append("-c = ").append(flagC).append("\n");
    sb.append("-d = ").append(flagD).append("\n");
    sb.append("-e = ").append(charset).append("\n");
    sb.append("-i = ").append(integer).append("\n");
    sb.append("-h = ").append(help).append("\n");
    sb.append("-n = ").append(number).append("\n\n");
    sb.append("Arguments\n");
    sb.append("text files = ").append(inputTextFiles).append("\n");
    sb.append("else files = ").append(inputFiles);
    return sb.toString();
  }
}


 Demo.javaに次のような引数を与えて実行するとこんな感じになる。

-a a1 -a a2 -a a3 --bbb -cd --encoding shift-jis -i 200 --help -n 20.1 test/test1.txt img/img.jpg test/test2.txt

f:id:nodamushi:20151103211142p:plain

Options
-a = [a1, a2, a3]
-b = true
-c = true
-d = true
-e = Shift_JIS
-i = input integer value is '200'
-h = true
-n = 20.1

Arguments
text files = [test\test1.txt, test\test2.txt]
else files = [img\img.jpg]

demo arguments.
[-a String]* [(-b|--bbb|--bbbb)] [-c] [-d] [(-e|--encoding) File Encoding] [-i Integer] [(-h|--help)] [-n Number] [InputFiles]+

   Options:
      -a        :multi string option

      -b
      --bbb
      --bbbb    :flag option

      -c        :

      -d        :

      -e
      --encoding:text file charset

      -h
      --help    :show this help

      -i        :

      -n        :

WindowsでもEmacsをDaemonのように使いたい

 Windowsで何のエディタ使っていますか?私はなぜか結局Emacsです。


 ところで、WindowsのEmacsはdaemonフラグが有効ではありません。
 server使えば似たようなことできるからいいといえばいいのですが、サーバー用のウィンドウが邪魔くさいです。
 最小化してもタスクバーに残るしね。HideItとか使ってみたことあるけど、自分でウィンドウ隠すという作業が面倒くさい。あと、タスクバーにいなくなっても、タスクトレイに存在するのが希に気になる。タスクトレイ実行ツールも試したけど、駄目だった。仮想デスクトップ作って見えないように押し込んだりとかいろいろ試したけど、あぁ、Daemonがほしい。


 というわけで、WindowsでもEmacsをDaemon化したいなーとかずっと思ってたので、ふと何を思ったのか似たような動作になるようにPowerShellでやってみました。

 方法としては

  1. emacs.exeを実行
  2. しばらく待機してから
  3. ウィンドウを非表示にする

ってだけ。まぁ、要するに今までHideItとかタスクトレイ実行ツールや仮想デスクトップに頼ってたのを自分で書いただけですね。とりあえず、自動でウィンドウが見えなくなるので、なんかDeamonっぽいです。
 ※serverの起動は.emacsに書くなりしてください。

コマンド 引数 説明
Emacs-Daemon [ bin-directory [ wait-time [work-directory]] デーモンっぽく起動してみる。
bin-directory:emacs.exeがあるディレクトリ。デフォルトは空文字(Pathに登録されている場合にだけうまく動く)
wait-time:待機ミリ秒
work-directory:作業ディレクトリ
Emacs-Kill Emacsの画面全部閉じる。Emacs開いてなくて、Power Shellだけ開いてるときに使うといいんじゃないかな

 コードは下にはっつけとくので、使ってみたいという希有な人は、適宜profile.ps1にでも貼り付けるなり、スクリプトにするなりしてください 

powershell -Command emacs-daemon

 とかを適当にWindows起動後に実行するようにすれば勝手に動いてくれるからよりデーモンライクだね。ちろちろ画面が出るのがうざいけど。



 ちなみに、「しばらく待機」ってのがやっかいで、早すぎるとウィンドウがとれなくて非表示に失敗するし、かといって待ちすぎるのもあれだし。
 とりあえず、私の環境では2秒じゃだめだけど、5秒だと安定して大丈夫っぽいから5秒待ってる。
 Process.WaitForInputIdleとかでできるかなぁとか思ってた時期が私にもありましたけど、全然無理だった。

 だれかうまい方法ご存じないですかね。誰かWindowsのEmacsでもDaemon化してくれませんかね。


PowerShellのコード

 まぁ、PowerShellというか、ほとんどC#だけど。

$CSCODE=@'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace EmacsDaemon
{
    public class WindowControl
    {
        [DllImport("user32.dll")]
        public static extern bool SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
        [DllImport("user32.dll")]
        public static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId);

        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool EnumWindows([MarshalAs(UnmanagedType.FunctionPtr)] EnumWindowsProc lpEnumFunc, IntPtr lParam);

        public static bool KillWindow(IntPtr hWnd) { return SendMessage(hWnd, 0x0112, 0xf060, 0); }
        public static bool HideWindow(IntPtr hWnd) { return ShowWindow(hWnd, 0); }

        class CloseProcess
        {
            Process process;
            public CloseProcess(Process p) { process = p; }
            public bool method(IntPtr hWnd, IntPtr lParam)
            {
                uint p = 0;
                GetWindowThreadProcessId(hWnd, ref p);
                if (p == process.Id)
                {
                    KillWindow(hWnd);
                }
                return true;
            }
        }
        public static void CloseAllWindow(Process process)
        {
            CloseProcess cp = new CloseProcess(process);
            EnumWindowsProc ewp = new EnumWindowsProc(cp.method);
            IntPtr i = new IntPtr();
            EnumWindows(ewp, i);
        }
    }
}
'@
Add-Type -Language CSharp -TypeDefinition $CSCODE

function Emacs-Daemon(){
  param($dir="",$wait=-1,$workDir=$env:HOME);
  $emacsexe="emacs.exe";
  if($dir -ne ""){
    $emacsexe = $dir +"\emacs.exe";
  }
  if($workDir -eq ""){
    $workDir = ".";
  }
  if($wait -eq -1){
    $wait = 5000;
  }
  $eproc=Start-Process $emacsexe -WindowStyle Hidden -PassThru  -WorkingDirectory $workDir
  [Threading.Thread]::Sleep($wait);#誰かもっといい方法教えて
  [EmacsDaemon.WindowControl]::HideWindow($eproc.MainWindowHandle);
}
function Emacs-Kill(){
  $eprocess = Get-Process "emacs";
  foreach($pr in $eprocess){
    [EmacsDaemon.WindowControl]::CloseAllWindow($pr);
  }
}

 てか、はてな記法ってPowerShellに対応していないんだね…。

KeySnailのKillLineをEmacs風に改良してみた

 f:id:nodamushi:20151019022132p:plain

 KeySnailネタ。moozさんのアイコンかわいいよね。
 というわけで、なんか、Firefoxがバージョンアップしたら.keysnail.jsの「以前にコピーしたテキスト一覧から選択して貼り付け」のletでエラーが出るらしく、久しぶりに.keysnail.jsを編集しました。

すでに修正されてた(´・д・`)

 自分で修正しんたんすけど、もしかしてって見てみたら、keysnail/functions.js at f22a53fac0c693ccb939b5398494be63d7e1e011 · mooz/keysnail · GitHubにもう一ヶ月ぐらい前に更新されてましたよー。
 うん、Firefox自動更新してないんだ。ごめんね。

 というわけで、コピって貼り付け。

    if (!command.kill.ring.length)
        return;
    
    let ct = command.getClipboardText();
    if (!command.kill.ring.length || ct != command.kill.ring[0]) {
        command.pushKillRing(ct);
    }
    
    prompt.selector(
        {
            message: "Paste:",
            collection: command.kill.ring,
            callback: function (i) { if (i >= 0) key.insertText(command.kill.ring[i]); }
        }
    );



Kill Lineがなんか変

 日頃からどーもなんか気にくわないな、とおもっていたKeySnailのkill-line。


 というのもこれ。ここ(↓)で、Ctrl+Kを押すと………
f:id:nodamushi:20151019012224p:plain
f:id:nodamushi:20151019012230p:plain
 うん、問題ないね。

 でも、ここ(↓)でCtrl+Kを押すと………
f:id:nodamushi:20151019012243p:plain
f:id:nodamushi:20151019012247p:plain
 あっるぅぇえ?(´・д・`) なぜか私のパソコンではこんなんになってなまいます。


 私のパソコンでもこう(↓)なってほしいんですよね。

f:id:nodamushi:20151019012252p:plain


 あと、気になるのこれ。
f:id:nodamushi:20151019031717p:plain
f:id:nodamushi:20151019031726p:plain

 論理行で削除するんじゃなくって、テキストエリアの折り返し行までが削除されるの。これ気に入らないの。




 というわけで、ついでだったので、そうなるように修正したのがこちら。

key.setEditKey('C-k', function (ev) {
    if (command.marked(ev))
            command.resetMark(ev);
    let ta = ev.originalTarget;
    let str = ta.value;

    let i = ta.selectionStart;
    for(let e=ta.value.length;i<e;i++){
        let c = str.charAt(i);
        if(c == "\r" || c == "\n" || c=="\u0085"){
            break;
        }
    }
    ta.selectionEnd = i;
    let cstr = ta.value.substring(ta.selectionStart,ta.selectionEnd).trim();
    command.copySelectedText(ta);
    goDoCommand('cmd_delete');
    if(!cstr){
        goDoCommand('cmd_beginLine');
        let pos = ta.selectionStart;
        goDoCommand('cmd_endLine');
        if(pos != ta.value.length){
            goDoCommand('cmd_deleteCharForward');   
        }else{
            goDoCommand('cmd_deleteCharBackward');
        }
    }
}, 'カーソルから先を一行カット (Kill line)');

 Emacsのkill-lineは削除した文字が空(空白のみの文字列含む)だと、改行文字も消すっぽいので、その処理を追加してあります。


 ちなみに、どうもうまく動かない戦犯は"cmd_deleteToEndOfLine"らしく、こいつを使わないようにすることが重要。なんか、このコマンドって条件はよくわからないんだけど、正しく動作しないことがあるっぽいです。
 最初は、if(!str)ブロックの中身も"cmd_deleteToEndOfLine"を呼び出してただけなんだけど、なぜか2行目にカーソルがあるときに、正しく動かないという状況がまれに発生しました。発生条件は全くもって不明。というわけで、上記の形になっています。文字列処理は嫌ので、キャレットの位置変化から最後の行かどうか判定しています。



 あ、なお、これはFirefoxのバグか、私のプライグイン環境との相性のバグなのかのどっちかです。
 KeySnailのバグではありません。





 あと、ついでに、Ctrl+Jで次の行を生成して移動するってのを作っておいた。
 単に改行だけにしたい人は、goDoCommandを削除してください。

key.setEditKey("C-j",function(ev){
    goDoCommand("cmd_endLine");
    key.generateKey(ev.originalTarget,KeyEvent.DOM_VK_RETURN,true);
},"新しい行を作成",true);


 以上です。




 ところで、EdgeでFirefoxのプラグインが動かせるかもという噂ですが、KeySnailがEdgeで動くかなぁ。
 動けばいいなぁ~ヽ( ・∀・)ノ

かゆいところに手が届かないATOKタッチキーボード

 すっかり忘れてたんですが、私Surface Pro3を随分前に買っていました。
 Pro4が出るらしいですね。Pro4は筆圧1024段間検知だとか。めっちゃ欲しい。


 さて、普段IMEにAtokを愛用している私。Surfaceでも利用しようとインストールしたんですが、

 SurfaceのタッチキーボードでのAtokの使いにくいのなんのって

 ダントツで使いにくいです。
 というわけで、愚痴がほぼすべてのレポートを記しておきます。




予測変換が邪魔くさい

普通に入力すると、予測変換が出てきます。

f:id:nodamushi:20151011233517j:plain

 最初はこれすら「うぜぇ」とか思っていたんですが、意外と慣れました。
 慣れると、まぁ、使い勝手が良いときもあるし、お節介が過ぎるときもある半々な感じです。

 が、問題は次。

f:id:nodamushi:20151011234330j:plain

 「予測変換」を確定した後に、何も押していないのに出てくるこれね。
 (ちなみに、デスクトップに増えていっているのは自動キャプチャ画像。)
 これで、空白を開けようとスペースを押そうものならこうなる。

f:id:nodamushi:20151011234458j:plain
 だあああ うぜぇええええ
 


 
 スペースって検索ボックスでは良く打つよね。その度にこうなるわけ。ストレスマッハ。

JustSystemsに聞いてみた

 これを解決する方法をJustSystemsに聞いてみました。返事によると、以下の自動表示の項目を「しない」に設定しろとのこと。

f:id:nodamushi:20151011235318j:plain

 するとこうな………
f:id:nodamushi:20151011235606j:plain

 変わらん。(デスクトップのキャプチャ画像が増えてるので時系列はちゃんと指示通り設定した後である)
 どうも、一回ソフトごと起動し直す必要があるらしい。
 というわけで、もう一回メモ帳を起動し直し、トライ。


f:id:nodamushi:20151011235815j:plain
 なんかよくわからん何もないウィンドウが表示される。うざい。

f:id:nodamushi:20151011235908j:plain
 「よそく」と打っても、予測変換は出てこない。
 違うんだよ。ここの予測変換は出てきてもいいんだよ。害悪ではなかったんだよ。

f:id:nodamushi:20151012000140j:plain
 やりました。予測変換、と打ち込んだ後に、余計な連中が出てきません。
 ですが、ちょっとキャプチャのタイミング上移りませんでしたが………

f:id:nodamushi:20151012000240j:plain
 入力後になんか何もないウィンドウが出てきます。うぜぇ


かゆいところに手が届かないAtok

 最大のストレス源である、変換確定後に余計な予測変換が出てくる機能を抑制することはできました。
 が、出てきてもいい予測変換まで抑制されるし、なんかうざいウィンドウは出てくるし、どうもかゆいところに手が届きません。
 あと、日本語入力用のATOKタッチキーボードが選択不可になったりして使いにくいことこの上ないです。(いったんMicrosoft IMEに変更してから、ATOKにすると選択できたり、よくわからん)

 あぁ、かゆいところに手が届きませんな。

 まぁ、結局Surfaceでは私はMicrosoftを使うことにして、ATOKはアンインストールしたんで、もう関係ないんですけどね。(この記事のためにわざわざインストールし直した)



 バージョンアップする度に余計な機能が追加されて馬鹿になっていくともっぱら評判のATOKさんですが、私の信仰心はいつまで持つのか。今年か来年中に見切りをつけようかと思っています。


 ところで、最近のMicrosoftは結構頑張ってるよね。
 今年度中に行われると噂のMicrosoftのEdgeで本当にFirefox,Chromeの既存拡張機能取り込みが来れば、Firefoxへのかすかに残っていた信仰心は完全に捨てる予定です。
 仮想デスクトップもいいね。MacやLinuxの仮想デスクトップにはまだ負けるけど。アイコンクリック一つで移動できる便利さが足りない。あとはGnuEmacsがWindowsでもdaemon使えるようになればもう何も怖くないね。serverは使えるのになんでdaemonは使えないんだろ?

 あと、環境変数のPathの設定をしやすくするみたい。地味にいい機能。

 Microsoftを信仰することにしましょうか。