1. Nimm jetzt an unserem Uhans - 3. ADVENT - Gewinnspiel teil - Alle Informationen findest Du hier!

Probleme mit KeyEvents in Input Method

Dieses Thema im Forum "Android App Entwicklung" wurde erstellt von teh_hahn, 10.08.2011.

  1. teh_hahn, 10.08.2011 #1
    teh_hahn

    teh_hahn Threadstarter Neuer Benutzer

    Beiträge:
    1
    Erhaltene Danke:
    0
    Registriert seit:
    10.08.2011
    Hallo zusammen,

    ich entwickle momentan eine Input Method für Google Android (API Level 11, d.h. Version 3.0) und habe dabei ein paar Verständnissschwierigkeiten bzw. Probleme im Zusammenhang mit der Klasse KeyEvent und deren Verwendung.

    Bei der Input Method handelt es sich um ein Software Keyboard, das in der Lage sein soll, Sondertasten des PCs an die daunterligende Applikation zu senden (z.B. ESC, CTRL, ALT, SHIFT).

    Um dies zu testen, verwende ich den Javascript Key Event Tester. Falls jemand eine bessere Möglichkeit weiß, wäre ich auch dafür schon einmal dankbar!

    Nun zu den eigentlichen Problemen. Das Senden von Zeichentasten (z.B. 'A', 'a', aber auch ENTER) habe ich mit der Methode InputConnection.commitText() realisiert. Dies funktioniert auch soweit.

    Bei den Sondertasten fangen die Probleme jedoch an. Ich habe mich an das offizielle Tutorial Creating an Input Method gehalten, das im Abschnitt Sending test to the application die Klasse KeyEvent nennt.

    Nun habe ich nachfolgenden Quelltest geschrieben, um zu Testen, ob auf diese Art und Weise die ESCAPE-Taste erkannt wird (analog zum Beispiel im Tutorial):
    Code:
    InputConnection ic = this.getCurrentInputConnection();
    if (ic != null) {
        long eventTime = SystemClock.uptimeMillis();
        ic.sendKeyEvent(
            new KeyEvent(
                eventTime, // The time (in uptimeMillis()) at which this key code originally went down.
                eventTime, // The time (in uptimeMillis()) at which this event happened.
                KeyEvent.ACTION_DOWN, // Action code: either ACTION_DOWN, ACTION_UP, or ACTION_MULTIPLE.
                KeyEvent.KEYCODE_ESCAPE, // The key code.
                0, // A repeat count for down events (> 0 if this is after the initial down) or event count for multiple events.
                0, // Flags indicating which meta keys are currently pressed.
                KeyCharacterMap.ALPHA, // The device ID that generated the key event.
                0, // Raw device scan code of the event. 
                KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE // The flags for this key event.
            )
        );
        ic.sendKeyEvent(
            new KeyEvent(
                eventTime, // The time (in uptimeMillis()) at which this key code originally went down.
                eventTime, // The time (in uptimeMillis()) at which this event happened.
                KeyEvent.ACTION_UP, // Action code: either ACTION_DOWN, ACTION_UP, or ACTION_MULTIPLE.
                KeyEvent.KEYCODE_ESCAPE, // The key code.
                0, // A repeat count for down events (> 0 if this is after the initial down) or event count for multiple events.
                0, // Flags indicating which meta keys are currently pressed.
                KeyCharacterMap.ALPHA, // The device ID that generated the key event.
                0, // Raw device scan code of the event. 
                KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE // The flags for this key event.
            )
        );
        Log.w("KEYCODE_ESCAPE", String.valueOf(KeyEvent.KEYCODE_ESCAPE)); //$NON-NLS-1$
    }
    Der oben genannte Javascript Key Tester zeigt darauf jedoch keinerlei Reaktion, über dem Software Keyboard erscheint jedoch die Zeichenkette "Wird angehalten...". Mit dieser Meldung kann ich allerdings nichts anfangen. Die Verwendung des ASCII-Codes (27 für ESC), führt ebenfalls zu keiner Rückmeldung des Javascript Key Tester:
    Code:
    this.getCurrentInputConnection().commitText(
        String.valueOf((char) 27), 1
    );
    Noch problematischer gestaltet sich für mich die Implementierung der PC Tasten ALT, CTRL und SHIFT. Es soll z.B. möglich sein, die Tastenkombination CTRL + A an die darunterliegende Applikation zu senden (also quasi jede beliebige Tastenkombination). Ich habe bisher Folgendes gemacht:
    1. Definition eines Attributs, dass eine Bitmaske für die aktuell gedrückten Metatasten darstellt:
    Code:
    /**
     * The mask that includes the modifier key meta state bits <tt>{@link
     * KeyEvent#META_ALT_ON}</tt>, <tt>{@link KeyEvent#META_CTRL_ON}</tt> and
     * <tt>{@link KeyEvent#META_SHIFT_ON}</tt>.
     */
    private int _iCurrentMetaKeyMask = 0;
    2. Methoden, die diese Bitmaske bei Druck auf eine der drei Tasten ALT, CTRL und SHIFT modifiziert:
    Code:
    /**
     * Helper method to send a control key (<i>Alt<i>) to the current editor.
     */
    private void _handleAlt() {
        this._iCurrentMetaKeyMask ^= KeyEvent.META_ALT_ON;
    }
    
    /**
     * Helper method to send a control key (<i>Ctrl<i>) to the current editor.
     */
    private void _handleCtrl() {
        this._iCurrentMetaKeyMask ^= KeyEvent.META_CTRL_ON;
    }
    
    /**
     * Helper method to send <i>Shift</i> to the current editor.
     */
    private void _handleShift() {
        this._iCurrentMetaKeyMask ^= KeyEvent.META_SHIFT_ON;
    }
    3. Erweiterung der Methode zum Senden von Zeichentasten (siehe auch weiter oben):
    Code:
    /**
     * Helper method to send a character key to hte current editor.
     *
     * @param primaryCode
     *            the unicode code of the key that was pressed.
     */
    private void _handleCharacter(int primaryCode) {
        Log.w("CURRENT_META_MASK", String.valueOf(this._iCurrentMetaKeyMask)); //$NON-NLS-1$
    
        InputConnection ic = this.getCurrentInputConnection();
    
        // Check whether the current bit mask of the meta keys is set.
        if (0 != this._iCurrentMetaKeyMask) {
            KeyEvent keyEvent = null;
            long eventTime = SystemClock.uptimeMillis();
    
            if ((this._iCurrentMetaKeyMask & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
                this.sendDownKeyEvent(KeyEvent.KEYCODE_ALT_LEFT);
            }
            if ((this._iCurrentMetaKeyMask & KeyEvent.META_CTRL_ON) == KeyEvent.META_CTRL_ON) {
                this.sendDownKeyEvent(KeyEvent.KEYCODE_CTRL_LEFT);
            }
            if ((this._iCurrentMetaKeyMask & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON) {
                this.sendDownKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT);
            }
    
            // ToDo: Wie soll das gehen? Mapping über ASCII auf KeyCodes???
            // Momentan wird immer A gesendet, falls Alt, Ctrl und/oder Shift
            // gedrückt wurde.
            keyEvent = new KeyEvent(
                SystemClock.uptimeMillis(), eventTime,
                KeyEvent.ACTION_DOWN,
                KeyEvent.KEYCODE_A,
                this._iCurrentMetaKeyMask
            );
            ic.sendKeyEvent(keyEvent);
        } else {
            ic.commitText(
                String.valueOf((char) primaryCode), 1
            );
        }
    }
    Was funktioniert ist Folgendes:

    • Bei Druck auf die Taste SHIFT und späteren Drucks auf eine andere Taste wird die Tastenkombination SHIFT+A gesendet (wird auch im Javascript Key Event Tester angezeigt).
    Was nicht funktioniert:

    • Bei Druck auf die Taste ALT und späteren Drucks auf eine andere Taste öffnet sich im Browser ein Texteingabefenster mit dem Buchstaben 'a' darin. Meine Vermutung: Das Betriebssystem legt sich darüber und greift die Funktion zuerst ab! Dies würde dann aber ja bedeuten, dass sich ALT für Webseiten, die z.B. JavaScript und Tastenkombination zusammen mit ALT für spezielle Funktionen verwenden mit Android nicht bedienen lassen! Oder stellt das ALT der Klasse KeyEvent nicht das Pendant zur Taste ALT des PCs dar?
    • Bei Druck auf die Taste CTRL und späteren Drucks auf eine andere Taste wird nur 'a' gesendet und CTRL nicht als Metataste erkannt.
    Des Weiteren stellt sich mir die Frage, wie ich primaryCode (ein Integer) in das entsprechende KeyEvent (z.B. KeyEvent.KEYCODE_A) umwandeln kann.
    Gibt es dafür bereits vorhandene Methoden? Ansonsten müsste man sich ja z.B. eine Map bauen, die diese Zuordnungen enthält (unschön!).

    Ich hoffe jemand hier hat Erfahrungen mit Input Methods und KeyEvents und kann mir bei dem Einen oder Anderen Problem weiter helfen.

    Viele Grüße.

    teh_hahn
     

Diese Seite empfehlen