Android Open Source - p1keyboard Palm One Wireless Keyboard 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

/* Copyright (C) 2011, Kenneth Skovhede
 * http://www.hexad.dk, opensource@hexad.dk
 * /*from www  .  ja  v  a  2s .c  om*/
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package mobi.omegacentauri.p1keyboard;

import java.io.OutputStream;
import java.util.UUID;

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

public class PalmOneWirelessKeyboardReader extends RfcommReader {

  private static final String LOG_NAME = "BluezIME:PalmOneWirelessKeyboardReader";
  public static final String DRIVER_NAME = "palmonewireless";
  public static final String DISPLAY_NAME = "PalmOne Wireless Keyboard";

  public int keys[] = new int[0x80];
  public boolean[] down = new boolean[0x80];
  public boolean capslock;
  public int[][] combining;
  
  int[][] acute = {
    {KeyEvent.KEYCODE_A, 0xC1},
    {KeyEvent.KEYCODE_C, 0x107},
    {KeyEvent.KEYCODE_E, 0xE9},
    {KeyEvent.KEYCODE_I, 0xED},
    {KeyEvent.KEYCODE_N, 0x144},
    {KeyEvent.KEYCODE_O, 0xF3},
    {KeyEvent.KEYCODE_S, 0x15B},
    {KeyEvent.KEYCODE_U, 0xFA},
    {KeyEvent.KEYCODE_Y, 0xFD},
    {KeyEvent.KEYCODE_Z, 0x17A}
  };

  int[][] dot = {
      {KeyEvent.KEYCODE_Z, 0x17C}
    };
  
  int[][] minus = {
      {KeyEvent.KEYCODE_L, 0x142},
      {KeyEvent.KEYCODE_H, 0x127}
  };
  
  int[][] cedilla = {
      {KeyEvent.KEYCODE_A, 0x105},
      {KeyEvent.KEYCODE_C, 0xE7},
      {KeyEvent.KEYCODE_E, 0x119}
  };
  
  public PalmOneWirelessKeyboardReader(String address, String sessionId, Context context, boolean startnotification) throws Exception {
    super(address, sessionId, context, startnotification);

    setupMap();
  }

  @Override
  public String getDriverName() {
    return DRIVER_NAME;
  }

  private void setupMap() {
    for (int i = 0; i < keys.length ; i++)
      keys[i] = -1;

    keys[0x4e] = KeyEvent.KEYCODE_MINUS;
    keys[0x0e] = KeyEvent.KEYCODE_GRAVE;
    keys[0x55] = KeyEvent.KEYCODE_EQUALS;

    keys[0x66] = KeyEvent.KEYCODE_DEL; // BACKSPACE!
    keys[0x0d] = KeyEvent.KEYCODE_TAB;
    keys[0x54] = KeyEvent.KEYCODE_LEFT_BRACKET;
    keys[0x5b] = KeyEvent.KEYCODE_RIGHT_BRACKET;
    keys[0x5d] = KeyEvent.KEYCODE_BACKSLASH;

    keys[0x4c] = KeyEvent.KEYCODE_SEMICOLON;
    keys[0x52] = KeyEvent.KEYCODE_APOSTROPHE;
    keys[0x5a] = KeyEvent.KEYCODE_ENTER;
    keys[0x48] = KeyEvent.KEYCODE_COMMA;
    keys[0x49] = KeyEvent.KEYCODE_PERIOD;
    keys[0x4a] = KeyEvent.KEYCODE_SLASH;

    keys[0x11] = KeyEvent.KEYCODE_HOME;

    keys[0x12] = KeyEvent.KEYCODE_SHIFT_LEFT;
    keys[0x59] = KeyEvent.KEYCODE_SHIFT_RIGHT;
    keys[0x29] = KeyEvent.KEYCODE_SPACE;

    keys[0x28] = KeyEvent.KEYCODE_DPAD_UP;
    keys[0x5e] = KeyEvent.KEYCODE_DPAD_LEFT;
    keys[0x60] = KeyEvent.KEYCODE_DPAD_DOWN;
    keys[0x2f] = KeyEvent.KEYCODE_DPAD_RIGHT;

    keys[0x16] = KeyEvent.KEYCODE_1;
    keys[0x1e] = KeyEvent.KEYCODE_2;
    keys[0x26] = KeyEvent.KEYCODE_3;
    keys[0x25] = KeyEvent.KEYCODE_4;
    keys[0x2e] = KeyEvent.KEYCODE_5;
    keys[0x36] = KeyEvent.KEYCODE_6;
    keys[0x3d] = KeyEvent.KEYCODE_7;
    keys[0x3e] = KeyEvent.KEYCODE_8;
    keys[0x46] = KeyEvent.KEYCODE_9;
    keys[0x45] = KeyEvent.KEYCODE_0;

    keys[0x15] = KeyEvent.KEYCODE_Q;
    keys[0x1d] = KeyEvent.KEYCODE_W;
    keys[0x24] = KeyEvent.KEYCODE_E;
    keys[0x2d] = KeyEvent.KEYCODE_R;
    keys[0x2c] = KeyEvent.KEYCODE_T;
    keys[0x35] = KeyEvent.KEYCODE_Y;
    keys[0x3c] = KeyEvent.KEYCODE_U;
    keys[0x43] = KeyEvent.KEYCODE_I;
    keys[0x44] = KeyEvent.KEYCODE_O;
    keys[0x4d] = KeyEvent.KEYCODE_P;

    keys[0x1c] = KeyEvent.KEYCODE_A;
    keys[0x1b] = KeyEvent.KEYCODE_S; 
    keys[0x23] = KeyEvent.KEYCODE_D;
    keys[0x2b] = KeyEvent.KEYCODE_F;
    keys[0x34] = KeyEvent.KEYCODE_G;
    keys[0x33] = KeyEvent.KEYCODE_H;
    keys[0x3b] = KeyEvent.KEYCODE_J;
    keys[0x42] = KeyEvent.KEYCODE_K;
    keys[0x4b] = KeyEvent.KEYCODE_L;

    keys[0x1a] = KeyEvent.KEYCODE_Z;
    keys[0x22] = KeyEvent.KEYCODE_X;
    keys[0x21] = KeyEvent.KEYCODE_C;
    keys[0x2a] = KeyEvent.KEYCODE_V;
    keys[0x32] = KeyEvent.KEYCODE_B;
    keys[0x31] = KeyEvent.KEYCODE_N;
    keys[0x3a] = KeyEvent.KEYCODE_M;

    keys[0x30] = KeyEvent.KEYCODE_ALT_RIGHT;

    keys[0x03] = KeyEvent.KEYCODE_MENU; // Windows key

    // The following won't work below Android 3.0, probably
    keys[0x02] = KeyEvent.KEYCODE_FUNCTION;
    keys[0x1f] = KeyEvent.KEYCODE_FORWARD_DEL;
    keys[0x58] = KeyEvent.KEYCODE_CAPS_LOCK;
    keys[0x14] = KeyEvent.KEYCODE_CTRL_LEFT;
  }

  @Override
  protected int setupConnection(ImprovedBluetoothDevice device, byte[] readBuffer) throws Exception {
    Exception lastException = null;

    for (int retry = 0; retry < 4 ; retry++) {
      OutputStream os = null;
      m_socket = null;
      lastException = null;

      try {
        m_socket = device.createRfcommSocketToServiceRecord(UUID.fromString(ImprovedBluetoothDevice.SPP));

        m_socket.connect();
        Log.d(LOG_NAME, "Connected to " + m_address);

        // put Brainlink in irDA mode at 9600 baud and switch to bridge mode
        os = m_socket.getOutputStream();

        os.write(new byte[] { '*', 'J', '1', 'Z' } );            
        //os.close();
      } catch(Exception e) {
        Log.e(LOG_NAME, "On attempt "+retry+" got "+e);
        lastException = e;
        if (os != null) {
          try {
            os.close();
          }
          catch (Exception e2) {
          }
        }
        if (m_socket != null) {
          try {
            m_socket.close();
          }
          catch (Exception e2) {
          }
        }
      }

      if (lastException == null)
        break;
    }

    if (lastException != null)
      throw lastException;


    m_input = m_socket.getInputStream();

    Log.d(LOG_NAME, "Have connection");

    readBuffer[0] = 0;
    return 1;
    //      return m_input.read(readBuffer);    
  }

  @Override
  protected int parseInputData(byte[] data, int read) {
    //Log.d(LOG_NAME, "Read data: " + getHexString(data, 0, read));
    if (read < 6)
      return read;
    if (data[0] != (byte)0xFF)
      return read - 1;
    if (data[1] != (byte)0xC0 || data[5] != (byte)0xC1)  {
      Log.v(LOG_NAME, "Strange data "+getHexString(data, 0, read));

      return read - 1;
    }


    read -= 6;

    // normally data[3] = data[2] ^ 0xFF and data[4] = data[2] ^ 0x67.
    // Thus each keycode is effectively transmitted three times.  Use
    // majority to recover it in case of corruption.

    int k1 = data[2];
    int k2 = data[3] ^ (byte)0xFF;
    int k3 = data[4] ^ (byte)0x67;

    int key;

    if (k1 == k2 || k1 == k3)
      key = k1;
    else if (k2 == k3)
      key = k2;
    else {
      Log.v(LOG_NAME, "Corrupted packet "+getHexString(data, 0, read));
      return read; // unrecoverably corrupt packet
    }

    int action;
    boolean repeat;

    if ( (key & 0x80) != 0 ) {
      action = KeyEvent.ACTION_UP;
      key &= 0x7F;
      repeat = false;
      down[key] = false;
    }
    else {
      action = KeyEvent.ACTION_DOWN;
      repeat = down[key];
      down[key] = true;
    }

    if (action == KeyEvent.ACTION_DOWN && key == 0x58)
      capslock = !capslock;

    int modifiers = 0;

    if (down[0x14] && action == KeyEvent.ACTION_DOWN) {
      int special = 0;

      switch(keys[key]) {
      case KeyEvent.KEYCODE_C:
        special = BluezService.SPECIAL_COPY;
        break;
      case KeyEvent.KEYCODE_V:
        special = BluezService.SPECIAL_PASTE;
        break;
      case KeyEvent.KEYCODE_X:
        special = BluezService.SPECIAL_PASTE;
        break;
      case KeyEvent.KEYCODE_A:
        special = BluezService.SPECIAL_SELECT_ALL;
        break;
      }

      if (special > 0) {
        if (!repeat)
          send(action, keys[key], modifiers, special);
        return read;
      }
    }

    boolean shifted = down[0x12] || down[0x59];
    boolean capitalize = (capslock && ! shifted) || (!capslock && shifted);
    boolean alphabetic = KeyEvent.KEYCODE_A <= keys[key] && keys[key] <= KeyEvent.KEYCODE_Z;
    boolean shift = (key == 0x12) || (key == 0x59);
    
    if (down[0x02] && action == KeyEvent.ACTION_DOWN) {
      // FN key
      switch(keys[key]) {
      case KeyEvent.KEYCODE_3:
        send(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SEARCH, 0, 0);
        send(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SEARCH, 0, 0);
        return read;
      case KeyEvent.KEYCODE_2:
        send(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU, 0, 0);
        send(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU, 0, 0);
        return read;
      case KeyEvent.KEYCODE_1:
        send(action, keys[key], modifiers, BluezService.SPECIAL_HOME);
        return read;
      case KeyEvent.KEYCODE_DPAD_UP:
        send(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_UP, 0, 0);
        send(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_PAGE_UP, 0, 0);
        return read;
      case KeyEvent.KEYCODE_DPAD_DOWN:
        send(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_DOWN, 0, 0);
        send(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_PAGE_DOWN, 0, 0);
        return read;
      case KeyEvent.KEYCODE_DPAD_LEFT:
        send(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MOVE_HOME, 0, 0);
        send(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MOVE_HOME, 0, 0);
        return read;
      case KeyEvent.KEYCODE_DPAD_RIGHT:
        send(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MOVE_END, 0, 0);
        send(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MOVE_END, 0, 0);
        return read;
      case KeyEvent.KEYCODE_Y: // yen
        send(KeyEvent.ACTION_DOWN, 165, 0, BluezService.SPECIAL_UNICODE);
        return read;
      case KeyEvent.KEYCODE_P: // pound
        send(KeyEvent.ACTION_DOWN, 0xA3, 0, BluezService.SPECIAL_UNICODE);
        return read;
      case KeyEvent.KEYCODE_Z: // mu
        send(KeyEvent.ACTION_DOWN, 0x3BC, 0, BluezService.SPECIAL_UNICODE);
        return read;
      case KeyEvent.KEYCODE_X: // c-cedilla
        send(KeyEvent.ACTION_DOWN, capitalize ? 0xC7 : 0xE7, 0, BluezService.SPECIAL_UNICODE);
        return read;
      case KeyEvent.KEYCODE_C: // sharp s
        if (capitalize) {
          send(KeyEvent.ACTION_DOWN, (int)'S', 0, BluezService.SPECIAL_UNICODE);
          send(KeyEvent.ACTION_DOWN, (int)'S', 0, BluezService.SPECIAL_UNICODE);
        }
        else {
          send(KeyEvent.ACTION_DOWN, 0xDF, 0, BluezService.SPECIAL_UNICODE);
        }
        return read;

      case KeyEvent.KEYCODE_V: // inverted !
        send(KeyEvent.ACTION_DOWN, 0xA1, 0, BluezService.SPECIAL_UNICODE);
        return read;

      case KeyEvent.KEYCODE_B: // n~
        send(KeyEvent.ACTION_DOWN, capitalize ? 0xD1 : 0xF1, 0, BluezService.SPECIAL_UNICODE);
        return read;

      case KeyEvent.KEYCODE_N: // N~
        send(KeyEvent.ACTION_DOWN, 0xD1, 0, BluezService.SPECIAL_UNICODE);
        return read;

      case KeyEvent.KEYCODE_M: // inverted ?
        send(KeyEvent.ACTION_DOWN, 0xBF, 0, BluezService.SPECIAL_UNICODE);
        return read;
        
      case KeyEvent.KEYCODE_D: 
        combining = acute;
        return read;
        
      case KeyEvent.KEYCODE_PERIOD:
        combining = dot;
        return read;
        
      case KeyEvent.KEYCODE_MINUS:
        combining = minus;
        return read;
        
      case KeyEvent.KEYCODE_COMMA:
        combining = cedilla;
        return read;
      }
    }

    if (keys[key] == KeyEvent.KEYCODE_HOME){
      if (action == KeyEvent.ACTION_DOWN)
        send(action, keys[key], modifiers, BluezService.SPECIAL_HOME);
      return read;
    } 
    
    if (action == KeyEvent.ACTION_DOWN && ! alphabetic && ! shift) 
      combining = null;
    
    if (action == KeyEvent.ACTION_DOWN && alphabetic && combining != null) {
      combine(keys[key], capitalize);
    }
    else if (keys[key] >= 0) {
        if (! (capslock && shifted && alphabetic ) ) {
          if (down[0x12])
            modifiers |= KeyEvent.META_SHIFT_LEFT_ON;
          if (down[0x59])
            modifiers |= KeyEvent.META_SHIFT_RIGHT_ON;
          if (capslock && (! down[0x12] && ! down[0x59]) )
            modifiers |= KeyEvent.META_CAPS_LOCK_ON;
        }
        if (down[0x14])
          modifiers |= KeyEvent.META_CTRL_LEFT_ON;
  
        send(action, keys[key], modifiers, 0);
      }

    return read;
  }
  
  private void combine(int key, boolean capitalize) {
    for (int[] k : combining) {
      if (k[0] == key) {
        send(KeyEvent.ACTION_DOWN, capitalize ? Character.toUpperCase(k[1]) : k[1], 0, BluezService.SPECIAL_UNICODE);
        break;
      }
    }
    combining = null;
  }

  private void send(int action, int keyCode, int modifiers, int special) {
    keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_ACTION, action);
    keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_KEY, keyCode);
    keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_MODIFIERS, modifiers);
    keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_ANALOG_EMULATED, false);
    keypressBroadcast.putExtra(BluezService.EVENT_KEYPRESS_SPECIAL, special);
    m_context.sendBroadcast(keypressBroadcast);
  }

  @Override
  protected void validateWelcomeMessage(byte[] data, int read) {
    Log.d(LOG_NAME, "Welcome message is: " + getHexString(data, 0, read));
  }
}




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