Browse Source

Add ButtonMap class / window.get_button_map() for querying keyboard layout + X11 implementation thereof

rdb 11 years ago
parent
commit
b1e95feb3b

+ 18 - 5
panda/src/display/graphicsWindow.cxx

@@ -77,8 +77,8 @@ GraphicsWindow::
   // Clean up python event handlers.
 #ifdef HAVE_PYTHON
   PythonWinProcClasses::iterator iter;
-  for (iter = _python_window_proc_classes.begin(); 
-       iter != _python_window_proc_classes.end(); 
+  for (iter = _python_window_proc_classes.begin();
+       iter != _python_window_proc_classes.end();
        ++iter) {
     delete *iter;
   }
@@ -340,6 +340,17 @@ has_keyboard(int device) const {
   return result;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: x11GraphicsWindow::get_keyboard_map
+//       Access: Published, Virtual
+//  Description: Returns a ButtonMap containing the association
+//               between raw buttons and virtual buttons.
+////////////////////////////////////////////////////////////////////
+ButtonMap *GraphicsWindow::
+get_keyboard_map() const {
+  return NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::enable_pointer_events
 //       Access: Published
@@ -391,8 +402,10 @@ disable_pointer_mode(int device) {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::get_pointer
 //       Access: Published
-//  Description: Returns the MouseData associated with the nth input
-//               device's pointer.
+//  Description: Returns the MouseData associated with the nth
+//               input device's pointer.  This is deprecated; use
+//               get_pointer_device().get_pointer() instead, or for
+//               raw mice, use the InputDeviceManager interface.
 ////////////////////////////////////////////////////////////////////
 MouseData GraphicsWindow::
 get_pointer(int device) const {
@@ -409,7 +422,7 @@ get_pointer(int device) const {
 //     Function: GraphicsWindow::move_pointer
 //       Access: Published, Virtual
 //  Description: Forces the pointer to the indicated position within
-//               the window, if possible.  
+//               the window, if possible.
 //
 //               Returns true if successful, false on failure.  This
 //               may fail if the mouse is not currently within the

+ 2 - 1
panda/src/display/graphicsWindow.h

@@ -29,6 +29,7 @@
 #include "modifierButtons.h"
 #include "buttonEvent.h"
 #include "keyboardButton.h"
+#include "buttonMap.h"
 #include "pnotify.h"
 #include "lightMutex.h"
 #include "lightReMutex.h"
@@ -82,7 +83,7 @@ PUBLISHED:
   MAKE_SEQ(get_input_device_names, get_num_input_devices, get_input_device_name);
   bool has_pointer(int device) const;
   bool has_keyboard(int device) const;
-  
+  virtual ButtonMap *get_keyboard_map() const;
 
   void enable_pointer_events(int device);
   void disable_pointer_events(int device);

+ 7 - 5
panda/src/putil/Sources.pp

@@ -21,8 +21,9 @@
     bamWriter.I bamWriter.h \
     bitArray.I bitArray.h \
     bitMask.I bitMask.h \
-    buttonHandle.I \
-    buttonHandle.h buttonRegistry.I buttonRegistry.h \
+    buttonHandle.I buttonHandle.h \
+    buttonMap.I buttonMap.h \
+    buttonRegistry.I buttonRegistry.h \
     cachedTypedWritableReferenceCount.h cachedTypedWritableReferenceCount.I \
     callbackData.h callbackData.I \
     callbackObject.h callbackObject.I \
@@ -84,7 +85,7 @@
     bamWriter.cxx \
     bitArray.cxx \
     bitMask.cxx \
-    buttonHandle.cxx buttonRegistry.cxx \
+    buttonHandle.cxx buttonMap.cxx buttonRegistry.cxx \
     cachedTypedWritableReferenceCount.cxx \
     callbackData.cxx \
     callbackObject.cxx \
@@ -132,8 +133,9 @@
     bamWriter.I bamWriter.h \
     bitArray.I bitArray.h \
     bitMask.I bitMask.h \
-    buttonHandle.I buttonHandle.h buttonRegistry.I \
-    buttonRegistry.h \
+    buttonHandle.I buttonHandle.h \
+    buttonMap.I buttonMap.h \
+    buttonRegistry.I buttonRegistry.h \
     cachedTypedWritableReferenceCount.h cachedTypedWritableReferenceCount.I \
     callbackData.h callbackData.I \
     callbackObject.h callbackObject.I \

+ 141 - 0
panda/src/putil/buttonMap.I

@@ -0,0 +1,141 @@
+// Filename: buttonMap.I
+// Created by:  rdb (09Mar14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonMap::get_num_buttons
+//       Access: Published
+//  Description: Returns the number of buttons that this button
+//               mapping specifies.
+////////////////////////////////////////////////////////////////////
+INLINE int ButtonMap::
+get_num_buttons() const {
+  return _buttons.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonMap::get_raw_button
+//       Access: Published
+//  Description: Returns the underlying raw button associated with
+//               the nth button.
+////////////////////////////////////////////////////////////////////
+INLINE ButtonHandle ButtonMap::
+get_raw_button(int i) const {
+  return _buttons[i]->_raw;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonMap::get_mapped_button
+//       Access: Published
+//  Description: Returns the nth mapped button, meaning the button
+//               that the nth raw button is mapped to.
+////////////////////////////////////////////////////////////////////
+INLINE ButtonHandle ButtonMap::
+get_mapped_button(int i) const {
+  return _buttons[i]->_mapped;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonMap::get_mapped_button_text
+//       Access: Published
+//  Description: Returns the text associated with the nth mapped
+//               button, meaning the button that the nth raw
+//               button is mapped to.
+////////////////////////////////////////////////////////////////////
+INLINE const string &ButtonMap::
+get_mapped_button_text(int i) const {
+  return _buttons[i]->_text;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonMap::get_mapped_button
+//       Access: Published
+//  Description: Returns the button that the given button is mapped
+//               to, or ButtonHandle::none() if this map does not
+//               specify a mapped button for the given raw button.
+////////////////////////////////////////////////////////////////////
+INLINE ButtonHandle ButtonMap::
+get_mapped_button(ButtonHandle raw) const {
+  pmap<int, ButtonNode>::const_iterator it;
+  it = _button_map.find(raw.get_index());
+  if (it == _button_map.end()) {
+    return ButtonHandle::none();
+  } else {
+    return it->second._mapped;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonMap::get_mapped_button
+//       Access: Published
+//  Description: Returns the button that the given button is mapped
+//               to, or ButtonHandle::none() if this map does not
+//               specify a mapped button for the given raw button.
+////////////////////////////////////////////////////////////////////
+INLINE ButtonHandle ButtonMap::
+get_mapped_button(const string &raw_name) const {
+  ButtonHandle raw_button = ButtonRegistry::ptr()->find_button(raw_name);
+  if (raw_button == ButtonHandle::none()) {
+    return ButtonHandle::none();
+  } else {
+    return get_mapped_button(raw_button);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtoMap::get_mapped_button_text
+//       Access: Published
+//  Description: If the button map specifies a special name for the
+//               button (eg. if the operating system or keyboard
+//               device has a localized name describing the key),
+//               returns it, or the empty string otherwise.
+//
+//               Note that this is not the same as
+//               get_mapped_button().get_name(), which returns the
+//               name of the Panda event associated with the button.
+////////////////////////////////////////////////////////////////////
+INLINE const string &ButtonMap::
+get_mapped_button_text(ButtonHandle raw) const {
+  pmap<int, ButtonNode>::const_iterator it;
+  it = _button_map.find(raw.get_index());
+  if (it == _button_map.end()) {
+    static const string empty = "";
+    return empty;
+  } else {
+    return it->second._text;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtoMap::get_mapped_button_text
+//       Access: Published
+//  Description: If the button map specifies a special name for the
+//               button (eg. if the operating system or keyboard
+//               device has a localized name describing the key),
+//               returns it, or the empty string otherwise.
+//
+//               Note that this is not the same as
+//               get_mapped_button().get_name(), which returns the
+//               name of the Panda event associated with the button.
+////////////////////////////////////////////////////////////////////
+INLINE const string &ButtonMap::
+get_mapped_button_text(const string &raw_name) const {
+  ButtonHandle raw_button = ButtonRegistry::ptr()->find_button(raw_name);
+  if (raw_button == ButtonHandle::none()) {
+    static const string empty = "";
+    return empty;
+  } else {
+    return get_mapped_button_text(raw_button);
+  }
+}

+ 33 - 0
panda/src/putil/buttonMap.cxx

@@ -0,0 +1,33 @@
+// Filename: buttonMap.cxx
+// Created by:  rdb (09Mar14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "buttonMap.h"
+
+TypeHandle ButtonMap::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonMap::map_button
+//       Access: Public
+//  Description: Registers a new button mapping.
+////////////////////////////////////////////////////////////////////
+void ButtonMap::
+map_button(ButtonHandle raw_button, ButtonHandle button, const string &text) {
+  int index = raw_button.get_index();
+  ButtonNode bnode;
+  bnode._raw = raw_button;
+  bnode._mapped = button;
+  bnode._text = text;
+  _button_map[index] = bnode;
+  _buttons.push_back(&_button_map[index]);
+}

+ 78 - 0
panda/src/putil/buttonMap.h

@@ -0,0 +1,78 @@
+// Filename: buttonMap.h
+// Created by:  rdb (07Mar14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef BUTTONMAP_H
+#define BUTTONMAP_H
+
+#include "pandabase.h"
+#include "typedReferenceCount.h"
+#include "buttonHandle.h"
+#include "buttonRegistry.h"
+#include "pmap.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ButtonMap
+// Description : This class represents a map containing all of the
+//               buttons of a (keyboard) device, though it can also
+//               be used as a generic mapping between ButtonHandles.
+//               It maps an underlying 'raw' button to a 'virtual'
+//               button, which may optionally be associated with an
+//               appropriate platform-specific name for the button.
+////////////////////////////////////////////////////////////////////
+class ButtonMap : public TypedReferenceCount {
+PUBLISHED:
+  INLINE int get_num_buttons() const;
+  INLINE ButtonHandle get_raw_button(int i) const;
+  INLINE ButtonHandle get_mapped_button(int i) const;
+  INLINE const string &get_mapped_button_text(int i) const;
+
+  INLINE ButtonHandle get_mapped_button(ButtonHandle raw) const;
+  INLINE ButtonHandle get_mapped_button(const string &raw_name) const;
+  INLINE const string &get_mapped_button_text(ButtonHandle raw) const;
+  INLINE const string &get_mapped_button_text(const string &raw_name) const;
+
+public:
+  void map_button(ButtonHandle raw_button, ButtonHandle button, const string &text = "");
+
+private:
+  struct ButtonNode {
+    ButtonHandle _raw;
+  	ButtonHandle _mapped;
+  	string _text;
+  };
+
+  pmap<int, ButtonNode> _button_map;
+  pvector<ButtonNode*> _buttons;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedReferenceCount::init_type();
+    register_type(_type_handle, "ButtonMap",
+                  TypedReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "buttonMap.I"
+
+#endif

+ 19 - 0
panda/src/putil/buttonRegistry.cxx

@@ -131,6 +131,25 @@ get_button(const string &name) {
   return button;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ButtonRegistry::find_button
+//       Access: Published
+//  Description: Finds a ButtonHandle in the registry matching the
+//               indicated name.  If there is no such ButtonHandle,
+//               returns ButtonHandle::none().
+////////////////////////////////////////////////////////////////////
+ButtonHandle ButtonRegistry::
+find_button(const string &name) {
+  NameRegistry::const_iterator ri;
+  ri = _name_registry.find(name);
+
+  if (ri != _name_registry.end()) {
+    return (*ri).second->_handle;
+  }
+
+  return ButtonHandle::none();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ButtonRegistry::find_ascii_button
 //       Access: Published

+ 1 - 0
panda/src/putil/buttonRegistry.h

@@ -48,6 +48,7 @@ public:
 
 PUBLISHED:
   ButtonHandle get_button(const string &name);
+  ButtonHandle find_button(const string &name);
   ButtonHandle find_ascii_button(char ascii_equivalent) const;
 
   void write(ostream &out) const;

+ 2 - 0
panda/src/putil/config_util.cxx

@@ -21,6 +21,7 @@
 #include "bitArray.h"
 #include "bitMask.h"
 #include "buttonHandle.h"
+#include "buttonMap.h"
 #include "cachedTypedWritableReferenceCount.h"
 #include "callbackData.h"
 #include "callbackObject.h"
@@ -186,6 +187,7 @@ init_libputil() {
   BitMask32::init_type();
   BitMask64::init_type();
   ButtonHandle::init_type();
+  ButtonMap::init_type();
   CPointerCallbackObject::init_type();
   CachedTypedWritableReferenceCount::init_type();
   CallbackData::init_type();

+ 1 - 0
panda/src/putil/p3putil_composite1.cxx

@@ -10,6 +10,7 @@
 #include "bitArray.cxx"
 #include "bitMask.cxx"
 #include "buttonHandle.cxx"
+#include "buttonMap.cxx"
 #include "buttonRegistry.cxx"
 #include "cachedTypedWritableReferenceCount.cxx"
 #include "callbackData.cxx"

+ 35 - 2
panda/src/x11display/x11GraphicsWindow.cxx

@@ -19,6 +19,7 @@
 #include "graphicsPipe.h"
 #include "keyboardButton.h"
 #include "mouseButton.h"
+#include "buttonMap.h"
 #include "clockObject.h"
 #include "pStatTimer.h"
 #include "textEncoder.h"
@@ -1545,8 +1546,10 @@ get_button(XKeyEvent &key_event, bool allow_shift) {
 //               Called by get_button(), above.
 ////////////////////////////////////////////////////////////////////
 ButtonHandle x11GraphicsWindow::
-map_button(KeySym key) {
+map_button(KeySym key) const {
   switch (key) {
+  case NoSymbol:
+    return ButtonHandle::none();
   case XK_BackSpace:
     return KeyboardButton::backspace();
   case XK_Tab:
@@ -1864,7 +1867,7 @@ map_button(KeySym key) {
 //  Description: Maps from a single X keycode to Panda's ButtonHandle.
 ////////////////////////////////////////////////////////////////////
 ButtonHandle x11GraphicsWindow::
-map_raw_button(KeyCode key) {
+map_raw_button(KeyCode key) const {
   switch (key) {
   case 9:  return KeyboardButton::escape();
   case 10: return KeyboardButton::ascii_key('1');
@@ -2001,6 +2004,36 @@ get_mouse_button(XButtonEvent &button_event) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: x11GraphicsWindow::get_keyboard_map
+//       Access: Private, Virtual
+//  Description: Returns a ButtonMap containing the association
+//               between raw buttons and virtual buttons.
+////////////////////////////////////////////////////////////////////
+ButtonMap *x11GraphicsWindow::
+get_keyboard_map() const {
+  // NB.  This could be improved by using the Xkb API.
+  //XkbDescPtr desc = XkbGetMap(_display, XkbAllMapComponentsMask, XkbUseCoreKbd);
+  ButtonMap *map = new ButtonMap;
+
+  for (int k = 9; k <= 135; ++k) {
+    ButtonHandle raw_button = map_raw_button(k);
+    if (raw_button == ButtonHandle::none()) {
+      continue;
+    }
+
+    KeySym sym = XKeycodeToKeysym(_display, k, 0);
+    ButtonHandle button = map_button(sym);
+    if (button == ButtonHandle::none()) {
+      continue;
+    }
+
+    map->map_button(raw_button, button, name);
+  }
+
+  return map;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: x11GraphicsWindow::check_event
 //       Access: Private, Static

+ 3 - 2
panda/src/x11display/x11GraphicsWindow.h

@@ -66,9 +66,10 @@ protected:
   void handle_keyrelease(XKeyEvent &event);
 
   ButtonHandle get_button(XKeyEvent &key_event, bool allow_shift);
-  ButtonHandle map_button(KeySym key);
-  ButtonHandle map_raw_button(KeyCode key);
+  ButtonHandle map_button(KeySym key) const;
+  ButtonHandle map_raw_button(KeyCode key) const;
   ButtonHandle get_mouse_button(XButtonEvent &button_event);
+  virtual ButtonMap *get_keyboard_map() const;
 
   static Bool check_event(X11_Display *display, XEvent *event, char *arg);