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

This commit is contained in:
rdb 2014-03-09 17:35:31 +00:00
parent 98ffa974ac
commit b1e95feb3b
12 changed files with 340 additions and 15 deletions

View File

@ -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

View File

@ -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);

View File

@ -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
panda/src/putil/buttonMap.I Normal file
View File

@ -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);
}
}

View File

@ -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]);
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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"

View File

@ -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

View File

@ -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);