Move keycode mapping to keyMap array instead of switch case entries.

This commit is contained in:
guru_meditation_no42
2021-04-13 22:50:59 -07:00
parent 2649471c5f
commit a4e95b1c98
2 changed files with 137 additions and 62 deletions

View File

@@ -28,12 +28,30 @@ public final class InputController implements OnClickListener, OnLongClickListen
private boolean keyState_attack = false;
private boolean keyState_flee = false;
private boolean keyState_endturn = false;
final private int KEY_UNHANDLED = 0; // Default, for unhandled keycodes
final private int KEY_UP = 1;
final private int KEY_DOWN = 2;
final private int KEY_LEFT = 3;
final private int KEY_RIGHT = 4;
final private int KEY_UP_LEFT = 5;
final private int KEY_UP_RIGHT = 6;
final private int KEY_DOWN_LEFT = 7;
final private int KEY_DOWN_RIGHT = 8;
final private int KEY_ATTACK = 9;
final private int KEY_FLEE = 10;
final private int KEY_END_TURN = 11;
final private int KEY_HERO_INFO = 12;
private char keyMap[]; // Android keycode to internal key event mapping. TODO: Configure via preferences
public InputController(ControllerContext controllers, WorldContext world) {
this.controllers = controllers;
this.world = world;
initializeKeyMap();
}
/* New keyboard handler. Both Key Down and Key Up events handled to allow conditional behaviours.
On 4-way dpad controllers, cursor keys, and WASD, diagonals are generated by chording two keys.
Single-key diagonals are supported on numeric keypad and 8-way dpads (not seen/tested in the wild).
@@ -42,78 +60,148 @@ public final class InputController implements OnClickListener, OnLongClickListen
be dangerous in tight spaces, modifiers are provided to "lock" the input until both keys are down.
TODO: Use delay timer to enable chorded diagonals on first move?
*/
// Map key codes to spectic internal actions
// TODO: Move mapping out of code, to JSON or XML file, or maybe eventually user preferences
private void initializeKeyMap() {
char key;
keyMap = new char[1024]; // Should be a long time before android exceeds 1024 keycodes
// Keys mapping to UP
key = KEY_UP;
keyMap[KeyEvent.KEYCODE_DPAD_UP] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_8] = key;
keyMap[KeyEvent.KEYCODE_8] = key;
keyMap[KeyEvent.KEYCODE_W] = key;
// Keys mapping to DOWN
key = KEY_DOWN;
keyMap[KeyEvent.KEYCODE_DPAD_DOWN] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_2] = key;
keyMap[KeyEvent.KEYCODE_2] = key;
keyMap[KeyEvent.KEYCODE_S] = key;
// Keys mapping to LEFT
key = KEY_LEFT;
keyMap[KeyEvent.KEYCODE_DPAD_LEFT] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_4] = key;
keyMap[KeyEvent.KEYCODE_4] = key;
keyMap[KeyEvent.KEYCODE_A] = key;
// Keys mapping to RIGHT
key = KEY_RIGHT;
keyMap[KeyEvent.KEYCODE_DPAD_RIGHT] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_6] = key;
keyMap[KeyEvent.KEYCODE_6] = key;
keyMap[KeyEvent.KEYCODE_D] = key;
// Keys mapping to UP_LEFT
key = KEY_UP_LEFT;
keyMap[KeyEvent.KEYCODE_DPAD_UP_LEFT] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_7] = key;
keyMap[KeyEvent.KEYCODE_7] = key;
keyMap[KeyEvent.KEYCODE_MOVE_HOME] = key;
// Keys mapping to UP_RIGHT
key = KEY_UP_RIGHT;
keyMap[KeyEvent.KEYCODE_DPAD_UP_RIGHT] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_9] = key;
keyMap[KeyEvent.KEYCODE_9] = key;
keyMap[KeyEvent.KEYCODE_PAGE_UP] = key;
// Keys mapping to DOWN_LEFT
key = KEY_DOWN_LEFT;
keyMap[KeyEvent.KEYCODE_DPAD_DOWN_LEFT] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_1] = key;
keyMap[KeyEvent.KEYCODE_1] = key;
keyMap[KeyEvent.KEYCODE_MOVE_END] = key;
// Keys mapping to DOWN_RIGHT
key = KEY_UP_LEFT;
keyMap[KeyEvent.KEYCODE_DPAD_DOWN_RIGHT] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_3] = key;
keyMap[KeyEvent.KEYCODE_3] = key;
keyMap[KeyEvent.KEYCODE_PAGE_DOWN] = key;
// Keys mapping to ATTACK
key = KEY_ATTACK;
keyMap[KeyEvent.KEYCODE_DPAD_CENTER] = key;
keyMap[KeyEvent.KEYCODE_BUTTON_A] = key;
keyMap[KeyEvent.KEYCODE_SPACE] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_5] = key;
// Keys mapping to FLEE
key = KEY_FLEE;
keyMap[KeyEvent.KEYCODE_BUTTON_X] = key;
keyMap[KeyEvent.KEYCODE_F] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_ENTER] = key;
keyMap[KeyEvent.KEYCODE_ENTER] = key;
// Keys mapping to END_TURN
key = KEY_END_TURN;
keyMap[KeyEvent.KEYCODE_BUTTON_Y] = key;
keyMap[KeyEvent.KEYCODE_E] = key;
keyMap[KeyEvent.KEYCODE_FORWARD_DEL] = key;
keyMap[KeyEvent.KEYCODE_NUMPAD_DOT] = key;
// Keys mapping to HERO_INFO
key = KEY_HERO_INFO;
keyMap[KeyEvent.KEYCODE_BUTTON_SELECT] = key;
keyMap[KeyEvent.KEYCODE_C] = key;
}
// Generate game actions based on mapped keys
public boolean onKeyboardAction(Context context, KeyEvent event) {
// L.log("onKeyboardAction(): Processing action " + event.getAction() + " for keyCode " + event.getKeyCode());
L.log("onKeyboardAction(): Processing action " + event.getAction() + " for keyCode " + event.getKeyCode());
if (event.getAction() != KeyEvent.ACTION_DOWN && event.getAction() != KeyEvent.ACTION_UP) return false; // don't handle other actions
boolean keydown = (event.getAction() == KeyEvent.ACTION_DOWN);
boolean inihbit = (keyState_attack || keyState_endturn || keyState_flee); // used to inhibit movement if an action key is held down
switch (event.getKeyCode()) {
if (event.getKeyCode() >= keyMap.length) return false; // just in case we get an oddball keycode
switch (keyMap[event.getKeyCode()]) {
// Basic movement handled first
// Ordinal directional keys - only modify one direction register, can be combined when
// used simultaneously to create synthetic diagonals
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_NUMPAD_8:
case KeyEvent.KEYCODE_8:
case KeyEvent.KEYCODE_W:
case KEY_UP:
keyState_dy = keydown ? -1 : 0;
if (!inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_NUMPAD_2:
case KeyEvent.KEYCODE_2:
case KeyEvent.KEYCODE_S:
case KEY_DOWN:
keyState_dy = keydown ? 1 : 0;
if (!inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_NUMPAD_4:
case KeyEvent.KEYCODE_4:
case KeyEvent.KEYCODE_A:
case KEY_LEFT:
keyState_dx = keydown ? -1 : 0;
if (!inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_NUMPAD_6:
case KeyEvent.KEYCODE_6:
case KeyEvent.KEYCODE_D:
case KEY_RIGHT:
keyState_dx = keydown ? 1 : 0;
if (!inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
// Diagonal directional keys. Modify both direction registers, can't be combined
// TODO: store individual key position to allow combinations. May not be worth the trouble.
case KeyEvent.KEYCODE_DPAD_UP_LEFT:
case KeyEvent.KEYCODE_NUMPAD_7:
case KeyEvent.KEYCODE_7:
case KeyEvent.KEYCODE_MOVE_HOME:
case KEY_UP_LEFT:
keyState_dx = keydown ? -1 : 0;
keyState_dy = keydown ? -1 : 0;
if (!inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KeyEvent.KEYCODE_DPAD_UP_RIGHT:
case KeyEvent.KEYCODE_NUMPAD_9:
case KeyEvent.KEYCODE_9:
case KeyEvent.KEYCODE_PAGE_UP:
case KEY_UP_RIGHT:
keyState_dx = keydown ? 1 : 0;
keyState_dy = keydown ? -1 : 0;
if (!inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KeyEvent.KEYCODE_DPAD_DOWN_LEFT:
case KeyEvent.KEYCODE_NUMPAD_1:
case KeyEvent.KEYCODE_1:
case KeyEvent.KEYCODE_MOVE_END:
case KEY_DOWN_LEFT:
keyState_dx = keydown ? -1 : 0;
keyState_dy = keydown ? 1 : 0;
if (!inihbit) onRelativeMovement(keyState_dx, keyState_dy);
break;
case KeyEvent.KEYCODE_DPAD_DOWN_RIGHT:
case KeyEvent.KEYCODE_NUMPAD_3:
case KeyEvent.KEYCODE_3:
case KeyEvent.KEYCODE_PAGE_DOWN:
case KEY_DOWN_RIGHT:
keyState_dx = keydown ? 1 : 0;
keyState_dy = keydown ? 1 : 0;
if (!inihbit) onRelativeMovement(keyState_dx, keyState_dy);
@@ -124,10 +212,7 @@ public final class InputController implements OnClickListener, OnLongClickListen
// "Attack" shortcut - freeze movement to allow chorded direction when key is released.
// if in combat, executes an attack on key release
case KeyEvent.KEYCODE_DPAD_CENTER: // Not sure if this is needed
case KeyEvent.KEYCODE_BUTTON_A: // lock movement until released for precise directional move/attack
case KeyEvent.KEYCODE_SPACE:
case KeyEvent.KEYCODE_NUMPAD_5:
case KEY_ATTACK:
if (keydown && !keyState_attack) { // key pressed - pause movement
if(!world.model.uiSelections.isInCombat) controllers.movementController.stopMovement();
} else if (!keydown && keyState_attack) { // key released - execute attack / move in direction
@@ -137,10 +222,7 @@ public final class InputController implements OnClickListener, OnLongClickListen
break;
// "Flee" shortcut. Intitiates flee when pressed. If a direction is held, moves in chosen direction when released
case KeyEvent.KEYCODE_BUTTON_X:
case KeyEvent.KEYCODE_F:
case KeyEvent.KEYCODE_NUMPAD_ENTER:
case KeyEvent.KEYCODE_ENTER:
case KEY_FLEE:
if (world.model.uiSelections.isInCombat) {
if (keydown && !keyState_flee) { // button pressed - set flee; movement locked while pressed
controllers.combatController.startFlee();
@@ -155,10 +237,7 @@ public final class InputController implements OnClickListener, OnLongClickListen
break;
// "End Turn" shortcut. Flag prevents repeated end turn if key is held down.
case KeyEvent.KEYCODE_BUTTON_Y:
case KeyEvent.KEYCODE_E:
case KeyEvent.KEYCODE_FORWARD_DEL:
case KeyEvent.KEYCODE_NUMPAD_DOT:
case KEY_END_TURN:
if (keydown && !keyState_endturn) {
if (world.model.uiSelections.isInCombat) controllers.combatController.endPlayerTurn();
}
@@ -166,11 +245,12 @@ public final class InputController implements OnClickListener, OnLongClickListen
break;
// "Hero Info" screen shortcut. New activity takes focus, so we don't need to worry about repeats.
case KeyEvent.KEYCODE_BUTTON_SELECT:
case KeyEvent.KEYCODE_C:
case KEY_HERO_INFO:
if (keydown) context.startActivity(new Intent(context, HeroinfoActivity.class));
break;
default: // unhandled key
case KEY_UNHANDLED: // Unhandled keycode
default: // unhandled keymap code entry (should not happen)
return false;
}

View File

@@ -4,8 +4,6 @@ import java.lang.ref.WeakReference;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
import com.gpl.rpg.AndorsTrail.R;
import com.gpl.rpg.AndorsTrail.activity.HeroinfoActivity;
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.controller.Constants;
@@ -34,20 +32,17 @@ import com.gpl.rpg.AndorsTrail.util.CoordRect;
import com.gpl.rpg.AndorsTrail.util.Size;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ImageButton;
public final class MainView extends SurfaceView
implements SurfaceHolder.Callback,
@@ -660,14 +655,14 @@ public final class MainView extends SurfaceView
if (v.controllers.preferences.enableUiAnimations) postDelayed(this, 0);
}
}
public void stop() {
stop = true;
}
}
@Override
public void onPlayerMoved(PredefinedMap map, Coord newPosition, Coord previousPosition) {
if (map != currentMap) return;
@@ -798,19 +793,19 @@ public final class MainView extends SurfaceView
movingSpritesRedrawTick.start();
}
}
@Override
public void onNewSpriteMoveFrame(SpriteMoveAnimation animation) {
//redrawMoveArea_(CoordRect.getBoundingRect(animation.origin, animation.destination, animation.actor.tileSize), animation);
}
@Override
public void onSpriteMoveCompleted(SpriteMoveAnimation animation) {
if (animation.map != currentMap) return;
movingSprites--;
redrawArea(CoordRect.getBoundingRect(animation.origin, animation.destination, animation.actor.tileSize), RedrawAreaDebugReason.EffectCompleted);
}
@Override
public void onAsyncAreaUpdate(CoordRect area) {
redrawArea(area, RedrawAreaDebugReason.AsyncRequest);