OpenSceneGraph/examples/osgkeyboard/osgkeyboard.cpp
Robert Osfield 11f9575b24 From Melchior Franz, "The GUIEventAdapter header file had KeySymbols for the super and
hyper keys defined already, but these modifiers were missing in
GUIEventAdapter::ModKeyMask, and the EventQueue ingored them as well.

The attached diff/archive adds the missing parts for Super/Hyper
modifier key support.


I'm aware that this might not be supported on all systems/keyboards
out of the box, but decided to submit it anyway because:

- developers are aware of differences between input devices
 (Some mice have scroll wheels, others don't. Some have five or
 more buttons, some have only one. Some keyboards don't have
 numpads, some have AltGr, some don't etc.)

- even if someone relies on Hyper/Super in distributed software,
 this is easy to fix and doesn't create lock-in conditions

- while the names Hyper/Super may only be common on X11, they are
 just symbol names and not OS-specific

- even though some systems might not offer these additional modifiers
 by default, it's likely that all of them have at least 8 modifier
 levels internally, so it should only be a matter of OS configuration
 to make them work

- having super/hyper available is useful to offer a user ways
 to define local key definitions that are safe from collisions with
 predefined "official" key assignments"
2008-04-11 11:10:12 +00:00

439 lines
15 KiB
C++

/* OpenSceneGraph example, osgkeyboard.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osg/io_utils>
#include <osg/MatrixTransform>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Switch>
#include <osg/Notify>
#include <osg/Geometry>
#include <osgText/Text>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
class KeyboardModel : public osg::Referenced
{
public:
KeyboardModel() { createKeyboard(); }
osg::Group* getScene() { return _scene.get(); }
void keyChange(int key,int value);
protected:
~KeyboardModel() {}
osg::Switch* addKey(osg::Vec3& pos, int key,const std::string& text,float width, float height);
osg::Switch* addKey(int key,osg::Switch* sw);
void createKeyboard();
typedef std::map<int, osg::ref_ptr<osg::Switch> > KeyModelMap;
osg::ref_ptr<osg::Group> _scene;
KeyModelMap _keyModelMap;
osg::ref_ptr<osgText::Text> _inputText;
};
void KeyboardModel::keyChange(int key,int value)
{
osg::notify(osg::INFO) << "key value change, code="<<std::hex << key << "\t value="<< value << std::dec << std::endl;
// toggle the keys graphical representation on or off via osg::Swithc
KeyModelMap::iterator itr = _keyModelMap.find(key);
if (itr!=_keyModelMap.end())
{
itr->second->setSingleChildOn(value);
}
if (value)
{
// when a key is pressed add the new data to the text field
if (key>0 && key<256)
{
// just add ascii characters right now...
_inputText->getText().push_back(key);
_inputText->update();
}
else if (key==osgGA::GUIEventAdapter::KEY_Return)
{
_inputText->getText().push_back('\n');
_inputText->update();
}
else if (key==osgGA::GUIEventAdapter::KEY_BackSpace || key==osgGA::GUIEventAdapter::KEY_Delete)
{
if (!_inputText->getText().empty())
{
_inputText->getText().pop_back();
_inputText->update();
}
}
}
}
osg::Switch* KeyboardModel::addKey(osg::Vec3& pos, int key,const std::string& text,float width, float height)
{
osg::Geode* geodeUp = new osg::Geode;
{
osgText::Text* textUp = new osgText::Text;
textUp->setFont("fonts/arial.ttf");
textUp->setColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
textUp->setCharacterSize(height);
textUp->setPosition(pos);
textUp->setDrawMode(osgText::Text::TEXT/*|osgText::Text::BOUNDINGBOX*/);
textUp->setAlignment(osgText::Text::LEFT_CENTER);
textUp->setAxisAlignment(osgText::Text::XZ_PLANE);
textUp->setText(text);
geodeUp->addDrawable(textUp);
}
osg::Geode* geodeDown = new osg::Geode;
{
osgText::Text* textDown = new osgText::Text;
textDown->setFont("fonts/arial.ttf");
textDown->setColor(osg::Vec4(1.0f,0.0f,1.0f,1.0f));
textDown->setCharacterSize(height);
textDown->setPosition(pos);
textDown->setDrawMode(osgText::Text::TEXT/*||osgText::Text::BOUNDINGBOX*/);
textDown->setAlignment(osgText::Text::LEFT_CENTER);
textDown->setAxisAlignment(osgText::Text::XZ_PLANE);
textDown->setText(text);
geodeDown->addDrawable(textDown);
}
osg::Switch* model = new osg::Switch;
model->addChild(geodeUp,true);
model->addChild(geodeDown,false);
_scene->addChild(model);
_keyModelMap[key] = model;
pos.x() += width;
return model;
}
osg::Switch* KeyboardModel::addKey(int key,osg::Switch* sw)
{
_keyModelMap[key] = sw;
return sw;
}
void KeyboardModel::createKeyboard()
{
_scene = new osg::Group;
osg::Vec3 origin(0.0f,0.0f,0.0f);
osg::Vec3 pos=origin;
addKey(pos,osgGA::GUIEventAdapter::KEY_Control_L,"Ctrl",2.0f,0.5f);
addKey(pos,osgGA::GUIEventAdapter::KEY_Super_L,"Super",2.0f,0.5f);
addKey(pos,osgGA::GUIEventAdapter::KEY_Alt_L,"Alt",2.0f,0.5f);
addKey(pos,osgGA::GUIEventAdapter::KEY_Space,"Space",3.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_Mode_switch,"Switch",2.0f,0.5f);
addKey(pos,osgGA::GUIEventAdapter::KEY_Super_R,"Super",2.0f,0.5f);
addKey(pos,osgGA::GUIEventAdapter::KEY_Menu,"Menu",2.0f,0.5f);
addKey(pos,osgGA::GUIEventAdapter::KEY_Control_R,"Ctrl",2.0f,0.5f);
osg::Vec3 middle(pos.x()+1.0f,0.0f,0.0f);
pos.x() = 0.0f;
pos.z() += 1.0f;
addKey(pos,osgGA::GUIEventAdapter::KEY_Shift_L,"Shift",2.0f,0.5f);
addKey(pos,'\\',"\\",1.0f,1.0f);
addKey('Z',addKey(pos,'z',"Z",1.0f,1.0f));
addKey('X',addKey(pos,'x',"X",1.0f,1.0f));
addKey('C',addKey(pos,'c',"C",1.0f,1.0f));
addKey('V',addKey(pos,'v',"V",1.0f,1.0f));
addKey('B',addKey(pos,'b',"B",1.0f,1.0f));
addKey('N',addKey(pos,'n',"N",1.0f,1.0f));
addKey('M',addKey(pos,'m',"M",1.0f,1.0f));
addKey('<',addKey(pos,',',",",1.0f,1.0f));
addKey('>',addKey(pos,'.',".",1.0f,1.0f));
addKey('?',addKey(pos,'/',"/",1.0f,1.0f));
addKey(pos,osgGA::GUIEventAdapter::KEY_Shift_R,"Shift",2.0f,0.5f);
pos.x() = 0.0f;
pos.z() += 1.0f;
addKey(pos,osgGA::GUIEventAdapter::KEY_Caps_Lock,"Caps",2.0f,0.5f);
addKey('A',addKey(pos,'a',"A",1.0f,1.0f));
addKey('S',addKey(pos,'s',"S",1.0f,1.0f));
addKey('D',addKey(pos,'d',"D",1.0f,1.0f));
addKey('F',addKey(pos,'f',"F",1.0f,1.0f));
addKey('G',addKey(pos,'g',"G",1.0f,1.0f));
addKey('H',addKey(pos,'h',"H",1.0f,1.0f));
addKey('J',addKey(pos,'j',"J",1.0f,1.0f));
addKey('K',addKey(pos,'k',"K",1.0f,1.0f));
addKey('L',addKey(pos,'l',"L",1.0f,1.0f));
addKey(':',addKey(pos,';',";",1.0f,1.0f));
addKey('@',addKey(pos,'\'',"'",1.0f,1.0f));
addKey('~',addKey(pos,'#',"#",1.0f,1.0f));
addKey(pos,osgGA::GUIEventAdapter::KEY_Return,"Return",4.0f,0.5f);
pos.x() = 0.0f;
pos.z() += 1.0f;
addKey(pos,osgGA::GUIEventAdapter::KEY_Tab,"Tab",2.0f,0.5f);
addKey('Q',addKey(pos,'q',"Q",1.0f,1.0f));
addKey('W',addKey(pos,'w',"W",1.0f,1.0f));
addKey('E',addKey(pos,'e',"E",1.0f,1.0f));
addKey('R',addKey(pos,'r',"R",1.0f,1.0f));
addKey('T',addKey(pos,'t',"T",1.0f,1.0f));
addKey('Y',addKey(pos,'y',"Y",1.0f,1.0f));
addKey('U',addKey(pos,'u',"U",1.0f,1.0f));
addKey('I',addKey(pos,'i',"I",1.0f,1.0f));
addKey('O',addKey(pos,'o',"O",1.0f,1.0f));
addKey('P',addKey(pos,'p',"P",1.0f,1.0f));
addKey('{',addKey(pos,'[',"[",1.0f,1.0f));
addKey('}',addKey(pos,']',"]",1.0f,1.0f));
pos.x() = 0.0f;
pos.z() += 1.0f;
addKey(pos,'`',"`",1.0f,1.0f);
addKey(pos,'1',"1",1.0f,1.0f);
addKey(pos,'2',"2",1.0f,1.0f);
addKey(pos,'3',"3",1.0f,1.0f);
addKey(pos,'4',"4",1.0f,1.0f);
addKey(pos,'5',"5",1.0f,1.0f);
addKey(pos,'6',"6",1.0f,1.0f);
addKey(pos,'7',"7",1.0f,1.0f);
addKey(pos,'8',"8",1.0f,1.0f);
addKey(pos,'9',"9",1.0f,1.0f);
addKey(pos,'0',"0",1.0f,1.0f);
addKey(pos,'-',"-",1.0f,1.0f);
addKey(pos,'=',"=",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_BackSpace,"Backspace",3.0f,0.5f);
pos.x() = 0.0f;
pos.z() += 1.5f;
float F_height = 0.5f;
addKey(pos,osgGA::GUIEventAdapter::KEY_Escape,"Esc",2.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F1,"F1",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F2,"F2",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F3,"F3",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F4,"F4",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F5,"F5",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F6,"F6",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F7,"F7",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F8,"F8",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F9,"F9",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F10,"F10",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F11,"F11",1.0f,F_height);
addKey(pos,osgGA::GUIEventAdapter::KEY_F12,"F12",1.0f,F_height);
float cursorMoveHeight=0.35f;
pos = middle;
addKey(pos,osgGA::GUIEventAdapter::KEY_Left,"Left",1.0f,cursorMoveHeight);
osg::Vec3 down = pos;
addKey(pos,osgGA::GUIEventAdapter::KEY_Down,"Down",1.0f,cursorMoveHeight);
addKey(pos,osgGA::GUIEventAdapter::KEY_Right,"Right",1.0f,cursorMoveHeight);
osg::Vec3 keypad = pos;
keypad.x()+=1.0f;
pos = down;
pos.z() += 1.0f;
addKey(pos,osgGA::GUIEventAdapter::KEY_Up,"Up",1.0f,cursorMoveHeight);
float homeHeight = 0.35f;
pos = middle;
pos.z() += 3.0;
addKey(pos,osgGA::GUIEventAdapter::KEY_Delete,"Delete",1.0f,homeHeight);
addKey(pos,osgGA::GUIEventAdapter::KEY_End,"End",1.0f,homeHeight);
addKey(pos,osgGA::GUIEventAdapter::KEY_Page_Down,"Page\nDown",1.0f,homeHeight);
pos = middle;
pos.z() += 4.0;
addKey(pos,osgGA::GUIEventAdapter::KEY_Insert,"Insert",1.0f,homeHeight);
addKey(pos,osgGA::GUIEventAdapter::KEY_Home,"Home",1.0f,homeHeight);
addKey(pos,osgGA::GUIEventAdapter::KEY_Page_Up,"Page\nUp",1.0f,homeHeight);
pos = middle;
pos.z() += 5.5;
addKey(pos,osgGA::GUIEventAdapter::KEY_Print,"PrtScrn\nSysRq",1.0f,homeHeight);
addKey(pos,osgGA::GUIEventAdapter::KEY_Scroll_Lock,"ScrLk",1.0f,homeHeight);
addKey(pos,osgGA::GUIEventAdapter::KEY_Pause,"Pause\nBreak",1.0f,homeHeight);
pos = keypad;
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Insert,"0",2.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Delete,".",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Enter,"Enter",1.0f,homeHeight);
pos = keypad;
pos.z() += 1.0f;
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_End,"1",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Down,"2",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Page_Down,"3",1.0f,1.0f);
pos = keypad;
pos.z() += 2.0f;
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Left,"4",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Begin,"5",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Right,"6",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Add,"+",1.0f,1.0f);
pos = keypad;
pos.z() += 3.0f;
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Home,"7",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Up,"8",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Page_Up,"9",1.0f,1.0f);
pos = keypad;
pos.z() += 4.0f;
addKey(pos,osgGA::GUIEventAdapter::KEY_Num_Lock,"Num\nLock",1.0f,0.3f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Divide,"/",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Multiply,"*",1.0f,1.0f);
addKey(pos,osgGA::GUIEventAdapter::KEY_KP_Subtract,"-",1.0f,1.0f);
float totalWidth = pos.x()-origin.x();
pos = origin;
pos.z() += -1.5f;
osg::Geode* geodeInput = new osg::Geode;
{
_inputText = new osgText::Text;
_inputText->setFont("fonts/arial.ttf");
_inputText->setColor(osg::Vec4(1.0f,1.0f,0.0f,1.0f));
_inputText->setCharacterSize(1.0f);
_inputText->setMaximumWidth(totalWidth);
_inputText->setPosition(pos);
_inputText->setDrawMode(osgText::Text::TEXT/*||osgText::Text::BOUNDINGBOX*/);
_inputText->setAlignment(osgText::Text::BASE_LINE);
_inputText->setAxisAlignment(osgText::Text::XZ_PLANE);
_inputText->setDataVariance(osg::Object::DYNAMIC);
_inputText->setText("Press some keys...");
geodeInput->addDrawable(_inputText.get());
_scene->addChild(geodeInput);
}
}
class KeyboardEventHandler : public osgGA::GUIEventHandler
{
public:
KeyboardEventHandler(KeyboardModel* keyboardModel):
_keyboardModel(keyboardModel) {}
virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
{
#if 1
// osg::notify(osg::NOTICE)<<"Mouse "<<ea.getButtonMask()<<std::endl;
#define PRINT(mask) osg::notify(osg::NOTICE)<<#mask<<" ="<<(ea.getModKeyMask() & mask)<<std::endl;
switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::KEYDOWN):
case(osgGA::GUIEventAdapter::KEYUP):
{
osg::notify(osg::NOTICE)<<std::endl;
PRINT(osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT);
PRINT(osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT);
PRINT(osgGA::GUIEventAdapter::MODKEY_LEFT_ALT);
PRINT(osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT);
PRINT(osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL);
PRINT(osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL);
PRINT(osgGA::GUIEventAdapter::MODKEY_LEFT_META);
PRINT(osgGA::GUIEventAdapter::MODKEY_RIGHT_META);
PRINT(osgGA::GUIEventAdapter::MODKEY_LEFT_SUPER);
PRINT(osgGA::GUIEventAdapter::MODKEY_RIGHT_SUPER);
PRINT(osgGA::GUIEventAdapter::MODKEY_LEFT_HYPER);
PRINT(osgGA::GUIEventAdapter::MODKEY_RIGHT_HYPER);
PRINT(osgGA::GUIEventAdapter::MODKEY_NUM_LOCK);
PRINT(osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK);
break;
}
default:
break;
}
#endif
switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::KEYDOWN):
{
_keyboardModel->keyChange(ea.getKey(),1);
return true;
}
case(osgGA::GUIEventAdapter::KEYUP):
{
_keyboardModel->keyChange(ea.getKey(),0);
return true;
}
default:
return false;
}
}
osg::ref_ptr<KeyboardModel> _keyboardModel;
};
int main(int , char **)
{
osgViewer::Viewer viewer;
osg::ref_ptr<KeyboardModel> keyboardModel = new KeyboardModel;
viewer.addEventHandler(new osgViewer::StatsHandler);
viewer.addEventHandler(new osgViewer::WindowSizeHandler());
viewer.addEventHandler(new KeyboardEventHandler(keyboardModel.get()));
viewer.setSceneData( keyboardModel->getScene() );
return viewer.run();
}