Panda3D
 All Classes Functions Variables Enumerations
rocketInputHandler.cxx
1 // Filename: rocketInputHandler.cxx
2 // Created by: rdb (20Dec11)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "rocketInputHandler.h"
16 #include "buttonEventList.h"
17 #include "dataGraphTraverser.h"
18 #include "linmath_events.h"
19 #include "rocketRenderInterface.h"
20 #include "keyboardButton.h"
21 #include "mouseButton.h"
22 
23 #include <Rocket/Core/Input.h>
24 
25 using namespace Rocket::Core::Input;
26 
27 TypeHandle RocketInputHandler::_type_handle;
28 
29 ////////////////////////////////////////////////////////////////////
30 // Function: RocketInputHandler::Constructor
31 // Access: Published
32 // Description:
33 ////////////////////////////////////////////////////////////////////
34 RocketInputHandler::
35 RocketInputHandler(const string &name) :
36  DataNode(name),
37  _mouse_xy(-1),
38  _mouse_xy_changed(false),
39  _modifiers(0),
40  _wheel_delta(0)
41 {
42  _pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type());
43  _button_events_input = define_input("button_events", ButtonEventList::get_class_type());
44 }
45 
46 ////////////////////////////////////////////////////////////////////
47 // Function: RocketInputHandler::Destructor
48 // Access: Published
49 // Description:
50 ////////////////////////////////////////////////////////////////////
51 RocketInputHandler::
52 ~RocketInputHandler() {
53 }
54 
55 ////////////////////////////////////////////////////////////////////
56 // Function: RocketInputHandler::get_rocket_key
57 // Access: Published
58 // Description: Returns the libRocket KeyIdentifier for the given
59 // ButtonHandle, or KI_UNKNOWN (0) if it wasn't known.
60 ////////////////////////////////////////////////////////////////////
63  static pmap<int, int> keymap;
65 
66  if (keymap.size() > 0) {
67  it = keymap.find(handle.get_index());
68 
69  if (it == keymap.end()) {
70  return 0;
71  } else {
72  return it->second;
73  }
74  }
75 
76  keymap[KeyboardButton::space().get_index()] = KI_SPACE;
77  keymap[KeyboardButton::backspace().get_index()] = KI_BACK;
78  keymap[KeyboardButton::tab().get_index()] = KI_TAB;
79  keymap[KeyboardButton::enter().get_index()] = KI_RETURN;
80  keymap[KeyboardButton::escape().get_index()] = KI_ESCAPE;
81  keymap[KeyboardButton::end().get_index()] = KI_END;
82  keymap[KeyboardButton::home().get_index()] = KI_HOME;
83  keymap[KeyboardButton::left().get_index()] = KI_LEFT;
84  keymap[KeyboardButton::up().get_index()] = KI_UP;
85  keymap[KeyboardButton::right().get_index()] = KI_RIGHT;
86  keymap[KeyboardButton::down().get_index()] = KI_DOWN;
87  keymap[KeyboardButton::insert().get_index()] = KI_INSERT;
88  keymap[KeyboardButton::del().get_index()] = KI_DELETE;
89  keymap[KeyboardButton::caps_lock().get_index()] = KI_CAPITAL;
90  keymap[KeyboardButton::f1().get_index()] = KI_F1;
91  keymap[KeyboardButton::f10().get_index()] = KI_F10;
92  keymap[KeyboardButton::f11().get_index()] = KI_F11;
93  keymap[KeyboardButton::f12().get_index()] = KI_F12;
94  keymap[KeyboardButton::f13().get_index()] = KI_F13;
95  keymap[KeyboardButton::f14().get_index()] = KI_F14;
96  keymap[KeyboardButton::f15().get_index()] = KI_F15;
97  keymap[KeyboardButton::f16().get_index()] = KI_F16;
98  keymap[KeyboardButton::f2().get_index()] = KI_F2;
99  keymap[KeyboardButton::f3().get_index()] = KI_F3;
100  keymap[KeyboardButton::f4().get_index()] = KI_F4;
101  keymap[KeyboardButton::f5().get_index()] = KI_F5;
102  keymap[KeyboardButton::f6().get_index()] = KI_F6;
103  keymap[KeyboardButton::f7().get_index()] = KI_F7;
104  keymap[KeyboardButton::f8().get_index()] = KI_F8;
105  keymap[KeyboardButton::f9().get_index()] = KI_F9;
106  keymap[KeyboardButton::help().get_index()] = KI_HELP;
107  keymap[KeyboardButton::lcontrol().get_index()] = KI_LCONTROL;
108  keymap[KeyboardButton::lshift().get_index()] = KI_LSHIFT;
109  keymap[KeyboardButton::num_lock().get_index()] = KI_NUMLOCK;
110  keymap[KeyboardButton::page_down().get_index()] = KI_NEXT;
111  keymap[KeyboardButton::page_up().get_index()] = KI_PRIOR;
112  keymap[KeyboardButton::pause().get_index()] = KI_PAUSE;
113  keymap[KeyboardButton::print_screen().get_index()] = KI_SNAPSHOT;
114  keymap[KeyboardButton::rcontrol().get_index()] = KI_RCONTROL;
115  keymap[KeyboardButton::rshift().get_index()] = KI_RSHIFT;
116  keymap[KeyboardButton::scroll_lock().get_index()] = KI_SCROLL;
117 
118  // these "OEM" keys have standard mappings in Panda3D
119  keymap[KeyboardButton::ascii_key(';').get_index()] = KI_OEM_1;
120  keymap[KeyboardButton::ascii_key('=').get_index()] = KI_OEM_PLUS;
121  keymap[KeyboardButton::ascii_key(',').get_index()] = KI_OEM_COMMA;
122  keymap[KeyboardButton::ascii_key('-').get_index()] = KI_OEM_MINUS;
123  keymap[KeyboardButton::ascii_key('.').get_index()] = KI_OEM_PERIOD;
124  keymap[KeyboardButton::ascii_key('/').get_index()] = KI_OEM_2;
125  keymap[KeyboardButton::ascii_key('`').get_index()] = KI_OEM_3;
126  keymap[KeyboardButton::ascii_key('[').get_index()] = KI_OEM_4;
127  keymap[KeyboardButton::ascii_key('\\').get_index()] = KI_OEM_5;
128  keymap[KeyboardButton::ascii_key(']').get_index()] = KI_OEM_6;
129 
130  // comment says this may either be "<>" or "\|", but "\" (unshifted) is handled already,
131  // and "<" is only available "shifted" on 101-keyboards, so assume it's this one...
132  keymap[KeyboardButton::ascii_key('<').get_index()] = KI_OEM_102;
133 
134  for (char c = 'a'; c <= 'z'; ++c) {
135  keymap[KeyboardButton::ascii_key(c).get_index()] = (c - 'a') + KI_A;
136  }
137  for (char c = '0'; c <= '9'; ++c) {
138  keymap[KeyboardButton::ascii_key(c).get_index()] = (c - '0') + KI_0;
139  }
140 
141  it = keymap.find(handle.get_index());
142  if (it != keymap.end()) {
143  return it->second;
144  }
145  return 0;
146 }
147 
148 ////////////////////////////////////////////////////////////////////
149 // Function: RocketInputHandler::do_transmit_data
150 // Access: Protected, Virtual
151 // Description: The virtual implementation of transmit_data(). This
152 // function receives an array of input parameters and
153 // should generate an array of output parameters. The
154 // input parameters may be accessed with the index
155 // numbers returned by the define_input() calls that
156 // were made earlier (presumably in the constructor);
157 // likewise, the output parameters should be set with
158 // the index numbers returned by the define_output()
159 // calls.
160 ////////////////////////////////////////////////////////////////////
161 void RocketInputHandler::
162 do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input,
163  DataNodeTransmit &output) {
164  Thread *current_thread = trav->get_current_thread();
165  MutexHolder holder(_lock);
166 
167  if (input.has_data(_pixel_xy_input)) {
168  // The mouse is within the window. Get the current mouse position.
169  const EventStoreVec2 *pixel_xy;
170  DCAST_INTO_V(pixel_xy, input.get_data(_pixel_xy_input).get_ptr());
171  LVecBase2 p = pixel_xy->get_value();
172 
173  // Determine if mouse moved from last position
174  if (p != _mouse_xy) {
175  _mouse_xy_changed = true;
176  _mouse_xy = p;
177  }
178  }
179 
180  ButtonEventList new_button_events;
181 
182  // Look for new button events.
183  if (input.has_data(_button_events_input)) {
184  const ButtonEventList *this_button_events;
185  DCAST_INTO_V(this_button_events, input.get_data(_button_events_input).get_ptr());
186  int num_events = this_button_events->get_num_events();
187  for (int i = 0; i < num_events; i++) {
188  const ButtonEvent &be = this_button_events->get_event(i);
189 
190  int rocket_key = KI_UNKNOWN;
191 
192  switch (be._type) {
193  case ButtonEvent::T_down:
194  if (be._button == KeyboardButton::control()) {
195  _modifiers |= KM_CTRL;
196  } else if (be._button == KeyboardButton::shift()) {
197  _modifiers |= KM_SHIFT;
198  } else if (be._button == KeyboardButton::alt()) {
199  _modifiers |= KM_ALT;
200  } else if (be._button == KeyboardButton::meta()) {
201  _modifiers |= KM_META;
202 
203  } else if (be._button == KeyboardButton::enter()) {
204  _text_input.push_back('\n');
205 
206  } else if (be._button == MouseButton::wheel_up()) {
207  _wheel_delta -= 1;
208  } else if (be._button == MouseButton::wheel_down()) {
209  _wheel_delta += 1;
210 
211  } else if (be._button == MouseButton::one()) {
212  _mouse_buttons[0] = true;
213  } else if (be._button == MouseButton::two()) {
214  _mouse_buttons[1] = true;
215  } else if (be._button == MouseButton::three()) {
216  _mouse_buttons[2] = true;
217  } else if (be._button == MouseButton::four()) {
218  _mouse_buttons[3] = true;
219  } else if (be._button == MouseButton::five()) {
220  _mouse_buttons[4] = true;
221  }
222 
223  rocket_key = get_rocket_key(be._button);
224  if (rocket_key != KI_UNKNOWN) {
225  _keys[rocket_key] = true;
226  }
227  break;
228 
229  case ButtonEvent::T_repeat:
230  if (be._button == KeyboardButton::enter()) {
231  _text_input.push_back('\n');
232  }
233 
234  rocket_key = get_rocket_key(be._button);
235  if (rocket_key != KI_UNKNOWN) {
236  _repeated_keys.push_back(rocket_key);
237  }
238  break;
239 
240  case ButtonEvent::T_up:
241  if (be._button == KeyboardButton::control()) {
242  _modifiers &= ~KM_CTRL;
243  } else if (be._button == KeyboardButton::shift()) {
244  _modifiers &= ~KM_SHIFT;
245  } else if (be._button == KeyboardButton::alt()) {
246  _modifiers &= ~KM_ALT;
247  } else if (be._button == KeyboardButton::meta()) {
248  _modifiers &= ~KM_META;
249 
250  } else if (be._button == MouseButton::one()) {
251  _mouse_buttons[0] = false;
252  } else if (be._button == MouseButton::two()) {
253  _mouse_buttons[1] = false;
254  } else if (be._button == MouseButton::three()) {
255  _mouse_buttons[2] = false;
256  } else if (be._button == MouseButton::four()) {
257  _mouse_buttons[3] = false;
258  } else if (be._button == MouseButton::five()) {
259  _mouse_buttons[4] = false;
260  }
261 
262  rocket_key = get_rocket_key(be._button);
263  if (rocket_key != KI_UNKNOWN) {
264  _keys[rocket_key] = false;
265  }
266  break;
267 
268  case ButtonEvent::T_keystroke:
269  // Ignore control characters; otherwise, they actually get added to strings in the UI.
270  if (be._keycode > 0x1F && (be._keycode < 0x7F || be._keycode > 0x9F)) {
271  _text_input.push_back(be._keycode);
272  }
273  break;
274 
275  case ButtonEvent::T_resume_down:
276  break;
277 
278  case ButtonEvent::T_move:
279  break;
280 
281  case ButtonEvent::T_candidate:
282  break;
283 
284  case ButtonEvent::T_raw_down:
285  break;
286 
287  case ButtonEvent::T_raw_up:
288  break;
289  }
290  }
291  }
292 }
293 
294 ////////////////////////////////////////////////////////////////////
295 // Function: RocketInputHandler::update_context
296 // Access: Public
297 // Description: Updates the libRocket context with the changes
298 // that we have gathered in do_transmit_data.
299 // Also calls Update() on the context.
300 ////////////////////////////////////////////////////////////////////
302 update_context(Rocket::Core::Context *context, int xoffs, int yoffs) {
303  MutexHolder holder(_lock);
304 
305  if (_keys.size() > 0) {
306  ButtonActivityMap::const_iterator it;
307  for (it = _keys.begin(); it != _keys.end(); ++it) {
308  if (it->second) {
309  context->ProcessKeyDown((KeyIdentifier) it->first, _modifiers);
310  } else {
311  context->ProcessKeyUp((KeyIdentifier) it->first, _modifiers);
312  }
313  }
314  _keys.clear();
315  }
316 
317  if (_repeated_keys.size() > 0) {
319 
320  for (it = _repeated_keys.begin(); it != _repeated_keys.end(); ++it) {
321  context->ProcessKeyUp((KeyIdentifier) *it, _modifiers);
322  context->ProcessKeyDown((KeyIdentifier) *it, _modifiers);
323  }
324  _repeated_keys.clear();
325  }
326 
327  if (_text_input.size() > 0) {
329  for (it = _text_input.begin(); it != _text_input.end(); ++it) {
330  context->ProcessTextInput(*it);
331  }
332  _text_input.clear();
333  }
334 
335  if (_mouse_xy_changed) {
336  _mouse_xy_changed = false;
337 
338  context->ProcessMouseMove(_mouse_xy.get_x() - xoffs,
339  _mouse_xy.get_y() - yoffs, _modifiers);
340  }
341 
342  if (_mouse_buttons.size() > 0) {
343  ButtonActivityMap::const_iterator it;
344  for (it = _mouse_buttons.begin(); it != _mouse_buttons.end(); ++it) {
345  if (it->second) {
346  context->ProcessMouseButtonDown(it->first, _modifiers);
347  } else {
348  context->ProcessMouseButtonUp(it->first, _modifiers);
349  }
350  }
351  _mouse_buttons.clear();
352  }
353 
354  if (_wheel_delta != 0) {
355  context->ProcessMouseWheel(_wheel_delta, _modifiers);
356  _wheel_delta = 0;
357  }
358 
359  context->Update();
360 }
static int get_rocket_key(const ButtonHandle handle)
Returns the libRocket KeyIdentifier for the given ButtonHandle, or KI_UNKNOWN (0) if it wasn&#39;t known...
The fundamental type of node for the data graph.
Definition: dataNode.h:64
int get_index() const
Returns the integer index associated with this ButtonHandle.
Definition: buttonHandle.I:184
static ButtonHandle three()
Returns the ButtonHandle associated with the third mouse button.
Definition: mouseButton.cxx:72
static ButtonHandle two()
Returns the ButtonHandle associated with the second mouse button.
Definition: mouseButton.cxx:61
void update_context(Rocket::Core::Context *context, int xoffs, int yoffs)
Updates the libRocket context with the changes that we have gathered in do_transmit_data.
static ButtonHandle one()
Returns the ButtonHandle associated with the first mouse button.
Definition: mouseButton.cxx:50
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:29
Records a button event of some kind.
Definition: buttonEvent.h:53
A handy class object for storing simple values (like integers or strings) passed along with an Event ...
Definition: paramValue.h:109
Records a set of button events that happened recently.
static ButtonHandle four()
Returns the ButtonHandle associated with the fourth mouse button.
Definition: mouseButton.cxx:83
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:28
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
const ButtonEvent & get_event(int n) const
Returns the nth event in the list.
int get_num_events() const
Returns the number of events in the list.
static ButtonHandle wheel_down()
Returns the ButtonHandle generated when the mouse wheel is rolled one notch downwards.
const EventParameter & get_data(int index) const
Extracts the data for the indicated index, if it has been stored, or the empty parameter if it has no...
This is the base class for all two-component vectors and points.
Definition: lvecBase2.h:105
static ButtonHandle five()
Returns the ButtonHandle associated with the fifth mouse button.
Definition: mouseButton.cxx:94
const Type & get_value() const
Retrieves the value stored in the parameter.
Definition: paramValue.I:136
A thread; that is, a lightweight process.
Definition: thread.h:51
TypedWritableReferenceCount * get_ptr() const
Retrieves a pointer to the actual value stored in the parameter.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
static ButtonHandle ascii_key(char ascii_equivalent)
Returns the ButtonHandle associated with the particular ASCII character, if there is one...
bool has_data(int index) const
Returns true if the indicated parameter has been stored, false otherwise.
static ButtonHandle wheel_up()
Returns the ButtonHandle generated when the mouse wheel is rolled one notch upwards.
Encapsulates the data generated from (or sent into) any particular DataNode.
Thread * get_current_thread() const
Returns the currently-executing thread object, as passed to the DataGraphTraverser constructor...
This object supervises the traversal of the data graph and the moving of data from one DataNode to it...