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