dgKeyframe2Chapterをリニューアル/オープンソース化しました

Pocket

かなり以前、TMPGEncシリーズのチャプターインデックス情報ファイルである.keyframeファイルを、mp4chap.exeなどに読み込ませる「hh:mm:ss:fff」形式のタイムコードファイル.chapters.txtに変換するdgKeyframe2Chapterというユーティリティを作成しました。

dgKeyframe2Chapterをリリースしました

dgKeyframe2Chapeter 1.3をリリースしました

もう10年近く前ですね、、

自分でもだいぶ使用頻度が落ちてきていますが、たまに機能要望などをいただくので世界で10人くらいは使っておられるのかも知れません(笑)。そして先日久しぶりにまたリクエストをいただいたので、COVID-19でヒマなGW中にやってみましょうかと久しぶりにソースを開いたら、あ、これVB.NET/WinFormsで作ってたんだった…リクエストのあった機能を足すだけなら頑張って思い出して作るのもアリでしたが、今後もメンテするとなると慣れているC#/WPFで作り直そうと決意。といいつつC#も数ヶ月ブランクがあって色々忘れておりGW中かかってしまいましたが一応完成。

ついでにGithubでソースも公開しておきました。通常利用の場合、「Release」タブから最新版のzipをダウンロードしてください。そんなに自分で使い込んでないので、細かいバグや使い勝手の悪さがあるかも知れません。なにかあればGithubのIssuesかこの記事のコメント欄にでもお知らせ下さいませ。

どうせなら最新版でと.NET Frameworkも4.8ベースに移行したので環境によってはそちらの導入も必要になるかも知れません。Windows 10 May 2019 Update (1903)以降なら導入済みのはずです。

VB.NETをC#に変換してみた時の作業メモ

Pocket

プログラミングの話題です。

Xamarinとか考えるとVisual StudioではVB.NETはオワコンでC#に移行すべきなんだろうなぁという雰囲気は以前からありましたが、Visual Studio for Mac(C#のみ)なんてのまで出てきちゃってさらに加速してきた感があります。Swiftもオープンソース化されて今後様々なプラットフォームの開発ができるようになるかもですが、現状C#ならWin/Mac/iOS/Androidいけちゃうわけですし。もちろんそれぞれGUI周りの実装が違うので、1つのソース(プロジェクト)で各プラットフォームのビルドが一発でできちゃう、とかいう世界にはまだならないですが、関数とかオブジェクトとか(内部処理的な)ライブラリを共有、転用できるだけでも大きなメリットでしょう(想像)。

ということでVisual Studio 2017を入れて見たついでに、実験的にフォーム1つだけの小さな自分用WindowsアプリをC#で作り直してみようかと思い立ちました。C#の勉強の為にはゼロから作り直す方が良いんでしょうが、とりあえず世の中にはVB->C#のコード変換をしてくれるツールがたくさんあるということだったのでまずはそちらで雰囲気をつかんでみることに。ポインタアレルギーを脱してないヘタレプログラマなので、Cと名のつくものは不安が先行しがち(^^;)。

で、最初に試したローカルアプリ型のツールはいまいちよくわからなかったので、ブラウザ上でコードをサクっと変換してくれるこちらを使ってみました。プロジェクトレベルで変換してくれるわけでなく、あくまでテキストレベルでVBコードをC#コード文法に書き直してくれるだけなので、VS2007上でC#の新規Windowsフォームアプリケーションのプロジェクトを作りました。そしてフォームデザイナーで土台となるフォーム(Form1)のプロパティだけ揃えておいて、載ってる部品を全選択して一括コピペします。ペーストされる座標が揃いませんが、カーソルキーで適当に揃えて確定。これでボタンやリストなどは名前やプロパティをそのまんま移植できました。次にForm1のコードをエディタで開き、上記サイトでまるっと変換したC#コードをペースト、、、しただけでは上手くいきませんでした。以下思い出せる範囲でメモ。

■using周り

冒頭にインポートするライブラリが、デフォルトのテンプレートと、変換したもので食い違います。特に変換した方のコードには、

なんてのが含まれています。どうもVB特有の関数やオブジェクトを使用するDLLらしいです。個々にうまく変換できなかったものを手直ししてても意外とVBにしかないものがあるみたいです。C#で全面的に書き直すのも手なんですが、.NET Frameworkに含まれるDLLなので使ったからといってユーザに別途追加インストールが必要になるとかではないので、特にこだわりがなければ使ってもいいんじゃないでしょうか。ゼロから書き直すプロジェクトなら避けた方がスリムなんでしょうけど。

特にファイルコピー周りの処理でVBの方が便利なところがあって、最終的には

というのも追加していくつかVB固有機能を使用しました。

逆に変換コードにはあってデフォルトテンプレートにあるものは名前からして使わなそうなものはコメントアウトしました。

■各メソッドの貼り付け場所

C#のバージョンの違いなのか、Form1クラス定義の開き方も少し違ってたりなので、念のためテンプレのままとし、クラス内のメソッド定義単位でペーストしました。

なんかはテンプレの方にもあるので重複に注意です。

■コードの手直し

ぶりっとコードをペーストすると盛大にエラーが出ます。さすがにそのまま完璧に変換とはいきません。

例えば、配列の添字がVBでは()、C#では[]ですが、これは自動では置換してくれません。()が他の意味にも使われている箇所があるので、自動では判別が難しいようです。

例えば、

なんてコードに対して、「メソッド名が必要です」が出て意味不明ですが、tmp[0]に直してやると消えます。文法的にはtmpという変数にいきなり引数がついてるので、「temp.hoge(0)みたいにメソッドがあるはずじゃねぇの?」という推論なんでしょうかね。まぁVSの推論エンジンですら、そこは配列の添字じゃないの?と提案できないくらいなので、サードパーティの無料自動変換プログラムができなくても責められないでしょう。わかってしまえば単純作業なのでせこせこと直していきます。

次に多かったのは、

のように文字列を文字列で分割して配列に格納したりするコードに対して、「‘string’ から ‘char’ へ変換することはできません。」と出ます。(古い.NETの)C#のSplitは分割文字として文字列ではなく単一の文字(char型)しか使えなかったらしい名残のようです。もともと分割の区切り文字が1文字の場合は、char型であることを明示するよう、ダブルクオートをシングルクオートに直してやるだけでOKです。

とか。では2文字以上の文字列を使いたい時は?ちょっと文法が変わりますが、同じ.Splitで

のようにすればいいみたい。めんどくさ!

■My.settingsへのアクセス

VB.NETではアプリの設定など短い情報を保存するMy.settingsという仕組みがあります。もちろんC#にもあるんですが、アクセス方法がちょっと違います。

となってる箇所に「現在のコンテキストに ‘My’ という名前は存在しません。」と出ます。MyのかわりにProperties(複数形なので注意)とし、Settingsの後にDefault.を挿入します。

これは変換サイトの方で頑張ってほしかった案件です。

もちろんセッテイング項目は自分で作り直しています。どこかのXMLファイルをコピーすれば一発かも知れませんが、まぁ数個だったので手で移しました。

■中身が移ってないイベントハンドラがある

変換後のコードで、変換処理にこけたのかわかりませんが、イベントハンドラの{}の中身が空のままのコードがいくつかありました。エラーもないのでちょっと恐いですね。全体見渡したり、数をチェックしたりして抜けがないか確認が必要です。

■GUIパーツと各イベントハンドラコードの紐付け

ある程度コードを手直し、よやくエラーが0になってビルドしてフォームが表示された時は感激です。しかし、一瞬後に絶望へとかわります。どのUIパーツをクリックしても反応しないのです。試しにデザイナーから適当なボタンをダブルクリックして、コードエディターに挿入されたイベントハンドラにMessageBox.Showとか書くと機能します。つまり、コピペでもってきた各ハンドラとデザイナー上のUIパーツが紐付いていないようなのです。一瞬、全てのパーツに同じ事をして{}内を書き写さないとダメなのかと青ざめましたが、幸い少しだけマシな方法がありました。

デザイナーでどれかのパーツを選択し、プロパティウインドウでイナズマのアイコンをクリックします。そうするとここにそのUIパーツが受け取れるイベント一覧が出てくるので、Clickなどコードを割り付けたいイベントを探し、その右列をクリックします。するとプルダウンメニューで当該Formのコード内にあるハンドラ一覧が出るので、選択してやれば紐付け完了です。

UIパーツはたくさんありますし、ひとつのUIパーツにClickとDouble ClickとEnterとなどなど複数のイベントを設定することも少なくないので、結構大変な作業になります。VBとC#のプロジェクトを同時に開いて1つずつ見比べながら書き写してくしかありません。またコード側からどこにも紐付いてないイベントハンドラが残ってるかどうかを知る術もありません。

まぁきっとこれもデザイナーのソースとなるテキストファイルを丸コピーできれば一緒に反映されるような気もするんですが、わかりませんでした。

■まとめ

上に書いた以外ではファイル周りで変換しきれていないコードがあったりしましたが、まぁVB.NETとC#の違いを調べながら書き直すのは良い勉強になりました。

むしろ大変なのは先のイベントハンドラの紐付けや設定項目の再作成など、Visual StudioのGUIでする作業の移植ですね。バージョン情報などを含むアセンブリ情報などもごっそりやり直しです。これは今回使ったようなコード変換系のサービスの難点でしょう。

先に使ったプロジェクトを読み込んで変換するタイプだとここらも一括で面倒みてくれるかも知れません。Webツールに移行する前にもう少しいじり倒してみればよかったかな。今回はForm1しかない小さなツールだったのでまだよかったですが、より大規模なソフトウェアの場合などは抜け漏れのチェックも大変になってきます。

いずれにせよC#自体は想像してたほどVBとかけ離れてたり、いきなりポインタの理解を迫られたりするようなものではなかった気がします。少なくともVBでできていたことを移植するだけなら、いくつかのVB固有関数を除けばほぼ単純な文法置換(()を[]とか文末セミコロンとか)で済みそうです。残りのVBプロジェクトを全部C#に移行させる理由はいまんとこないですが、今後新規に作る時はC#にしてみようかなというくらいの気持ちにはなりました。あとは買っておいた解説本を眺めておこうと思います。

確かな力が身につくC#「超」入門 (Informatics&IDEA)

確かな力が身につくC#「超」入門 (Informatics&IDEA)

北村 愛実
6,730円(06/06 20:25時点)
Amazonの情報を掲載しています

 

Swift Playgrounds 入門コンテンツの解説サイト作りました

Pocket

少し前からサイドバーで紹介してますが、Apple がリリースしているiPad向けプログラミング学習アプリ「Swift Playgrounds」の攻略サイトというか、コード例と解説を掲載したサイトを作りました

Swift Playgroundsはアプリ内で教材コンテンツを追加ダウンロードする仕組みになっていますが、その入門コンテンツである「コードを学ぼう」の1と2の全ステージを本日ようやく網羅しましたので改めてご紹介。

プログラムに唯一絶対の正解はないので、単なる攻略サイトみたいなものを作るのは野暮かと思いましたが、それでも「プログラミングを勉強したいけど、身近に聞ける人がいなくて先へ進めず諦めてしまった」なんて不幸が回避できるならと思い、コードはあくまで正解“例”であることを強調しつつ、アプリ内の出題でカバーしきれてない部分の解説を丁寧にするよう心がけました。さっそく親子で参考にしていただいたというコメントもいただきやってよかったなと。

しかしやっと1,2が終わったとほぼ同時にPlaygrounds自体がアップデートされ「コードを学ぼう」も3がリリースされてしまいました。個々の解説を丁寧に書きすぎて結構時間がかかってしまったので、ちょっと今すぐ続きに着手できるかはビミョウな気持ちです(^^;)。まぁ、ざっとみた感じ3は基本を離れてよりクリエイティブな内容に寄っている印象なので、このサイトの役割としては少し範囲外かなという気もしています。Swiftの基本文法やループ、条件分岐、変数、配列といったプログラミング言語に共通の概念については「コードを学ぼう」1と2で一通り触れており、そのフォローという意味で一区切りかなぁと。まぁ1,2の反響や要望をみてまた考えます。

英語版が公開された時にいくつかのITサイトの連載やブログで紹介されたものはありますが、3月に日本語化されてから本格的に全ステージを網羅したものはたぶんまだなかったと思うので、まだ不完全ながらも、これからPlaygroundsにチャレンジしてみようと思う人の助けになればなと思います。

タオルグリップ法を支援するiPhoneアプリのプロト作って見た

Pocket

タオルを短時間握るだけで血圧が改善できるというハンドグリップ法なるものの記事を見つけ、iOSの通知機能の手習いで支援アプリを作って見た。

こんな感じで、アプリ起動してスタートしておくと、以後は他のことしてても定期的に通知が来るという簡単なもの。片手でタオルを握り、もう片方でスマフォをいじってればいい、という。どうだろ、ちゃんと作り込んだらニーズあるかしら。

13260069_10209552332352030_4460919170323275006_n

技術的にはあまり面倒な部分はなかった。実際にはアプリがフォアグラウンドにいる時はそのアプリ自身の通知は受け取れないので、スタート後はホームを押なりスリープするなりしてもらうか、きちんと実装してアプリがフォアグラウンドにいるときにはアプリ上にメッセージが出るよう同期処理をする必要がありそう。スタートした後、自身で終了するのが技術的には可能なんだけど、ガイドライン的には非推奨っぽい。

でまぁ作ってひと月ほど立つんですが、まぁほとんどの日は忘れますねw。あと防水端末でお風呂で使いたいなぁとか。そういう意味ではAndroidで作るべき?

あと一分休憩をいれることになってるけど、左右交互なら別にいらなくないのか?とか。今は、右->休憩->左->休憩->…だけど、休憩を挟まず左右交互にやるエクスプレスモードも作りたくなってる今日この頃。

デジタルハンドグリップメーター MCZ-5041 931327

デジタルハンドグリップメーター MCZ-5041 931327

12,887円(06/07 12:09時点)
Amazonの情報を掲載しています

KeyRemap4MacBookでSublime Text2を除外する

Pocket

今日、Facebook経由でSublime Text2というプログラマ向けテキストエディタを知り、ヨサゲなので使い始めてみました。とりあえず何がスゴいかはこちらの日本語入門動画がオススメです。

で、試していて最初に困ったのが、Ctrl-AがEmacsキーバインドの行頭移動ではなく全選択になっていた点。さっそくカスタマイズしようとしたらそんな設定はどこにもない。あぁ、そうかMacのキーバインドをカスタマイズするKeyRemap4MacBookでWindowsライクにしてたからな。Emacs、Terminal、VMWareなどでは適用除外してくれるのですっかり忘れてた。しかし、標準ではKeyRemap4MacBookがSublime Text2などという新しいエディタを知っているわけもなく、除外設定もありません。

ということで、こちらの記事を参考にさせていただき、自作設定を追加しました。まず、元となる標準設定の、Use PC Style Copy/Paste、Use PC Style Undo、Use PC Style Select All、Use PC Style Save(それぞれTerminalやEmacsを除く版の方)の4つの設定を「/Library/org.pqrs/KeyRemap4MacBook/app/KeyRemap4MacBook.app/Contents/Resources/include/checkbox/for_pc_users.xml」から引っこ抜いてきます(<item>~</item>がひとまとまりです)。次に、KeyRemap4MacBookの設定パネルから「Misc & Uninstall」タブを開き「Open private.xml」をクリック。Finderで表示されたウインドウをエディタで開き、しかるべき位置にペーストします。元のfor_pc_users.xmlを直接編集してしまうと、おそらくバージョンアップ時に上書きされてしまうので、必ずカスタム設定はprivate.xmlの方に書いておくようにしましょう。

で赤字の位置を修正します。

  • Sublimeのアプリ名を認識させる為にappdefタグを追加(ちなみにcom.sublimetext.2はアプリバンドルの中のinfo.plistを見ました)。
  • identifierタグの中身がカブると怒られるので、private.や_and_sublimeを追加
  • notタグにappdefで定義したappnameを追加

以上。保存し、KeyRmap4MacBookコントロールパネルで「Change Key」タブに戻り、「ReloadXML」ボタンを押せば項目一覧の一番上に新設定が出現するはずです。

<?xml version="1.0"?>
<root>
   <appdef>
        <appname>SUBLIME2</appname>
        <equal>com.sublimetext.2</equal>
    </appdef>

    <item>
      <name>Use PC Style Copy/Paste</name>
      <appendix>(Control+C to Command_L+C)</appendix>
      <appendix>(Control+V to Command_L+V)</appendix>
      <appendix>(Control+X to Command_L+X)</appendix>
      <appendix>(Except in Terminal, VM, RDC, Emacs, X11, Eclipse, SublimeText2)</appendix>
      <identifier>private.remap.copy_paste_winstyle_no_term_and_sublime</identifier>
      <not>EMACS, TERMINAL, VIRTUALMACHINE, REMOTEDESKTOPCONNECTION, X11, ECLIPSE, SUBLIME2</not>
      <autogen>–KeyToKey– KeyCode::C, VK_CONTROL, KeyCode::C, ModifierFlag::COMMAND_L</autogen>
      <autogen>–KeyToKey– KeyCode::V, VK_CONTROL, KeyCode::V, ModifierFlag::COMMAND_L</autogen>
      <autogen>–KeyToKey– KeyCode::X, VK_CONTROL, KeyCode::X, ModifierFlag::COMMAND_L</autogen>
    </item>

    <item>
      <name>Use PC Style Undo</name>
      <appendix>(Control+Z to Command_L+Z)</appendix>
      <appendix>(Except in Terminal, VM, RDC, Emacs, X11, Eclipse, SublimeText2)</appendix>
      <identifier>private.remap.undo_winstyle_no_term_and_sublime</identifier>
      <not>EMACS, TERMINAL, VIRTUALMACHINE, REMOTEDESKTOPCONNECTION, X11, ECLIPSE, SUBLIME2</not>
      <autogen>–KeyToKey– KeyCode::Z, VK_CONTROL, KeyCode::Z, ModifierFlag::COMMAND_L</autogen>
    </item>

    <item>
      <name>Use PC Style Select All</name>
      <appendix>(Control+A to Command_L+A)</appendix>
      <appendix>(Except in Terminal, VM, RDC, Emacs, X11, Eclipse, SublimeText2)</appendix>
      <identifier>private.remap.select_all_winstyle_no_term_and_sublime</identifier>
      <not>EMACS, TERMINAL, VIRTUALMACHINE, REMOTEDESKTOPCONNECTION, X11, ECLIPSE, SUBLIME2</not>
      <autogen>–KeyToKey– KeyCode::A, VK_CONTROL, KeyCode::A, ModifierFlag::COMMAND_L</autogen>
    </item>

    <item>
      <name>Use PC Style Save</name>
      <appendix>(Control+S to Command_L+S)</appendix>
      <appendix>(Except in Terminal, VM, RDC, Emacs, X11, Eclipse, SublimeText2)</appendix>
      <identifier>private.remap.save_winstyle_no_term_and_sublime</identifier>
      <not>EMACS, TERMINAL, VIRTUALMACHINE, REMOTEDESKTOPCONNECTION, X11, ECLIPSE, SUBLIME2</not>
      <autogen>–KeyToKey– KeyCode::S, VK_CONTROL, KeyCode::S, ModifierFlag::COMMAND_L</autogen>
    </item>

</root>