特定の条件下において、InputActionのbConsumeInputをfalseにしても複数のIMCに入力がこない

お世話になっております。

複数のIMCを設定した場合の挙動について質問があります。

同様の設定であるInputAction A と B があり​、それぞれ同様のキーを別々のIMCで設定してあるとします。

BにのみChorded Actionで同時押しのみ入力が有効となるよう設定し、​AよりBのMappingContextのPriorityを高く設定する場合、

Bの入力が有効になるとAの入力がこなくなります。

InputActionのbConsumeInputはfalseにしているので、Priorityが低く入力がこないといったわけではなさそうなんですが、

何か手順に不備などありますでしょうか?​

再現手順
​【症状確認手順】

  1. 添付の「SampleProject」を起動してください
  2. ThirdPersonMap.umapを開いてください
  3. BP_ThirdPersonCharacter.uassetを開き、変数 IsOverPriorityのデフォルト値をfalseにしてください
  4. PIEを起動し、Shift+移動キーでキャラクターが操作できることを確認してください
  5. BP_ThirdPersonCharacter.uassetを開き、変数 IsOverPriorityのデフォルト値をtrueにしてください
  6. ​PIEを起動し、Shift+移動キーでキャラクターが操作できないことを確認してください

​【変更箇所】

  • 変更:/Game/ThirdPerson/Input/Actions/IA_Move.uasset
    • bConsumeInputをfalseに変更
  • 変更:/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.uasset
    • AddMappingContextにてIMC_Testを追加
      • 変数 IsOverPriorityにて、IMC_TestをIMC_DefaultよりPriorityを大きくするか分岐するようにしています
  • 追加:​/Game/ThirdPerson/Input/Actions/IA_Trigger.uasset
    • IA_Testの同時押し用に追加
  • 追加:​/Game/ThirdPerson/Input/Actions/IA_Test.uasset
    • IA_Moveの内容をそのままコピーし、Chorded Actionを追加で同時押しのみ入力が有効となるよう設定
  • 追加:​/Game/ThirdPerson/Input/IMC_Test.uasset
    • IA_TriggerはShift、IA_TestはIMC_DefaultのIA_Moveと同様のキーを設定

お世話になっております。

ご質問および、大変使いやすい再現プロジェクトのご提供、誠にありがとうございます。

本件ですが、Enhanced Input Systemの仕様によるものです。

同システムでは、Chord Action をトリガーに組み込んだアクション(e.g. IA_Test)にバインドされたキー(e.g. WASD、上下左右、左サムスティック)と同じキーがバインドされた下位優先度のアクション(e.g. IA_Move)の成立を、誤トリガー防止のために強制的にブロックする機構が存在しております。

参考:

これは、UInputTriggerChordBlockerと呼ばれる内部使用専用のトリガーが、暗黙的に対象アクションに挿入されることによって実現されております。

https://dev.epicgames.com/documentation/en\-us/unreal\-engine/API/Plugins/EnhancedInput/UInputTriggerChordBlocker

※ IEnhancedInputSubsystemInterface::InjectChordBlockers()も参照

従いまして、AとBの両方の入力を同時成立させたい用途がある場合は、Bの入力優先度をAより低く設定していただく必要があります。また、[Shift] + [WASD]でダッシュ、単に[WASD]で歩く、のような操作系を実現する場合はChord Actionではなく、Shiftだけの単体入力アクションをとってゲームロジック側で処理する方法が無難となります。

以上、よろしくお願いいたします。

お世話になっております。

回答のご確認および追加のご質問ありがとうございます。

> 1.Chord Actionをトリガーに組み込んだアクションを同じPriorityに複数設定されている場合について

> Chord Actionをトリガーに組み込んだアクションを同じPriorityに複数設定されている場合について、

> 同優先度のアクションにはブロックする機構の影響を受けない認識なんですが、合っていますでしょうか?

Chord Actionをトリガーに組み込んだアクションを同じPriorityに「複数」設定するというのは、具体的にどのような設定を指しているかお尋ねしてもよろしいでしょうか。

複数設定の件を置いておきますと、同優先度のアクションであっても、同じInput Mapping Context (IMC)に設定されたアクション間であれば、ブロックする機構は機能します。

たとえば、「A=パンチ、 B=キック、 A + キック​ = スペシャル攻撃」のような設定が同じIMCに設定されていた場合(下線部がChord Actionで指定されたアクションとする)、スペシャル攻撃は同じキーを使用する「パンチ」をブロックします。ほか、この例で考えられる挙動としては、

・あるIMC_01に「A=パンチ、B=キック」を設定し、別のIMC_02に「A + キック​ = スペシャル攻撃」を設定した場合、IMC_02の優先度をIMC_01より明確に下げなければスペシャル攻撃はトリガーされません。これはIMC_02を評価する前にIMC_01を評価しておかないとChord Actionが成立しないためです。

・同じ設定例でIMC_01とIMC_02を同じ優先度でAdd Mapping Contextした場合、「同じ優先度」であるためIMC間の明確な優先度がつけられず、結果としてIMC_02がIMC_01より先に評価される(スペシャル攻撃が絶対にトリガーされなくなる)ことがあります。IMCに同じ優先度を振っても、同じIMCとして同一視できるよう「マージ」されるわけではない(どちらを先に評価すべきかのヒントをエンジンに与えてないだけという結果になる)という点にご注意ください。

> 2.InputActionのbConsumeInputが無視される場合について

> Chord ActionのようにInputActionのbConsumeInput関係なく、

> 下位優先度のアクションをブロックされるような状況があれば教えていただきたいです。

Chord Actionは現状唯一の例外と言ってよく、ほかはbConsumeInputのOn/Offで意図通り制御できるかと思います。

なお、コンソールコマンドで「ShowDebug EnhancedInput」​を実行しますと、インゲームのビューポートに現在有効なIMCとそのIMC内で設定されたアクション、キーバインド、アクションのステータスをデバッグ文字表記でモニタリングできるようになります。ブロック用トリガーが機能しているかどうかなどの細かい状況まではつかめないのですが、IMC間の優先度の把握ができ、設定が意図通り機能しているかどうかを比較的容易につかめるかと思いますので、必要に応じてご活用ください。

以上、よろしくお願いいたします。

お世話になっております。

詳細にご説明いただき誠にありがとうございます。おかげさまで理解が深まり、大変助かりました。

また、コンソールコマンドについても活用させていただきます。

> Chord Actionをトリガーに組み込んだアクションを同じPriorityに「複数」設定するというのは、具体的にどのような設定を指しているかお尋ねしてもよろしいでしょうか。

説明不足で申し訳ございません。

InputAction A と B と Cがあり、同時押し用のInputAction Trigger_B、Trigger_Cがあります。

IMC_01に「A」、IMC_02に「B 、Trigger_B」、IMC_03に「C 、Trigger_C」があり、

A と B と Cは同じ入力キー、Trigger_B と Trigger_Cは同じ入力キーに割り当てているとします。

(下線部がChord Actionで指定されたアクションでトリガーとなるアクションは同じIMCに設定されているものを使用しています)

以上の条件でAddMappingContextを行う際、Priorityの関係がIMC_01 > IMC_02 = IMC_03となる場合について、

手元で確認したところ、すべてのアクションが機能していたため、Chord Actionで指定されたアクションについては

同優先度のアクションのブロックする機構の影響を受けないように感じました。

こちら認識間違っておりますでしょうか?

(追加で調査したところ、IMC_01 > IMC_02 > IMC_03の場合についてもすべてのアクションが機能していたため、Chord Actionで指定されたアクション同士はブロックする機構の影響を受けないんでしょうか?)

以上、よろしくお願いいたします。

お世話になっております。

設定例のご提示ありがとうございます。

> 以上の条件でAddMappingContextを行う際、Priorityの関係がIMC_01 > IMC_02 = IMC_03となる場合について、

> 手元で確認したところ、すべてのアクションが機能していたため、Chord Actionで指定されたアクションについては

> 同優先度のアクションのブロックする機構の影響を受けないように感じました。

> こちら認識間違っておりますでしょうか?

当方の手元で確認したところ、IMC_02とIMC_03が同じプライオリティであったとしても、結果的にメモリ上で先になったIMCが、後に置かれたIMCのChordedマッピング(※Chorded Actionをトリガーに持つアクション)をブロックしました。よって、ご提示いただいたような「ブロック影響のなさ」は、通常の設定では起こりえないと認識しております。

[Image Removed]当方で作成したプロジェクトを本投稿に添付しましたのでご確認ください。プロジェクトを開き、PIEをスタートさせると自動的にShowDebug EnhancedInputが有効になり、テストが可能になります。1キーをIA_A、IA_B、IA_Cに、2キーをTrigger_B、Trigger_Cに割り当てています。IA_BおよびIA_CはトリガーにChorded Actionを持ち、それぞれTrigger_BとTrigger_Cを指定しています。

お手元ですべてのアクションが有効になったというケースはまた何か別の条件によるものではないかと思います。再現プロジェクトをご提供いただければ、調査いたします。

なお、IMC追加時に与えるPriorityはあくまでソート上のヒントであって、同じPriorityを付与したIMCがあっても、どちらかが配列内で先に置かれてしまう以上、必ず優劣がつきます。今回の再現プロジェクトでは、IMC_01 (優先度10)、IMC_02 (優先度 0)、IMC_03(優先度0)としましたが、結果的に IMC_01 > IMC_03 > IMC_02 というソート結果となり、IMC_03に優先度5などを与えた場合と同じ処理結果になっております。

// エンジンに実装されたIMCをソートするコード // 優先度が同じ2つのIMCがあっても、1つのIMCにマージはされず、 // どちらかが先にソートされる OrderedInputContexts.ValueSort([](const int32& A, const int32& B) { return A > B; });> (追加で調査したところ、IMC_01 > IMC_02 > IMC_03の場合についてもすべてのアクションが機能していたため、Chord Actionで指定されたアクション同士はブロックする機構の影響を受けないんでしょうか?)

ブロックが生じるのは、「Corded Actionをトリガーに持つマッピングと、同じキーを持つもの」となります。この条件に当てはまる場合、Chorded Actionで指定されたアクションもブロックの対象となります。

[Image Removed]

誤認識を防ぐために、エンジン内部で用いられている名称を元に、用語として、

・TriggerにChorded Actionを持つマッピングを「Chordedマッピング」

・Chorded Actionトリガーで指定されたアクションを「Chordingアクション」

・Chordingアクションに紐づけられたマッピングを「Chordingマッピング」

と整理したいと思います。UInputTriggerChordBlockerの暗黙的な注入は、Chordedマッピングと同じキーを持つ、後優先のマッピングすべてに対して行われます。今回の場合は、IMC_02の「1 - IA_B」がそれに相当しましたが、仮にIMC_02のマッピングを「1 - Trigger_B」「2 - IA_B」のように入れ替えますと、今度は「Trigger B」が(たとえChorded Actionで指定されたアクション=Chording アクション/マッピングだとしても)ブロックされます。

[Image Removed]参考までに該当処理のエンジンコードを下に引用いたします。ブロッカーの注入がマッピング(アクション)の種類をチェックせずに行っていることがご確認いただけるかと思います。

`// Inject chord blockers into all lower priority action mappings with a shared key
for (int32 MappingIndex : ChordedMappings)
{
FEnhancedActionKeyMapping& ChordMapping = PlayerInput->EnhancedActionMappings[MappingIndex];
for (int32 i = MappingIndex + 1; i < PlayerInput->EnhancedActionMappings.Num(); ++i)
{
FEnhancedActionKeyMapping& Mapping = PlayerInput->EnhancedActionMappings[i];
if (Mapping.Action && Mapping.Key == ChordMapping.Key)
{
// If we have no explicit triggers we can’t inject an implicit as it may cause us to fire when we shouldn’t.
auto AnyExplicit = (const UInputTrigger* Trigger) { return Trigger->GetTriggerType() == ETriggerType::Explicit; };
if (!HasTriggerWith(AnyExplicit, Mapping.Triggers) && !HasTriggerWith(AnyExplicit, Mapping.Action->Triggers))
{
// Insert a down trigger to ensure we have valid rules for triggering when the chord blocker is active.
Mapping.Triggers.Add(NewObject());
Mapping.Triggers.Last()->ActuationThreshold = SMALL_NUMBER; // TODO: “No trigger” actuates on any non-zero value but Down has a threshold so this is a hack to reproduce no trigger behavior!
}

UInputTriggerChordBlocker* ChordBlocker = NewObject(PlayerInput);
ChordBlocker->ChordAction = ChordMapping.Action;
// TODO: If the chording action is bound at a lower priority than the blocked action its trigger state will be evaluated too late, which may produce unintended effects on the first tick.
Mapping.Triggers.Add(ChordBlocker);
}
}
}`一度ご確認ください。

以上、よろしくお願いいたします。

お世話になっております。

​サンプルプロジェクト及び、詳細な説明ありがとうございます。

いただいたサンプルプロジェクトから、ブロックする挙動について確認することが出来ました。

**>お手元ですべてのアクションが有効になったというケースはまた何か別の条件によるものではないかと思います。再現プロジェクトをご提供いただければ、調査いたします。**​

お伝えしていた現象についての再現プロジェクトを添付いたしましたので、ご確認お願いいたします。

WASDキーをIA_A、IA_B、IA_Cに、ShiftキーをTrigger_B、Trigger_Cに割り当てており、

IA_BおよびIA_CはトリガーにChorded Actionを持ち、それぞれTrigger_BとTrigger_Cを指定しています。

また、​再現プロジェクト作成途中に一部現象に誤りがあったので、補足させていただきます。

すべてのアクションが機能しているとお伝えしておりましたが、一部はブロックが発生していたようです。

再現プロジェクトではShift+WASキーで機能し、Shift+Dキーでは機能しない挙動をしておりました。

こちらの現象について、何か設定間違いなどで発生しているのでしょうか?​

[Image Removed]​

以上、よろしくお願いいたします。​

お世話になっております。

再現プロジェクトのご提供をありがとうございます。

調査してみたところ、入力アクション側のトリガーにChordedActionが仕込んである場合、仕様通り各種機能が動作しないことが分かりました。

ご確認用に、IA_B、IA_C側のChordedActionを外し、すべてInput Mapping Context側にChordedActionを仕込みなおした改変プロジェクトを添付いたしました。こちらでは上述の説明通りにブロッカーが動作するかと思います。

不具合と思われますので、報告の準備が済み次第、バグトラッカーで社内報告を進めて参ります。

本日すぐにご案内できる回避策としては(大変ご面倒だと思うのですが)、アクション側のトリガーではなくInput Mapping Context側のマッピングのトリガーでChorded Actionを設定していただく、、、ということになるかと存じます。

以上、取り急ぎご連絡申し上げます。

お世話になっております。

返信遅くなり申し訳ありません。

サンプルプロジェクトありがとうございます。

説明していただいた通り、ブロッカーが動作すること確認できました。

頂いたサンプルプロジェクトのIMC_03のような下位のPriorityの場合についても入力が効くようにしたい場合、

下記コードをコメントアウトすることで解決するのですが、こちらの対応方法に何かリスクはありますでしょうか?

また、別途よい方法などあれば教えていただきたいです。

UInputTriggerChordBlocker* ChordBlocker = NewObject<UInputTriggerChordBlocker>(PlayerInput); ChordBlocker->ChordAction = ChordMapping.Action; // TODO: If the chording action is bound at a lower priority than the blocked action its trigger state will be evaluated too late, which may produce unintended effects on the first tick. Mapping.Triggers.Add(ChordBlocker);

お世話になっております。

ご返信いただきありがとうございます。

こちらの現象について、Enhanced Input Systemの仕様ということで承知いたしました。

誤解を招くサンプルで申し訳ないのですが、実際には歩きとダッシュを切り替えたいのではなく、

インゲームからポーズなど様々な入力の遷移管理が複雑になってしまうことから、

関連するIMCを一度にセットを行うよう変更したいため、質問させていただきました。

また、追加でこちらからいくつか質問させてください。

1.Chord Actionをトリガーに組み込んだアクションを同じPriorityに複数設定されている場合について

Chord Actionをトリガーに組み込んだアクションを同じPriorityに複数設定されている場合について、

同優先度のアクションにはブロックする機構の影響を受けない認識なんですが、合っていますでしょうか?

2.InputActionのbConsumeInputが無視される場合について

Chord ActionのようにInputActionのbConsumeInput関係なく、

下位優先度のアクションをブロックされるような状況があれば教えていただきたいです。

以上、よろしくお願いいたします。

お世話になっております。

エンジン改造で​UInputTriggerChordBlockerの挿入処理自体をオミットする場合、シンプルにInjectChordBlockers()関数の呼び出し側をコメントアウトしていただく形も取れるかと思います。

// ここをコメントアウト // InjectChordBlockers(ChordedMappings);リスクについてですが、改めてブロックの仕組みをふりかえりますと、このブロック処理は「 A+B ボタンの同時押し操作が成立しているときは、Aボタン操作を成立させない」といった措置を実現するためにあります。あまり適切なたとえではありませんが、たとえば文字打ち込みの仕事をしている場面を考えた場合、Shift + W を押したときに、「Ww」とw入力が2回反映されると、困る場合もあるかと思います。Chord Blockerのコメントアウトのリスクは、同時押しをしたときに2つのアクションがトリガーされる展開をエンジン側で防げなくなる、という点が挙げられるかと存じます。

逆に申し上げますと、リスクはそれだけですので、「ブロックされる方がかえって困る」​「不都合なアクションの暴発は、自前で管理して排他する」のであれば、大きな問題はないかと思います。また、別の改造案として、(Chorded Actionでは通常無視される)bConsumeInputのフラグチェックを追加し、true時のみブロッカーの​挿入を従来通り行う、というアプローチも考えられます。

// 以下のif文を改造 // if (Mapping.Action && Mapping.Key == ChordMapping.Key) if (Mapping.Action->bConsumeInput && Mapping.Action && Mapping.Key == ChordMapping.Key)

なお、Chord BlockerがInput Mapping Contextで追加したChorded Actionでなければ正しく機能しなかった件は、社内でバグ報告を行いました。Public Issue化の承認が下り次第、下記URLで修正状況を追跡いただけるようになります。

以上、よろしくお願いいたします。​

お世話になっております。

対応のリスク、バグトラックについて承知いたしました。

また、教えていただいたフラグチェックの追加についても検討させていただきます。

長らくご対応いただき、誠にありがとうございました。

お世話になっております。

ご確認ありがとうございました。

それでは本件は回答済みとしてCloseさせていただきます。

参考までに、今回のスレッドで解説した事項に関連した情報をまとめた簡単な資料を本投稿に添付いたします。社内用途で作成したものであるため、乱筆乱文についてはご容赦ください。何かのお役に立てば幸いです。

以上、よろしくお願いいたします。