Panda3D
 All Classes Functions Variables Enumerations
buttonThrower.cxx
1 // Filename: buttonThrower.cxx
2 // Created by: drose (12Mar02)
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 "buttonThrower.h"
16 
17 #include "buttonEvent.h"
18 #include "buttonEventList.h"
19 #include "dataNodeTransmit.h"
20 #include "throw_event.h"
21 #include "event.h"
22 #include "indent.h"
23 #include "dcast.h"
24 
25 TypeHandle ButtonThrower::_type_handle;
26 
27 
28 ////////////////////////////////////////////////////////////////////
29 // Function: ButtonThrower::Constructor
30 // Access: Public
31 // Description:
32 ////////////////////////////////////////////////////////////////////
33 ButtonThrower::
34 ButtonThrower(const string &name) :
35  DataNode(name)
36 {
37  _button_events_input = define_input("button_events", ButtonEventList::get_class_type());
38  _button_events_output = define_output("button_events", ButtonEventList::get_class_type());
39 
40  _button_events = new ButtonEventList;
41 
42  _specific_flag = true;
43  _time_flag = false;
44  _throw_buttons_active = false;
45 }
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: ButtonThrower::Destructor
49 // Access: Published, Virtual
50 // Description:
51 ////////////////////////////////////////////////////////////////////
52 ButtonThrower::
53 ~ButtonThrower() {
54 }
55 
56 
57 ////////////////////////////////////////////////////////////////////
58 // Function: ButtonThrower::add_parameter
59 // Access: Public
60 // Description: Adds the indicated parameter to the list of
61 // parameters that will be passed with each event
62 // generated by this ButtonThrower.
63 ////////////////////////////////////////////////////////////////////
64 void ButtonThrower::
66  _parameters.push_back(obj);
67 }
68 
69 
70 ////////////////////////////////////////////////////////////////////
71 // Function: ButtonThrower::get_num_parameters
72 // Access: Public
73 // Description: Returns the number of parameters that have been added
74 // to the list of parameters to be passed with each
75 // event generated by this ButtonThrower.
76 ////////////////////////////////////////////////////////////////////
79  return _parameters.size();
80 }
81 
82 ////////////////////////////////////////////////////////////////////
83 // Function: ButtonThrower::get_parameter
84 // Access: Public
85 // Description: Returns the nth parameter that has been added to the
86 // list of parameters passed with each event generated
87 // by this ButtonThrower.
88 ////////////////////////////////////////////////////////////////////
90 get_parameter(int n) const {
91  nassertr(n >= 0 && n < (int)_parameters.size(), EventParameter(0));
92  return _parameters[n];
93 }
94 
95 ////////////////////////////////////////////////////////////////////
96 // Function: ButtonThrower::add_throw_button
97 // Access: Published
98 // Description: Adds a new button to the set of buttons that the
99 // ButtonThrower explicitly processes.
100 //
101 // If set_throw_buttons_active is false (which is the
102 // default), the ButtonThrower will process all buttons.
103 // Otherwise, the ButtonThrower will only process events
104 // for the button(s) explicitly named by this function;
105 // buttons not on the list will be ignored by this
106 // object and passed on downstream to the child node(s)
107 // in the data graph. A button that *is* on the list
108 // will be processed by the ButtonThrower and not passed
109 // on to the child node(s).
110 //
111 // The return value is true if the button is added, or
112 // false if it was already in the set.
113 ////////////////////////////////////////////////////////////////////
114 bool ButtonThrower::
115 add_throw_button(const ModifierButtons &mods, const ButtonHandle &button) {
116  ThrowButtonDef &def = _throw_buttons[button];
117 
118  // This is a vector of ModifierButtons for which the indicated
119  // button is handled. Make sure the current ModifierButtons object
120  // is not already on the list.
121  ThrowButtonDef::iterator di;
122  for (di = def.begin(); di != def.end(); ++di) {
123  if (mods.matches(*di)) {
124  return false;
125  }
126  }
127 
128  def.push_back(mods);
129  return true;
130 }
131 
132 ////////////////////////////////////////////////////////////////////
133 // Function: ButtonThrower::remove_throw_button
134 // Access: Published
135 // Description: Removes the indicated button from the set of buttons
136 // that the ButtonThrower explicitly processes. See
137 // add_throw_button().
138 //
139 // The return value is true if the button is removed, or
140 // false if it was not on the set.
141 ////////////////////////////////////////////////////////////////////
142 bool ButtonThrower::
143 remove_throw_button(const ModifierButtons &mods, const ButtonHandle &button) {
144  ThrowButtons::iterator ti = _throw_buttons.find(button);
145  if (ti == _throw_buttons.end()) {
146  // No buttons of this kind are in the set.
147  return false;
148  }
149 
150  ThrowButtonDef &def = (*ti).second;
151 
152  // This is a vector of ModifierButtons for which the indicated
153  // button is handled.
154  ThrowButtonDef::iterator di;
155  for (di = def.begin(); di != def.end(); ++di) {
156  if (mods.matches(*di)) {
157  def.erase(di);
158  if (def.empty()) {
159  _throw_buttons.erase(ti);
160  }
161  return true;
162  }
163  }
164 
165  // The indicated ModifierButtons are not applied to this button in
166  // the set.
167  return false;
168 }
169 
170 ////////////////////////////////////////////////////////////////////
171 // Function: ButtonThrower::has_throw_button
172 // Access: Published
173 // Description: Returns true if the indicated button is on the set of
174 // buttons that will be processed by the ButtonThrower,
175 // false otherwise. See add_throw_button().
176 ////////////////////////////////////////////////////////////////////
177 bool ButtonThrower::
178 has_throw_button(const ModifierButtons &mods, const ButtonHandle &button) const {
179  ThrowButtons::const_iterator ti = _throw_buttons.find(button);
180  if (ti == _throw_buttons.end()) {
181  // No buttons of this kind are in the set.
182  return false;
183  }
184 
185  const ThrowButtonDef &def = (*ti).second;
186 
187  // This is a vector of ModifierButtons for which the indicated
188  // button is handled.
189  ThrowButtonDef::const_iterator di;
190  for (di = def.begin(); di != def.end(); ++di) {
191  if (mods.matches(*di)) {
192  return true;
193  }
194  }
195 
196  // The indicated ModifierButtons are not applied to this button in
197  // the set.
198  return false;
199 }
200 
201 ////////////////////////////////////////////////////////////////////
202 // Function: ButtonThrower::has_throw_button
203 // Access: Published
204 // Description: Returns true if the indicated button, in conjunction
205 // with any nonspecified modifier buttons, is on the set
206 // of buttons that will be processed by the
207 // ButtonThrower. That is to say, returns true if this
208 // button was ever passed as the second parameter
209 // add_throw_button(), regardless of what the first
210 // parameter was.
211 ////////////////////////////////////////////////////////////////////
212 bool ButtonThrower::
213 has_throw_button(const ButtonHandle &button) const {
214  ThrowButtons::const_iterator ti = _throw_buttons.find(button);
215  if (ti == _throw_buttons.end()) {
216  // No buttons of this kind are in the set.
217  return false;
218  }
219 
220  const ThrowButtonDef &def = (*ti).second;
221  return !def.empty();
222 }
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: ButtonThrower::clear_throw_buttons
226 // Access: Published
227 // Description: Empties the set of buttons that were added via
228 // add_throw_button(). See add_throw_button().
229 ////////////////////////////////////////////////////////////////////
230 void ButtonThrower::
232  _throw_buttons.clear();
233 }
234 
235 ////////////////////////////////////////////////////////////////////
236 // Function: ButtonThrower::write
237 // Access: Public, Virtual
238 // Description: Throw all events for button events found in the data
239 // element.
240 ////////////////////////////////////////////////////////////////////
241 void ButtonThrower::
242 write(ostream &out, int indent_level) const {
243  DataNode::write(out, indent_level);
244  if (_throw_buttons_active) {
245  indent(out, indent_level)
246  << "Processing keys:\n";
247  // Write the list of buttons that we're processing.
248  ThrowButtons::const_iterator ti;
249  for (ti = _throw_buttons.begin(); ti != _throw_buttons.end(); ++ti) {
250  ButtonHandle button = (*ti).first;
251  const ThrowButtonDef &def = (*ti).second;
252  ThrowButtonDef::const_iterator di;
253  for (di = def.begin(); di != def.end(); ++di) {
254  indent(out, indent_level + 2)
255  << (*di).get_prefix() << button.get_name() << "\n";
256  }
257  }
258  }
259 }
260 
261 ////////////////////////////////////////////////////////////////////
262 // Function: ButtonThrower::do_specific_event
263 // Access: Private
264 // Description: Generates an event of the indicated name, adding on
265 // all of the user-requested parameters.
266 ////////////////////////////////////////////////////////////////////
267 void ButtonThrower::
268 do_specific_event(const string &event_name, double time) {
269  if (_specific_flag) {
270  PT(Event) event = new Event(_prefix + event_name);
271 
272  if (_time_flag) {
273  event->add_parameter(time);
274  }
275 
276  ParameterList::const_iterator pi;
277  for (pi = _parameters.begin(); pi != _parameters.end(); ++pi) {
278  event->add_parameter(*pi);
279  }
280 
281  throw_event(event);
282  }
283 }
284 
285 ////////////////////////////////////////////////////////////////////
286 // Function: ButtonThrower::do_general_event
287 // Access: Private
288 // Description: Generates an appropriate general event, if one is
289 // configured.
290 ////////////////////////////////////////////////////////////////////
291 void ButtonThrower::
292 do_general_event(const ButtonEvent &button_event, const string &button_name) {
293  string event_name;
294  switch (button_event._type) {
295  case ButtonEvent::T_down:
296  event_name = _button_down_event;
297  break;
298 
299  case ButtonEvent::T_resume_down:
300  break;
301 
302  case ButtonEvent::T_up:
303  event_name = _button_up_event;
304  break;
305 
306  case ButtonEvent::T_repeat:
307  event_name = _button_repeat_event;
308  break;
309 
310  case ButtonEvent::T_keystroke:
311  event_name = _keystroke_event;
312  break;
313 
314  case ButtonEvent::T_candidate:
315  event_name = _candidate_event;
316  break;
317 
318  case ButtonEvent::T_move:
319  event_name = _move_event;
320  break;
321 
322  case ButtonEvent::T_raw_down:
323  event_name = _raw_button_down_event;
324  break;
325 
326  case ButtonEvent::T_raw_up:
327  event_name = _raw_button_up_event;
328  break;
329  }
330  if (event_name.empty()) {
331  // This general event is not configured.
332  return;
333  }
334 
335  PT(Event) event = new Event(event_name);
336 
337  if (_time_flag) {
338  event->add_parameter(button_event._time);
339  }
340 
341  // Now add the appropriate parameters.
342  switch (button_event._type) {
343  case ButtonEvent::T_down:
344  case ButtonEvent::T_resume_down:
345  case ButtonEvent::T_up:
346  case ButtonEvent::T_repeat:
347  case ButtonEvent::T_raw_down:
348  case ButtonEvent::T_raw_up:
349  event->add_parameter(button_name);
350  break;
351 
352  case ButtonEvent::T_keystroke:
353  event->add_parameter(wstring(1, button_event._keycode));
354  break;
355 
356  case ButtonEvent::T_candidate:
357  event->add_parameter(button_event._candidate_string);
358  break;
359 
360  case ButtonEvent::T_move:
361  event_name = _move_event;
362  break;
363  }
364 
365  ParameterList::const_iterator pi;
366  for (pi = _parameters.begin(); pi != _parameters.end(); ++pi) {
367  event->add_parameter(*pi);
368  }
369 
370  throw_event(event);
371 }
372 
373 ////////////////////////////////////////////////////////////////////
374 // Function: ButtonThrower::do_transmit_data
375 // Access: Protected, Virtual
376 // Description: The virtual implementation of transmit_data(). This
377 // function receives an array of input parameters and
378 // should generate an array of output parameters. The
379 // input parameters may be accessed with the index
380 // numbers returned by the define_input() calls that
381 // were made earlier (presumably in the constructor);
382 // likewise, the output parameters should be set with
383 // the index numbers returned by the define_output()
384 // calls.
385 ////////////////////////////////////////////////////////////////////
386 void ButtonThrower::
387 do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input,
388  DataNodeTransmit &output) {
389  // Clear our outgoing button events. We'll fill it up again with
390  // just those events that want to carry on.
391  _button_events->clear();
392 
393  if (input.has_data(_button_events_input)) {
394  const ButtonEventList *button_events;
395  DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
396 
397  int num_events = button_events->get_num_events();
398  for (int i = 0; i < num_events; i++) {
399  const ButtonEvent &be = button_events->get_event(i);
400  string event_name = be._button.get_name();
401 
402  if (be._type == ButtonEvent::T_down || be._type == ButtonEvent::T_repeat) {
403  // Button down.
404  if (!_mods.button_down(be._button)) {
405  // We only prepend modifier names on the button-down events,
406  // and only for buttons which are not themselves modifiers.
407  event_name = _mods.get_prefix() + event_name;
408  }
409 
410  if (!_throw_buttons_active || has_throw_button(_mods, be._button)) {
411  // Process this button.
412  if (be._type == ButtonEvent::T_repeat) {
413  do_specific_event(event_name + "-repeat", be._time);
414  } else {
415  do_specific_event(event_name, be._time);
416  }
417  do_general_event(be, event_name);
418 
419  } else {
420  // Don't process this button; instead, pass it down to future
421  // generations.
422  _button_events->add_event(be);
423  }
424 
425  } else if (be._type == ButtonEvent::T_resume_down) {
426  // Button resume down. The button was pressed at some earlier
427  // time, and the event was only just now detected. Don't
428  // throw an event now (since we already missed it), but do
429  // make sure our modifiers are up-to-date.
430  _mods.button_down(be._button);
431 
432  } else if (be._type == ButtonEvent::T_up) {
433  // Button up.
434  _mods.button_up(be._button);
435 
436  // We always throw button "up" events if we have any
437  // definition for the button at all, regardless of the state
438  // of the modifier keys.
439  if (!_throw_buttons_active || has_throw_button(be._button)) {
440  do_specific_event(event_name + "-up", be._time);
441  do_general_event(be, event_name);
442  }
443  if (_throw_buttons_active) {
444  // Now pass the event on to future generations. We always
445  // pass "up" events, even if we are intercepting this
446  // particular button; unless we're processing all buttons in
447  // which case it doesn't matter.
448  _button_events->add_event(be);
449  }
450 
451  } else if (be._type == ButtonEvent::T_raw_down) {
452  // Raw button down.
453  if (!_throw_buttons_active || has_throw_button(be._button)) {
454  // Process this button.
455  do_specific_event("raw-" + event_name, be._time);
456  do_general_event(be, event_name);
457 
458  } else {
459  // Don't process this button; instead, pass it down to future
460  // generations.
461  _button_events->add_event(be);
462  }
463 
464  } else if (be._type == ButtonEvent::T_raw_up) {
465  // Raw button up.
466  if (!_throw_buttons_active || has_throw_button(be._button)) {
467  // Process this button.
468  do_specific_event("raw-" + event_name + "-up", be._time);
469  do_general_event(be, event_name);
470  }
471  if (_throw_buttons_active) {
472  // Now pass the event on to future generations. We always
473  // pass "up" events, even if we are intercepting this
474  // particular button; unless we're processing all buttons in
475  // which case it doesn't matter.
476  _button_events->add_event(be);
477  }
478 
479  } else {
480  // Some other kind of button event (e.g. keypress). Don't
481  // throw an event for this, but do pass it down.
482  _button_events->add_event(be);
483  do_general_event(be, "");
484  }
485  }
486  }
487 
488  output.set_data(_button_events_output, EventParameter(_button_events));
489 }
bool button_down(ButtonHandle button)
Records that a particular button has been pressed.
The fundamental type of node for the data graph.
Definition: dataNode.h:64
This class monitors the state of a number of individual buttons and tracks whether each button is kno...
An optional parameter associated with an event.
bool has_throw_button(const ModifierButtons &mods, const ButtonHandle &button) const
Returns true if the indicated button is on the set of buttons that will be processed by the ButtonThr...
void add_parameter(const EventParameter &obj)
Adds the indicated parameter to the list of parameters that will be passed with each event generated ...
bool add_throw_button(const ModifierButtons &mods, const ButtonHandle &button)
Adds a new button to the set of buttons that the ButtonThrower explicitly processes.
bool matches(const ModifierButtons &other) const
Returns true if the set of buttons indicated as down by this ModifierButtons object is the same set o...
Records a button event of some kind.
Definition: buttonEvent.h:53
bool button_up(ButtonHandle button)
Records that a particular button has been released.
Records a set of button events that happened recently.
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.
void set_data(int index, const EventParameter &data)
Sets the data for the indicated parameter.
string get_name() const
Returns the name of the button.
int get_num_events() const
Returns the number of events in the list.
bool remove_throw_button(const ModifierButtons &mods, const ButtonHandle &button)
Removes the indicated button from the set of buttons that the ButtonThrower explicitly processes...
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...
void clear_throw_buttons()
Empties the set of buttons that were added via add_throw_button().
A named event, possibly with parameters.
Definition: event.h:36
TypedWritableReferenceCount * get_ptr() const
Retrieves a pointer to the actual value stored in the parameter.
string get_prefix() const
Returns a string which can be used to prefix any button name or event name with the unique set of mod...
virtual void write(ostream &out, int indent_level=0) const
Throw all events for button events found in the data element.
int get_num_parameters() const
Returns the number of parameters that have been added to the list of parameters to be passed with eac...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
bool has_data(int index) const
Returns true if the indicated parameter has been stored, false otherwise.
Encapsulates the data generated from (or sent into) any particular DataNode.
EventParameter get_parameter(int n) const
Returns the nth parameter that has been added to the list of parameters passed with each event genera...
This object supervises the traversal of the data graph and the moving of data from one DataNode to it...