Crear un SoftKeyboard con múltiples / caracteres alternos por tecla

Seguí los ejemplos en developer.android.com sobre los métodos de entrada y jugué con la aplicación de muestra SoftKeyboard . Estos juntos proporcionan información más que suficiente sobre la creación de un teclado simple.

Lo que no puedo ver en la API es la capacidad de crear caracteres alternativos / múltiples por tecla, que está disponible en el teclado estándar (teclado LatinIME).

enter image description here

La imagen de arriba es el resultado de una pulsación larga en la tecla “a”. Cuando presiona prolongadamente una tecla, es posible llenar una ventana emergente con caracteres alternativos.

enter image description here

También es posible dar una sugerencia emergente sobre algunas teclas que le indicará al usuario que mantenga presionada una tecla para obtener el menú emergente.

Hasta ahora no he encontrado una sola fuente de información sobre cómo se logra esto, con suerte alguien podrá darme una ventaja, hasta entonces seguiré el código fuente del teclado incorporado y veré si puedo realizar ingeniería inversa. eso.

Editar: Ayudaría si el enlace de developer.android.com con el teclado LatinIME no se vinculó con una imagen de una oveja 🙂 Código fuente real para LatinIME.java .

Edición 2: más como referencia que cualquier otra cosa, esta es la secuencia que creo que se realiza una acción longPress habitual para mostrar el teclado emergente en KeyboardView.java :

onTouchEvent() onModifiedTouchEvent() mHandkler.handleMessage() with MSG_LONGPRESS openPopupIfRequired() onLongPress() 

Editar 3:

Todavía no me he dado cuenta de esto: ¿cómo agregar sugerencias de tags a las teclas? Una respuesta sugiere que no está integrado en la API y, de hecho, no he encontrado el código para hacerlo. Sin embargo, el Teclado en 2.3.4 (API 10) muestra esta funcionalidad implementada:

enter image description here

Me gustaría mucho averiguar cómo lo hace, pero no onDraw() método onDraw() en ninguna parte, lo que me hace pensar que se está escribiendo fuera del elemento KeyboardView. No obstante, no puedo encontrar el archivo de layout utilizado para mostrar el elemento KeyboardView en el teclado incorporado. Si alguien sabe dónde encontrarlo, tal vez eso me dé la pista que necesito.

Editar 4: tecla movida Previsualizar pregunta aquí ya que está ligeramente fuera de tema:

¿Cómo se desactiva la ventana de vista previa de la tecla SoftKeyboard?

Implementación de ventana emergente de tecla alternativa:

Para cada tecla que desee tener un teclado emergente, debe definir popupCharacters y popupKeyboard :

/res/xml/[Keyboard].xml

  

popupKeyboard es una representación XML del teclado utilizado en la ventana emergente que contiene las teclas alternativas:

/res/xml/keyboard_popup_template.xml

   

Diseñar la ventana emergente de tecla alternativa:

Si desea cambiar el diseño / estilo de la ventana emergente (que por defecto es @android: layout / keyboard_popup_keyboard.xml ) puede especificar un atributo android:popupLayout que apunta a un archivo de diseño:

  

Implementación de superposición de vista previa clave:

La única solución que he podido unir para mostrar vistas previas clave (Sin reescribir completamente el código fuente de KeyboardView) es la siguiente:

Envolviendo la etiqueta con un con una altura especificada al multiplicar la clave Height por la cantidad de filas. Dentro de esta etiqueta, simplemente he creado un LinearLayout para mantener filas, luego un LinearLayout para cada fila que contiene un TextView con un peso igual al valor de% p especificado para cada :

  

Y con estilo:

  

Que produce esto:

enter image description here

¡No estaré contento hasta que haya logrado implementar esto de la misma manera que lo hace el Teclado del sistema!

A juzgar por mi propio bash de codificar un teclado, descubrí que:

  • Las funciones atractivas generalmente requieren que amplíe KeyboardView y básicamente escriba grandes partes del código de dibujo. Lamentablemente, no puede hacer esto anulando algunos métodos clave, ya que casi todo es privado. Es posible que desee echar un vistazo (y tomar un código de:
    • (base)/core/java/android/inputmethodservice/KeyboardView.java (repo de código de núcleo android)
    • (apps)/other/LatinIME/LatinKeyboardView.java (repository de aplicaciones principales android)

Tenga en cuenta que la oveja en android.kernel.org está allí para decirle que el repository está cerrado debido a las cookies, pero hay espejos del código en otro lugar (desafortunadamente, perdió los enlaces).

  • La base KeyboardView no admite sugerencias de teclas sombreadas, debe codificar su propio KeyboardView para tener la posibilidad de anular el método onDraw ().

Ahora en lo que puedes hacer:

  • Puede solucionar este problema proporcionando imágenes para las claves: use xml

    Declare los valores de cadena que contienen las claves que desea en este teclado res/values/strings.xml :

      àáâãäåæ  

    Luego, use ambos en la definición del diseño de su teclado:

      
    • También puede usar la función de doble toque, triple toque, … para generar alternativas para la tecla que está tocando. Para hacerlo, simplemente use una lista para los códigos clave de Android:

    producirá 97 = ‘ a ‘ para un solo toque, 224 = ‘ à ‘ para doble toque y 230 = ‘ æ ‘ para triple toque.

    La duración de dos pulsaciones se establece en 800 ms en el código fuente de Android. Desafortunadamente está codificado (y un poco alto, creo).

    Tenga en cuenta que, al hacer doble clic, básicamente envía una ‘ a ‘ primero, luego, en el segundo toque, envía ‘ à ‘. Algunas aplicaciones, no les gustará esto.

Ese teclado emergente con el botón de cerrar es molesto cuando solo tenemos un carácter emergente. Una forma más simple es anular el método onLongPress de la clase KeyboardView de esta manera.

 @Override protected boolean onLongPress(Key key) { if (key.codes[0] == '1') { getOnKeyboardActionListener().onKey('!', null); return true; } } 

Si desea tener un texto encima de su clave, puede hacerlo en el método onDraw () en su clase que anula KeyboardView

  @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); ... Paint paint = new Paint(); paint.setTextAlign(Paint.Align.CENTER); paint.setTextSize(18); paint.setColor(Color.WHITE); //get all your keys and draw whatever you want List  keys = getKeyboard().getKeys(); for(Keyboard.Key key: keys) { if(key.label != null) { if (key.label.toString().equals("q") || key.label.toString().equals("Q")) canvas.drawText(String.valueOf(1), key.x + (key.width / 2) + 10, key.y + 25, paint); else if (key.label.toString().equals("w") || key.label.toString().equals("W")) canvas.drawText(String.valueOf(2), key.x + (key.width / 2) + 10, key.y + 25, paint); else if (key.label.toString().equals("e") || key.label.toString().equals("E")) canvas.drawText(String.valueOf(3), key.x + (key.width / 2) + 10, key.y + 25, paint); else if (key.label.toString().equals("r") || key.label.toString().equals("R")) canvas.drawText(String.valueOf(4), key.x + (key.width / 2) + 10, key.y + 25, paint); else if (key.label.toString().equals("t") || key.label.toString().equals("T")) canvas.drawText(String.valueOf(5), key.x + (key.width / 2) + 10, key.y + 25, paint); else if (key.label.toString().equals("y") || key.label.toString().equals("Y")) canvas.drawText(String.valueOf(6), key.x + (key.width / 2) + 10, key.y + 25, paint); else if (key.label.toString().equals("u") || key.label.toString().equals("U")) canvas.drawText(String.valueOf(7), key.x + (key.width / 2) + 10, key.y + 25, paint); else if (key.label.toString().equals("i") || key.label.toString().equals("I")) canvas.drawText(String.valueOf(8), key.x + (key.width / 2) + 10, key.y + 25, paint); else if (key.label.toString().equals("o") || key.label.toString().equals("o")) canvas.drawText(String.valueOf(9), key.x + (key.width / 2) + 10, key.y + 25, paint); else if (key.label.toString().equals("p") || key.label.toString().equals("P")) canvas.drawText(String.valueOf(0), key.x + (key.width / 2) + 10, key.y + 25, paint); else {} } } } 

Para cualquiera que trate de ignorar el teclado emergente tocando fuera de su área de visualización, he tenido un poco de suerte al poner un TouchListener en el KeyboardView dentro de la clase que extiende InputMethodService

 public class YourIME extends InputMethodService{ @Override public View onCreateInputView() { mInputView = (LatinKeyboardView) getLayoutInflater().inflate(R.layout.input, null); setLatinKeyboard(mQwertyKeyboard); mInputView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { if(motionEvent.getAction() == MotionEvent.ACTION_DOWN) { mInputView.closing(); // Close popup keyboard if it's showing } return false; } }); return mInputView; } // The rest of your ime ... } 

si quieres tener un texto encima de tu clave, puedes hacerlo en el método onDraw () en tu clase que amplía KeyboardView. Hice algo como esto, tal vez esto podría ayudar a alguien

enter image description here

  @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); Log.d("LatinKeyboardView", "onDraw"); Paint paint = new Paint(); paint.setTextAlign(Paint.Align.CENTER); paint.setTextSize(30); paint.setColor(Color.LTGRAY); List keys = getKeyboard().getKeys(); for (Key key : keys) { if (key.label != null) { switch (key.codes[0]) { //qQ case 81: case 113: case 1602: case 1618: canvas.drawText(String.valueOf(1), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //wW case 87: case 119: case 1608: case 1572: canvas.drawText(String.valueOf(2), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //eE case 69: case 101: case 1593: case 1617: canvas.drawText(String.valueOf(3), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //rR case 82: case 114: case 1585: case 1681: canvas.drawText(String.valueOf(4), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //tT case 84: case 116: case 1578: case 1657: canvas.drawText(String.valueOf(5), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //yY case 89: case 121: case 1746: case 1552: canvas.drawText(String.valueOf(6), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //uU case 85: case 117: case 1569: case 1574: canvas.drawText(String.valueOf(7), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //iI case 73: case 105: case 1740: case 1648: canvas.drawText(String.valueOf(8), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //oO case 79: case 111: case 1729: case 1731: canvas.drawText(String.valueOf(9), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //pP case 80: case 112: case 1662: case 1615: canvas.drawText(String.valueOf(0), key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //aA case 65: case 97: case 1575: case 1570: canvas.drawText("@", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //sS case 83: case 115: case 1587: case 1589: canvas.drawText("#", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //dD case 68: case 100: case 1583: case 1672: canvas.drawText("$", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //fF case 70: case 102: case 1601: case 1613: canvas.drawText("%", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //gG case 71: case 103: case 1711: case 1594: canvas.drawText("&", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //hH case 72: case 104: case 1726: case 1581: canvas.drawText("-", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //jJ case 74: case 106: case 1580: case 1590: canvas.drawText("+", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //kK case 75: case 107: case 1705: case 1582: canvas.drawText("(", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //lL case 76: case 108: case 1604: case 1614: canvas.drawText(")", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //zZ case 90: case 122: case 1586: case 1584: canvas.drawText("*", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //xX case 88: case 120: case 1588: case 1679: canvas.drawText("\"", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //cC case 67: case 99: case 1670: case 1579: canvas.drawText("\'", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //vV case 86: case 118: case 1591: case 1592: canvas.drawText(":", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //bB case 66: case 98: case 1576: case 1616: canvas.drawText(";", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //nN case 78: case 110: case 1606: case 1722: canvas.drawText("!", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; //mM case 77: case 109: case 1605: case 1611: canvas.drawText("?", key.x + (key.width - keyXAxis), key.y + keyYAxis, paint); break; } } } } 

ajustar estos ejes de acuerdo a su elección

 int keyXAxis = 25; int keyYAxis = 50;