Panda3D
Loading...
Searching...
No Matches
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
24using std::string;
25
26TypeHandle ButtonThrower::_type_handle;
27
28
29/**
30 *
31 */
32ButtonThrower::
33ButtonThrower(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 */
49ButtonThrower::
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 */
59add_parameter(const EventParameter &obj) {
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 */
69get_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 */
78get_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 */
99add_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 */
124remove_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 */
155has_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 */
185has_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 */
202 _throw_buttons.clear();
203}
204
205/**
206 * Throw all events for button events found in the data element.
207 */
209write(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 */
232void ButtonThrower::
233do_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 */
253void ButtonThrower::
254do_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 */
343void ButtonThrower::
344do_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}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Records a set of button events that happened recently.
get_num_events
Returns the number of events in the list.
get_event
Returns the nth event in the list.
Records a button event of some kind.
Definition buttonEvent.h:49
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
get_name
Returns the name of the button.
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...
get_num_parameters
Returns the number of parameters that have been added to the list of parameters to be passed with eac...
bool add_throw_button(const ModifierButtons &mods, const ButtonHandle &button)
Adds a new button to the set of buttons that the ButtonThrower explicitly processes.
void clear_throw_buttons()
Empties the set of buttons that were added via add_throw_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.
virtual void write(std::ostream &out, int indent_level=0) const
Throw all events for button events found in the data element.
void add_parameter(const EventParameter &obj)
Adds the indicated parameter to the list of parameters that will be passed with each event generated ...
get_parameter
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...
Encapsulates the data generated from (or sent into) any particular DataNode.
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 set_data(int index, const EventParameter &data)
Sets the data for the indicated parameter.
bool has_data(int index) const
Returns true if the indicated parameter has been stored, false otherwise.
The fundamental type of node for the data graph.
Definition dataNode.h:52
An optional parameter associated with an event.
TypedWritableReferenceCount * get_ptr() const
Retrieves a pointer to the actual value stored in the parameter.
A named event, possibly with parameters.
Definition event.h:33
This class monitors the state of a number of individual buttons and tracks whether each button is kno...
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...
bool button_up(ButtonHandle button)
Records that a particular button has been released.
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...
bool button_down(ButtonHandle button)
Records that a particular button has been pressed.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
This is our own Panda specialization on the default STL vector.
Definition pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.