The Pedigree Project  0.1
InputManager.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "pedigree/kernel/machine/InputManager.h"
21 #include "pedigree/kernel/LockGuard.h"
22 #include "pedigree/kernel/Log.h"
23 #include "pedigree/kernel/compiler.h"
24 #include "pedigree/kernel/process/Event.h"
25 #include "pedigree/kernel/process/Scheduler.h"
26 #include "pedigree/kernel/process/Thread.h"
27 #include "pedigree/kernel/process/eventNumbers.h"
28 #include "pedigree/kernel/processor/Processor.h"
29 #include "pedigree/kernel/processor/ProcessorInformation.h"
30 #include "pedigree/kernel/utilities/Iterator.h"
31 #include "pedigree/kernel/utilities/utility.h"
32 
33 // Incoming relative mouse movements are divided by this
34 #define MOUSE_REDUCE_FACTOR 1
35 
36 class InputEvent : public Event
37 {
38  public:
39  InputEvent(
40  InputManager::InputNotification *pNote, uintptr_t param,
41  uintptr_t handlerAddress);
42  virtual ~InputEvent();
43 
44  virtual size_t serialize(uint8_t *pBuffer);
45 
46  static bool unserialize(uint8_t *pBuffer, InputEvent &event);
47 
48  virtual size_t getNumber();
49 
50  InputManager::CallbackType getType();
51 
52  uint64_t getKey();
53  ssize_t getRelX();
54  ssize_t getRelY();
55  ssize_t getRelZ();
56 
57  void getButtonStates(bool states[64], size_t maxDesired = 64);
58 
59  private:
60  InputManager::InputNotification m_Notification;
61 
62  uintptr_t m_nParam;
63 };
64 
66 
68  : m_InputQueue(), m_QueueLock(), m_Callbacks()
69 #ifdef THREADS
70  ,
71  m_InputQueueSize(0), m_pThread(0)
72 #endif
73  ,
74  m_bActive(false)
75 {
76 }
77 
79 {
80 }
81 
83 {
84  m_bActive = true;
85 
86 // Start the worker thread.
87 #ifdef THREADS
88  m_pThread = new Thread(
89  Processor::information().getCurrentThread()->getParent(), &trampoline,
90  reinterpret_cast<void *>(this));
91 #else
92  WARNING("InputManager: No thread support, no worker thread will be active");
93 #endif
94 }
95 
97 {
98  m_bActive = false;
99 
100 #ifdef THREADS
102  m_pThread->join();
103 #endif
104 
105  // Clean up lists, in case anything came in while we were canceling.
106  m_Callbacks.clear();
107  m_InputQueue.clear();
108 }
109 
110 void InputManager::keyPressed(uint64_t key)
111 {
113  note->type = Key;
114  note->data.key.key = key;
115 
116  putNotification(note);
117 }
118 
119 void InputManager::rawKeyUpdate(uint8_t scancode, bool bKeyUp)
120 {
122  note->type = RawKey;
123  note->data.rawkey.scancode = scancode;
124  note->data.rawkey.keyUp = bKeyUp;
125 
126  putNotification(note);
127 }
128 
129 void InputManager::machineKeyUpdate(uint8_t scancode, bool bKeyUp)
130 {
132  note->type = MachineKey;
133  note->data.machinekey.scancode = scancode;
134  note->data.machinekey.keyUp = bKeyUp;
135 
136  putNotification(note);
137 }
138 
140  ssize_t relX, ssize_t relY, ssize_t relZ, uint32_t buttonBitmap)
141 {
142  // Smooth input out
143  relX /= MOUSE_REDUCE_FACTOR;
144  relY /= MOUSE_REDUCE_FACTOR;
145  relZ /= MOUSE_REDUCE_FACTOR;
146 
148  note->type = Mouse;
149  note->data.pointy.relx = relX;
150  note->data.pointy.rely = relY;
151  note->data.pointy.relz = relZ;
152  for (size_t i = 0; i < 64; i++)
153  note->data.pointy.buttons[i] = buttonBitmap & (1 << i);
154 
155  putNotification(note);
156 }
157 
159  ssize_t relX, ssize_t relY, ssize_t relZ, uint32_t buttonBitmap)
160 {
162  note->type = Joystick;
163  note->data.pointy.relx = relX;
164  note->data.pointy.rely = relY;
165  note->data.pointy.relz = relZ;
166  for (size_t i = 0; i < 64; i++)
167  note->data.pointy.buttons[i] = buttonBitmap & (1 << i);
168 
169  putNotification(note);
170 }
171 
173 {
174  // Early short-circuit - don't push onto the queue if no callbacks present.
175  if (m_Callbacks.count() == 0)
176  {
177  WARNING("InputManager dropping input - no callbacks to send to!");
178  delete note;
179  return;
180  }
181 
183 
184  // Can we mitigate this notification?
185  if (note->type == Mouse)
186  {
188  it != m_InputQueue.end(); it++)
189  {
190  if ((*it)->type == Mouse)
191  {
192  (*it)->data.pointy.relx += note->data.pointy.relx;
193  (*it)->data.pointy.rely += note->data.pointy.rely;
194  (*it)->data.pointy.relz += note->data.pointy.relz;
195 
196  for (int i = 0; i < 64; i++)
197  {
198  if (note->data.pointy.buttons[i])
199  (*it)->data.pointy.buttons[i] = true;
200  }
201 
202  // Merged, this precise logic means only one mouse event is ever
203  // in the queue, so it's safe to just return here.
204  return;
205  }
206  }
207  }
208 
209 #ifdef THREADS
210  m_InputQueue.pushBack(note);
212 #else
213  // No need for locking, as no threads exist
215  it != m_Callbacks.end(); it++)
216  {
217  if (*it)
218  {
219  callback_t func = (*it)->func;
220  note->meta = (*it)->meta;
221  func(*note);
222  }
223  }
224 
225  delete note;
226 #endif
227 }
228 
230  CallbackType filter, callback_t callback, void *meta, Thread *pThread,
231  uintptr_t param)
232 {
234  CallbackItem *item = new CallbackItem;
235  item->func = callback;
236 #ifdef THREADS
237  item->pThread = pThread;
238 #endif
239  item->nParam = param;
240  item->filter = filter;
241  item->meta = meta;
242  m_Callbacks.pushBack(item);
243 }
244 
246  callback_t callback, void *meta, Thread *pThread)
247 {
250  it != m_Callbacks.end();)
251  {
252  if (*it)
253  {
254  if (
255 #ifdef THREADS
256  (pThread == (*it)->pThread) &&
257 #endif
258  (callback == (*it)->func) && (meta == (*it)->meta))
259  {
260  delete *it;
261  it = m_Callbacks.erase(it);
262  continue;
263  }
264  }
265 
266  ++it;
267  }
268 }
269 
271 {
272 #ifdef THREADS
275  it != m_Callbacks.end();)
276  {
277  if (*it)
278  {
279  if (pThread == (*it)->pThread)
280  {
281  delete *it;
282  it = m_Callbacks.erase(it);
283  continue;
284  }
285  }
286 
287  ++it;
288  }
289 
290  return false;
291 #endif
292 }
293 
295 {
296  InputManager *p = reinterpret_cast<InputManager *>(ptr);
297  p->mainThread();
298  return 0;
299 }
300 
302 {
303 #ifdef THREADS
304  while (isActive())
305  {
307  if (!m_InputQueue.count())
308  continue;
309 
311  InputNotification *pNote = m_InputQueue.popFront();
313 
314  if (m_Callbacks.count() == 0)
315  {
316  // Drop the input on the floor - no callbacks to read it in!
317  WARNING("InputManager dropping input - no callbacks to send to!");
318  delete pNote;
319  continue;
320  }
321 
322  // Don't send the key to applications if it was zero
323  if (!pNote)
324  continue;
325 
327  it != m_Callbacks.end(); it++)
328  {
329  if (*it)
330  {
331  if ((*it)->filter & pNote->type)
332  {
333  Thread *pThread = (*it)->pThread;
334  callback_t func = (*it)->func;
335  if (!pThread)
336  {
339  pNote->meta = (*it)->meta;
340  func(*pNote);
341  continue;
342  }
343 
344  InputEvent *pEvent = new InputEvent(
345  pNote, (*it)->nParam,
346  reinterpret_cast<uintptr_t>(func));
347  NOTICE("InputManager: sending event " << pEvent << "!");
348  if (!pThread->sendEvent(pEvent))
349  {
350  WARNING("InputManager - Thread::sendEvent failed, "
351  "skipping this callback");
352  delete pEvent;
353  }
354  }
355  }
356  }
357 
358  // Yield to run the events we just transmitted.
360 
361  delete pNote;
362  }
363 #endif
364 }
365 
366 InputEvent::InputEvent(
367  InputManager::InputNotification *pNote, uintptr_t param,
368  uintptr_t handlerAddress)
369  : Event(handlerAddress, true, 0), m_Notification(), m_nParam(param)
370 {
371  m_Notification = *pNote;
372 }
373 
374 InputEvent::~InputEvent()
375 {
376 }
377 
378 size_t InputEvent::serialize(uint8_t *pBuffer)
379 {
380  void *alignedBuffer = ASSUME_ALIGNMENT(pBuffer, sizeof(uintptr_t));
381  uintptr_t *buf = reinterpret_cast<uintptr_t *>(alignedBuffer);
382  buf[0] = EventNumbers::InputEvent;
383  buf[1] = m_nParam;
384  MemoryCopy(
385  &buf[2], &m_Notification, sizeof(InputManager::InputNotification));
386  return sizeof(InputManager::InputNotification) + (sizeof(uintptr_t) * 2);
387 }
388 
389 bool InputEvent::unserialize(uint8_t *pBuffer, InputEvent &event)
390 {
391  void *alignedBuffer = ASSUME_ALIGNMENT(pBuffer, sizeof(uintptr_t));
392  uintptr_t *buf = reinterpret_cast<uintptr_t *>(alignedBuffer);
393  if (*buf != EventNumbers::InputEvent)
394  return false;
395 
396  MemoryCopy(
397  &event.m_Notification, &buf[2],
399  return true;
400 }
401 
403 {
404  return EventNumbers::InputEvent;
405 }
406 
407 InputManager::CallbackType InputEvent::getType()
408 {
409  return m_Notification.type;
410 }
411 
412 uint64_t InputEvent::getKey()
413 {
414  return m_Notification.data.key.key;
415 }
416 
417 ssize_t InputEvent::getRelX()
418 {
419  return m_Notification.data.pointy.relx;
420 }
421 
422 ssize_t InputEvent::getRelY()
423 {
424  return m_Notification.data.pointy.rely;
425 }
426 
427 ssize_t InputEvent::getRelZ()
428 {
429  return m_Notification.data.pointy.relz;
430 }
431 
432 void InputEvent::getButtonStates(bool states[64], size_t maxDesired)
433 {
434  for (size_t i = 0; i < maxDesired; i++)
435  states[i] = m_Notification.data.pointy.buttons[i];
436 }
Semaphore m_InputQueueSize
Key press queue Semaphore.
Definition: InputManager.h:203
void release()
Definition: Spinlock.cc:273
static const int Key
Definition: InputManager.h:40
void * meta
Meta pointer for the InputNotifications we generate.
Definition: InputManager.h:186
static InputManager m_Instance
Static instance.
Definition: InputManager.h:158
Spinlock m_QueueLock
Definition: InputManager.h:196
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition: Semaphore.h:62
void machineKeyUpdate(uint8_t scancode, bool bKeyUp)
Called whenever a machine-specific key scancode comes in.
void putNotification(InputNotification *note)
void installCallback(CallbackType filter, callback_t callback, void *meta=0, Thread *pThread=0, uintptr_t param=0)
Installs a callback.
bool acquire(bool recurse=false, bool safe=true)
Definition: Spinlock.cc:43
void mouseUpdate(ssize_t relX, ssize_t relY, ssize_t relZ, uint32_t buttonBitmap)
Called whenever mouse input comes in.
static ProcessorInformation & information()
Definition: Processor.cc:45
bool isActive() const
Returns whether the instance is creating notifications.
Definition: InputManager.h:151
void keyPressed(uint64_t key)
Called whenever a key is pressed and needs to be added to the queue.
List< CallbackItem * > m_Callbacks
Callback list.
Definition: InputManager.h:199
void removeCallback(callback_t callback, void *meta=0, Thread *pThread=0)
Removes a callback.
#define WARNING(text)
Definition: Log.h:78
bool sendEvent(Event *pEvent)
Definition: Thread.cc:529
List< InputNotification * > m_InputQueue
Input queue (for distribution to applications)
Definition: InputManager.h:190
void initialise()
Begins the worker thread.
Definition: InputManager.cc:82
void joystickUpdate(ssize_t relX, ssize_t relY, ssize_t relZ, uint32_t buttonBitmap)
Called whenever joystick input comes in.
void release(size_t n=1)
Definition: Semaphore.cc:239
InputManager()
Default constructor.
Definition: InputManager.cc:67
#define NOTICE(text)
Definition: Log.h:74
virtual size_t serialize(uint8_t *pBuffer)
::Iterator< T, node_t > Iterator
Definition: List.h:71
static Scheduler & instance()
Definition: Scheduler.h:48
static int trampoline(void *ptr)
Thread trampoline.
callback_t func
The handler function.
Definition: InputManager.h:169
Thread * m_pThread
Thread object for our worker thread.
Definition: InputManager.h:206
virtual ~InputManager()
Default destructor.
Definition: InputManager.cc:78
CallbackType filter
Filter for this callback.
Definition: InputManager.h:183
bool m_bActive
Are we active?
Definition: InputManager.h:210
Definition: Thread.h:54
Definition: Event.h:48
virtual size_t getNumber()
void mainThread()
Main worker thread.
void yield()
Definition: Scheduler.cc:135
void shutdown()
Shuts down the worker thread, clears queues, and removes callbacks.
Definition: InputManager.cc:96
void rawKeyUpdate(uint8_t scancode, bool bKeyUp)
bool join()
Definition: Thread.cc:836
void(* callback_t)(InputNotification &)
Callback function type.
Definition: InputManager.h:92
bool removeCallbackByThread(Thread *pThread)