2011-07-22 5 views
5

私はOSXで高解像度と高フレームレートでマウスの動きを取得したいと思います。OSXでの高解像度と高いフレームレートのマウス座標? (または他の解決策?)

"ハイフレームレート" = 60 FPS以上(好ましくは> 120)
"高解像度" =サブピクセルは

値問題
私はおよそモニターのリフレッシュレートで実行されているOpenGLのビューを持っていますしたがって、〜60 fpsです。私は周りを見回すためにマウスを使用するので、私はマウスのカーソルを隠して、私はマウスのデルタ値に頼っています。

問題は、マウスイベントが非常に低いフレームレートで入力され、値が整数(ピクセル全体)にスナップされることです。これにより、「不安定な」視聴体験が発生します。ここで時間をかけて、マウスのデルタ値の可視化です:

mouse delta X 
    ^    xx 
    2 |  x x x  x xx 
    | x x x x    xx x x x 
    0 |x-x-x--xx-x-x-xx--x-x----x-xx-x-----> frame 
    | 
-2 | 
    v 

これが右にマウスを少し動かすユーザから作成した典型的な(短縮)曲線です。各xは各フレームのdeltaX値を表し、deltaX値は整数に丸められているため、このグラフは実際にはかなり正確です。見て分かるように、deltaXの値は1つのフレームで0.000、次に1.000であるが、再び0.000、次に2.000、そして再び0.000、そして3.000,0.000などとなる。

これは、ビューが2.000単位を1フレーム回転させ、次に0.000単位を回転して3.000単位を回転することを意味します。これは、マウスが多かれ少なかれ一定速度でドラッグされている間に発生します。言うまでもなく、これはやっかいなようです。

どうすれば1)マウスのイベントフレームレートを増やすことができますか? 2)サブピクセル値を取得する?

は、これまでのところ
私は次のことを試してみた:

- (void)mouseMoved:(NSEvent *)theEvent { 
    CGFloat dx, dy; 
    dx = [theEvent deltaX]; 
    dy = [theEvent deltaY]; 
    // ... 
    actOnMouse(dx,dy); 
} 

まあ、これは明らかでした。 dxここではfloatですが、値は常に丸められます(0.000,1.000など)。上記のグラフが作成されます。

次のステップは、WindowServerに入る前にマウスイベントを試してみることでした。私はイベントの発火率が少し高くなっていると考えているものの、

eventMask = (1 << kCGEventMouseMoved); 
eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 
      0, eventMask, myCGEventCallback, NULL); 
//... 
myCGEventCallback(...){ 
    double dx = CGEventGetDoubleValueField(event, kCGMouseEventDeltaX); 
    double dy = CGEventGetDoubleValueField(event, kCGMouseEventDeltaY); 
} 

はまだ値がn.000次のとおりです。だから私はCGEventTrapを作成しました。しかしそれはまだ60 fpsではありません。私はまだ上記のチャートを取得します。

また、マウスの感度を高く設定してから、私の側で値を下げてみました。しかし、OSXはある種の加速や何かを追加しているようだ。値は本当に「不安定」になり、結果的には使えなくなり、火の速さはまだまだ低い。

私は運がないので、ウサギの穴の中でマウスのイベントに従っています。私はIOKitに到着しました。これは私のために怖いです。それは狂ったことだ。アップルのドキュメントは奇妙になり、「もしあなたがこの深いところにいるなら、本当に必要なのはヘッダファイルだ」と言われるようです。

私はヘッダーファイルを読んでいます。そして私はいくつかの面白い小物を見つけました。ライン377上の<IOKit/hidsystem/IOLLEvent.h>

この構造体があります:

struct { /* For mouse-down and mouse-up events */ 
    UInt8 subx;  /* sub-pixel position for x */ 
    UInt8 suby;  /* sub-pixel position for y */ 
    // ... 
} mouse; 

を参照してください、それはサブピクセル位置を言います! OK。その後、73行目に<IOKit/hidsystem/IOLLParameter.h>

#define kIOHIDPointerResolutionKey  "HIDPointerResolution" 

Hmm。

OSXはサブピクセルのマウス座標を深く知っていると感じています。マウスの生の動きをフレームごとに読み取る方法が必要ですが、それらを取得する方法はわかりません値。

質問
私は何を求めていますか?

  • OSXで高いフレームレートのマウスイベントを取得する方法はありますか? (例コード?)
  • OSXでサブピクセルのマウス座標を取得する方法はありますか? (例コード?)
  • フレームごとに「生の」マウスデルタを読み取る方法はありますか? (つまり、は、はイベントに依存しません)
  • NXEventsを取得する方法、またはHIDParametersを設定する方法はありますか?コード例?マックOS Xは、解像度に依存しないように設計されているため(だから私は自分自身でこれを深く掘ることができます...)

(長い記事のために申し訳ありませんが)

答えて

1

サブピクセル座標の可能性が存在します。スクリーン上の2x2ハードウェアピクセルの正方形はソフトウェア内の単一の仮想ピクセルを表すことができ、カーソルを(x + 0.5, y + 0.5)に置くことができる。

通常の1倍スケーリングを使用する実際のMacでは、マウスカーソルを画面上の小数点ピクセル位置に移動できないため、サブピクセル座標は表示されません。マウスの移動量は正確に1ピクセルです。

1

ポインターデバイスのデルタ情報にアクセスする必要がある場合は、イベントディスパッチシステムより低いレベルでuser-space USB APIsを使用する必要があります。

1

あなたは二重の値を取得するためにこれを使用することができ、マウス用のIOHIDDeviceのコールバックを使用している場合:

double doubleValue = IOHIDValueGetScaledValue(inIOHIDValueRef, kIOHIDTransactionDirectionTypeOutput); 
5

を(これは非常に遅く答えですが、私が考える1はまだその他人のために有用ですこれに遭遇します。)

マウス入力をフィルタリングしましたか?これは、フィルタリングが遅れと精度の間のトレードオフになる傾向があるため、扱いにくいことがあります。しかし、何年も前、私はマウスの動きをどのようにフィルタリングし、ゲーム開発サイトの記事を書いたのかを説明した記事を書いた。リンクはhttp://www.flipcode.com/archives/Smooth_Mouse_Filtering.shtmlです。ここ

そのサイトが活発に開発されなくなっている(と離れて行く場合があります)ので、関連の抜粋です。ほとんどの場合には


、フィルタリングは、平均化を意味します。しかし、単に時間の経過とともにマウスの動きを平均化すると、遅れが導入されます。どのように副作用を導入することなく、どのようにフィルタリングしますか?さて、平均化を使用しますが、いくつかのインテリジェンスでそれを行います。同時に、ユーザーがフィルタリングを細かく制御できるようにして、調整することができます。

平均化されたマウス入力の非線形フィルタを使用します。ここでは、古い値がフィルタリングされた結果に与える影響がより小さくなります。それはあなたがマウスを動かすかどうかにかかわらず、すべてのフレーム

仕組み

、我々は、履歴バッファに現在のマウスの動きを入れて、最も古い履歴値を削除します。したがって、私たちの履歴には常にXのサンプルが含まれています。ここで、Xは「履歴バッファーサイズ」であり、時間の経過とともにサンプリングされた最新のマウスの動きを表します。

ヒストリバッファサイズを10に設定し、バッファ全体の標準平均を使用した場合、フィルタは多くの遅延を導入します。 60FPSマシンでは、マウスの動きが速く、1/6秒遅れます。速いアクションゲームでは、これは非常にスムーズですが、事実上使用できません。同じシナリオでは、2のヒストリバッファサイズは、遅れはほとんどありませんが、フィルタリングは非常に貧弱です(プレーヤーの反応が荒く、ジャッキーです)。

非線形フィルタは、この相互排他的なシナリオと戦うためのものです。アイデアはとてもシンプルです。ヒストリバッファのすべての値を等しく盲目的に平均化するのではなく、重み付けして平均化します。まず、1.0のウェイトから始めます。したがって、ヒストリバッファの最初の値(現在のフレームのマウス入力)はフルウェイトです。次に、このウェイトに「ウェイトモディファイア」(たとえば... 0.2)を掛け、ヒストリバッファの次の値に移動します。さらに時間が経つにつれて(私たちの歴史バッファーを通って)、値は最終的な結果に及ぼす重さ(影響力)がますます小さくなります。

現在のフレームのサンプルは100%の重量を持ち、前のサンプルは50%の重量を持ち、次の最も古いサンプルは25%の重量を持ち、次のサンプルは12.5%の重量を持ちます等々。これをグラフ化すると、曲線のように見えます。したがって、重み変更の背後にあるアイデアは、履歴のサンプルが古くなると曲線がどれほど急激に下がるかを制御することです。

遅れを減少させることは、重量調節剤を減少させることを意味する。ウェイトモディファイアを0にすると、フィルタリングされていない生のフィードバックがユーザに提供されます。 1.0に増加すると、結果はヒストリバッファ内のすべての値の単純な平均になります。

細かい制御のために、履歴バッファーサイズと重量修飾子の2つの変数をユーザーに提供します。私は履歴バッファーのサイズを10にする傾向があり、私が幸せになるまでは体重変更子で遊んでいるだけです。

関連する問題