tawasuyu

sergio/humanoid

HTML 57Markdown 1TOML 10 Sutichaykuna

⎇ 8380e44a0947bafb169773353ce2b2036aff9e70 keyboard/src/main/java/com/rizoma/trazo/model/KeyLayout.kt 75 siq'ikuna · 2.8 KB Ñawpa willay ch'uya

Trazo: teclado MessagEase remasterizado (IME v0.1) e3dd167a1 · 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) {
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}