3

先日、SDLマルチメディアライブラリを使用して小さなC ++プログラミングをコーディングしようとしていたところ、この小さな問題に遭遇し、最終的に試行錯誤で解決しました。問題は、私が問題を解決するために何をしたかは理解しているが、問題の性質は本当に理解していないということです。

問題は、SDLでのキーボードイベント処理にありました。プログラムを終了するための1回のキー押下を処理するコードは単純明快です。[eventQueueはSDL_Event構造体です]

//checks for keypress events..
if ( eventQueue.type == SDL_KEYDOWN )
{ 
    //note: uses the boolean logical '==' equals operator..
    if ( eventQueue.key.keysym.sym == SDLK_ESCAPE )
    {
        running = false;
    }
}

上記のコードでは、ESCAPEキーを単独で押すだけでメインループが終了し、プログラムがクリーンアップされて閉じます...

ただし...修飾キー(shift / alt / ctrl)を使用するキー押下を処理するために必要なコードは、「==」演算子では正しく機能しませんでした。等式(論理?)演算子の代わりにビット単位のAND演算子を使用する必要があることを知るのに何年もかかりました。

//checks for keypress events..
if ( eventQueue.type == SDL_KEYDOWN )
{ 
    //note: requires the use of the bitwise AND operator..
    if (( eventQueue.key.keysym.mod & KMOD_ALT ) && (eventQueue.key.keysym.sym == SDLK_F4 ))
    {
        running = false;
    }
}

ここでの私の混乱は、「keysym.sym」メンバーを使用する場合は論理演算子「==」が正常に機能するが、「keysym.mod」メンバーを使用する場合は「&」を使用する必要があるという事実に起因します。ビットごとのAND演算子。

さて、推測しなければならないのは、「keysym.sym」がキーボードの単一のキーを表す単一の数値を処理するだけでよいのに対し、「keysym.mod」はShiftキー、Ctrlキー、Altキーのさまざまな組み合わせを処理するには...?

私の質問を要約すると、なぜこれが当てはまるのですか?試行錯誤以外に、特定のデータをビット演算子または論理/等式演算子と比較する必要があるかどうかを知る方法はありますか?「keysym.sym==SDLK_F4」は正常に機能するのに、「keysym.mod == KMOD_ALT」は機能しないのはなぜですか?10進数を含む演算が、ビット値を比較する演算とは異なる結果になるのはなぜですか?論理演算が機能し、ビット演算が機能しない状況もありますか?

4

3 に答える 3

5

ビット単位のANDはやや特殊です。==等しいかどうかをチェックしますが、ビット単位のAND演算子を使用すると、数値の個々のビットを操作できます。

イベントがキーのリストとして定義されていると想像してください。

event = ['a', 'shift', 'ctrl']

次に、特定の修飾子がイベントの一部であるかどうかを簡単に確認できます。

if 'shift' in event:
  # ...

inビット単位のANDは、ステートメントのようなものです。イベントは、次のように2進数として定義できます。

event = 00010010

これで、ビット単位のANDを実行すると、修飾子も2進数として表されるため、特定の修飾子がイベントに適用されているかどうかを簡単に確認できます。

  00010001  # event (18)
& 00010000  # shift key (8)
----------
  00010000  # you get a non-zero answer, so the shift key is in the event
----------

  00010001  # event (18)
& 00001000  # "z" key (4)
----------
  00000000  # you get zero because the "z" key wasn't a part of the event
----------

ビットごとのORを使用して、次のようなイベントを作成できます。

  00000001  # shift key (1)
| 10100000  # "a" key (160)
----------
  10100001  # resulting event (161)
----------

ウィキペディアはビット演算をかなりうまくまとめています:

ビット単位の演算は、個々のビットのレベルで1つ以上のビットパターンまたは2進数を操作します。これは、プロセッサによって直接サポートされる高速でプリミティブなアクションであり、比較や計算のために値を操作するために使用されます。単純な低コストのプロセッサでは、通常、ビット単位の演算は除算よりも大幅に高速で、乗算よりも数倍高速であり、加算よりも大幅に高速な場合があります。最近のプロセッサは、命令パイプラインやその他のアーキテクチャ設計の選択が長いため、通常、ビット単位の演算と同じ速度で加算と乗算を実行しますが、ビット単位の演算は、リソースの使用量が少ないため、通常、消費電力/パフォーマンスが低くなります。

基本的に、ビット演算子を使用すると、整数のビットに格納されている情報を効率的に処理できます。

于 2012-08-14T03:57:53.247 に答える
3

ここで何をしたか

eventQueue.key.keysym.mod & KMOD_ALT

比較操作ではなく、ビットマスキング操作です。比較操作は、CおよびC ++では暗黙的です。ゼロと評価される式は「false」を意味し、ゼロ以外の値はすべて「true」を意味します。あなたのような論理式で使用される場合、これはの省略形です

(eventQueue.key.keysym.mod & KMOD_ALT) != 0

次にビット演算について説明します。特定の値は、2つ以上の値のビットの組み合わせを表します。たとえば、keysym.symALTのビットパターン(それ自体は左右のALTの組み合わせ)と、同時に押すことができる他のキーの組み合わせを表します。組み合わせから1つの値を分離するために、ビットマスキング手法が使用されます。対象のビットに1があり、他のすべてのビットに0がある値(つまりKMOD_ALT)は、組み合わせ値(あなたの場合は)とAND演算されますkeysym.sym。のsでkeysym.sym示されるビットののビット。1KMOD_ALT

最終的な結果はeventQueue.key.keysym.mod & KMOD_ALT、ALTが押された場合にのみゼロ以外になります。

于 2012-08-14T03:57:13.960 に答える
1

免責事項:私はSDLについてほとんど何も知りません。私がここで答えているのは、主に当て推量からです。

キーボードには、他にいくつのキーが押されてもキーイベントを生成すると予想されるキーがいくつかあります。Shift、、などの修飾キーはそのようなキーAltCtrlあり(他にあるかどうかはわかりません)、キーボードの製造元はそれらを同時に押すことができることを確認する必要があります。残りのキーは通常のキーであり、各キーボードの回路に応じて、同時に押すとキーイベントが生成される場合と生成されない場合があります。

通常のキーが押されると、キーイベントがトリガーされます(修飾キーを押すとイベントがトリガーされるかどうかはわかりません)。通常のキーがsym入力されており、通常のキーが押されたときに修飾キーが押されているかどうかがに記録されmodます。実装に関しては、mod特定の修飾キーが押されているかどうかを定義するために、の特定のビットが使用されていることは間違いありません。ビットがオンになっているかどうかを確認するには&、修飾キーが押されているかどうかを示すために使用されるビットを定義する定数を使用してビット単位で指定する必要があります。

于 2012-08-14T04:00:51.937 に答える