kdeui Library API Documentation

kshortcutdialog.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2002,2003 Ellis Whitehead <ellis@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include "kshortcutdialog.h" 00021 00022 #include <qvariant.h> 00023 00024 #ifdef Q_WS_X11 00025 #define XK_XKB_KEYS 00026 #define XK_MISCELLANY 00027 #include <X11/Xlib.h> // For x11Event() 00028 #include <X11/keysymdef.h> // For XK_... 00029 00030 #ifdef KeyPress 00031 const int XKeyPress = KeyPress; 00032 const int XKeyRelease = KeyRelease; 00033 const int XFocusOut = FocusOut; 00034 const int XFocusIn = FocusIn; 00035 #undef KeyRelease 00036 #undef KeyPress 00037 #undef FocusOut 00038 #undef FocusIn 00039 #endif 00040 #elif defined(Q_WS_WIN) 00041 # include <kkeyserver.h> 00042 #endif 00043 00044 #include <kshortcutdialog_simple.h> 00045 #include <kshortcutdialog_advanced.h> 00046 00047 #include <qbuttongroup.h> 00048 #include <qcheckbox.h> 00049 #include <qframe.h> 00050 #include <qlayout.h> 00051 #include <qradiobutton.h> 00052 #include <qtimer.h> 00053 #include <qvbox.h> 00054 00055 #include <kapplication.h> 00056 #include <kconfig.h> 00057 #include <kdebug.h> 00058 #include <kglobal.h> 00059 #include <kiconloader.h> 00060 #include <kkeynative.h> 00061 #include <klocale.h> 00062 #include <kstdguiitem.h> 00063 #include <kpushbutton.h> 00064 00065 bool KShortcutDialog::s_showMore = false; 00066 00067 KShortcutDialog::KShortcutDialog( const KShortcut& shortcut, bool bQtShortcut, QWidget* parent, const char* name ) 00068 : KDialogBase( parent, name, true, i18n("Configure Shortcut"), 00069 KDialogBase::Details|KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Cancel, true ) 00070 { 00071 setButtonText(Details, i18n("Advanced")); 00072 m_stack = new QVBox(this); 00073 m_stack->setMinimumWidth(360); 00074 m_stack->setSpacing(0); 00075 m_stack->setMargin(0); 00076 setMainWidget(m_stack); 00077 00078 m_simple = new KShortcutDialogSimple(m_stack); 00079 00080 m_adv = new KShortcutDialogAdvanced(m_stack); 00081 m_adv->hide(); 00082 00083 m_bQtShortcut = bQtShortcut; 00084 00085 m_bGrab = false; 00086 m_iSeq = 0; 00087 m_iKey = 0; 00088 m_ptxtCurrent = 0; 00089 m_bRecording = false; 00090 m_mod = 0; 00091 00092 m_simple->m_btnClearShortcut->setPixmap( SmallIcon( "locationbar_erase" ) ); 00093 m_adv->m_btnClearPrimary->setPixmap( SmallIcon( "locationbar_erase" ) ); 00094 m_adv->m_btnClearAlternate->setPixmap( SmallIcon( "locationbar_erase" ) ); 00095 connect(m_simple->m_btnClearShortcut, SIGNAL(clicked()), 00096 this, SLOT(slotClearShortcut())); 00097 connect(m_adv->m_btnClearPrimary, SIGNAL(clicked()), 00098 this, SLOT(slotClearPrimary())); 00099 connect(m_adv->m_btnClearAlternate, SIGNAL(clicked()), 00100 this, SLOT(slotClearAlternate())); 00101 00102 connect(m_adv->m_txtPrimary, SIGNAL(clicked()), 00103 m_adv->m_btnPrimary, SLOT(animateClick())); 00104 connect(m_adv->m_txtAlternate, SIGNAL(clicked()), 00105 m_adv->m_btnAlternate, SLOT(animateClick())); 00106 connect(m_adv->m_btnPrimary, SIGNAL(clicked()), 00107 this, SLOT(slotSelectPrimary())); 00108 connect(m_adv->m_btnAlternate, SIGNAL(clicked()), 00109 this, SLOT(slotSelectAlternate())); 00110 00111 KGuiItem ok = KStdGuiItem::ok(); 00112 ok.setText( i18n( "OK" ) ); 00113 setButtonOK( ok ); 00114 00115 KGuiItem cancel = KStdGuiItem::cancel(); 00116 cancel.setText( i18n( "Cancel" ) ); 00117 setButtonCancel( cancel ); 00118 00119 setShortcut( shortcut ); 00120 resize( 0, 0 ); 00121 00122 s_showMore = KConfigGroup(KGlobal::config(), "General").readBoolEntry("ShowAlternativeShortcutConfig", s_showMore); 00123 updateDetails(); 00124 00125 #ifdef Q_WS_X11 00126 kapp->installX11EventFilter( this ); // Allow button to capture X Key Events. 00127 #endif 00128 } 00129 00130 KShortcutDialog::~KShortcutDialog() 00131 { 00132 KConfigGroup group(KGlobal::config(), "General"); 00133 group.writeEntry("ShowAlternativeShortcutConfig", s_showMore); 00134 } 00135 00136 void KShortcutDialog::setShortcut( const KShortcut & shortcut ) 00137 { 00138 m_shortcut = shortcut; 00139 updateShortcutDisplay(); 00140 } 00141 00142 void KShortcutDialog::updateShortcutDisplay() 00143 { 00144 QString s[2] = { m_shortcut.seq(0).toString(), m_shortcut.seq(1).toString() }; 00145 00146 if( m_bRecording ) { 00147 m_ptxtCurrent->setDefault( true ); 00148 m_ptxtCurrent->setFocus(); 00149 00150 // Display modifiers for the first key in the KKeySequence 00151 if( m_iKey == 0 ) { 00152 if( m_mod ) { 00153 QString keyModStr; 00154 if( m_mod & KKey::WIN ) keyModStr += KKey::modFlagLabel(KKey::WIN) + "+"; 00155 if( m_mod & KKey::ALT ) keyModStr += KKey::modFlagLabel(KKey::ALT) + "+"; 00156 if( m_mod & KKey::CTRL ) keyModStr += KKey::modFlagLabel(KKey::CTRL) + "+"; 00157 if( m_mod & KKey::SHIFT ) keyModStr += KKey::modFlagLabel(KKey::SHIFT) + "+"; 00158 s[m_iSeq] = keyModStr; 00159 } 00160 } 00161 // When in the middle of entering multi-key shortcuts, 00162 // add a "," to the end of the displayed shortcut. 00163 else 00164 s[m_iSeq] += ","; 00165 } 00166 else { 00167 m_adv->m_txtPrimary->setDefault( false ); 00168 m_adv->m_txtAlternate->setDefault( false ); 00169 this->setFocus(); 00170 } 00171 00172 s[0].replace('&', QString::fromLatin1("&&")); 00173 s[1].replace('&', QString::fromLatin1("&&")); 00174 00175 m_simple->m_txtShortcut->setText( s[0] ); 00176 m_adv->m_txtPrimary->setText( s[0] ); 00177 m_adv->m_txtAlternate->setText( s[1] ); 00178 00179 // Determine the enable state of the 'Less' button 00180 bool bLessOk; 00181 // If there is no shortcut defined, 00182 if( m_shortcut.count() == 0 ) 00183 bLessOk = true; 00184 // If there is a single shortcut defined, and it is not a multi-key shortcut, 00185 else if( m_shortcut.count() == 1 && m_shortcut.seq(0).count() <= 1 ) 00186 bLessOk = true; 00187 // Otherwise, we have an alternate shortcut or multi-key shortcut(s). 00188 else 00189 bLessOk = false; 00190 enableButton(Details, bLessOk); 00191 } 00192 00193 void KShortcutDialog::slotDetails() 00194 { 00195 s_showMore = (m_adv->isHidden()); 00196 updateDetails(); 00197 } 00198 00199 void KShortcutDialog::updateDetails() 00200 { 00201 bool showAdvanced = s_showMore || (m_shortcut.count() > 1); 00202 setDetails(showAdvanced); 00203 m_bRecording = false; 00204 m_iSeq = 0; 00205 m_iKey = 0; 00206 00207 if (showAdvanced) 00208 { 00209 m_simple->hide(); 00210 m_adv->show(); 00211 m_adv->m_btnPrimary->setChecked( true ); 00212 slotSelectPrimary(); 00213 } 00214 else 00215 { 00216 m_ptxtCurrent = m_simple->m_txtShortcut; 00217 m_adv->hide(); 00218 m_simple->show(); 00219 m_simple->m_txtShortcut->setDefault( true ); 00220 m_simple->m_txtShortcut->setFocus(); 00221 m_adv->m_btnMultiKey->setChecked( false ); 00222 } 00223 kapp->processEvents(); 00224 adjustSize(); 00225 } 00226 00227 void KShortcutDialog::slotSelectPrimary() 00228 { 00229 m_bRecording = false; 00230 m_iSeq = 0; 00231 m_iKey = 0; 00232 m_ptxtCurrent = m_adv->m_txtPrimary; 00233 m_ptxtCurrent->setDefault(true); 00234 m_ptxtCurrent->setFocus(); 00235 updateShortcutDisplay(); 00236 } 00237 00238 void KShortcutDialog::slotSelectAlternate() 00239 { 00240 m_bRecording = false; 00241 m_iSeq = 1; 00242 m_iKey = 0; 00243 m_ptxtCurrent = m_adv->m_txtAlternate; 00244 m_ptxtCurrent->setDefault(true); 00245 m_ptxtCurrent->setFocus(); 00246 updateShortcutDisplay(); 00247 } 00248 00249 void KShortcutDialog::slotClearShortcut() 00250 { 00251 m_shortcut.setSeq( 0, KKeySequence() ); 00252 updateShortcutDisplay(); 00253 } 00254 00255 void KShortcutDialog::slotClearPrimary() 00256 { 00257 m_shortcut.setSeq( 0, KKeySequence() ); 00258 m_adv->m_btnPrimary->setChecked( true ); 00259 slotSelectPrimary(); 00260 } 00261 00262 void KShortcutDialog::slotClearAlternate() 00263 { 00264 if( m_shortcut.count() == 2 ) 00265 m_shortcut.init( m_shortcut.seq(0) ); 00266 m_adv->m_btnAlternate->setChecked( true ); 00267 slotSelectAlternate(); 00268 } 00269 00270 void KShortcutDialog::slotMultiKeyMode( bool bOn ) 00271 { 00272 // If turning off multi-key mode during a recording, 00273 if( !bOn && m_bRecording ) { 00274 m_bRecording = false; 00275 m_iKey = 0; 00276 updateShortcutDisplay(); 00277 } 00278 } 00279 00280 #ifdef Q_WS_X11 00281 /* we don't use the generic Qt code on X11 because it allows us 00282 to grab the keyboard so that all keypresses are seen 00283 */ 00284 bool KShortcutDialog::x11Event( XEvent *pEvent ) 00285 { 00286 switch( pEvent->type ) { 00287 case XKeyPress: 00288 x11KeyPressEvent( pEvent ); 00289 return true; 00290 case XKeyRelease: 00291 x11KeyReleaseEvent( pEvent ); 00292 return true; 00293 case XFocusIn: 00294 if (!m_bGrab) { 00295 //kdDebug(125) << "FocusIn and Grab!" << endl; 00296 grabKeyboard(); 00297 m_bGrab = true; 00298 } 00299 //else 00300 // kdDebug(125) << "FocusIn" << endl; 00301 break; 00302 case XFocusOut: 00303 if (m_bGrab) { 00304 //kdDebug(125) << "FocusOut and Ungrab!" << endl; 00305 releaseKeyboard(); 00306 m_bGrab = false; 00307 } 00308 //else 00309 // kdDebug(125) << "FocusOut" << endl; 00310 break; 00311 default: 00312 //kdDebug(125) << "x11Event->type = " << pEvent->type << endl; 00313 break; 00314 } 00315 return KDialogBase::x11Event( pEvent ); 00316 } 00317 00318 static uint getModsFromModX( uint keyModX ) 00319 { 00320 uint mod = 0; 00321 if( keyModX & KKeyNative::modX(KKey::SHIFT) ) mod += KKey::SHIFT; 00322 if( keyModX & KKeyNative::modX(KKey::CTRL) ) mod += KKey::CTRL; 00323 if( keyModX & KKeyNative::modX(KKey::ALT) ) mod += KKey::ALT; 00324 if( keyModX & KKeyNative::modX(KKey::WIN) ) mod += KKey::WIN; 00325 return mod; 00326 } 00327 00328 static bool convertSymXToMod( uint keySymX, uint* pmod ) 00329 { 00330 switch( keySymX ) { 00331 // Don't allow setting a modifier key as an accelerator. 00332 // Also, don't release the focus yet. We'll wait until 00333 // we get a 'normal' key. 00334 case XK_Shift_L: case XK_Shift_R: *pmod = KKey::SHIFT; break; 00335 case XK_Control_L: case XK_Control_R: *pmod = KKey::CTRL; break; 00336 case XK_Alt_L: case XK_Alt_R: *pmod = KKey::ALT; break; 00337 // FIXME: check whether the Meta or Super key are for the Win modifier 00338 case XK_Meta_L: case XK_Meta_R: 00339 case XK_Super_L: case XK_Super_R: *pmod = KKey::WIN; break; 00340 case XK_Hyper_L: case XK_Hyper_R: 00341 case XK_Mode_switch: 00342 case XK_Num_Lock: 00343 case XK_Caps_Lock: 00344 break; 00345 default: 00346 return false; 00347 } 00348 return true; 00349 } 00350 00351 void KShortcutDialog::x11KeyPressEvent( XEvent* pEvent ) 00352 { 00353 KKeyNative keyNative( pEvent ); 00354 uint keyModX = keyNative.mod(); 00355 uint keySymX = keyNative.sym(); 00356 00357 m_mod = getModsFromModX( keyModX ); 00358 00359 if( keySymX ) { 00360 m_bRecording = true; 00361 00362 uint mod = 0; 00363 if( convertSymXToMod( keySymX, &mod ) ) { 00364 if( mod ) 00365 m_mod |= mod; 00366 } 00367 else 00368 keyPressed( KKey(keyNative) ); 00369 } 00370 updateShortcutDisplay(); 00371 } 00372 00373 void KShortcutDialog::x11KeyReleaseEvent( XEvent* pEvent ) 00374 { 00375 // We're only interested in the release of modifier keys, 00376 // and then only when it's for the first key in a sequence. 00377 if( m_bRecording && m_iKey == 0 ) { 00378 KKeyNative keyNative( pEvent ); 00379 uint keyModX = keyNative.mod(); 00380 uint keySymX = keyNative.sym(); 00381 00382 m_mod = getModsFromModX( keyModX ); 00383 00384 uint mod = 0; 00385 if( convertSymXToMod( keySymX, &mod ) && mod ) { 00386 m_mod &= ~mod; 00387 if( !m_mod ) 00388 m_bRecording = false; 00389 } 00390 updateShortcutDisplay(); 00391 } 00392 } 00393 #elif defined(Q_WS_WIN) 00394 void KShortcutDialog::keyPressEvent( QKeyEvent * e ) 00395 { 00396 kdDebug() << e->text() << " " << (int)e->text()[0].latin1()<< " " << (int)e->ascii() << endl; 00397 //if key is a letter, it must be stored as lowercase 00398 int keyQt = QChar( e->key() & 0xff ).isLetter() ? 00399 (QChar( e->key() & 0xff ).lower().latin1() | (e->key() & 0xffff00) ) 00400 : e->key(); 00401 int modQt = KKeyServer::qtButtonStateToMod( e->state() ); 00402 KKeyNative keyNative( KKey(keyQt, modQt) ); 00403 m_mod = keyNative.mod(); 00404 uint keySym = keyNative.sym(); 00405 00406 switch( keySym ) { 00407 case Key_Shift: 00408 m_mod |= KKey::SHIFT; 00409 m_bRecording = true; 00410 break; 00411 case Key_Control: 00412 m_mod |= KKey::CTRL; 00413 m_bRecording = true; 00414 break; 00415 case Key_Alt: 00416 m_mod |= KKey::ALT; 00417 m_bRecording = true; 00418 break; 00419 case Key_Menu: 00420 case Key_Meta: //unused 00421 break; 00422 default: 00423 if( keyNative.sym() == Key_Return && m_iKey > 0 ) { 00424 accept(); 00425 return; 00426 } 00427 //accept 00428 if (keyNative.sym()) { 00429 KKey key = keyNative; 00430 key.simplify(); 00431 KKeySequence seq; 00432 if( m_iKey == 0 ) 00433 seq = key; 00434 else { 00435 seq = m_shortcut.seq( m_iSeq ); 00436 seq.setKey( m_iKey, key ); 00437 } 00438 m_shortcut.setSeq( m_iSeq, seq ); 00439 00440 if(m_adv->m_btnMultiKey->isChecked()) 00441 m_iKey++; 00442 00443 m_bRecording = true; 00444 00445 updateShortcutDisplay(); 00446 00447 if( !m_adv->m_btnMultiKey->isChecked() ) 00448 QTimer::singleShot(500, this, SLOT(accept())); 00449 } 00450 return; 00451 } 00452 00453 // If we are editing the first key in the sequence, 00454 // display modifier keys which are held down 00455 if( m_iKey == 0 ) { 00456 updateShortcutDisplay(); 00457 } 00458 } 00459 00460 bool KShortcutDialog::event ( QEvent * e ) 00461 { 00462 if (e->type()==QEvent::KeyRelease) { 00463 int modQt = KKeyServer::qtButtonStateToMod( static_cast<QKeyEvent*>(e)->state() ); 00464 KKeyNative keyNative( KKey(static_cast<QKeyEvent*>(e)->key(), modQt) ); 00465 uint keySym = keyNative.sym(); 00466 00467 bool change = true; 00468 switch( keySym ) { 00469 case Key_Shift: 00470 if (m_mod & KKey::SHIFT) 00471 m_mod ^= KKey::SHIFT; 00472 break; 00473 case Key_Control: 00474 if (m_mod & KKey::CTRL) 00475 m_mod ^= KKey::CTRL; 00476 break; 00477 case Key_Alt: 00478 if (m_mod & KKey::ALT) 00479 m_mod ^= KKey::ALT; 00480 break; 00481 default: 00482 change = false; 00483 } 00484 if (change) 00485 updateShortcutDisplay(); 00486 } 00487 return KDialogBase::event(e); 00488 } 00489 #endif 00490 00491 void KShortcutDialog::keyPressed( KKey key ) 00492 { 00493 kdDebug(125) << "keyPressed: " << key.toString() << endl; 00494 00495 key.simplify(); 00496 if( m_bQtShortcut ) { 00497 key = key.keyCodeQt(); 00498 if( key.isNull() ) { 00499 // TODO: message box about key not able to be used as application shortcut 00500 } 00501 } 00502 00503 KKeySequence seq; 00504 if( m_iKey == 0 ) 00505 seq = key; 00506 else { 00507 // Remove modifiers 00508 key.init( key.sym(), 0 ); 00509 seq = m_shortcut.seq( m_iSeq ); 00510 seq.setKey( m_iKey, key ); 00511 } 00512 00513 m_shortcut.setSeq( m_iSeq, seq ); 00514 00515 m_mod = 0; 00516 if( m_adv->m_btnMultiKey->isChecked() && m_iKey < KKeySequence::MAX_KEYS - 1 ) 00517 m_iKey++; 00518 else { 00519 m_iKey = 0; 00520 m_bRecording = false; 00521 } 00522 00523 updateShortcutDisplay(); 00524 00525 if( !m_adv->m_btnMultiKey->isChecked() ) 00526 QTimer::singleShot(500, this, SLOT(accept())); 00527 } 00528 00529 #include "kshortcutdialog.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:10:15 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003