【LabVIEW】ペン(マウス)とジョイスティック操作時間計測

イラストを描いていて、かなりの時間が経過をしているのに思ったほど作業が進んでいないと思うことがありました。

感覚としてはかなり描いたつもりでも実際はあまり描けていないということがあるため、どこに時間が使用されているのかを数値として可視化出来るようにするため本プログラムを作成しています。

本記事の要約

ペン(マウス)とジョイスティック(TABMATE)の操作時間を計測するソフトの解説

計測項目について

 イラストを描いているときの線画作業のみに着目をして計測プログラムを作成しています。また、使用するイラストソフトをCLIP STUDIO PAINTと仮定してます。

CLIP STUDIO PAINTで使用する機器
  • ペンタブレット(マウスと同じ扱い)
  • TABMATE(ジョイスティック扱い)
  • キーボード(ショートカット機能はTABMATEに割り振り)
線画を描いている時の操作
  • ペンタブレットによる入力
  • TABMATEのキーを入力
  • カーソルのみが移動する(ペンタブレットをホバリング)
  • 操作無し

※TABMATEでショートカットを操作するためキーボードによる操作は無しと想定

ソフトの概要

ソフトの機能コンセプト
  • フロントパネル(ソフト画面上)にカーソルがある場合は計測しない
  • 計測開始ボタンが押された場合のみ計測する(一時停止が出来る)
  • 計測数値をリセットすることが可能
  • マウスON時間とカーソルの移動時間は切り分けてある。(同時計測しない)

ソフト注意事項
※ペンタブレットとTABMATEが両方同時に操作されていると両方同時に計測される仕様です。
ソフトを起動する前にTABMATEを起動させておかないと、初期化が行われなていないため反応しません。ソフトを起動する前にTABMATEを起動させてください。

LabVIEW VIファイル配布

LabVIEWファイルをGoogleドライブでダウンロード出来るようにしています。(LabVIEW2019で作成しています。)

https://drive.google.com/file/d/15brf1vmnawUSlQbBwnmbeiXMS2jZt4NL/view?usp=sharing

※使用については自己責任でお願いします。
※今のところ実行ファイルでの配布を予定はしていません。必要な方がもしいれば、Twitterにでも連絡をお願いします。

ソフトの説明

デバイス(ペンやTABMATE)からの入力データをまずは受け取ってから、時間の計算をしています。

生産者(デバイス入力データ)と消費者(時間の計算)で処理を分けた方が良かったりする場合もありますが、今回のプログラムは各工程の処理時間が十分に早いため特に分けていません。(ループ速度は11ms程度なので人が遅延を感じる速度ではありません。)

左から順に解説をしていきます。

フロントパネル制御器と表示器を初期化、計測データ読み込み

「フロントパネルにある制御器と表示器の初期化」と「各種デバイスの初期化」については下記リンク先で説明をしています。
http://canvas-cluster.com/labview-mouse-event-dll/#toc_id_2_1

リンク先では初期化後にリファレンスを閉じていませんでしたが、今回のソフトで初期化後にリファレンスを閉じています。何回も初期化をするわけではないため、リファレンスを閉じていなくても問題にはなりませんが念のため閉じています。

初期化の間にある「データ読み込み」サブVIについてですが、フロントパネル上に表示をさせるために読み込んでいるわけではありません。別の機能として使用するために読み込んでいます。

データの読書き

サブVIをFGV(機能的グローバル変数)の構成で作成をしています。

「読み込んだデータ」と「ファイルパス」を書き込み時にも使用するためWhileループのシフトレジスタ内に保存を行い、次回サブVIが呼び出された際に上記2つのデータ読み込めるようにしています。

「読み込んだデータ」と「ファイルパス」をサブVI内で受け渡しを出来るようにすることでメインVI内にワイヤーを配線しなくてもよくなります。保守性と可読性が良くなります。

データの読込について

ファイルの読み込みについては、TrueがサブVIに入力された場合に有効になります。

機能

・指定のフォルダがない場合はフォルダを作成します。フォルダが存在する場合は何も作成しません。

・指定のファイルが存在しない場合は空ファイルを作成します。存在する場合は何もしません。

上記2点を行っている理由ですが、「文字列スプレッドシート」を用いてデータを読み込むため、ファイルパスが正しくないとエラーが出力されてしまいます。とりあえず、ファイルがあればエラーが出力されないため、ファイルが存在しない場合は空ファイルを作成しています。

実行ファイルをCドライブのProgramフォルダにインストールした場合、実行ファイルの直下にデータ保存することが出来ません。推奨もされていません。そのためファイルパスを各ユーザーのAppData⇒Romingに保存するようにファイルパスを変更する必要があります。(例:C:\Users\%USERPROFILE%\AppData\Roaming\任意フォルダ名/ファイル名)

※ファイルが存在しない場合は、「文字列スプレッドシート」からデータを読み込まないという手段をとることも出来ますが、後でファイルを作成するのが判っているので常に読み込むようにしています。(書き込み側にフォルダとファイル作成の機能を入れるか読込に持ってくるかの違いです。)

データの書き込みについて

データをファイルに書き込むときはシフトレジスタ内に保存されていた「ファイルパス」と「読み込んだデータを」取り出しています。

「読み込んだデータ」に新しい計測データを追加する必要があるため、配列の挿入を使用して最終行に追加してから書き込みを行っています。

プログラムのメインループ

メインループへの入力データは上から順に

入力データ

①以前に計測をしたデータ(通常は使用しない)

②計測開始ボタン用の値、計測開始ボタンが押された場合、Falseにデータが書き換わる。

③デバイスのリファレンスクラスタ

④エラークラスタ

⑤マウスカーソルの位置データ

⑥時間データ(前のループから何秒経過したかを計測するため)

⑦計測データ配列(値の受け渡しがクラスタよりも楽だった)

⑧隠しデータ用:停止ボタンのキャンセル回数を計測

メインループを10msで回している理由ですが、8ms以下だとループ速度が速すぎて、ペンタブレットの入力を取りこぼす場合があったので余裕を持って10msのループ速度にしています。(イベントストラクチャのタイムアウト1msと合わせると約11msでループが回っています。)

処理の分岐についてはイベントストラクチャで全て管理を行っています。各項目と処理の内容は下記の通りです。

イベントストラクチャのケース
  • タイムアウト:各動作の計測を行っています。
  • 計測開始:計測を開始させます。
  • リセット:計測データを初期化します。
  • 終了:プログラムを終了します。
  • パネルを閉じる?:ウィンドウの「×」マークを押された場合の動作(プログラム終了)

イベントストラクチャ:タイムアウト

①計測開始判定
タイムアウト内にあるケースストラクチャが「False」の場合、計測を開始するようにしています。

起動直後は一時停止ボタンとは別のブールを「True」に設定しているため、OR関数から「True」が出力されるように設定を行い、計測が勝手に開始されないようにしています。

計測をしないので、ケースストラクチャの「True」には処理は特にありません。次のループから計測が開始される可能性があるため、計測に使用する時間だけ更新するようにしています。

②デバイスからの出力

ペンタブレット(マウス)やTABMATE(ジョイスティック)からの入力状況を監視しています。デバイスから入力があった場合、出力されているクラスタデータのどれかが「True」で出力されます。

③フロントパネルにマウスカーソルはいるのか?

フロントパネル内にマウスカーソルがいるのかを判定しています。フロントパネル内にマウスカーソルいる場合は計測しないようにするために使っています。

サブVIの詳細な内容については下記リンク先で別プログラムを解説したときに記載をしています。
http://canvas-cluster.com/labview-mouse-event-dll/#toc_id_2_5

④クラスタ及び配列データの処理

デバイスから出力されたクラスタデータは「ブールデータ」ではありますが、キーが入力されたかどうかを判定したいだけなので1つのブールデータにまとめます。

1.クラスタデータを配列に変換

2.配列要素をOR判定してくれる関数に入力

3.クラスタ内のいずれかに「True」があった場合、「True」が出力される

マウスが動いたかどうかについては1つ前のループで取得したマウス座標と現在のマウス座標を比較して判定を行います。

1.現在のマウス座標と前のマウス座標を計算します。

2.マウスの動く方向によってはマイナスになるため、絶対値の関数を使いプラスにします。

3.以上の関数を使い、カーソルが1px以上動いたか?で判定します。

4.カーソルの座標は「X」軸と「Y」軸があるためクラスタで出力されます。

5.後は同じようにクラスタを配列に変換しOR関数でいずれかの方向に動いたかを判定します。

⑤入力データ判定

各デバイスから取得したブールのデータを処理して、「今、何をしているか?」を判定して配列データとして出力をしています。配列データの作成は配列置換を用いてます。

フロントパネルの範囲内?
フロントパネル内にマウスカーソルがある場合、「True」判定され、フロントパネル領域外になると「False」になります。しかし、今回のプログラムではフロントパネル外にマウスカーソルがいる場合を「True」と判定したかったので、「Not関数」を挿入しています。

マウスはクリックされた?
ペンタブレットやマウスがクリックされた場合は「True」が出力されます。

カーソルが移動した?
処理としてはこれが一番複雑な処理です。無駄な処理をしている可能性もある。マウスが入力されている場合は、カーソルが移動したと判定(False)しないようにしています。

また、カーソルが移動していない状態でマウスやジョイスティックからの操作ない場合はカーソル停止として何も行動をしていないという判定(True)にしています。(サボり)

ジョイスティックは操作された?
ジョイスティックからのキー入力があった場合は「True」が出力されます。

⑥計測時間を加算処理

各デバイスのキー入力状況が配列で出力されているためForループに指標配列で入力することでForループのループ回数を決めています。

※厳密には並列でForループ内の処理をした方が計測誤差が出にくいので良いとは思いますが、十分早く処理出来るので無視してます。

基本的にはフロントパネル外でキー入力があった場合(AND関数)は、計測時間に加算を行ったデータをForループ外へ出力をします。(フロントパネル外でカーソルが動いていない場合は対象)
フロントパネル内やキー入力がない場合は元々のデータをそのまま出力します。

⑦カーソル停止(サボり時間)

何となくで作ったサブVIです。サボり時間が一定の時間になるとビープ音とダイアログが表示されます。

10分以上、30分以上、60分以上になった場合に表示されます。

条件の時間範囲で、何度もビープ音とダイアログが表示されるのは、邪魔なので、「初めて呼び出す?」関数を使用して一度だけしか表示しないようにしています。

問題があって、ダイアログのOKボタンを押すまでは計測が止まってしまいます。解決策としてはサブVIのフロントパネルをダイアログの代わりとして表示をするという方法があります。
https://forums.ni.com/t5/LabVIEW/How-to-create-modeless-dialog/td-p/575206?profile.language=en

イベントストラクチャ:タイムアウト内の計測関連処理については以上です。あとは、簡単な処理を少ししているだけです。

イベントストラクチャ:計測開始

計測開始ボタンが押された場合のイベントストラクチャです。

計測開始ボタンの旧値(False)をイベントストラクチャ:タイムアウトにあるOR関数へ入力を行い、計測を開始できるようにします。

Falseの定数をそのまま入力しても良かったのですが、旧値から入力することにしました。ボタンをラッチではなくスイッチにしている場合は、定数を使用する必要があります。

計測を開始するのに一時停止ボタンが押されたままの状態では都合が悪いので、計測開始ボタンが押された場合、強制的に一時停止を解除するようにしています。
一時停止のプロパティノードの「値」をFlaseに変更します。

イベントストラクチャ:リセット

イベントストラクチャのリセットでも一時停止にFalseを入力して一時停止を解除しています。

リセットは計測データを破棄して計測データのデータフローに「0(ゼロ)」を入力して初期化しています。

イベントストラクチャ:終了

終了ボタンが押された場合にプログラムがそのまま終了すると間違えた押した可能性もあるため、「本当に終了するのか?」を確認するようにダイアログを表示するようにしています。

ダイアログボックスの「はい」が押された場合はダイアログから「True」が出力されるためプログラムは終了します。「いいえ」の場合は「False」が出力されるのでプログラムは継続します。

このイベントストラクチャ内に隠し機能として、今までの計測データを表示するためのサブVIを仕込んでいます。
隠し機能なので、通常は行わないような手順を組み込むべきですが今回は、終了ボタンのプログラム終了を累計で5回キャンセルした場合に出現するようにしています。

ダイアログの「いいえ」を押すと「False」が出力され、その場合のみカウントアップを行うようにプログラムを組んでいます。累計で5回以上になった場合、ケースストラクチャがTrueになり、サブVIが呼び出されます。

サブVIのフロントパネルを呼び出す方法は「サブVIを右クリック」⇒「サブVIノード設定」⇒「呼び出されたらフロントパネルを表示」で表示します。

適当に作った機能なので複雑なことはせずに、計測データの配列データをグラフで表示しているだけです。1列目にある時間のデータがグラフ表示では不要なので、2D配列を転置して、不要な行をまとめ削除して、再度転置しています。(あまり綺麗な処理じゃないかも)

という簡単な隠し機能です。

イベントストラクチャ:パネルを閉じる?

終了ボタン以外に、ウィンドウの右上(Windowsの場合)にある「×」マークでウィンドウを閉じる場合にもダイアログでプログラムを終了するのが確認するようにしています。

ダイアログで「はい」を押した場合は、プログラムが終了します。「いいえ」ならプログラムは継続します。

メインループ終了後

メインループが終了した場合、開いているデバイスのリファレンスを全て閉じます。

また、計測データを書き込んで、最後にエラーがもし有る場合はエラーを表示するようにします。特にエラーが無ければ何も表示されずに終わります。

最後に

イラストの線画を描いているときどの作業に最も時間がかかっているかを、本ソフトを使用して確認をしたところ下記のような結果となりました。「下書き⇒線画」での作業結果となります。

1時間集中して作業を行ったつもりですが、約1/5は何もしていない時間が存在しました。

迷ったりして考え事をしている時間のようです。