Panda3D
buttonRegistry.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 buttonRegistry.cxx
10  * @author drose
11  * @date 2000-03-01
12  */
13 
14 #include "buttonRegistry.h"
15 #include "config_putil.h"
16 
17 #include <stdio.h>
18 
19 // In general, we use the util_cat->info() syntax in this file (instead of
20 // util_cat.info()), because much of this work is done at static init time,
21 // and we must use the arrow syntax to force initialization of the util_cat
22 // category.
23 
24 ButtonRegistry *ButtonRegistry::_global_pointer = nullptr;
25 
26 
27 /**
28  * Registers a new ButtonHandle with the indicated name, and if specified, the
29  * indicated ASCII equivalent. Returns true if the button was registered, or
30  * false it was already registered; in either case, the new ButtonHandle is
31  * loaded into the first parameter.
32  *
33  * If the alias is not ButtonHandle::none(), it indicates an alias (alternate
34  * name) for the same button. Each button is allowed to have one alias, and
35  * multiple different buttons can refer to the same alias. The alias should
36  * be the more general name for the button, for instance, shift is an alias
37  * for lshift, but not vice-versa.
38  *
39  * This defines a new kind of button matching the indicated name. The
40  * ButtonHandle can then be passed around to devices as a button in its own
41  * right.
42  */
44 register_button(ButtonHandle &button_handle, const std::string &name,
45  ButtonHandle alias, char ascii_equivalent) {
46  NameRegistry::iterator ri;
47  ri = _name_registry.find(name);
48 
49  if (ri == _name_registry.end()) {
50  // The name was not already used; this is the first time this button has
51  // been defined.
52 
53  int index = -1;
54  if (ascii_equivalent != '\0') {
55  if (_handle_registry[ascii_equivalent] == nullptr) {
56  index = ascii_equivalent;
57  } else {
58  util_cat->error()
59  << "Attempt to register multiple buttons under ASCII equivalent "
60  << ascii_equivalent << "\n";
61  }
62  }
63 
64 #ifdef NOTIFY_DEBUG
65  // This code runs at static init time, so cannot use the
66  // util_cat.is_spam() syntax.
67  if (util_cat->is_spam()) {
68  util_cat->spam()
69  << "Registering button " << name << "\n";
70  }
71 #endif
72 
73  if (index == -1) {
74  // It's not an ASCII equivalent; make up a new number.
75  index = _handle_registry.size();
76  _handle_registry.push_back(nullptr);
77  }
78 
79  ButtonHandle new_handle;
80  new_handle._index = index;
81 
82  RegistryNode *rnode = new RegistryNode(new_handle, alias, name);
83  _handle_registry[index] = rnode;
84  _name_registry[name] = rnode;
85 
86  button_handle = new_handle;
87  return true;
88  }
89 
90  RegistryNode *rnode = (*ri).second;
91  nassertr(rnode->_name == (*ri).first, false);
92  nassertr(rnode->_handle._index >= 0 &&
93  rnode->_handle._index < (int)_handle_registry.size(), false);
94  nassertr(_handle_registry[rnode->_handle._index] == rnode, false);
95  nassertr(rnode->_handle._index != 0, false);
96 
97  if (button_handle != rnode->_handle) {
98  // Hmm, we seem to have a contradictory button registration!
99  util_cat->warning()
100  << "Attempt to register button " << name << " more than once!\n";
101 
102  button_handle = rnode->_handle;
103  }
104  return false;
105 }
106 
107 /**
108  * Finds a ButtonHandle in the registry matching the indicated name. If there
109  * is no such ButtonHandle, registers a new one and returns it.
110  */
112 get_button(const std::string &name) {
113  NameRegistry::const_iterator ri;
114  ri = _name_registry.find(name);
115 
116  if (ri != _name_registry.end()) {
117  return (*ri).second->_handle;
118  }
119 
120  ButtonHandle button;
121  register_button(button, name);
122  return button;
123 }
124 
125 /**
126  * Finds a ButtonHandle in the registry matching the indicated name. If there
127  * is no such ButtonHandle, returns ButtonHandle::none().
128  */
130 find_button(const std::string &name) {
131  NameRegistry::const_iterator ri;
132  ri = _name_registry.find(name);
133 
134  if (ri != _name_registry.end()) {
135  return (*ri).second->_handle;
136  }
137 
138  return ButtonHandle::none();
139 }
140 
141 /**
142  * Finds a ButtonHandle in the registry matching the indicated ASCII
143  * equivalent character. If there is no such ButtonHandle, returns
144  * ButtonHandle::none().
145  */
147 find_ascii_button(char ascii_equivalent) const {
148  if (_handle_registry[ascii_equivalent] == nullptr) {
149  return ButtonHandle::none();
150  }
151  return _handle_registry[ascii_equivalent]->_handle;
152 }
153 
154 /**
155  *
156  */
157 void ButtonRegistry::
158 write(std::ostream &out) const {
159  out << "ASCII equivalents:\n";
160  for (int i = 1; i < 128; i++) {
161  if (_handle_registry[i] != nullptr) {
162  char hex[12];
163  sprintf(hex, "%02x", (unsigned int)i);
164  nassertv(strlen(hex) < 12);
165 
166  out << " " << hex << " " << _handle_registry[i]->_name << "\n";
167  }
168  }
169 
170  out << "\nOther buttons:\n";
171  NameRegistry::const_iterator ri;
172  for (ri = _name_registry.begin(); ri != _name_registry.end(); ++ri) {
173  if (!(*ri).second->_handle.has_ascii_equivalent()) {
174  out << " " << (*ri).second->_name;
175  if ((*ri).second->_alias != ButtonHandle::none()) {
176  out << " (alias " << (*ri).second->_alias << ")";
177  }
178  out << "\n";
179  }
180  }
181 }
182 
183 
184 /**
185  *
186  */
187 ButtonRegistry::
188 ButtonRegistry() {
189  // We'll start by filling up the handle_registry with 128 entries for
190  // ButtonHandle::none(), as well as for all the ASCII equivalents.
191 
192  _handle_registry.reserve(128);
193  int i;
194  for (i = 0; i < 128; i++) {
195  _handle_registry.push_back(nullptr);
196  }
197 }
198 
199 /**
200  * Constructs the ButtonRegistry object for the first time.
201  */
202 void ButtonRegistry::
203 init_global_pointer() {
204  _global_pointer = new ButtonRegistry;
205 }
206 
207 
208 /**
209  *
210  */
211 ButtonRegistry::RegistryNode *ButtonRegistry::
212 look_up(ButtonHandle handle) const {
213  nassertr(handle._index != 0, nullptr);
214 
215  if (handle._index < 0 ||
216  handle._index >= (int)_handle_registry.size()) {
217  util_cat->fatal()
218  << "Invalid ButtonHandle index " << handle._index
219  << "! Is memory corrupt?\n";
220  return nullptr;
221  }
222 
223  return _handle_registry[handle._index];
224 }
ButtonHandle find_button(const std::string &name)
Finds a ButtonHandle in the registry matching the indicated name.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The ButtonRegistry class maintains all the assigned ButtonHandles in a given system.
ButtonHandle find_ascii_button(char ascii_equivalent) const
Finds a ButtonHandle in the registry matching the indicated ASCII equivalent character.
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:26
ButtonHandle get_button(const std::string &name)
Finds a ButtonHandle in the registry matching the indicated name.
bool register_button(ButtonHandle &button_handle, const std::string &name, ButtonHandle alias=ButtonHandle::none(), char ascii_equivalent='\0')
Registers a new ButtonHandle with the indicated name, and if specified, the indicated ASCII equivalen...