Android Open Source - p1keyboard Game Stop Reader






From Project

Back to project page p1keyboard.

License

The source code is released under:

GNU Lesser General Public License

If you think the Android project p1keyboard listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package mobi.omegacentauri.p1keyboard;
/*from ww w .  j a  v  a 2 s  . co  m*/
import java.lang.reflect.InvocationTargetException;
import java.util.UUID;

import mobi.omegacentauri.p1keyboard.R;

import android.content.Context;
import android.util.Log;
import android.view.KeyEvent;

public class GameStopReader extends RfcommReader {
  
  private static final boolean D = false;
  
  public static final String DRIVER_NAME = "gamestop";
  public static final String DISPLAY_NAME = "GameStop Red Samurai Controller";
  
  private final byte MAGIC_NUMBER = (byte)0xA1;
  private final byte MAGIC_NUMBER_MESSAGE = (byte)0x01;
  private final byte MAGIC_NUMBER_HEADER = (byte)0xfe;
  private final byte MAGIC_NUMBER_BATTERY= (byte)0xff;
  
  private final int MESSAGE_LENGTH = 8;
  private final int HEADER_LENGTH = 18;
  private final int BATTERY_LENGTH = 7;

  //The max value a nub can report
  private static int ANALOG_NUB_MAX_VALUE = 127;
  //How far the nub must be pressed for it to issue an emulated keypress
  private static int ANALOG_NUB_THRESHOLD = ANALOG_NUB_MAX_VALUE / 2;

  //This is the number of directions supported, hardcoded
  private static final int SUPPORTED_DIRECTIONS = 8;
  
  //This is the number of buttons supported, hardcoded
  private static final int SUPPORTED_BUTTONS = 14;
    
  //These three keep track of the last known state of buttons, directions and emulated direction-buttons
  private boolean[] m_buttons = new boolean[SUPPORTED_BUTTONS];
  private int[] m_directions = new int[SUPPORTED_DIRECTIONS / 2];
  private boolean[] m_lastDirectionsKeys = new boolean[SUPPORTED_DIRECTIONS];
  
  //These are buffers that are used to read/parse input data,
  // they are reused to prevent re-allocation and garbage collections.
  //If they have the wrong size, they will be re-allocated once
  private int[] _directionValues = new int[SUPPORTED_DIRECTIONS / 2];
  
  //This is the reason we only support 8 directions (and my device only has 4)
  private static final int[] ANALOG_KEYCODES = new int[] { 
    KeyEvent.KEYCODE_W, //Left knob right 
    KeyEvent.KEYCODE_A, //Left knob left
    KeyEvent.KEYCODE_S, //Left knob down
    KeyEvent.KEYCODE_D,  //Left knob up

    KeyEvent.KEYCODE_6, //Right knob right
    KeyEvent.KEYCODE_4, //Right knob left
    KeyEvent.KEYCODE_5, //Right knob down
    KeyEvent.KEYCODE_8  //Right knob up
  };
  
  //Mapping of reported scan-codes to Android keypress values
  private static final int[] KEYCODE_MAPPINGS = {    
    FutureKeyCodes.KEYCODE_BUTTON_1,  //Button 1
    FutureKeyCodes.KEYCODE_BUTTON_2,  //Button 2
    FutureKeyCodes.KEYCODE_BUTTON_3,  //Button 3
    FutureKeyCodes.KEYCODE_BUTTON_4,  //Button 4

    FutureKeyCodes.KEYCODE_DPAD_UP,    //DPAD Up
    FutureKeyCodes.KEYCODE_DPAD_LEFT,  //DPAD Left
    FutureKeyCodes.KEYCODE_DPAD_DOWN,  //DPAD Down
    FutureKeyCodes.KEYCODE_DPAD_RIGHT, //DPAD Right

    FutureKeyCodes.KEYCODE_BUTTON_SELECT,   //Select
    FutureKeyCodes.KEYCODE_BUTTON_START,    //Start
    FutureKeyCodes.KEYCODE_BUTTON_5,     //L3
    FutureKeyCodes.KEYCODE_BUTTON_6,     //R3

    FutureKeyCodes.KEYCODE_BUTTON_L1,     //L1
    FutureKeyCodes.KEYCODE_BUTTON_L2,     //R1
    FutureKeyCodes.KEYCODE_BUTTON_R1,     //L2
    FutureKeyCodes.KEYCODE_BUTTON_R2     //R2
  };
  
  public GameStopReader(String address, String sessionId, Context context, boolean startnotification) throws Exception {
    super(address, sessionId, context, startnotification);
  }
  
  @Override
  public String getDriverName() {
    return DRIVER_NAME;
  }
  
  @Override
  protected int parseInputData(byte[] data, int read) {
  
    int offset = 0;
    int remaining = read;
    
    //This should always be true
    while (remaining > 3 && data[offset + 0] == MAGIC_NUMBER) {
      if (data[offset + 1] == MAGIC_NUMBER_BATTERY) {
        remaining -= BATTERY_LENGTH;
        offset += BATTERY_LENGTH;
      } else if (data[offset + 1] == MAGIC_NUMBER_HEADER) {
        remaining -= HEADER_LENGTH;
        offset += HEADER_LENGTH;
      } else if (data[offset + 1] == MAGIC_NUMBER_MESSAGE) {
        int buttons = ((data[offset + 6] & 0xff) << 8) | (data[offset + 7] & 0xff);
        //For some strange reason, the UP bit is flipped
        int up = (buttons & (1 << 8)) == 0 ? 1 : 0;
        buttons = (buttons & ~(1 << 8)) | (up << 8);
        
        _directionValues[0] = (data[offset + 2] & 0xff) - 0x80;
        _directionValues[1] = (data[offset + 3] & 0xff) - 0x80;
        _directionValues[2] = (data[offset + 4] & 0xff) - 0x80;
        _directionValues[3] = (data[offset + 5] & 0xff) - 0x80;
        
        for(int i = 0; i < m_buttons.length; i++) {
          boolean state =  (buttons & (1 << (15 - i))) != 0;
          if (state != m_buttons[i]) {
            m_buttons[i] = state;
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_ACTION, state ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP);
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_KEY, KEYCODE_MAPPINGS[i]);
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_MODIFIERS, 0);
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_ANALOG_EMULATED, false);
            m_context.sendBroadcast(keypressBroadcast);
          }
        }
        
        for(int i = 0; i < m_directions.length; i++) {
          boolean large = _directionValues[i] > ANALOG_NUB_THRESHOLD;
          boolean small = _directionValues[i] < -ANALOG_NUB_THRESHOLD;
          
          if (large != m_lastDirectionsKeys[i * 2]) {
            m_lastDirectionsKeys[i * 2] = large;
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_ACTION, large ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP);
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_KEY, ANALOG_KEYCODES[i]);
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_ANALOG_EMULATED, true);
            m_context.sendBroadcast(keypressBroadcast);
          }
          
          if (small != m_lastDirectionsKeys[(i * 2) + 1]) {
            m_lastDirectionsKeys[(i * 2) + 1] = small;
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_ACTION, small ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP);
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_KEY, ANALOG_KEYCODES[i]);
            keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_ANALOG_EMULATED, true);
            m_context.sendBroadcast(keypressBroadcast);
          }
          
          if (_directionValues[i] != m_directions[i]) {
            directionBroadcast.putExtra(BluezService.EVENT_DIRECTIONALCHANGE_DIRECTION, i);
            directionBroadcast.putExtra(BluezService.EVENT_DIRECTIONALCHANGE_VALUE, _directionValues[i]);
            m_context.sendBroadcast(directionBroadcast);
            m_directions[i] = _directionValues[i];
          }
            
        }
        
        remaining -= MESSAGE_LENGTH;
        offset += MESSAGE_LENGTH;
        
      } else {
        //Ditch the rest
        remaining = 0;
      }
    }
    
    return remaining;
  }
  
  @Override
  protected int setupConnection(ImprovedBluetoothDevice device, byte[] readBuffer) throws Exception {
    try {
      //Most devices supports using the reflection method
      if (D) Log.d(getDriverName(), "Attempting reflection connect");
      return super.setupConnection(device, readBuffer);
    } catch (Exception ex) {

      if (D) Log.d(getDriverName(), "Reflection connect failed, error: " + ex.getMessage());

      if (D && ex instanceof InvocationTargetException) {
        InvocationTargetException tex = (InvocationTargetException)ex;
        Log.e(getDriverName(), "TargetInvocation cause: " + (tex.getCause() == null ? "<null>" : tex.getCause().toString()));
        Log.e(getDriverName(), "TargetInvocation target: " + (tex.getTargetException() == null ? "<null>" : tex.getTargetException().toString()));
      }

      try {
        if (D) Log.d(getDriverName(), "Attempting createRfcommSocketToServiceRecord connect");

        //In case the reflection method was not present, we try the correct method
            m_socket = device.createRfcommSocketToServiceRecord(UUID.fromString("8e1f0cf7-508f-4875-b62c-fbb67fd34812"));
            m_socket.connect();

            if (D) Log.d(getDriverName(), "Connected with createRfcommSocketToServiceRecord() to " + m_address);
          
          m_input = m_socket.getInputStream();
          return m_input.read(readBuffer);
          
      } catch (Exception ex2) {
        if (D) Log.e(getDriverName(), "Failed on createRfcommSocketToServiceRecord: " + ex2.getMessage());
        
        //Report the original error, not the secondary
        throw ex;
      }
      
    }
  }
  
  @Override
  protected void validateWelcomeMessage(byte[] data, int read) {
    //TODO: Find some documentation that explains how to parse the message
  }

  public static int[] getButtonCodes() {
    return new int[] { 
        FutureKeyCodes.KEYCODE_DPAD_UP,    //DPAD Up
        FutureKeyCodes.KEYCODE_DPAD_LEFT,  //DPAD Left
        FutureKeyCodes.KEYCODE_DPAD_DOWN,  //DPAD Down
        FutureKeyCodes.KEYCODE_DPAD_RIGHT, //DPAD Right

        FutureKeyCodes.KEYCODE_BUTTON_1,  //Button 1
        FutureKeyCodes.KEYCODE_BUTTON_2,  //Button 2
        FutureKeyCodes.KEYCODE_BUTTON_3,  //Button 3
        FutureKeyCodes.KEYCODE_BUTTON_4,  //Button 4

        FutureKeyCodes.KEYCODE_BUTTON_SELECT,   //Select
        FutureKeyCodes.KEYCODE_BUTTON_START,    //Start
        FutureKeyCodes.KEYCODE_BUTTON_5,     //L3
        FutureKeyCodes.KEYCODE_BUTTON_6,     //R3

        FutureKeyCodes.KEYCODE_BUTTON_L1,     //L1
        FutureKeyCodes.KEYCODE_BUTTON_L2,     //R1
        FutureKeyCodes.KEYCODE_BUTTON_R1,     //L2
        FutureKeyCodes.KEYCODE_BUTTON_R2,     //R2

        KeyEvent.KEYCODE_W, //Left knob right 
        KeyEvent.KEYCODE_A, //Left knob left
        KeyEvent.KEYCODE_S, //Left knob down
        KeyEvent.KEYCODE_D,  //Left knob up

        KeyEvent.KEYCODE_6, //Right knob right
        KeyEvent.KEYCODE_4, //Right knob left
        KeyEvent.KEYCODE_5, //Right knob down
        KeyEvent.KEYCODE_8  //Right knob up
    };
  }

  public static int[] getButtonNames() {
    return new int[] { 
        R.string.gamestop_dpad_up, 
        R.string.gamestop_dpad_left, 
        R.string.gamestop_dpad_down, 
        R.string.gamestop_dpad_right, 
        
        R.string.gamestop_button_1, 
        R.string.gamestop_button_2, 
        R.string.gamestop_button_3, 
        R.string.gamestop_button_4, 

        R.string.gamestop_button_start, 
        R.string.gamestop_button_select, 
        R.string.gamestop_button_l3, 
        R.string.gamestop_button_r3, 

        R.string.gamestop_button_l1, 
        R.string.gamestop_button_l2, 
        R.string.gamestop_button_r1, 
        R.string.gamestop_button_r2, 

        R.string.gamestop_leftknob_left, 
        R.string.gamestop_leftknob_right, 
        R.string.gamestop_leftknob_up, 
        R.string.gamestop_leftknob_down, 

        R.string.gamestop_rightknob_left, 
        R.string.gamestop_rightknob_right, 
        R.string.gamestop_rightknob_up, 
        R.string.gamestop_rightknob_down, 
    };
  }
}




Java Source Code List

mobi.omegacentauri.p1keyboard.BGP100Reader.java
mobi.omegacentauri.p1keyboard.BluezDriverInterface.java
mobi.omegacentauri.p1keyboard.BluezForegroundService.java
mobi.omegacentauri.p1keyboard.BluezIMESettings.java
mobi.omegacentauri.p1keyboard.BluezIME.java
mobi.omegacentauri.p1keyboard.BluezService.java
mobi.omegacentauri.p1keyboard.ButtonConfiguration.java
mobi.omegacentauri.p1keyboard.DataDumpReader.java
mobi.omegacentauri.p1keyboard.DeviceScanActivity.java
mobi.omegacentauri.p1keyboard.FutureKeyCodes.java
mobi.omegacentauri.p1keyboard.GameStopReader.java
mobi.omegacentauri.p1keyboard.HIDKeyboard.java
mobi.omegacentauri.p1keyboard.HIDReaderBase.java
mobi.omegacentauri.p1keyboard.HIDipega.java
mobi.omegacentauri.p1keyboard.ImprovedBluetoothDevice.java
mobi.omegacentauri.p1keyboard.PalmOneWirelessKeyboardReader.java
mobi.omegacentauri.p1keyboard.PhonejoyReader.java
mobi.omegacentauri.p1keyboard.Preferences.java
mobi.omegacentauri.p1keyboard.RfcommReader.java
mobi.omegacentauri.p1keyboard.WiimoteReader.java
mobi.omegacentauri.p1keyboard.ZeemoteReader.java
mobi.omegacentauri.p1keyboard.iCadeReader.java
mobi.omegacentauri.p1keyboard.iControlPadReader.java