互動遊戲核心在於輸入響應。MIDP 1.0 提供三層鍵盤抽象:**原始鍵碼 → 遊戲動作 → 高級事件**。理解三者關係與差異,是跨機型輸入處理的基石。
| 層級 | API | 特點 | 適用場景 |
|---|---|---|---|
| 原始鍵碼 | keyPressed(int keyCode)getKeyName(keyCode) | 設備特定、數值固定 (0=48, 9=57, * =42, # =35) 方向鍵常為負值 (-1~-7) | 文字輸入、特定功能鍵、除錯 |
| 遊戲動作 | getGameAction(keyCode)返回: UP/DOWN/LEFT/RIGHT/FIRE/ GAME_A~D | **跨平台標準化**,將物理鍵映射為邏輯動作 僅覆蓋 8~12 個常用動作 | **遊戲移動/確認/取消/選單** 核心邏輯 |
| 高級事件 | CommandListenerCommand + 軟鍵 | UI 導向、系統分發、支援長按選單 | 選單、對話框、表單操作 |
protected void keyPressed(int keyCode) { /* 按下瞬間 */ }
protected void keyRepeated(int keyCode) { /* 長按重複 (設備依賴) */ }
protected void keyReleased(int keyCode) { /* 鬆開瞬間 */ }
注意:keyRepeated 並非所有設備支援,遊戲長按邏輯建議自行在主迴路用狀態機實現。
public void keyPressed(int keyCode) {
switch (keyCode) {
case 48: case 49: case 50: /* 數字鍵 */ break;
case -1: /* UP */ break; // 某設備方向鍵
default: break;
}
}
缺點:硬編碼鍵碼,移植必改代碼,邏輯與輸入耦合。
public void keyPressed(int keyCode) {
int action = getGameAction(keyCode);
switch (action) {
case Canvas.UP: y = Math.max(0, y - 2); break;
case Canvas.DOWN: y = Math.min(getHeight(), y + 2); break;
case Canvas.LEFT: x = Math.max(0, x - 2); break;
case Canvas.RIGHT: x = Math.min(getWidth(), x + 2); break;
case Canvas.FIRE: shoot(); break;
}
}
優點:零配置適配大多數手機方向鍵/確認鍵。缺點:無法覆蓋數字鍵、*、#、軟鍵等擴充功能。
keyState,每 bit 對應一虛擬鍵 (Bit 0=UP, 1=DOWN, 2=LEFT, 3=RIGHT, 4=FIRE, 5=数字0...)keyPressed/Released 只負責 **映射物理鍵碼 → 設定/清除對應 bit**(keyState & MASK) != 0mapKeyCode(int keyCode) -> int virtualBit **每機型一份實現**public class InputManager {
// 虛擬鍵位掩碼
public static final int VK_UP = 1 << 0;
public static final int VK_DOWN = 1 << 1;
public static final int VK_LEFT = 1 << 2;
public static final int VK_RIGHT = 1 << 3;
public static final int VK_FIRE = 1 << 4;
public static final int VK_NUM0 = 1 << 5;
// ... 至 VK_NUM9, VK_STAR, VK_POUND, VK_SOFT1, VK_SOFT2
private int keyState = 0;
// Canvas 回呼委託
public void onKeyPressed(int keyCode) {
int vk = mapKeyCode(keyCode);
if (vk != 0) keyState |= vk;
}
public void onKeyReleased(int keyCode) {
int vk = mapKeyCode(keyCode);
if (vk != 0) keyState &= ~vk;
}
// 邏輯層查詢
public boolean isPressed(int vk) { return (keyState & vk) != 0; }
public boolean isJustPressed(int vk) { /* 需額外記錄前幀狀態 */ return false; }
// --- 每機型專屬實現 ---
protected int mapKeyCode(int keyCode) {
// 預設:標準遊戲動作映射
int action = Canvas.getGameAction(keyCode); // 需實例或靜態輔助
switch (action) {
case Canvas.UP: return VK_UP;
case Canvas.DOWN: return VK_DOWN;
case Canvas.LEFT: return VK_LEFT;
case Canvas.RIGHT: return VK_RIGHT;
case Canvas.FIRE: return VK_FIRE;
}
// 數字鍵通用映射 (ASCII 碼)
if (keyCode >= '0' && keyCode <= '9') return VK_NUM0 << (keyCode - '0');
if (keyCode == '*') return VK_STAR;
if (keyCode == '#') return VK_POUND;
// 方向鍵負值常見映射 (Nokia/SonyEricsson)
switch (keyCode) {
case -1: return VK_UP;
case -2: return VK_DOWN;
case -3: return VK_LEFT;
case -4: return VK_RIGHT;
case -5: return VK_FIRE;
case -6: return VK_SOFT1;
case -7: return VK_SOFT2;
}
return 0; // 未識別
}
}
// Motorola V600 等
case 1: return VK_UP; // 實際測試獲取
case 6: return VK_DOWN;
case 2: return VK_LEFT;
case 5: return VK_RIGHT;
case 20: return VK_FIRE;
case 22: return VK_SOFT1;
case 21: return VK_SOFT2;
case 10: return VK_NUM0; // 視具體定義
pressStartTime[vk],超過閾值觸發加速/連發lastReleaseTime[vk],兩次間隔 < 300ms 判定雙擊(keyState & (VK_LEFT | VK_FIRE)) == (VK_LEFT | VK_FIRE) 同時按下public class InputDemo extends Canvas implements Runnable {
private int x, y, speed = 3;
private InputManager input = new InputManager();
public InputDemo() {
x = getWidth()/2; y = getHeight()/2;
new Thread(this).start();
}
protected void keyPressed(int k) { input.onKeyPressed(k); }
protected void keyReleased(int k) { input.onKeyReleased(k); }
public void run() {
while (true) {
if (input.isPressed(InputManager.VK_UP)) y = Math.max(0, y - speed);
if (input.isPressed(InputManager.VK_DOWN)) y = Math.min(getHeight(), y + speed);
if (input.isPressed(InputManager.VK_LEFT)) x = Math.max(0, x - speed);
if (input.isPressed(InputManager.VK_RIGHT)) x = Math.min(getWidth(), x + speed);
repaint(); serviceRepaints();
try { Thread.sleep(33); } catch (Exception e) {}
}
}
protected void paint(Graphics g) {
g.setColor(0xFFFFFF); g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0); g.fillRect(x, y, 20, 20);
}
}
MIDP 1.0 鍵盤處理**進化路徑**:硬編碼 keyCode → getGameAction() 標準動作 → 虛擬鍵位狀態機 + 映射表。專業遊戲**必須採用方案三**,將平台差異封裝在 mapKeyCode() 單一函數,上層邏輯純粹查詢位掩碼,實現真正的「一碼多機」與複雜輸入組合支援。