Panda3D
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.
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.
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.
bool has_data(int index) const
Returns true if the indicated parameter has been stored, false otherwise.
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:28
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
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.
bool remove_throw_button(const ModifierButtons &mods, const ButtonHandle &button)
Removes the indicated button from the set of buttons that the ButtonThrower explicitly processes...
EventParameter get_parameter(int n) const
Returns the nth parameter that has been added to the list of parameters passed with each event genera...
TypedWritableReferenceCount * get_ptr() const
Retrieves a pointer to the actual value stored in the parameter.
virtual void write(ostream &out, int indent_level=0) const
Throw all events for button events found in the data element.
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
int get_num_parameters() const
Returns the number of parameters that have been added to the list of parameters to be passed with eac...
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:85
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...