Beispiel #1
0
  public void run() {
    byteBuffer = ByteBuffer.allocate(BUFFER_SIZE);
    charBuffer = CharBuffer.allocate(BUFFER_SIZE);

    /* for East Asian character widths */
    byte[] wideAttribute = new byte[BUFFER_SIZE];

    byteArray = byteBuffer.array();
    charArray = charBuffer.array();

    CoderResult result;

    int bytesRead = 0;
    byteBuffer.limit(0);
    int bytesToRead;
    int offset;
    int charWidth;

    EastAsianWidth measurer = EastAsianWidth.getInstance();

    try {
      while (true) {
        charWidth = bridge.charWidth;
        bytesToRead = byteBuffer.capacity() - byteBuffer.limit();
        offset = byteBuffer.arrayOffset() + byteBuffer.limit();
        bytesRead = transport.read(byteArray, offset, bytesToRead);

        if (bytesRead > 0) {
          byteBuffer.limit(byteBuffer.limit() + bytesRead);

          synchronized (this) {
            result = decoder.decode(byteBuffer, charBuffer, false);
          }

          if (result.isUnderflow() && byteBuffer.limit() == byteBuffer.capacity()) {
            byteBuffer.compact();
            byteBuffer.limit(byteBuffer.position());
            byteBuffer.position(0);
          }

          offset = charBuffer.position();

          measurer.measure(charArray, 0, offset, wideAttribute, bridge.defaultPaint, charWidth);
          buffer.putString(charArray, wideAttribute, 0, charBuffer.position());
          bridge.propagateConsoleText(charArray, charBuffer.position());
          charBuffer.clear();
          bridge.redraw();
        }
      }
    } catch (IOException e) {
      Log.e(TAG, "Problem while handling incoming data in relay thread", e);
    }
  }
 /**
  * Handle meta key presses where the key can be locked on.
  *
  * <p>1st press: next key to have meta state<br>
  * 2nd press: meta state is locked on<br>
  * 3rd press: disable meta state
  *
  * @param code
  */
 public void metaPress(int code) {
   if ((metaState & (code << 1)) != 0) {
     metaState &= ~(code << 1);
   } else if ((metaState & code) != 0) {
     metaState &= ~code;
     metaState |= code << 1;
   } else metaState |= code;
   bridge.redraw();
 }
  /**
   * Handle onKey() events coming down from a {@link TerminalView} above us. Modify the keys to make
   * more sense to a host then pass it to the transport.
   */
  public boolean onKey(View v, int keyCode, KeyEvent event) {
    try {
      final boolean hardKeyboardHidden = manager.hardKeyboardHidden;

      // Ignore all key-up events except for the special keys
      if (event.getAction() == KeyEvent.ACTION_UP) {
        // There's nothing here for virtual keyboard users.
        if (!hardKeyboard || (hardKeyboard && hardKeyboardHidden)) return false;

        // skip keys if we aren't connected yet or have been disconnected
        if (bridge.isDisconnected() || bridge.transport == null) return false;

        if (PreferenceConstants.KEYMODE_RIGHT.equals(keymode)) {
          if (keyCode == KeyEvent.KEYCODE_ALT_RIGHT && (metaState & META_SLASH) != 0) {
            metaState &= ~(META_SLASH | META_TRANSIENT);
            bridge.transport.write('/');
            return true;
          } else if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT && (metaState & META_TAB) != 0) {
            metaState &= ~(META_TAB | META_TRANSIENT);
            bridge.transport.write(0x09);
            return true;
          }
        } else if (PreferenceConstants.KEYMODE_LEFT.equals(keymode)) {
          if (keyCode == KeyEvent.KEYCODE_ALT_LEFT && (metaState & META_SLASH) != 0) {
            metaState &= ~(META_SLASH | META_TRANSIENT);
            bridge.transport.write('/');
            return true;
          } else if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT && (metaState & META_TAB) != 0) {
            metaState &= ~(META_TAB | META_TRANSIENT);
            bridge.transport.write(0x09);
            return true;
          }
        }

        return false;
      }

      // check for terminal resizing keys
      if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
        bridge.increaseFontSize();
        return true;
      } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
        bridge.decreaseFontSize();
        return true;
      }

      // skip keys if we aren't connected yet or have been disconnected
      if (bridge.isDisconnected() || bridge.transport == null) return false;

      bridge.resetScrollPosition();

      if (keyCode == KeyEvent.KEYCODE_UNKNOWN && event.getAction() == KeyEvent.ACTION_MULTIPLE) {
        byte[] input = event.getCharacters().getBytes(encoding);
        bridge.transport.write(input);
        return true;
      }

      int curMetaState = event.getMetaState();
      final int orgMetaState = curMetaState;

      if ((metaState & META_SHIFT_MASK) != 0) {
        curMetaState |= KeyEvent.META_SHIFT_ON;
      }

      if ((metaState & META_ALT_MASK) != 0) {
        curMetaState |= KeyEvent.META_ALT_ON;
      }

      int key = event.getUnicodeChar(curMetaState);
      // no hard keyboard?  ALT-k should pass through to below
      if ((orgMetaState & KeyEvent.META_ALT_ON) != 0 && (!hardKeyboard || hardKeyboardHidden)) {
        key = 0;
      }

      if ((key & KeyCharacterMap.COMBINING_ACCENT) != 0) {
        mDeadKey = key & KeyCharacterMap.COMBINING_ACCENT_MASK;
        return true;
      }

      if (mDeadKey != 0) {
        key = KeyCharacterMap.getDeadChar(mDeadKey, keyCode);
        mDeadKey = 0;
      }

      final boolean printing = (key != 0 && keyCode != KeyEvent.KEYCODE_ENTER);

      // otherwise pass through to existing session
      // print normal keys
      if (printing) {
        metaState &= ~(META_SLASH | META_TAB);

        // Remove shift and alt modifiers
        final int lastMetaState = metaState;
        metaState &= ~(META_SHIFT_ON | META_ALT_ON);
        if (metaState != lastMetaState) {
          bridge.redraw();
        }

        if ((metaState & META_CTRL_MASK) != 0) {
          metaState &= ~META_CTRL_ON;
          bridge.redraw();

          // If there is no hard keyboard or there is a hard keyboard currently hidden,
          // CTRL-1 through CTRL-9 will send F1 through F9
          if ((!hardKeyboard || (hardKeyboard && hardKeyboardHidden)) && sendFunctionKey(keyCode))
            return true;

          key = keyAsControl(key);
        }

        // handle pressing f-keys
        if ((hardKeyboard && !hardKeyboardHidden)
            && (curMetaState & KeyEvent.META_SHIFT_ON) != 0
            && sendFunctionKey(keyCode)) return true;

        if (key < 0x80) bridge.transport.write(key);
        else
          // TODO write encoding routine that doesn't allocate each time
          bridge.transport.write(new String(Character.toChars(key)).getBytes(encoding));

        return true;
      }

      // send ctrl and meta-keys as appropriate
      if (!hardKeyboard || hardKeyboardHidden) {
        int k = event.getUnicodeChar(0);
        int k0 = k;
        boolean sendCtrl = false;
        boolean sendMeta = false;
        if (k != 0) {
          if ((orgMetaState & HC_META_CTRL_ON) != 0) {
            k = keyAsControl(k);
            if (k != k0) sendCtrl = true;
            // send F1-F10 via CTRL-1 through CTRL-0
            if (!sendCtrl && sendFunctionKey(keyCode)) return true;
          } else if ((orgMetaState & KeyEvent.META_ALT_ON) != 0) {
            sendMeta = true;
            sendEscape();
          }
          if (sendMeta || sendCtrl) {
            bridge.transport.write(k);
            return true;
          }
        }
      }
      // try handling keymode shortcuts
      if (hardKeyboard && !hardKeyboardHidden && event.getRepeatCount() == 0) {
        if (PreferenceConstants.KEYMODE_RIGHT.equals(keymode)) {
          switch (keyCode) {
            case KeyEvent.KEYCODE_ALT_RIGHT:
              metaState |= META_SLASH;
              return true;
            case KeyEvent.KEYCODE_SHIFT_RIGHT:
              metaState |= META_TAB;
              return true;
            case KeyEvent.KEYCODE_SHIFT_LEFT:
              metaPress(META_SHIFT_ON);
              return true;
            case KeyEvent.KEYCODE_ALT_LEFT:
              metaPress(META_ALT_ON);
              return true;
          }
        } else if (PreferenceConstants.KEYMODE_LEFT.equals(keymode)) {
          switch (keyCode) {
            case KeyEvent.KEYCODE_ALT_LEFT:
              metaState |= META_SLASH;
              return true;
            case KeyEvent.KEYCODE_SHIFT_LEFT:
              metaState |= META_TAB;
              return true;
            case KeyEvent.KEYCODE_SHIFT_RIGHT:
              metaPress(META_SHIFT_ON);
              return true;
            case KeyEvent.KEYCODE_ALT_RIGHT:
              metaPress(META_ALT_ON);
              return true;
          }
        } else {
          switch (keyCode) {
            case KeyEvent.KEYCODE_ALT_LEFT:
            case KeyEvent.KEYCODE_ALT_RIGHT:
              metaPress(META_ALT_ON);
              return true;
            case KeyEvent.KEYCODE_SHIFT_LEFT:
            case KeyEvent.KEYCODE_SHIFT_RIGHT:
              metaPress(META_SHIFT_ON);
              return true;
          }
        }
      }

      // look for special chars
      switch (keyCode) {
        case KEYCODE_ESCAPE:
          sendEscape();
          return true;
        case KeyEvent.KEYCODE_TAB:
          bridge.transport.write(0x09);
          return true;
        case KeyEvent.KEYCODE_SEARCH:
          // check to see which shortcut the search button triggers
          String search =
              manager.prefs.getString(PreferenceConstants.SEARCH, PreferenceConstants.SEARCH_ESC);
          if (PreferenceConstants.SEARCH_BACKBTN.equals(search)) {
            // TODO: figure out what to do here!
          } else if (PreferenceConstants.SEARCH_ESC.equals(search)) {
            sendEscape();
          }
          return true;
        case KeyEvent.KEYCODE_CAMERA:

          // check to see which shortcut the camera button triggers
          String camera =
              manager.prefs.getString(
                  PreferenceConstants.CAMERA, PreferenceConstants.CAMERA_CTRLA_SPACE);
          if (PreferenceConstants.CAMERA_CTRLA_SPACE.equals(camera)) {
            bridge.transport.write(0x01);
            bridge.transport.write(' ');
          } else if (PreferenceConstants.CAMERA_CTRLA.equals(camera)) {
            bridge.transport.write(0x01);
          } else if (PreferenceConstants.CAMERA_ESC.equals(camera)) {
            ((vt320) buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0);
          } else if (PreferenceConstants.CAMERA_ESC_A.equals(camera)) {
            ((vt320) buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0);
            bridge.transport.write('a');
          }

          break;

        case KeyEvent.KEYCODE_DEL:
          ((vt320) buffer).keyPressed(vt320.KEY_BACK_SPACE, ' ', getStateForBuffer());
          metaState &= ~META_TRANSIENT;
          return true;
        case KeyEvent.KEYCODE_ENTER:
          ((vt320) buffer).keyTyped(vt320.KEY_ENTER, ' ', 0);
          metaState &= ~META_TRANSIENT;
          return true;

        case KeyEvent.KEYCODE_DPAD_LEFT:
          if (selectingForCopy) {
            selectionArea.decrementColumn();
            bridge.redraw();
          } else {
            ((vt320) buffer).keyPressed(vt320.KEY_LEFT, ' ', getStateForBuffer());
            metaState &= ~META_TRANSIENT;
            bridge.tryKeyVibrate();
          }
          return true;

        case KeyEvent.KEYCODE_DPAD_UP:
          if (selectingForCopy) {
            selectionArea.decrementRow();
            bridge.redraw();
          } else {
            ((vt320) buffer).keyPressed(vt320.KEY_UP, ' ', getStateForBuffer());
            metaState &= ~META_TRANSIENT;
            bridge.tryKeyVibrate();
          }
          return true;

        case KeyEvent.KEYCODE_DPAD_DOWN:
          if (selectingForCopy) {
            selectionArea.incrementRow();
            bridge.redraw();
          } else {
            ((vt320) buffer).keyPressed(vt320.KEY_DOWN, ' ', getStateForBuffer());
            metaState &= ~META_TRANSIENT;
            bridge.tryKeyVibrate();
          }
          return true;

        case KeyEvent.KEYCODE_DPAD_RIGHT:
          if (selectingForCopy) {
            selectionArea.incrementColumn();
            bridge.redraw();
          } else {
            ((vt320) buffer).keyPressed(vt320.KEY_RIGHT, ' ', getStateForBuffer());
            metaState &= ~META_TRANSIENT;
            bridge.tryKeyVibrate();
          }
          return true;

        case KeyEvent.KEYCODE_DPAD_CENTER:
          if (selectingForCopy) {
            if (selectionArea.isSelectingOrigin()) selectionArea.finishSelectingOrigin();
            else {
              if (clipboard != null) {
                // copy selected area to clipboard
                String copiedText = selectionArea.copyFrom(buffer);

                clipboard.setText(copiedText);
                // XXX STOPSHIP
                //							manager.notifyUser(manager.getString(
                //									R.string.console_copy_done,
                //									copiedText.length()));

                selectingForCopy = false;
                selectionArea.reset();
              }
            }
          } else {
            if ((metaState & META_CTRL_ON) != 0) {
              sendEscape();
              metaState &= ~META_CTRL_ON;
            } else metaPress(META_CTRL_ON);
          }

          bridge.redraw();

          return true;
        case KeyEvent.KEYCODE_PAGE_UP:
          ((vt320) buffer).keyPressed(vt320.KEY_PAGE_UP, ' ', getStateForBuffer());
          metaState &= ~META_TRANSIENT;
          bridge.tryKeyVibrate();
          return true;
        case KeyEvent.KEYCODE_PAGE_DOWN:
          ((vt320) buffer).keyPressed(vt320.KEY_PAGE_DOWN, ' ', getStateForBuffer());
          metaState &= ~META_TRANSIENT;
          bridge.tryKeyVibrate();
          return true;
        case KeyEvent.KEYCODE_MOVE_HOME:
          //				((vt320) buffer).keyPressed(vt320.KEY_HOME, ' ',getStateForBuffer());
          ((vt320) buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0);
          bridge.transport.write("[1~".getBytes());
          metaState &= ~META_TRANSIENT;
          bridge.tryKeyVibrate();
          return true;
        case KeyEvent.KEYCODE_MOVE_END:
          //				((vt320) buffer).keyPressed(vt320.KEY_END, ' ',getStateForBuffer());
          ((vt320) buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0);
          bridge.transport.write("[4~".getBytes());
          metaState &= ~META_TRANSIENT;
          bridge.tryKeyVibrate();
          return true;
      }

    } catch (IOException e) {
      Log.e(TAG, "Problem while trying to handle an onKey() event", e);
      try {
        bridge.transport.flush();
      } catch (IOException ioe) {
        Log.d(TAG, "Our transport was closed, dispatching disconnect event");
        bridge.dispatchDisconnect(false);
      }
    } catch (NullPointerException npe) {
      Log.d(TAG, "Input before connection established ignored.");
      return true;
    }

    return false;
  }