abouttreesummaryrefslogcommitdiff
path: root/srcs/juloo.keyboard2/Gesture.java
blob: 5ee666b8590b14f767c2d0650ee1f1d9d064bbab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package juloo.keyboard2;

public final class Gesture
{
  /** The pointer direction that caused the last state change.
      Integer from 0 to 15 (included). */
  int current_dir;

  State state;

  public Gesture(int starting_direction)
  {
    current_dir = starting_direction;
    state = State.Swiped;
  }

  enum State
  {
    Cancelled,
    Swiped,
    Rotating_clockwise,
    Rotating_anticlockwise,
    Ended_swipe,
    Ended_center,
    Ended_clockwise,
    Ended_anticlockwise
  }

  enum Name
  {
    None,
    Swipe,
    Roundtrip,
    Circle,
    Anticircle
  }

  /** Angle to travel before a rotation gesture starts. A threshold too low
      would be too easy to reach while doing back and forth gestures, as the
      quadrants are very small. In the same unit as [current_dir] */
  static final int ROTATION_THRESHOLD = 2;

  /** Return the currently recognized gesture. Return [null] if no gesture is
      recognized. Might change everytime [changed_direction] return [true]. */
  public Name get_gesture()
  {
    switch (state)
    {
      case Cancelled:
        return Name.None;
      case Swiped:
      case Ended_swipe:
        return Name.Swipe;
      case Ended_center:
        return Name.Roundtrip;
      case Rotating_clockwise:
      case Ended_clockwise:
        return Name.Circle;
      case Rotating_anticlockwise:
      case Ended_anticlockwise:
          return Name.Anticircle;
    }
    return Name.None; // Unreachable
  }

  public boolean is_in_progress()
  {
    switch (state)
    {
      case Swiped:
      case Rotating_clockwise:
      case Rotating_anticlockwise:
        return true;
    }
    return false;
  }

  public int current_direction() { return current_dir; }

  /** The pointer changed direction. Return [true] if the gesture changed
      state and [get_gesture] return a different value. */
  public boolean changed_direction(int direction)
  {
    int d = dir_diff(current_dir, direction);
    boolean clockwise = d > 0;
    switch (state)
    {
      case Swiped:
        if (Math.abs(d) < ROTATION_THRESHOLD)
          return false;
        // Start a rotation
        state = (clockwise) ?
          State.Rotating_clockwise : State.Rotating_anticlockwise;
        current_dir = direction;
        return true;
      // Check that rotation is not reversing
      case Rotating_clockwise:
      case Rotating_anticlockwise:
        current_dir = direction;
        if ((state == State.Rotating_clockwise) == clockwise)
          return false;
        state = State.Cancelled;
        return true;
    }
    return false;
  }

  /** Return [true] if [get_gesture] will return a different value. */
  public boolean moved_to_center()
  {
    switch (state)
    {
      case Swiped: state = State.Ended_center; return true;
      case Rotating_clockwise: state = State.Ended_clockwise; return false;
      case Rotating_anticlockwise: state = State.Ended_anticlockwise; return false;
    }
    return false;
  }

  /** Will not change the gesture state. */
  public void pointer_up()
  {
    switch (state)
    {
      case Swiped: state = State.Ended_swipe; break;
      case Rotating_clockwise: state = State.Ended_clockwise; break;
      case Rotating_anticlockwise: state = State.Ended_anticlockwise; break;
    }
  }

  static int dir_diff(int d1, int d2)
  {
    final int n = 16;
    // Shortest-path in modulo arithmetic
    if (d1 == d2)
      return 0;
    int left = (d1 - d2 + n) % n;
    int right = (d2 - d1 + n) % n;
    return (left < right) ? -left : right;
  }
}