tawasuyu

sergio/humanoid

HTML 50Markdown 1TOML 10 Sutichaykuna

⎇ 5227fbf1abfb2a437968ebc63692560c3a929230 keyboard/src/main/java/com/rizoma/trazo/model/KeyLayout.kt 139 siq'ikuna · 5.6 KB Ñawpa willay ch'uya

Trazo: arreglar cursor al reposicionar + mayúsculas en R↑ y columna reordenada 5227fbf1a · Sergio ·

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    /** Dirección de swipe que activa mayúsculas en vez de emitir carácter (la R↑). */
17    val shiftDir: Dir? = null,
18) {
19    fun charFor(dir: Dir): Char? = if (dir == Dir.C) center else swipes[dir]
20}
21
22object Layouts {
23
24    /**
25     * Letras — layout MessagEase ESPAÑOL AUTÉNTICO, mapeado 1:1 desde el teclado
26     * oficial de Exideas (Spanish). Toques A N I / D O R / T E S.
27     *   · Acentos en swipe sobre su vocal: á(A↙) í(I↑) é(E←) ó(T↓) ú(T↑).
28     *   · ñ en N↑, l en N↓.  ü y ç en la tecla D.  v en A↘.
29     *   · O es el hub: q u p / c · b / g h j  (la h, antes tecla propia, va en O↓).
30     *   · Puntuación frecuente en la E. La R lleva mayús (shift) con trazo ↑ en la UI.
31     *
32     * Overlay de símbolos en modo letra: cada dirección SIN letra recibe el mismo símbolo
33     * que esa posición de tecla tiene en [symbols] (espejo posicional → el símbolo queda en
34     * el mismo sitio en ambas capas). Los que chocan con una letra viven solo en ?123.
35     * Excepción español: ¿ ¡ chocan con x/l, así que se reubican juntos en la tecla I.
36     */
37    val letters: List<KeyDef> = listOf(
38        // fila superior: A N I   (símbolos espejo de 1 2 3)
39        KeyDef('a', mapOf(Dir.S to 'á', Dir.SE to 'v', Dir.SW to '$', Dir.E to '-')),
40        KeyDef(
41            'n',
42            mapOf(
43                Dir.N to 'ñ', Dir.S to 'l',
44                Dir.NW to '`', Dir.NE to '´', Dir.W to '+', Dir.E to '!', Dir.SW to '/', Dir.SE to '\\',
45            ),
46        ),
47        KeyDef(
48            'i',
49            mapOf(
50                Dir.NW to 'í', Dir.SW to 'x',
51                Dir.W to '?', Dir.S to '=', Dir.SE to '€', Dir.E to '¿', Dir.NE to '¡',
52            ),
53        ),
54        // fila media: D O R   (símbolos espejo de 4 5 6)
55        KeyDef(
56            'd',
57            mapOf(
58                Dir.N to 'ü', Dir.E to 'k', Dir.S to 'ç',
59                Dir.NW to '{', Dir.NE to '%', Dir.W to '(', Dir.SW to '[', Dir.SE to '_',
60            ),
61        ),
62        KeyDef(
63            'o',
64            mapOf(
65                Dir.NW to 'q', Dir.N to 'u', Dir.NE to 'p', Dir.E to 'b',
66                Dir.SE to 'j', Dir.S to 'h', Dir.SW to 'g', Dir.W to 'c',
67            ),
68        ),
69        KeyDef(
70            'r',
71            mapOf(
72                Dir.W to 'm',
73                Dir.NW to '|', Dir.NE to '}', Dir.E to ')', Dir.SW to '@', Dir.SE to ']',
74            ),
75            shiftDir = Dir.N, // R↑ = mayúsculas (OFF→ON→LOCK)
76        ),
77        // fila inferior: T E S   (símbolos espejo de 7 8 9)
78        KeyDef(
79            't',
80            mapOf(
81                Dir.N to 'ú', Dir.NE to 'y', Dir.S to 'ó',
82                Dir.NW to '~', Dir.W to '<', Dir.E to '*', Dir.SE to '\t',
83            ),
84        ),
85        KeyDef(
86            'e',
87            mapOf(
88                Dir.N to 'w', Dir.W to 'é', Dir.E to 'z',
89                Dir.NE to '\'', Dir.SE to ':', Dir.S to '.', Dir.SW to ',', Dir.NW to '"',
90            ),
91        ),
92        KeyDef(
93            's',
94            mapOf(
95                Dir.NW to 'f', Dir.N to '&',
96                Dir.NE to '°', Dir.W to '#', Dir.E to '>', Dir.SW to ';',
97            ),
98        ),
99    )
100
101    /**
102     * Números y símbolos — capa MessagEase ESPAÑOL AUTÉNTICA (captura oficial de Exideas).
103     * Dígitos 1-9 en marcador telefónico; cada símbolo en su dirección de trazo original.
104     * Desviaciones respecto a la captura (esta app no tiene celda 0 dedicada como MessagEase):
105     *   · 0 → 5↓ (la tecla 5 va libre; toca 5 y desliza abajo).
106     *   · ¿ ¡ no salen en la captura pero el español los exige: ¡ en 2↓, ¿ en 3↙.
107     */
108    val symbols: List<KeyDef> = listOf(
109        // fila 1: 1 2 3
110        KeyDef('1', mapOf(Dir.E to '-', Dir.SW to '$')),
111        KeyDef(
112            '2',
113            mapOf(
114                Dir.NW to '`', Dir.N to '^', Dir.NE to '´', Dir.W to '+',
115                Dir.E to '!', Dir.S to '¡', Dir.SW to '/', Dir.SE to '\\',
116            ),
117        ),
118        KeyDef('3', mapOf(Dir.W to '?', Dir.SW to '¿', Dir.S to '=', Dir.SE to '€')),
119        // fila 2: 4 5 6
120        KeyDef('4', mapOf(Dir.NW to '{', Dir.NE to '%', Dir.W to '(', Dir.SW to '[', Dir.SE to '_')),
121        KeyDef('5', mapOf(Dir.S to '0')),
122        KeyDef('6', mapOf(Dir.NW to '|', Dir.NE to '}', Dir.E to ')', Dir.SW to '@', Dir.SE to ']')),
123        // fila 3: 7 8 9
124        KeyDef('7', mapOf(Dir.NW to '~', Dir.N to '¨', Dir.W to '<', Dir.E to '*', Dir.SE to '\t')),
125        KeyDef('8', mapOf(Dir.NW to '"', Dir.NE to '\'', Dir.SW to ',', Dir.S to '.', Dir.SE to ':')),
126        KeyDef('9', mapOf(Dir.N to '&', Dir.NE to '°', Dir.W to '#', Dir.E to '>', Dir.SW to ';')),
127    )
128}
129
130/** Geometría: convierte el delta de un gesto en una de las 9 direcciones. */
131fun directionOf(dx: Float, dy: Float, tapRadiusPx: Float): Dir {
132    if (hypot(dx, dy) < tapRadiusPx) return Dir.C
133    var deg = Math.toDegrees(atan2(dy.toDouble(), dx.toDouble())) // 0=E, 90=S (y hacia abajo)
134    if (deg < 0) deg += 360.0
135    // 8 sectores de 45° centrados en cada eje.
136    val order = arrayOf(Dir.E, Dir.SE, Dir.S, Dir.SW, Dir.W, Dir.NW, Dir.N, Dir.NE)
137    val idx = (((deg + 22.5) / 45.0).toInt()) % 8
138    return order[idx]
139}