1///////////////////////////////////////////////////////////////////////////// 2// Name: keyboard.cpp 3// Purpose: Keyboard wxWidgets sample 4// Author: Vadim Zeitlin 5// Modified by: 6// Created: 07.04.02 7// RCS-ID: $Id: keyboard.cpp 53395 2008-04-28 11:09:33Z VS $ 8// Copyright: (c) 2002 Vadim Zeitlin 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx/wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27// for all others, include the necessary headers (this file is usually all you 28// need because it includes almost all "standard" wxWidgets headers) 29#ifndef WX_PRECOMP 30 #include "wx/wx.h" 31#endif 32 33#if !wxUSE_LOG 34# error You must set wxUSE_LOG to 1 in setup.h 35#endif 36 37// ---------------------------------------------------------------------------- 38// private classes 39// ---------------------------------------------------------------------------- 40 41// Define a new application type, each program should derive a class from wxApp 42class MyApp : public wxApp 43{ 44public: 45 // override base class virtuals 46 // ---------------------------- 47 48 // this one is called on application startup and is a good place for the app 49 // initialization (doing it here and not in the ctor allows to have an error 50 // return: if OnInit() returns false, the application terminates) 51 virtual bool OnInit(); 52}; 53 54// Define a new frame type: this is going to be our main frame 55class MyFrame : public wxFrame 56{ 57public: 58 // ctor(s) 59 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, 60 long style = wxDEFAULT_FRAME_STYLE); 61 62 ~MyFrame() { delete m_logTarget; } 63 64 // event handlers (these functions should _not_ be virtual) 65 void OnQuit(wxCommandEvent& event); 66 void OnAbout(wxCommandEvent& event); 67 void OnClear(wxCommandEvent& event); 68 void OnSkip(wxCommandEvent& event); 69 void OnShowRaw(wxCommandEvent& event); 70 71 void OnSize(wxSizeEvent& event); 72 73private: 74 wxLog *m_logTarget; 75 76 class TextWindow *m_winText; 77 wxListBox *m_lboxLog; 78 79 // any class wishing to process wxWidgets events must use this macro 80 DECLARE_EVENT_TABLE() 81}; 82 83// A log target which just redirects the messages to a listbox 84class LboxLogger : public wxLog 85{ 86public: 87 LboxLogger(wxListBox *lbox, wxLog *logOld) 88 { 89 m_lbox = lbox; 90 //m_lbox->Disable(); -- looks ugly under MSW 91 m_logOld = logOld; 92 } 93 94 virtual ~LboxLogger() 95 { 96 wxLog::SetActiveTarget(m_logOld); 97 } 98 99private: 100 // implement sink functions 101 virtual void DoLog(wxLogLevel level, const wxChar *szString, time_t t) 102 { 103 // don't put trace messages into listbox or we can get into infinite 104 // recursion 105 if ( level == wxLOG_Trace ) 106 { 107 if ( m_logOld ) 108 { 109 // cast is needed to call protected method 110 ((LboxLogger *)m_logOld)->DoLog(level, szString, t); 111 } 112 } 113 else 114 { 115 wxLog::DoLog(level, szString, t); 116 } 117 } 118 119 virtual void DoLogString(const wxChar *szString, time_t WXUNUSED(t)) 120 { 121 wxString msg; 122 TimeStamp(&msg); 123 msg += szString; 124 125 #ifdef __WXUNIVERSAL__ 126 m_lbox->AppendAndEnsureVisible(msg); 127 #else // other ports don't have this method yet 128 m_lbox->Append(msg); 129 m_lbox->SetFirstItem(m_lbox->GetCount() - 1); 130 #endif 131 } 132 133 // the control we use 134 wxListBox *m_lbox; 135 136 // the old log target 137 wxLog *m_logOld; 138}; 139 140class TextWindow : public wxWindow 141{ 142public: 143 TextWindow(wxWindow *parent) 144 : wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 145 wxRAISED_BORDER) 146 { 147 m_skip = true; 148 m_showRaw = false; 149 150 SetBackgroundColour(*wxBLUE); 151 } 152 153 void SetSkip(bool skip) { m_skip = skip; } 154 void SetShowRaw(bool show) { m_showRaw = show; } 155 156protected: 157 void OnKeyDown(wxKeyEvent& event) { LogEvent(_T("Key down"), event); } 158 void OnKeyUp(wxKeyEvent& event) { LogEvent(_T("Key up"), event); } 159 void OnChar(wxKeyEvent& event) { LogEvent(_T("Char"), event); } 160 161 void OnPaint(wxPaintEvent& WXUNUSED(event)) 162 { 163 wxPaintDC dc(this); 164 dc.SetTextForeground(*wxWHITE); 165 dc.DrawLabel(_T("Press keys here"), GetClientRect(), wxALIGN_CENTER); 166 } 167 168private: 169 static inline wxChar GetChar(bool on, wxChar c) { return on ? c : _T('-'); } 170 171 void LogEvent(const wxChar *name, wxKeyEvent& event); 172 173 bool m_skip; 174 bool m_showRaw; 175 176 DECLARE_EVENT_TABLE() 177}; 178 179BEGIN_EVENT_TABLE(TextWindow, wxWindow) 180 EVT_KEY_DOWN(TextWindow::OnKeyDown) 181 EVT_KEY_UP(TextWindow::OnKeyUp) 182 EVT_CHAR(TextWindow::OnChar) 183 184 EVT_PAINT(TextWindow::OnPaint) 185END_EVENT_TABLE() 186 187// ---------------------------------------------------------------------------- 188// constants 189// ---------------------------------------------------------------------------- 190 191// IDs for the controls and the menu commands 192enum 193{ 194 // menu items 195 Keyboard_Quit = 1, 196 197 Keyboard_Clear, 198 Keyboard_Skip, 199 Keyboard_ShowRaw, 200 201 // it is important for the id corresponding to the "About" command to have 202 // this standard value as otherwise it won't be handled properly under Mac 203 // (where it is special and put into the "Apple" menu) 204 Keyboard_About = wxID_ABOUT 205}; 206 207// ---------------------------------------------------------------------------- 208// event tables and other macros for wxWidgets 209// ---------------------------------------------------------------------------- 210 211// the event tables connect the wxWidgets events with the functions (event 212// handlers) which process them. It can be also done at run-time, but for the 213// simple menu events like this the static method is much simpler. 214BEGIN_EVENT_TABLE(MyFrame, wxFrame) 215 EVT_MENU(Keyboard_Quit, MyFrame::OnQuit) 216 EVT_MENU(Keyboard_About, MyFrame::OnAbout) 217 218 EVT_MENU(Keyboard_Clear, MyFrame::OnClear) 219 EVT_MENU(Keyboard_Skip, MyFrame::OnSkip) 220 EVT_MENU(Keyboard_ShowRaw, MyFrame::OnShowRaw) 221 222 EVT_SIZE(MyFrame::OnSize) 223END_EVENT_TABLE() 224 225// Create a new application object: this macro will allow wxWidgets to create 226// the application object during program execution (it's better than using a 227// static object for many reasons) and also declares the accessor function 228// wxGetApp() which will return the reference of the right type (i.e. MyApp and 229// not wxApp) 230IMPLEMENT_APP(MyApp) 231 232// ============================================================================ 233// implementation 234// ============================================================================ 235 236// ---------------------------------------------------------------------------- 237// the application class 238// ---------------------------------------------------------------------------- 239 240// 'Main program' equivalent: the program execution "starts" here 241bool MyApp::OnInit() 242{ 243 // create the main application window 244 MyFrame *frame = new MyFrame(_T("Keyboard wxWidgets App"), 245 wxPoint(50, 50), wxSize(450, 340)); 246 247 // and show it (the frames, unlike simple controls, are not shown when 248 // created initially) 249 frame->Show(true); 250 251 // success: wxApp::OnRun() will be called which will enter the main message 252 // loop and the application will run. If we returned false here, the 253 // application would exit immediately. 254 return true; 255} 256 257// ---------------------------------------------------------------------------- 258// main frame 259// ---------------------------------------------------------------------------- 260 261// frame constructor 262MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style) 263 : wxFrame(NULL, wxID_ANY, title, pos, size, style), 264 m_winText(NULL) 265{ 266#if wxUSE_MENUS 267 // create a menu bar 268 wxMenu *menuFile = new wxMenu; 269 menuFile->Append(Keyboard_Clear, _T("&Clear log\tCtrl-L")); 270 menuFile->AppendSeparator(); 271 menuFile->Append(Keyboard_Quit, _T("E&xit\tAlt-X"), _T("Quit this program")); 272 273 wxMenu *menuKeys = new wxMenu; 274 menuKeys->AppendCheckItem(Keyboard_ShowRaw, _T("Show &raw keys\tCtrl-R")); 275 menuKeys->AppendSeparator(); 276 menuKeys->AppendCheckItem(Keyboard_Skip, _T("&Skip key down\tCtrl-S")); 277 278 // the "About" item should be in the help menu 279 wxMenu *menuHelp = new wxMenu; 280 menuHelp->Append(Keyboard_About, _T("&About...\tF1"), _T("Show about dialog")); 281 282 // now append the freshly created menu to the menu bar... 283 wxMenuBar *menuBar = new wxMenuBar(); 284 menuBar->Append(menuFile, _T("&File")); 285 menuBar->Append(menuKeys, _T("&Keys")); 286 menuBar->Append(menuHelp, _T("&Help")); 287 288 // ... and attach this menu bar to the frame 289 SetMenuBar(menuBar); 290 291 menuBar->Check(Keyboard_Skip, true); 292 293#ifndef wxHAS_RAW_KEY_CODES 294 menuBar->Enable(Keyboard_ShowRaw, false); 295#endif // !wxHAS_RAW_KEY_CODES 296#endif // wxUSE_MENUS 297 298 m_winText = new TextWindow(this); 299 m_lboxLog = new wxListBox(this, wxID_ANY); 300 301 m_logTarget = new LboxLogger(m_lboxLog, wxLog::GetActiveTarget()); 302 wxLog::SetActiveTarget(m_logTarget); 303 304#if wxUSE_STATUSBAR 305 // create a status bar just for fun (by default with 1 pane only) 306 CreateStatusBar(2); 307 SetStatusText(_T("Welcome to wxWidgets!")); 308#endif // wxUSE_STATUSBAR 309} 310 311// event handlers 312 313void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) 314{ 315 // true is to force the frame to close 316 Close(true); 317} 318 319void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) 320{ 321 wxString msg = _T("Demonstrates keyboard event processing in wxWidgets\n") 322 _T("(c) 2002 Vadim Zeitlin"); 323 324 wxMessageBox(msg, _T("About wxKeyboard"), wxOK | wxICON_INFORMATION, this); 325} 326 327void MyFrame::OnClear(wxCommandEvent& WXUNUSED(event)) 328{ 329 m_lboxLog->Clear(); 330} 331 332void MyFrame::OnSkip(wxCommandEvent& event) 333{ 334 m_winText->SetSkip(event.IsChecked()); 335} 336 337void MyFrame::OnShowRaw(wxCommandEvent& event) 338{ 339 m_winText->SetShowRaw(event.IsChecked()); 340} 341 342void MyFrame::OnSize(wxSizeEvent& WXUNUSED(event)) 343{ 344 if ( m_winText ) 345 { 346 wxSize size = GetClientSize(); 347 m_winText->SetSize(0, 0, size.x, 50); 348 m_lboxLog->SetSize(0, 51, size.x, size.y - 50); 349 } 350} 351 352// ---------------------------------------------------------------------------- 353// TextWindow 354// ---------------------------------------------------------------------------- 355 356void TextWindow::LogEvent(const wxChar *name, wxKeyEvent& event) 357{ 358 wxString key; 359 long keycode = event.GetKeyCode(); 360 switch ( keycode ) 361 { 362 case WXK_BACK: key = _T("BACK"); break; 363 case WXK_TAB: key = _T("TAB"); break; 364 case WXK_RETURN: key = _T("RETURN"); break; 365 case WXK_ESCAPE: key = _T("ESCAPE"); break; 366 case WXK_SPACE: key = _T("SPACE"); break; 367 case WXK_DELETE: key = _T("DELETE"); break; 368 case WXK_START: key = _T("START"); break; 369 case WXK_LBUTTON: key = _T("LBUTTON"); break; 370 case WXK_RBUTTON: key = _T("RBUTTON"); break; 371 case WXK_CANCEL: key = _T("CANCEL"); break; 372 case WXK_MBUTTON: key = _T("MBUTTON"); break; 373 case WXK_CLEAR: key = _T("CLEAR"); break; 374 case WXK_SHIFT: key = _T("SHIFT"); break; 375 case WXK_ALT: key = _T("ALT"); break; 376 case WXK_CONTROL: key = _T("CONTROL"); break; 377 case WXK_MENU: key = _T("MENU"); break; 378 case WXK_PAUSE: key = _T("PAUSE"); break; 379 case WXK_CAPITAL: key = _T("CAPITAL"); break; 380 case WXK_END: key = _T("END"); break; 381 case WXK_HOME: key = _T("HOME"); break; 382 case WXK_LEFT: key = _T("LEFT"); break; 383 case WXK_UP: key = _T("UP"); break; 384 case WXK_RIGHT: key = _T("RIGHT"); break; 385 case WXK_DOWN: key = _T("DOWN"); break; 386 case WXK_SELECT: key = _T("SELECT"); break; 387 case WXK_PRINT: key = _T("PRINT"); break; 388 case WXK_EXECUTE: key = _T("EXECUTE"); break; 389 case WXK_SNAPSHOT: key = _T("SNAPSHOT"); break; 390 case WXK_INSERT: key = _T("INSERT"); break; 391 case WXK_HELP: key = _T("HELP"); break; 392 case WXK_NUMPAD0: key = _T("NUMPAD0"); break; 393 case WXK_NUMPAD1: key = _T("NUMPAD1"); break; 394 case WXK_NUMPAD2: key = _T("NUMPAD2"); break; 395 case WXK_NUMPAD3: key = _T("NUMPAD3"); break; 396 case WXK_NUMPAD4: key = _T("NUMPAD4"); break; 397 case WXK_NUMPAD5: key = _T("NUMPAD5"); break; 398 case WXK_NUMPAD6: key = _T("NUMPAD6"); break; 399 case WXK_NUMPAD7: key = _T("NUMPAD7"); break; 400 case WXK_NUMPAD8: key = _T("NUMPAD8"); break; 401 case WXK_NUMPAD9: key = _T("NUMPAD9"); break; 402 case WXK_MULTIPLY: key = _T("MULTIPLY"); break; 403 case WXK_ADD: key = _T("ADD"); break; 404 case WXK_SEPARATOR: key = _T("SEPARATOR"); break; 405 case WXK_SUBTRACT: key = _T("SUBTRACT"); break; 406 case WXK_DECIMAL: key = _T("DECIMAL"); break; 407 case WXK_DIVIDE: key = _T("DIVIDE"); break; 408 case WXK_F1: key = _T("F1"); break; 409 case WXK_F2: key = _T("F2"); break; 410 case WXK_F3: key = _T("F3"); break; 411 case WXK_F4: key = _T("F4"); break; 412 case WXK_F5: key = _T("F5"); break; 413 case WXK_F6: key = _T("F6"); break; 414 case WXK_F7: key = _T("F7"); break; 415 case WXK_F8: key = _T("F8"); break; 416 case WXK_F9: key = _T("F9"); break; 417 case WXK_F10: key = _T("F10"); break; 418 case WXK_F11: key = _T("F11"); break; 419 case WXK_F12: key = _T("F12"); break; 420 case WXK_F13: key = _T("F13"); break; 421 case WXK_F14: key = _T("F14"); break; 422 case WXK_F15: key = _T("F15"); break; 423 case WXK_F16: key = _T("F16"); break; 424 case WXK_F17: key = _T("F17"); break; 425 case WXK_F18: key = _T("F18"); break; 426 case WXK_F19: key = _T("F19"); break; 427 case WXK_F20: key = _T("F20"); break; 428 case WXK_F21: key = _T("F21"); break; 429 case WXK_F22: key = _T("F22"); break; 430 case WXK_F23: key = _T("F23"); break; 431 case WXK_F24: key = _T("F24"); break; 432 case WXK_NUMLOCK: key = _T("NUMLOCK"); break; 433 case WXK_SCROLL: key = _T("SCROLL"); break; 434 case WXK_PAGEUP: key = _T("PAGEUP"); break; 435 case WXK_PAGEDOWN: key = _T("PAGEDOWN"); break; 436 case WXK_NUMPAD_SPACE: key = _T("NUMPAD_SPACE"); break; 437 case WXK_NUMPAD_TAB: key = _T("NUMPAD_TAB"); break; 438 case WXK_NUMPAD_ENTER: key = _T("NUMPAD_ENTER"); break; 439 case WXK_NUMPAD_F1: key = _T("NUMPAD_F1"); break; 440 case WXK_NUMPAD_F2: key = _T("NUMPAD_F2"); break; 441 case WXK_NUMPAD_F3: key = _T("NUMPAD_F3"); break; 442 case WXK_NUMPAD_F4: key = _T("NUMPAD_F4"); break; 443 case WXK_NUMPAD_HOME: key = _T("NUMPAD_HOME"); break; 444 case WXK_NUMPAD_LEFT: key = _T("NUMPAD_LEFT"); break; 445 case WXK_NUMPAD_UP: key = _T("NUMPAD_UP"); break; 446 case WXK_NUMPAD_RIGHT: key = _T("NUMPAD_RIGHT"); break; 447 case WXK_NUMPAD_DOWN: key = _T("NUMPAD_DOWN"); break; 448 case WXK_NUMPAD_PAGEUP: key = _T("NUMPAD_PAGEUP"); break; 449 case WXK_NUMPAD_PAGEDOWN: key = _T("NUMPAD_PAGEDOWN"); break; 450 case WXK_NUMPAD_END: key = _T("NUMPAD_END"); break; 451 case WXK_NUMPAD_BEGIN: key = _T("NUMPAD_BEGIN"); break; 452 case WXK_NUMPAD_INSERT: key = _T("NUMPAD_INSERT"); break; 453 case WXK_NUMPAD_DELETE: key = _T("NUMPAD_DELETE"); break; 454 case WXK_NUMPAD_EQUAL: key = _T("NUMPAD_EQUAL"); break; 455 case WXK_NUMPAD_MULTIPLY: key = _T("NUMPAD_MULTIPLY"); break; 456 case WXK_NUMPAD_ADD: key = _T("NUMPAD_ADD"); break; 457 case WXK_NUMPAD_SEPARATOR: key = _T("NUMPAD_SEPARATOR"); break; 458 case WXK_NUMPAD_SUBTRACT: key = _T("NUMPAD_SUBTRACT"); break; 459 case WXK_NUMPAD_DECIMAL: key = _T("NUMPAD_DECIMAL"); break; 460 case WXK_NUMPAD_DIVIDE: key = _T("NUMPAD_DIVIDE"); break; 461 462 default: 463 { 464 if ( keycode < 256 ) 465 { 466 if ( keycode == 0 ) 467 { 468#if wxUSE_UNICODE 469 const wxChar u = event.GetUnicodeKey(); 470 if ( u ) 471 key.Printf(_T("Unicode char '%c' (U+%04x)"), u, u); 472 else 473#endif 474 key.Printf(_T("NUL")); 475 } 476 else if ( keycode < 27 ) 477 { 478 key.Printf(_T("Ctrl-%c"), 479 (unsigned char)(_T('A') + keycode - 1)); 480 } 481 else 482 { 483 key.Printf(_T("'%c'"), (unsigned char)keycode); 484 } 485 } 486 else 487 { 488 key.Printf(_T("unknown (%ld)"), keycode); 489 } 490 } 491 } 492 493 wxString msg; 494 msg.Printf(_T("%s event: %s (flags = %c%c%c%c)"), 495 name, 496 key.c_str(), 497 GetChar(event.ControlDown(), _T('C')), 498 GetChar(event.AltDown(), _T('A')), 499 GetChar(event.ShiftDown(), _T('S')), 500 GetChar(event.MetaDown(), _T('M'))); 501 502 if ( m_showRaw ) 503 { 504 msg += wxString::Format(_T(" (raw key code/flags: %lu and 0x%lx)"), 505 (unsigned long)event.GetRawKeyCode(), 506 (unsigned long)event.GetRawKeyFlags()); 507 } 508 509 wxLogMessage(msg); 510 511 if ( m_skip ) 512 { 513 event.Skip(); 514 } 515} 516