Blame view

build2/epsilon-master/ion/src/emscripten/events_keyboard.cpp 6.15 KB
6663b6c9   adorian   projet complet av...
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
  #include <ion/events.h>
  #include "events_keyboard.h"
  #include "display.h"
  extern "C" {
  #include <SDL/SDL.h>
  }
  #include <emscripten.h>
  
  template<typename T, int N>
  class Queue {
  public:
    Queue() : m_first(&m_elements[0]), m_last(&m_elements[0]) {}
    int size() {
      if (m_last >= m_first) {
        return m_last - m_first;
      } else {
        return m_last - (m_first - N);
      }
    }
  
    void enqueue(T element) {
      if (size() > N) {
        // Queue is full
        return;
      }
      *m_last = element;
      m_last = next(m_last);
    }
  
    T dequeue() {
      if (size() <= 0) {
        // Dequeueing an empty queue
        return T();
      }
      T e = *m_first;
      m_first = next(m_first);
      return e;
    }
  
  private:
    T * next(T * p) {
      if (p >= m_elements + N) {
        return m_elements;
      } else {
        return p + 1;
      }
    }
    T * m_first;
    T * m_last;
    T m_elements[N];
  };
  
  static Queue<Ion::Events::Event, 1024> sEventQueue;
  
  void IonEventsEmscriptenPushKey(int keyNumber) {
    /* Note: This uses the *current* modifier state to generate the event. If some
     * other modifiers were in the queue before, those won't be taken into account
     * when the event corresponding to this key is dequeued.
     * In practice, this should not happen because we push keys one by one. */
    Ion::Events::Event event = Ion::Events::Event((Ion::Keyboard::Key)keyNumber, Ion::Events::isShiftActive(), Ion::Events::isAlphaActive());
    sEventQueue.enqueue(event);
  }
  
  void IonEventsEmscriptenPushEvent(int eventNumber) {
    sEventQueue.enqueue(Ion::Events::Event(eventNumber));
  }
  
  Ion::Keyboard::State Ion::Keyboard::scan() {
    // FIXME
    // On the Emscripten platform, scan() is used in :
    //   - shouldInterrupt(), from interruptHelper.h
    //   - apps_container.cpp
    //   - apps/hardware_test/keyboard_test_controller.cpp
    //  We would like to check if there is a Back event that would interrupt the
    //  Python or Poincare computation, but it is quite difficult to get because
    //  the runLoop is blocking in JavaScript and Events do not get pushed in
    //  sEvent.
    //  We still need to override the dummy/events_keyboard.cpp function, which
    //  returns that all keys are always pressed and thus interrupts Python
    //  computations after 20000 calls.
    return 0;
  }
  
  namespace Ion {
  namespace Events {
  
  static constexpr Event sEventForASCIICharAbove32[95] = {
    Space, Exclamation, DoubleQuotes, None, None, None, None, None,
    LeftParenthesis, RightParenthesis, Multiplication, Plus, Comma, Minus, Dot, Division,
    Zero, One, Two, Three, Four, Five, Six, Seven,
    Eight, Nine, Colon, SemiColon, Lower, Equal, Greater, Question,
    None, UpperA, UpperB, UpperC, UpperD, UpperE, UpperF, UpperG,
    UpperH, UpperI, UpperJ, UpperK, UpperL, UpperM, UpperN, UpperO,
    UpperP, UpperQ, UpperR, UpperS, UpperT, UpperU, UpperV, UpperW,
    UpperX, UpperY, UpperZ, LeftBracket, None, RightBracket, Power, Underscore,
    None, LowerA, LowerB, LowerC, LowerD, LowerE, LowerF, LowerG,
    LowerH, LowerI, LowerJ, LowerK, LowerL, LowerM, LowerN, LowerO,
    LowerP, LowerQ, LowerR, LowerS, LowerT, LowerU, LowerV, LowerW,
    LowerX, LowerY, LowerZ, LeftBrace, None, RightBrace, None
  };
  
  static bool sleepWithTimeout(int duration, int * timeout) {
    if (*timeout >= duration) {
      emscripten_sleep(duration);
      *timeout -= duration;
      return false;
    } else {
      emscripten_sleep(*timeout);
      *timeout = 0;
      return true;
    }
  }
  
  static Event eventFromSDLEvent(SDL_Event sdlEvent) {
    if (sdlEvent.type != SDL_KEYDOWN) {
      return None;
    }
    if (sdlEvent.key.keysym.mod & KMOD_CTRL) {
      switch (sdlEvent.key.keysym.sym) {
        case SDLK_BACKSPACE:
          return Clear;
        case SDLK_x:
          return Cut;
        case SDLK_c:
          return Copy;
        case SDLK_v:
          return Paste;
      }
    }
    if (sdlEvent.key.keysym.mod & KMOD_ALT) {
      if (sdlEvent.key.keysym.mod & KMOD_SHIFT) {
        switch (sdlEvent.key.keysym.sym) {
          case SDLK_s:
            return Arcsine;
          case SDLK_c:
            return Arccosine;
          case SDLK_t:
            return Arctangent;
        }
      }
      switch (sdlEvent.key.keysym.sym) {
        case SDLK_ESCAPE:
          return Home;
        case SDLK_RETURN:
          return OK;
        case SDLK_v:
          return Var;
        case SDLK_BACKSPACE:
          return Clear;
        case SDLK_x:
          return Exp;
        case SDLK_n:
          return Ln;
        case SDLK_l:
          return Log;
        case SDLK_i:
          return Imaginary;
        case SDLK_EQUALS:
          return Sto;
        case SDLK_s:
          return Sine;
        case SDLK_c:
          return Cosine;
        case SDLK_t:
          return Tangent;
        case SDLK_p:
          return Pi;
        case SDLK_r:
          return Sqrt;
        case SDLK_2:
          return Square;
        case SDLK_e:
          return EE;
        case SDLK_a:
          return Ans;
      }
    }
    switch(sdlEvent.key.keysym.sym) {
      case SDLK_UP:
        return Up;
      case SDLK_DOWN:
        return Down;
      case SDLK_LEFT:
        return Left;
      case SDLK_RIGHT:
        return Right;
      case SDLK_RETURN:
        return EXE;
      case SDLK_ESCAPE:
        return Back;
      case SDLK_TAB:
        return Toolbox;
      case SDLK_BACKSPACE:
        return Backspace;
    }
    if (sdlEvent.key.keysym.unicode >= 32 && sdlEvent.key.keysym.unicode < 127) {
      return sEventForASCIICharAbove32[sdlEvent.key.keysym.unicode-32];
    }
    return None;
  }
  
  Event getEvent(int * timeout) {
    // If multiple events are in the queue, don't waste time refreshing the display
    if (sEventQueue.size() <= 1) {
      Ion::Display::Emscripten::refresh();
    }
  
    while (true) {
      // Look up events in the queue
      if (sEventQueue.size() > 0) {
        Event event = sEventQueue.dequeue();
        if (event.isKeyboardEvent()) {
          updateModifiersFromEvent(event);
        }
        return event;
      }
  
      // Or directly from browser events, converted to SDL events by Emscripten
      SDL_Event sdlEvent;
      SDL_PollEvent(&sdlEvent);
      Event eventFromSDL = eventFromSDLEvent(sdlEvent);
      if (eventFromSDL != None) {
        return eventFromSDL;
      }
  
      if (sleepWithTimeout(10, timeout)) {
        return None;
      }
    }
    return None;
  }
  
  }
  }
  
  namespace Ion {
  namespace Events {
  namespace Emscripten {
  
  void init() {
    SDL_EnableUNICODE(1); // We're using Unicode values from Keyboard input
  }
  
  }
  }
  }