Androidでジョイスティックですが、USBホスト機能でキー入力として拾えることに気付きました。
http://d.hatena.ne.jp/naoya2k/20120212/p1
であれば、Java API側でSTRIG(0)を[RETURN]に変換してしまえば良いですね。これで、SD6031イメージファイル選択プログラムもジョイスティックで使えます。
SPACE FIGHTERもジョイスティックでプレイ!
qt_input.cpp
/* Skelton for retropc emulator Qt Version : tanam Date : 2013.05.18 - */ #include "emu.h" #include "vm/vm.h" #include "fifo.h" #include "fileio.h" #ifdef Q_OS_WIN32 #include <mmsystem.h> #endif #define STICK0_SPACE 0x80 #define STICK0_LEFT 0x20 #define STICK0_RIGHT 0x10 #define STICK0_DOWN 0x08 #define STICK0_UP 0x04 #define STICK0_STOP 0x02 #define STICK0_SHIFT 0x01 #define KEY_KEEP_FRAMES 3 #define COUNTOF(arr) (sizeof(arr) / sizeof((arr)[0])) // Qtキーコード -> 仮想キーコード 変換テーブル std::map<int, int> VKTable; static const struct { int InKey; // Qtのキーコード int VKey; // 仮想キーコード } VKeyDef[] = { { Qt::Key_unknown, 0xff }, { Qt::Key_1, '1' }, // 1 ! { Qt::Key_Exclam, '1' }, // 1 ! { Qt::Key_2, '2' }, // 2 " { Qt::Key_QuoteDbl, '2' }, // 2 " { Qt::Key_3, '3' }, // 3 # { Qt::Key_NumberSign, '3' }, // 3 # { Qt::Key_4, '4' }, // 4 $ { Qt::Key_Dollar, '4' }, // 4 $ { Qt::Key_5, '5' }, // 5 % { Qt::Key_Percent, '5' }, // 5 % { Qt::Key_6, '6' }, // 6 & { Qt::Key_Ampersand, '6' }, // 6 & { Qt::Key_7, '7' }, // 7 ' { Qt::Key_Apostrophe, '7' }, // 7 ' { Qt::Key_8, '8' }, // 8 ( { Qt::Key_ParenLeft, '8' }, // 8 ( { Qt::Key_9, '9' }, // 9 ) { Qt::Key_ParenRight, '9' }, // 9 ) { Qt::Key_0, '0' }, // 0 { Qt::Key_Minus, 0xBD }, // - = { Qt::Key_Equal, 0xBD }, // - = { Qt::Key_AsciiCircum, 0xDE }, // ^ ~ { Qt::Key_AsciiTilde, 0xDE }, // ^ ~ { Qt::Key_Backspace, 0x2E }, // Delete { Qt::Key_Insert, 0x2D }, // Insert { Qt::Key_Escape, 0x1B }, // ESC { Qt::Key_Q, 'Q' }, // q Q { Qt::Key_W, 'W' }, // w W { Qt::Key_E, 'E' }, // e E { Qt::Key_R, 'R' }, // r R { Qt::Key_T, 'T' }, // t T { Qt::Key_Y, 'Y' }, // y Y { Qt::Key_U, 'U' }, // u U { Qt::Key_I, 'I' }, // i I { Qt::Key_O, 'O' }, // o O { Qt::Key_P, 'P' }, // p P { Qt::Key_At, 0xC0 }, // @ ` { Qt::Key_QuoteLeft, 0xC0 }, // @ ` { Qt::Key_BracketLeft, 0xDB }, // [ { { Qt::Key_BraceLeft, 0xDB }, // [ { { Qt::Key_Return, 0x0D }, // CR { Qt::Key_Up, 0x26 }, // ↑ { Qt::Key_Down, 0x28 }, // ↓ { Qt::Key_Left, 0x25 }, // ← { Qt::Key_Right, 0x27 }, // → { Qt::Key_Control, 0x11 }, // L-Ctrl { Qt::Key_A, 'A' }, // a A { Qt::Key_S, 'S' }, // s S { Qt::Key_D, 'D' }, // d D { Qt::Key_F, 'F' }, // f F { Qt::Key_G, 'G' }, // g G { Qt::Key_H, 'H' }, // h H { Qt::Key_J, 'J' }, // j J { Qt::Key_K, 'K' }, // k K { Qt::Key_L, 'L' }, // l L { Qt::Key_Semicolon, 0xBB }, // ; + { Qt::Key_Plus, 0xBB }, // ; + { Qt::Key_Colon, 0xBA }, // : * { Qt::Key_Asterisk, 0xBA }, // : * { Qt::Key_BracketRight,0xDD }, // ] } { Qt::Key_BraceRight, 0xDD }, // ] } { Qt::Key_Shift, 0x10 }, // L-Shift { Qt::Key_Z, 'Z' }, // z Z { Qt::Key_X, 'X' }, // x X { Qt::Key_C, 'C' }, // c C { Qt::Key_V, 'V' }, // v V { Qt::Key_B, 'B' }, // b B { Qt::Key_N, 'N' }, // n N { Qt::Key_M, 'M' }, // m M { Qt::Key_Comma, 0xBC }, // , < { Qt::Key_Less, 0xBC }, // , < { Qt::Key_Period, 0xBE }, // . > { Qt::Key_Greater, 0xBE }, // . > { Qt::Key_Slash, 0xBF }, // / ? { Qt::Key_Question, 0xBF }, // / ? { Qt::Key_End, 0xDC }, // 円 { Qt::Key_F1, 0x70 }, // F1 { Qt::Key_F2, 0x71 }, // F2 { Qt::Key_F3, 0x72 }, // F3 { Qt::Key_F4, 0x73 }, // F4 { Qt::Key_F5, 0x74 }, // F5 { Qt::Key_F6, 0x75 }, // かな { Qt::Key_F7, 0x76 }, // カナ { Qt::Key_F8, 0x77 }, // GRAPH { Qt::Key_F9, 0x78 }, // STOP { Qt::Key_Space, 0x20 }, // Space { Qt::Key_Home, 0x24 }, // Home { Qt::Key_Delete, 0x2E }, // Delete { Qt::Key_PageUp, 0x21 }, // PAGE { Qt::Key_PageDown, 0x22 }, // PAGE { Qt::Key_Tab, 0x09 }, // TAB { Qt::Key_Backslash, 0xE2 }, // ろ { Qt::Key_Menu, 0 }, // ESCAPE { Qt::Key_Alt, 0xff }, // ALT { 0, 0x1b }, // MENU }; int OSD_ConvertKeyCode( int scode ) { if(VKTable.count(scode) == 0){ qDebug("keycode %x unknown\n", scode); return 0xff; } return VKTable[scode]; } void EMU::keyPressEvent(QKeyEvent *event) { bool keep_frames = false; int code = OSD_ConvertKeyCode(event->key()); qDebug("p:keycode %x\n", code); if (code==VK_LEFT) joy_status[2] |= STICK0_LEFT; else if (code==VK_RIGHT) joy_status[2] |= STICK0_RIGHT; else if (code==VK_DOWN) joy_status[2] |= STICK0_DOWN; else if (code==VK_UP) joy_status[2] |= STICK0_UP; else if (code==VK_F9) joy_status[2] |= STICK0_STOP; else if (code==VK_SHIFT) joy_status[2] |= STICK0_SHIFT; else joy_status[2] |= STICK0_SPACE; key_status[code] = keep_frames ? KEY_KEEP_FRAMES : 0x80; if (code == 0) ShowPopup(); return; } void EMU::keyReleaseEvent(QKeyEvent *event) { int code = OSD_ConvertKeyCode(event->key()); qDebug("r:keycode %x\n", code); bool keep_frames = false; if (code==VK_LEFT) joy_status[2] &= ~STICK0_LEFT; else if (code==VK_RIGHT) joy_status[2] &= ~STICK0_RIGHT; else if (code==VK_DOWN) joy_status[2] &= ~STICK0_DOWN; else if (code==VK_UP) joy_status[2] &= ~STICK0_UP; else if (code==VK_F9) joy_status[2] &= ~STICK0_STOP; else if (code==VK_SHIFT) joy_status[2] &= ~STICK0_SHIFT; else joy_status[2] &= ~STICK0_SPACE; if (key_status[code]) key_status[code] &= 0x7f; return; } void EMU::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::RightButton) ShowPopup(); return; } void EMU::initialize_input() { // initialize status memset(key_status, 0, sizeof(key_status)); memset(joy_status, 0, sizeof(joy_status)); #ifdef Q_OS_WIN32 // initialize joysticks joy_num = joyGetNumDevs(); for(int i = 0; i < joy_num && i < 2; i++) { JOYCAPS joycaps; if(joyGetDevCaps(i, &joycaps, sizeof(joycaps)) == JOYERR_NOERROR) { joy_mask[i] = (1 << joycaps.wNumButtons) - 1; } else { joy_mask[i] = 0x0f; // 4buttons } } #endif // initialize keycode convert table // Qtキーコード -> 仮想キーコード 変換テーブル初期化 for( int i=0; i < COUNTOF(VKeyDef); i++ ) VKTable[VKeyDef[i].InKey] = VKeyDef[i].VKey; } void EMU::release_input() { ; } void EMU::update_input() { #ifdef Q_OS_WIN32 // update joystick status memset(joy_status, 0, 8); for(int i = 0; i < joy_num && i < 2; i++) { JOYINFOEX joyinfo; joyinfo.dwSize = sizeof(JOYINFOEX); joyinfo.dwFlags = JOY_RETURNALL; if(joyGetPosEx(i, &joyinfo) == JOYERR_NOERROR) { if(joyinfo.dwYpos < 0x3fff) joy_status[i] |= 0x01; // up if(joyinfo.dwYpos > 0xbfff) joy_status[i] |= 0x02; // down if(joyinfo.dwXpos < 0x3fff) joy_status[i] |= 0x04; // left if(joyinfo.dwXpos > 0xbfff) joy_status[i] |= 0x08; // right joy_status[i] |= ((joyinfo.dwButtons & joy_mask[i]) << 4); } } #endif }
QtActivity.java
(省略) //@ANDROID-11 //QtCreator import android.app.Fragment; //QtCreator import android.view.ActionMode; //QtCreator import android.view.ActionMode.Callback; //@ANDROID-11 import android.media.*; (省略) // Audio private static Thread mAudioThread; private static AudioTrack mAudioTrack; public static native void nativeRunAudioThread(); // Audio private static Object buf; public static Object audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) { int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO; int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT; int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1); Log.v("SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer"); // Let the user pick a larger buffer if they really want -- but ye // gods they probably shouldn't, the minimums are horrifyingly high // latency already desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize); mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM); audioStartThread(); Log.v("SDL", "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer"); if (is16Bit) { buf = new short[desiredFrames * (isStereo ? 2 : 1)]; } else { buf = new byte[desiredFrames * (isStereo ? 2 : 1)]; } return buf; } public static void audioStartThread() { mAudioThread = new Thread(new Runnable() { public void run() { mAudioTrack.play(); nativeRunAudioThread(); } }); // I'd take REALTIME if I could get it! mAudioThread.setPriority(Thread.MAX_PRIORITY); mAudioThread.start(); } public static void audioWriteShortBuffer(short[] buffer) { for (int i = 0; i < buffer.length; ) { int result = mAudioTrack.write(buffer, i, buffer.length - i); if (result > 0) { i += result; } else if (result == 0) { try { Thread.sleep(1); } catch(InterruptedException e) { // Nom nom } } else { Log.w("SDL", "SDL audio: error return from write(short)"); return; } } } public static void audioWriteByteBuffer(byte[] buffer) { for (int i = 0; i < buffer.length; ) { int result = mAudioTrack.write(buffer, i, buffer.length - i); if (result > 0) { i += result; } else if (result == 0) { try { Thread.sleep(1); } catch(InterruptedException e) { // Nom nom } } else { Log.w("SDL", "SDL audio: error return from write(short)"); return; } } } public static void audioQuit() { if (mAudioThread != null) { try { mAudioThread.join(); } catch(Exception e) { Log.v("SDL", "Problem stopping audio thread: " + e); } mAudioThread = null; //Log.v("SDL", "Finished waiting for audio thread"); } if (mAudioTrack != null) { mAudioTrack.stop(); mAudioTrack = null; } } (省略) @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode==4) keyCode=0x100000; if (keyCode==188) keyCode=0x100000; if (keyCode==189) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==190) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==191) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==192) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==193) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==194) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==195) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==196) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==197) keyCode=KeyEvent.KEYCODE_ENTER; if (QtApplication.m_delegateObject != null && QtApplication.onKeyDown != null) return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyDown, keyCode, event); else return super.onKeyDown(keyCode, event); } (省略) @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode==4) keyCode=0x100000; if (keyCode==188) keyCode=0x100000; if (keyCode==189) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==190) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==191) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==192) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==193) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==194) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==195) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==196) keyCode=KeyEvent.KEYCODE_ENTER; if (keyCode==197) keyCode=KeyEvent.KEYCODE_ENTER; if (QtApplication.m_delegateObject != null && QtApplication.onKeyDown != null) return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyUp, keyCode, event); else return super.onKeyUp(keyCode, event); } (省略)