⎇ b021d6829a602218866114f86e2350d80f0500e2
keyboard/src/main/java/com/rizoma/trazo/model/KeyLayout.kt
Historia
crudo
Trazo: layout MessagEase auténtico + fila de funciones sobre la barra de nav
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 — layout MessagEase AUTÉNTICO (inglés), tomado de la fuente de Thumb-Key
24 * (sucesor FOSS de MessagEase). Toques A N I / H O R / T E S; las secundarias en su
25 * dirección de trazo original (V = A↘ hacia O, D = O↓, C = O←, etc.).
26 * Añadido para español: Ñ con trazo ↑ en la N. Puntuación frecuente en la E.
27 */
28 val letters: List<KeyDef> = listOf(
29 // fila superior: A N I
30 KeyDef('a', mapOf(Dir.SE to 'v')),
31 KeyDef('n', mapOf(Dir.S to 'l', Dir.N to 'ñ')),
32 KeyDef('i', mapOf(Dir.SW to 'x')),
33 // fila media: H O R
34 KeyDef('h', mapOf(Dir.E to 'k')),
35 KeyDef(
36 'o',
37 mapOf(
38 Dir.NW to 'q', Dir.N to 'u', Dir.NE to 'p', Dir.E to 'b',
39 Dir.SE to 'j', Dir.S to 'd', Dir.SW to 'g', Dir.W to 'c',
40 ),
41 ),
42 KeyDef('r', mapOf(Dir.W to 'm')),
43 // fila inferior: T E S
44 KeyDef('t', mapOf(Dir.NE to 'y')),
45 KeyDef(
46 'e',
47 mapOf(
48 Dir.N to 'w', Dir.NE to '\'', Dir.E to 'z',
49 Dir.SE to ':', Dir.S to '.', Dir.SW to ',',
50 ),
51 ),
52 KeyDef('s', mapOf(Dir.NW to 'f')),
53 )
54
55 /**
56 * Números y símbolos. Dígitos 1-9 en posición de marcador telefónico; 0 y la
57 * puntuación frecuente como swipes.
58 */
59 val symbols: List<KeyDef> = listOf(
60 KeyDef('1', mapOf(Dir.N to '!', Dir.E to '@')),
61 KeyDef('2', mapOf(Dir.N to '"', Dir.E to '#')),
62 KeyDef('3', mapOf(Dir.N to '\'', Dir.W to '$')),
63 KeyDef('4', mapOf(Dir.N to '%', Dir.E to '&')),
64 KeyDef('5', mapOf(Dir.N to '*', Dir.E to '+', Dir.W to '-', Dir.S to '=')),
65 KeyDef('6', mapOf(Dir.N to '/', Dir.W to '\\')),
66 KeyDef('7', mapOf(Dir.N to '(', Dir.E to ')')),
67 KeyDef('8', mapOf(Dir.N to ',', Dir.E to '.', Dir.W to '?')),
68 KeyDef('9', mapOf(Dir.N to ';', Dir.W to ':', Dir.E to '0')),
69 )
70}
71
72/** Geometría: convierte el delta de un gesto en una de las 9 direcciones. */
73fun directionOf(dx: Float, dy: Float, tapRadiusPx: Float): Dir {
74 if (hypot(dx, dy) < tapRadiusPx) return Dir.C
75 var deg = Math.toDegrees(atan2(dy.toDouble(), dx.toDouble())) // 0=E, 90=S (y hacia abajo)
76 if (deg < 0) deg += 360.0
77 // 8 sectores de 45° centrados en cada eje.
78 val order = arrayOf(Dir.E, Dir.SE, Dir.S, Dir.SW, Dir.W, Dir.NW, Dir.N, Dir.NE)
79 val idx = (((deg + 22.5) / 45.0).toInt()) % 8
80 return order[idx]
81}