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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:26
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.
ButtonHandle find_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...
ButtonHandle get_button(const std::string &name)
Finds a ButtonHandle in the registry matching the indicated name.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.