質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

5991閲覧

Java KeyListener を使ったキー入力の処理について

Zooey

総合スコア55

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2017/01/19 09:50

いつも KeyListener を使ったキー入力の処理ついて迷ってしまいます。
現在は後述のコードが示すように、押されたキーを ArrayList につっこんで if文 でひとつひとつ処理する方法をよく使っています(同時押しに対応するため)。これを書いていて「if文 がとても冗長だ。」といつも感じます。かといって switch文 を使うと、同時押しに対応できません。もっとなにかスマートに実装できる方法があるでしょうか(同時押しに対応したものでおねがいします)(or みなさんはどのように処理していますか?)

(※実装部分のみ抜粋)

Java

1 private ArrayList<Integer> key_pressed = new ArrayList<Integer>(); 2 3 public void _update() { 4 // マウス全般の処理 5 /* 省略 */ 6 // ここまで 7 8 // キーボードでのスクロール移動処理 9 byte speed = 1; 10 11 if(isPressed(KeyEvent.VK_SHIFT)) { 12 speed = 2; 13 } 14 15 if(isPressed(KeyEvent.VK_UP)) { 16 viewport_y += speed; 17 } 18 if(isPressed(KeyEvent.VK_DOWN)) { 19 viewport_y -= speed; 20 } 21 if(isPressed(KeyEvent.VK_LEFT)) { 22 viewport_x += speed; 23 } 24 if(isPressed(KeyEvent.VK_RIGHT)) { 25 viewport_x -= speed; 26 } 27 // ここまで 28 29 // キーボードでの拡大と縮小 30 if(isPressed(KeyEvent.VK_A) && grid_cell_size < max_grid_cell_size) { 31 grid_cell_size++; 32 } 33 if(isPressed(KeyEvent.VK_Z) && grid_cell_size > min_grid_cell_size) { 34 grid_cell_size--; 35 } 36 // ここまで 37 } 38 39 @Override 40 public void keyTyped(KeyEvent e) { 41 42 } 43 @Override 44 public void keyPressed(KeyEvent e) { 45 if(key_pressed.contains(e.getKeyCode())) return; 46 47 key_pressed.add(new Integer(e.getKeyCode())); 48 } 49 @Override 50 public void keyReleased(KeyEvent e) { 51 key_pressed.remove(new Integer(e.getKeyCode())); 52 } 53 54 public boolean isPressed(Integer keyCode) { 55 return key_pressed.contains(keyCode); 56 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

Java

1// interfaceを一つ作る。 2interface Proc { 3 public void doProc(); 4} 5 6// キーごとに処理をmapに登録していく 7Map<Integer, Proc> procMap = new HashMap<>(); 8procMap.put(KeyEvent.VK_UP, new Proc(){ 9 public void doProc() { 10 // やりたい処理を書く 11 } 12}); 13procMap.put(KeyEvent.VK_DOWN, new Proc(){ 14 public void doProc() { 15 // やりたい処理を書く 16 } 17}); 18// 以下たくさん 19// ちなみにJava8ならラムダ式を使えばこれで済む 20procMap.put(KeyEvent.VK_LEFT, () -> { 21 // やりたい処理を書く 22}); 23 24// _update内 25for(Integer key : key_pressed) { 26 procMap.get(key).doProc(); 27}

このように処理をinterfaceの無名クラス実装で書くことにより、スマートにfor文でまとめることができます。

###注意
このやり方だと処理される順がキーを押された順になるので、質問の中でやっているspeedの調整等はすこし工夫が必要になると思います。

投稿2017/01/19 10:00

編集2017/01/19 10:06
masaya_ohashi

総合スコア9206

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masaya_ohashi

2017/01/19 10:02

まあこれだと複数のキーが押されたときにだけ起こる処理とか書けないですけどね。
Zooey

2017/01/22 10:23

ご回答有り難うございました。おかげでコードをすっきりできました。 汎用性が高く、わかりやすいです。 >複数のキーが押されたときにだけ起こる処理 このような処理は書かないつもりで問題ないので大丈夫ですが、もし必要になったら適当にフラグたてたりしておきます。 あと // _update内 for(Integer key : key_pressed) { procMap.get(key).doProc(); } こちらの処理なのですが、nullチェックがないとぬるぽが発生するので一応報告しておきます
masaya_ohashi

2017/01/23 00:05

あー、たしかにcontainsKeyで事前にチェック等したほうがよかったですね。報告ありがとうございます!
swordone

2017/01/23 00:28

Java8ならgetOrDefaultで何もしないProcを引数に指定して1文で書けるけど、 素直にnullチェックした方がいいか。
guest

0

同時押しを処理する場合、質問者さんのコードにあるように現在押されている状態のキーを覚えておくわけですが、その覚え方の工夫は可能かも知れません。

キーを一つ一つリストの要素とすると同時押しのキー数がそれほど多くなることはないので効率が問題になるわけではないですが、一つ一つのキーが押されたかどうかの判定になります。それをなんとかしたいならListをやめてキーに対応したビットマスクのようなもので考える方法もあるかと思います。

興味のあるキーの集合(K1, K2, ...)に対してそれぞれビット位置を決めておき、KEY_PRESSEDでint型のmaskの対応ビットをセットしてKEY_RELEASEDで対応ビットをクリアすればよいわけです。

しかし・・・例に挙げておられるキー処理だとせっかくビットマスクにしてもキー判定(下記のdoSomethingByKeyStatus)はスッキリしますが別の情報の初期化なんかのコードは増えます。どちらかというと「スッキリさせる」というより若干効率がよくなる気がする自己満足的なコードと言えるかもしれません。下記のコードはイメージを掴む目的でいろいろ省略してますが意図は伝わると思います。

java

1class なんかのクラス implements KeyListener { 2 int keyMask; 3 int[] horizontalMove = { .... }; 4 int[] verticalMove = { .... }; 5 6 @Override public void keyPressed(KeyEvent ev) { 7 Integer bit = keyCodeToBitPositionMap.get(ev.getCode()); 8 if (bit != null) { 9 keyMask |= 1 << bit; 10 } 11 } 12 13 @Override public void keyReleased(KeyEvent ev) { 省略 } 14 15 void doSomethingByKeyStatus() { 16 speed = (keyMask & SHIFT) == 0 ? 1 : 2; 17 viewport_x += speed * horizontalMove[keyMask & (LEFT|RIGHT)]; 18 viewport_y += speed * verticalMove[keyMask & (UP|DOWN)]; 19 ... etc. 20 } 21}

投稿2017/01/19 10:34

KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zooey

2017/01/22 10:26

ご回答有り難うございました。今回はわかりやすく設計しておきたかったのでmasaya_ohashiさんの回答をベストアンサーにさせていただきましたが、ビットマスクを使った処理の仕方があったとは勉強になりました。ビット演算に興味があるので非常に面白かったです。別の機会で使ってみようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問