タイトル【SnapXShot制作記】キーセンスは意外に簡単にできたが…カテゴリーSnapXShot制作記
作成日2000/11/28 15:18:38作成者新居雅行
今さら説明の必要もないとは思うが、筆者はMac OSに関する原稿を書くのが主な仕事だ。もちろん、画面ショットは頻繁に作る必要があり、Mac OSではSnapZ Pro(Ambrosia Software)のヘビーユーザである。しかしながら、Mac OS Xとなって、今までのように、Command+shift+3の機能がなくなってしまい、代わりにGrabというアプリケーションで画面ショットが作成できるようになった。ただし、Grab以外のアプリケーションの画面を撮影するには、10秒待って画面ショットを行なう機能を使うしかなった。それもかったるいのであるが、もっと問題なのは、画面ショットが1つ1つのウインドウにしか保持されず、1つ1つ手作業で保存しないといけないことだ。これが面倒で、かつ間違えやすい。後から撮影したはずのショットがどこかに行ってしまって捜しまわるということも経験している。連番で即ファイルに残る…これが欲しかった。
MDOnlineでは、以前にAppleからリリースされているSuper SnapShotというアプリケーションを紹介したが、その記事で、このソフトを改造すると画面ショットツールを作成できることを紹介した。誰かやるかなという期待を持ちながらも結果的に自分で書いて自分でやることになってしまったのである。それが、SnapXShotである。とにかく、Mac OS Xの記事を書く時の画面ショットを少しでも気楽に作成できるようにしたいという願いがあったからだ。

Super SnapShotはすでにCarbon化されている。Mac OS X Public BetaにCodeWarrior 6を入れて、Super SnapShotをコンパイルすることは何のエラーもなくできた。まずは、とにかく、Command+shift+3でのスクリーンショットと自動的にファイル保存を組み込んでみた。非効率な部分などは多々あるが、千里の道も一歩からというし、とにかく、自分の作業環境を少しずつでも改善したいということもあったので、まずはもっとも安直な手法を取ってみた。

CarbonではCarbon Event Modelを使って、WaitNextEventによる「ぐるぐる回し」
を避けましょうというのがスローガンである。もちろん、それを目指したいが、Super SnapShotは残念ながらぐるぐる回しをしている。そこで、いわゆるNullイベント時にキーセンスをして、もし指定されたキーであれば画面ショットをファイルに残すというプログラムで作ってみた。まずは動かすことが重要である。それから改良すればいいという開き直りだ(それじゃあだめだとおっしゃる方もいらっしゃるかもしれないが、そこは筆者の力量の問題もあるので大目を見てもらいたい)。
WaitNextEvent直後に、GetKeysというEvent ManagerのAPIを使って、キーセンスを行なう。したがって、別にFKEYのコンビネーションでなくてもキーセンスは可能だし、この方法だと後からのカスタマイズも可能となる。ただし、キーを押し続けたときには何もしないように、ループで逐一GetKeysに来る時に、変数に覚えさせておいた直前のGetKeysの値と比較して、違いがあるかどうかを判断する処理も組み込んだ。
こうしたNullイベントに処理を割り込ませる方法は、実は、相当以前だが、筆者が配付していたシェアウエアのClipFilerで試したことがある。だが、Mac OS(というか、当時は漢字Talkだったが…)ではキーの取りこぼしも多く、あまりうまい方法ではなかった。しかしながら、マルチタスクがしっかりしているMac OS Xではちょっと使った限りでは取りこぼしはめったにないという感触である。もっとも、それだけ頻繁にNullイベントが入っているのであれば、SnapXShotが立ち上がっていることでのパフォーマンスの低下が懸念されるが、それについてはこれからちゃんとマルチタスクに適した手法に切り替えることで対処しようと思う。
画面ショットを保存する方法は、やや悩んだが、とにかくうまくできた。というのは、実はCでまともにプログラミングするのは正直なところ「Macintoshアプリケーションプログラミング」以来だということもある。最近はJavaでのプログラミングが多かったので、勘を取り戻すのに一苦労というところだったが、小池さんの原稿やセミナーをしつこく(笑)聞きに行った甲斐もあってQuickDrawの世界にもすんなり入り込めた。
Super SnapShotにはすでに便利な関数があるので、もちろんそれを使った。関数呼び出し1つで、画面ショットまるままがPixMapで得られる。また、Pictureをファイルに書き込む関数もある。あとは、PixMapからPictureを作るところを自分で作ればいいのだが、それも他の部分を参考にするととりあえずはできあがった。Picture作成のためのダミーのグラフポートはOpenPortではなくCreateNewPortで作成するなどはCarbonらしいところである。

だが、しかし、当然引っ掛かったところもある。小池さんのセミナーで「おかしなところがあると必ず落ちるぞ」と聞いていたのだが、確かに落ちた。実は、ダミーのグラフポートをカレントにはしたものの、それまでのグラフポートを保存し、使用後に戻す作業をプログラムに組み込んでいなかった。すると、案の定、2度目の画面ショットで必ず落ちるという結果になった。なお、PixMapをPictureにするときにはCopyBitsを使うのだが、その引数のややこしい部分は、プログラムの他の部分を参考にして組み立てた。
ファイル処理も、ToolboxのFile Managerなどを使って作成できる。つまり、FSSpecを使ってファイルを指定する。フォルダの検索では、FindFolderを使うのだが、定数でkDocumentsFolderTypeを指定すると、ログインしているアカウントのDocumentsフォルダを返す。だけど、実はここでいちばんはまった。なぜか、FSMakeFSSpecで妙なエラーを返す。さらに悪いことに、CodeWarrior 6はMac OS X Public Betaで動かすとデバッグができない(やり方があるのだろうか?)。標準出力にログを取りながらいろいろ見たところ、どうも「\pShot.pict」によってPascal文字列を指定したつもりがそうはなっていないようなのだ。「エン・ピー」というキャラクタの入ったC文字列になってしまっているようなのだ。そこで、\pの記述はあきらめ、文字列はC形式で記述し、適時c2pstrでPascal文字列を得るようにとりあえずしている。
なお、数字をファイル名に割り込ませるあたりは当然ながら文字列処理がからむ。ここでもCFStringを使うとかっこいいのは分かっているが、とりあえず動かすために、標準ライブラリを使ってstrcpyなどとやることにした。(実は標準ライブラリこそ10年振りくらいかもしれない…「THINK Cプログラミング技法」以来だ。)ところが、Super SnapShotの標準ライブラリに対応するライブラリが、Carbon対応でないものがプロジェクトに読み込まれいるために、物凄い勢いでエラーが出てくる。最終的にはライブラリとしては、「CarbonLib」「MSL RuntimePPC.Lib」に加え、「MSL C.Carbon.Lib」「MSL SIOUX.Carbon.Lib」をマージしたプロジェクトとすることで事なきを得た。

以上のように、とにかくどさくさではあるが、とにかくキー操作で自動的に画面ショットがファイルにたまるようになった。決してほめられた解決法ではないとおっしゃるかもしれないが、まずは結果オーライと割り切らせてもらいたい。マウスポインタが入らないのはちょっと痛いで、これもなんとかしたいところだが、当面は画像ソフトで組み入れることにしよう。
今後、まともなプログラムにしていく段階で、ソースについても公開したいと思う。現状では、Appleのサンプルプログラムに突っ込みをしている。Appleのサンプルについては改変しての公開は難しいので、まじめに作る上で、自作部分とサンプルの部分を分離することを考えている。だけど、まずはProject Builderへの移行かなと思い、実はさっそくソースを移行してみた。で、コンパイル!…でうまく行く程甘くなかった。ヘッダ関連がなんかずごく違うので、コンパイルを通すのにちょっとかかりそうだ。サンプルプログラムの使っていない部分も多いので、抜本的に変えた方がいいかもしれない。しかも、カスタマイズのためのダイアログボックス作りを考えれば、nibベースのCarbonアプリケーションかなとも思っているが、どうせなら、画面ショット部分はCarbonでもユーザインタフェースをCocoaで作るのがいいのかもしれないなど、まだ方針が揺らいでいる。だが、とにかく何かを作りながら、開発プロセスを紹介するというコーナーを継続させる意志は強く持っている。
関連リンクSnapXShot