【Unity】【C#】InputSystem で Android のバックキーの isPressed がなぜか一定時間で false になる? 
2020/10/14 Wed [edit]
InputSystem も Verified (正式版) となり、(旧)InputManager との混在も可能でもあるが、いずれ InputSystem の方法を中心として使いたいので調査中。
Android ではあまりハードウェアキーボードの概念は無いが(オプションで付けるのは別として)、バックキーは (旧)InputManager 時代から、Input.GetKeyDown(KeyCode.Escape) で取得できる。
InputSystem でも Keyboard.current[Key.Escape] でも取得できたので、色々実験していたら、少し Input とは違う挙動を発見した。バグなのか仕様なのかわからないので(一応 Unity公式にバグレポートとして送っておいた → 再現できたので、後のバージョンで対応するとのこと)、同じ問題に出くわす人のために、とりあえず記録だけしておこう。
(※) Unity 2019.4.12f1 / InputSystem 1.0.0 / Windows10(x64) で確認
問題というのはタイトルにもおおよそ書いてあるが、具体的には「Android でバックキーの長押しを試していたら、一定時間で勝手に isPressed が false になってしまい、挙動が変わってしまった」というものだった。
実はこの「バックキーの長押し判定」というのは、私が配布しているプラグインのデモにも使われているのだが、それを InputSystem に書き換えて試していたら、上手く動かなかった事で見つけた。
少なくとも Input.GetKeyDown(KeyCode.Escape) では長く押しても判定できたのだが、InputSystem の場合、約1秒前後、バックキーを押していると、なぜか Keyboard.current[Key.Escape] は false になってしまうようだ(※エディタや Standalone ではならない。Android ランタイムのみ)。
とりあえず、試した簡単な実験用コードを載せておこう。
なんてことはない、ただ「バックキーを押す→継続→離す」といった動作をログに出しているだけだ。実際には Android の実機ではログが見えないので、プラグインに入っている XDebug.Log を使っている。
●簡単な実験用コード
using System;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
public class AndroidBackKeyTest : MonoBehaviour
{
#if ENABLE_INPUT_SYSTEM
public Key targetKey = Key.Escape;
public KeyCode targetKeyCode = KeyCode.Escape;
// Use this for initialization
private void Start()
{
Debug.Log($"Platform : {Application.platform}");
Debug.Log($"SystemInfo.operatingSystem : {SystemInfo.operatingSystem}");
}
bool keyPressing;
bool keyCodePressing;
float keyPassedTime;
float keyCodePassedTime;
// Update is called once per frame
private void Update()
{
if (Keyboard.current[targetKey].wasPressedThisFrame)
{
keyPressing = true;
keyPassedTime = Time.time;
Debug.Log($"<color=cyan>[frame:{Time.frameCount}][passed:0.000] [{targetKey}].wasPressedThisFrame</color>");
}
if (Input.GetKeyDown(targetKeyCode))
{
keyCodePressing = true;
keyCodePassedTime = Time.time;
Debug.Log($"[<color=cyan>frame:{Time.frameCount}][passed:0.000] GetKeyDown({targetKeyCode})</color>");
}
if (keyPressing)
{
if (Keyboard.current[targetKey].isPressed)
{
Debug.Log($"[frame:{Time.frameCount}][passed:{(Time.time - keyPassedTime):F3}] [{targetKey}].isPressed");
}
if (Keyboard.current[targetKey].wasReleasedThisFrame)
{
Debug.Log($"<color=magenta>[frame:{Time.frameCount}][passed:{(Time.time - keyPassedTime):F3}] [{targetKey}].wasPressedThisFrame</color>");
keyPressing = false;
}
}
if (keyCodePressing)
{
if (Input.GetKey(targetKeyCode))
{
Debug.Log($"<color=#999999>[frame:{Time.frameCount}][passed:{(Time.time - keyCodePassedTime):F3}] GetKey({targetKeyCode})</color>");
}
if (Input.GetKeyUp(targetKeyCode))
{
Debug.Log($"<color=magenta>[frame:{Time.frameCount}][passed:{(Time.time - keyCodePassedTime):F3}] GetKeyUp({targetKeyCode})</color>");
keyCodePressing = false;
}
}
}
#endif
}
●短い間だけバックキーを押したとき![]() | ●1秒以上押したとき![]() |
スクショでは、「短い間だけバックキーを押したとき」と「1秒以上押したとき」のログの状態をキャプチャしている。これを見ると、通常なら、"Input.GetKey(KeyCode)" と "Keyboard.current[Key].isPressed" がペアで出ているのが正しいのだが、なぜか1秒前後以降で "Keyboard.current[Key].isPressed" の方が出てこないことがわかる(「指を離す」操作は出ている[マゼンタの色])。
ただし、この現象はエディタや Standalone でビルドした場合は出ない。正常にペアでログは表示される。
ちなみに、isPressed を使わないで、継続も判定するなら、以下のような条件分けすれば、事足りる(普通の機器なら、キーはユニークなので、押したときにフラグを上げて、離したときフラグを下げれば、それ以外でフラグがtrueのとき、継続となる)。
bool keyPressing;
private void Update()
{
if (Keyboard.current[targetKey].wasPressedThisFrame)
{
keyPressing = true;
//押したときの処理
}
if (keyPressing)
{
if (Keyboard.current[targetKey].wasReleasedThisFrame)
{
//離したときの処理
keyPressing = false;
}
else
{
//継続中の処理
}
}
}
ただ、以前の記事に『日本語変換キーや CapsLock キーを使うと(単体で CapsLock を押すとおかしくなる)、Keyboard.current.anyKey が利かなくなることがある』と書いたが、Unity公式からは「現象を確認できない」と返信が来ている。もしかしたら、私は「Windows 日本語106キーボード」だが、Unityの中の人は「Mac 英語104キーボード」など、ハードウェアで結果の違いがあるのかも知れない。なので、Android も Galaxy と Xperia で違う、なんて可能性もある(掲載時点: InputSystem 1.0.0)。
ググって過去記事を見ていても(Preview時代)、日本語機能が使えない、みたいな話は出てくるしね。まだ InputSystem も初期バージョンは問題があるかも知れない。
ただ幸いなことに、今の所、(旧)InputManager と InputSystem は共存できるので(Edit>Player Settings>Other Settings>Active Input Handling で Both を選択すれば、同時に使える)、しばらくは安定してない関数(私の見たところだと、Keyboard.current.anyKey などは、日本語入力や CapsLock など、入力方法を変更すると、機能が無効になったりすることがある ← ただし使っているハードウェアによるかも?)は (旧)Input を使った方が良いだろう。マウスホイールの戻値の単位が違うことも確認してるし、Input は静的なメソッドなので、そのまま使えていたが、InputSystm は 各 class で定義されているので、null チェックしないと、脱着されたときにヌルポが出るかも知れない。
細かい挙動が違う可能性もあるので、一気に InputSystem に移行すると、痛い目にあう気がする。しばらくは色々な機器で試してから導入・移行を検討した方が良いかも知れない(一部の人だけ使えなくなる、なんてトラブルが発生する恐れがある)。
マニュアルを見てると、「No corresponding API yet.」(まだ対応するものがない)というのがいくつもあるので、全て新旧一致できるわけではないようだが、よく使われる機能なら完全互換でいけそうなものも多いね。
ただ、今まで使っていた (旧)InputManager のコード(※主に Input) は全て書き換えないとならないので、大変な労力がいるのが難点。なので、しばらくは一部機能だけ使う感じになるだろう。
いずれ、スワイプ, ピンチ, 長押しなどのライブラリも InputSystem に対応しようと思っているが、ラッパー関数でも作らないと、旧新互換で作るのは骨が折れるね(笑)。
(関連記事)
【Unity】【C#】InputSystem.Key をリアルタイムで調べる / Windows 日本語キーボードでの Key 一覧
【Unity】【C#】InputSystem の Keyboard クラスと (旧)Input.GetKey の対応
【Unity】【C#】(旧)KeyCode と InputSystem.Key の対応
【Unity】【C#】InputSystem の Mouse クラスと(旧)Input.GetMouseButton の対応
【Unity】【C#】InputSystem でマウスのホイール(scroll)取得と (旧)Input との対応
【Unity】【C#】InputSystem.TouchPhase の IsActive(), IsEndedOrCanceled() [拡張メソッド] の具体値
【Unity】【C#】InputSystem の displayName や control path から Key (キーコード) を取得(変換)する
- 関連記事
トラックバック
トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/372-b5cd83e6
この記事にトラックバックする(FC2ブログユーザー)
| h o m e |