⎇ e3dd167a16e071c181b3d4f3bc77664f9cf053ab
keyboard/src/main/java/com/rizoma/trazo/model/KeyLayout.kt
Ñawpa willay
ch'uya
Trazo: teclado MessagEase remasterizado (IME v0.1)
1package com.rizoma.trazo.model
2
3import kotlin.math.atan2
4import kotlin.math.hypot
5
6/** Las 9 direcciones de una tecla: centro (toque) + 8 swipes. */
7enum class Dir { C, N, NE, E, SE, S, SW, W, NW }
8
9/**
10 * Una tecla del grid 3x3. [center] es el toque; [swipes] mapea cada dirección
11 * de deslizamiento a su carácter. Todo es dato → la distribución se ajusta sin tocar UI.
12 */
13data class KeyDef(
14 val center: Char,
15 val swipes: Map<Dir, Char> = emptyMap(),
16) {
17 fun charFor(dir: Dir): Char? = if (dir == Dir.C) center else swipes[dir]
18}
19
20object Layouts {
21
22 /**
23 * Letras — remaster del espíritu MessagEase para español.
24 * Los 9 toques son las letras más frecuentes en su posición MessagEase clásica
25 * (A N I / H O R / T E S). Las 8 direcciones del centro (O) llevan las secundarias
26 * frecuentes; las raras y la Ñ van en los bordes. Tweakable a gusto.
27 */
28 val letters: List<KeyDef> = listOf(
29 // fila superior
30 KeyDef('a', mapOf(Dir.E to 'q', Dir.S to 'z')),
31 KeyDef('n', mapOf(Dir.S to 'f', Dir.E to 'v')),
32 KeyDef('i', mapOf(Dir.S to 'j', Dir.W to 'k')),
33 // fila media
34 KeyDef('h', mapOf(Dir.N to 'w', Dir.S to 'x')),
35 KeyDef(
36 'o',
37 mapOf(
38 Dir.N to 'u', Dir.NE to 'b', Dir.E to 'c', Dir.SE to 'd',
39 Dir.S to 'g', Dir.SW to 'p', Dir.W to 'm', Dir.NW to 'l',
40 ),
41 ),
42 KeyDef('r', mapOf(Dir.S to 'y')),
43 // fila inferior
44 KeyDef('t', mapOf(Dir.N to 'ñ')),
45 KeyDef('e', emptyMap()),
46 KeyDef('s', emptyMap()),
47 )
48
49 /**
50 * Números y símbolos. Dígitos 1-9 en posición de marcador telefónico; 0 y la
51 * puntuación frecuente como swipes.
52 */
53 val symbols: List<KeyDef> = listOf(
54 KeyDef('1', mapOf(Dir.N to '!', Dir.E to '@')),
55 KeyDef('2', mapOf(Dir.N to '"', Dir.E to '#')),
56 KeyDef('3', mapOf(Dir.N to '\'', Dir.W to '$')),
57 KeyDef('4', mapOf(Dir.N to '%', Dir.E to '&')),
58 KeyDef('5', mapOf(Dir.N to '*', Dir.E to '+', Dir.W to '-', Dir.S to '=')),
59 KeyDef('6', mapOf(Dir.N to '/', Dir.W to '\\')),
60 KeyDef('7', mapOf(Dir.N to '(', Dir.E to ')')),
61 KeyDef('8', mapOf(Dir.N to ',', Dir.E to '.', Dir.W to '?')),
62 KeyDef('9', mapOf(Dir.N to ';', Dir.W to ':', Dir.E to '0')),
63 )
64}
65
66/** Geometría: convierte el delta de un gesto en una de las 9 direcciones. */
67fun directionOf(dx: Float, dy: Float, tapRadiusPx: Float): Dir {
68 if (hypot(dx, dy) < tapRadiusPx) return Dir.C
69 var deg = Math.toDegrees(atan2(dy.toDouble(), dx.toDouble())) // 0=E, 90=S (y hacia abajo)
70 if (deg < 0) deg += 360.0
71 // 8 sectores de 45° centrados en cada eje.
72 val order = arrayOf(Dir.E, Dir.SE, Dir.S, Dir.SW, Dir.W, Dir.NW, Dir.N, Dir.NE)
73 val idx = (((deg + 22.5) / 45.0).toInt()) % 8
74 return order[idx]
75}