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 #endif 00041 00042 #include <kshortcutdialog_simple.h> 00043 #include <kshortcutdialog_advanced.h> 00044 00045 #include <qbuttongroup.h> 00046 #include <qcheckbox.h> 00047 #include <qframe.h> 00048 #include <qlayout.h> 00049 #include <qradiobutton.h> 00050 #include <qtimer.h> 00051 #include <qvbox.h> 00052 00053 #include <kapplication.h> 00054 #include <kconfig.h> 00055 #include <kdebug.h> 00056 #include <kglobal.h> 00057 #include <kiconloader.h> 00058 #include <kkeynative.h> 00059 #include <klocale.h> 00060 #include <kstdguiitem.h> 00061 #include <kpushbutton.h> 00062 00063 bool KShortcutDialog::s_showMore = false; 00064 00065 KShortcutDialog::KShortcutDialog( const KShortcut& shortcut, bool bQtShortcut, QWidget* parent, const char* name ) 00066 : KDialogBase( parent, name, true, i18n("Configure Shortcut"), 00067 KDialogBase::Details|KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Cancel, true ) 00068 { 00069 setButtonText(Details, i18n("Advanced")); 00070 m_stack = new QVBox(this); 00071 m_stack->setMinimumWidth(360); 00072 m_stack->setSpacing(0); 00073 m_stack->setMargin(0); 00074 setMainWidget(m_stack); 00075 00076 m_simple = new KShortcutDialogSimple(m_stack); 00077 00078 m_adv = new KShortcutDialogAdvanced(m_stack); 00079 m_adv->hide(); 00080 00081 m_bQtShortcut = bQtShortcut; 00082 00083 m_bGrab = false; 00084 m_iSeq = 0; 00085 m_iKey = 0; 00086 m_ptxtCurrent = 0; 00087 m_bRecording = false; 00088 m_mod = 0; 00089 00090 m_simple->m_btnClearShortcut->setPixmap( SmallIcon( "locationbar_erase" ) ); 00091 m_adv->m_btnClearPrimary->setPixmap( SmallIcon( "locationbar_erase" ) ); 00092 m_adv->m_btnClearAlternate->setPixmap( SmallIcon( "locationbar_erase" ) ); 00093 connect(m_simple->m_btnClearShortcut, SIGNAL(clicked()), 00094 this, SLOT(slotClearShortcut())); 00095 connect(m_adv->m_btnClearPrimary, SIGNAL(clicked()), 00096 this, SLOT(slotClearPrimary())); 00097 connect(m_adv->m_btnClearAlternate, SIGNAL(clicked()), 00098 this, SLOT(slotClearAlternate())); 00099 00100 connect(m_adv->m_txtPrimary, SIGNAL(clicked()), 00101 m_adv->m_btnPrimary, SLOT(animateClick())); 00102 connect(m_adv->m_txtAlternate, SIGNAL(clicked()), 00103 m_adv->m_btnAlternate, SLOT(animateClick())); 00104 connect(m_adv->m_btnPrimary, SIGNAL(clicked()), 00105 this, SLOT(slotSelectPrimary())); 00106 connect(m_adv->m_btnAlternate, SIGNAL(clicked()), 00107 this, SLOT(slotSelectAlternate())); 00108 00109 KGuiItem ok = KStdGuiItem::ok(); 00110 ok.setText( i18n( "OK" ) ); 00111 setButtonOK( ok ); 00112 00113 KGuiItem cancel = KStdGuiItem::cancel(); 00114 cancel.setText( i18n( "Cancel" ) ); 00115 setButtonCancel( cancel ); 00116 00117 setShortcut( shortcut ); 00118 resize( 0, 0 ); 00119 00120 s_showMore = KConfigGroup(KGlobal::config(), "General").readBoolEntry("ShowAlternativeShortcutConfig", s_showMore); 00121 updateDetails(); 00122 00123 #ifdef Q_WS_X11 00124 kapp->installX11EventFilter( this ); // Allow button to capture X Key Events. 00125 #endif 00126 } 00127 00128 KShortcutDialog::~KShortcutDialog() 00129 { 00130 KConfigGroup group(KGlobal::config(), "General"); 00131 group.writeEntry("ShowAlternativeShortcutConfig", s_showMore); 00132 } 00133 00134 void KShortcutDialog::setShortcut( const KShortcut & shortcut ) 00135 { 00136 m_shortcut = shortcut; 00137 updateShortcutDisplay(); 00138 } 00139 00140 void KShortcutDialog::updateShortcutDisplay() 00141 { 00142 QString s[2] = { m_shortcut.seq(0).toString(), m_shortcut.seq(1).toString() }; 00143 00144 if( m_bRecording ) { 00145 m_ptxtCurrent->setDefault( true ); 00146 m_ptxtCurrent->setFocus(); 00147 00148 // Display modifiers for the first key in the KKeySequence 00149 if( m_iKey == 0 ) { 00150 if( m_mod ) { 00151 QString keyModStr; 00152 if( m_mod & KKey::WIN ) keyModStr += KKey::modFlagLabel(KKey::WIN) + "+"; 00153 if( m_mod & KKey::ALT ) keyModStr += KKey::modFlagLabel(KKey::ALT) + "+"; 00154 if( m_mod & KKey::CTRL ) keyModStr += KKey::modFlagLabel(KKey::CTRL) + "+"; 00155 if( m_mod & KKey::SHIFT ) keyModStr += KKey::modFlagLabel(KKey::SHIFT) + "+"; 00156 s[m_iSeq] = keyModStr; 00157 } 00158 } 00159 // When in the middle of entering multi-key shortcuts, 00160 // add a "," to the end of the displayed shortcut. 00161 else 00162 s[m_iSeq] += ","; 00163 } 00164 else { 00165 m_adv->m_txtPrimary->setDefault( false ); 00166 m_adv->m_txtAlternate->setDefault( false ); 00167 this->setFocus(); 00168 } 00169 00170 s[0].replace('&',"&&"); 00171 s[1].replace('&',"&&"); 00172 00173 m_simple->m_txtShortcut->setText( s[0] ); 00174 m_adv->m_txtPrimary->setText( s[0] ); 00175 m_adv->m_txtAlternate->setText( s[1] ); 00176 00177 // Determine the enable state of the 'Less' button 00178 bool bLessOk; 00179 // If there is no shortcut defined, 00180 if( m_shortcut.count() == 0 ) 00181 bLessOk = true; 00182 // If there is a single shortcut defined, and it is not a multi-key shortcut, 00183 else if( m_shortcut.count() == 1 && m_shortcut.seq(0).count() <= 1 ) 00184 bLessOk = true; 00185 // Otherwise, we have an alternate shortcut or multi-key shortcut(s). 00186 else 00187 bLessOk = false; 00188 enableButton(Details, bLessOk); 00189 } 00190 00191 void KShortcutDialog::slotDetails() 00192 { 00193 s_showMore = (m_adv->isHidden()); 00194 updateDetails(); 00195 } 00196 00197 void KShortcutDialog::updateDetails() 00198 { 00199 bool showAdvanced = s_showMore || (m_shortcut.count() > 1); 00200 setDetails(showAdvanced); 00201 m_bRecording = false; 00202 m_iSeq = 0; 00203 m_iKey = 0; 00204 00205 if (showAdvanced) 00206 { 00207 m_simple->hide(); 00208 m_adv->show(); 00209 m_adv->m_btnPrimary->setChecked( true ); 00210 slotSelectPrimary(); 00211 } 00212 else 00213 { 00214 m_ptxtCurrent = m_simple->m_txtShortcut; 00215 m_adv->hide(); 00216 m_simple->show(); 00217 m_simple->m_txtShortcut->setDefault( true ); 00218 m_simple->m_txtShortcut->setFocus(); 00219 m_adv->m_btnMultiKey->setChecked( false ); 00220 } 00221 kapp->processEvents(); 00222 adjustSize(); 00223 } 00224 00225 void KShortcutDialog::slotSelectPrimary() 00226 { 00227 m_bRecording = false; 00228 m_iSeq = 0; 00229 m_iKey = 0; 00230 m_ptxtCurrent = m_adv->m_txtPrimary; 00231 m_ptxtCurrent->setDefault(true); 00232 m_ptxtCurrent->setFocus(); 00233 updateShortcutDisplay(); 00234 } 00235 00236 void KShortcutDialog::slotSelectAlternate() 00237 { 00238 m_bRecording = false; 00239 m_iSeq = 1; 00240 m_iKey = 0; 00241 m_ptxtCurrent = m_adv->m_txtAlternate; 00242 m_ptxtCurrent->setDefault(true); 00243 m_ptxtCurrent->setFocus(); 00244 updateShortcutDisplay(); 00245 } 00246 00247 void KShortcutDialog::slotClearShortcut() 00248 { 00249 m_shortcut.setSeq( 0, KKeySequence() ); 00250 updateShortcutDisplay(); 00251 } 00252 00253 void KShortcutDialog::slotClearPrimary() 00254 { 00255 m_shortcut.setSeq( 0, KKeySequence() ); 00256 m_adv->m_btnPrimary->setChecked( true ); 00257 slotSelectPrimary(); 00258 } 00259 00260 void KShortcutDialog::slotClearAlternate() 00261 { 00262 if( m_shortcut.count() == 2 ) 00263 m_shortcut.init( m_shortcut.seq(0) ); 00264 m_adv->m_btnAlternate->setChecked( true ); 00265 slotSelectAlternate(); 00266 } 00267 00268 void KShortcutDialog::slotMultiKeyMode( bool bOn ) 00269 { 00270 // If turning off multi-key mode during a recording, 00271 if( !bOn && m_bRecording ) { 00272 m_bRecording = false; 00273 m_iKey = 0; 00274 updateShortcutDisplay(); 00275 } 00276 } 00277 00278 #ifdef Q_WS_X11 00279 bool KShortcutDialog::x11Event( XEvent *pEvent ) 00280 { 00281 switch( pEvent->type ) { 00282 case XKeyPress: 00283 x11KeyPressEvent( pEvent ); 00284 return true; 00285 case XKeyRelease: 00286 x11KeyReleaseEvent( pEvent ); 00287 return true; 00288 case XFocusIn: 00289 if (!m_bGrab) { 00290 //kdDebug(125) << "FocusIn and Grab!" << endl; 00291 grabKeyboard(); 00292 m_bGrab = true; 00293 } 00294 //else 00295 // kdDebug(125) << "FocusIn" << endl; 00296 break; 00297 case XFocusOut: 00298 if (m_bGrab) { 00299 //kdDebug(125) << "FocusOut and Ungrab!" << endl; 00300 releaseKeyboard(); 00301 m_bGrab = false; 00302 } 00303 //else 00304 // kdDebug(125) << "FocusOut" << endl; 00305 break; 00306 default: 00307 //kdDebug(125) << "x11Event->type = " << pEvent->type << endl; 00308 break; 00309 } 00310 return KDialogBase::x11Event( pEvent ); 00311 } 00312 00313 static uint getModsFromModX( uint keyModX ) 00314 { 00315 uint mod = 0; 00316 if( keyModX & KKeyNative::modX(KKey::SHIFT) ) mod += KKey::SHIFT; 00317 if( keyModX & KKeyNative::modX(KKey::CTRL) ) mod += KKey::CTRL; 00318 if( keyModX & KKeyNative::modX(KKey::ALT) ) mod += KKey::ALT; 00319 if( keyModX & KKeyNative::modX(KKey::WIN) ) mod += KKey::WIN; 00320 return mod; 00321 } 00322 00323 static bool convertSymXToMod( uint keySymX, uint* pmod ) 00324 { 00325 switch( keySymX ) { 00326 // Don't allow setting a modifier key as an accelerator. 00327 // Also, don't release the focus yet. We'll wait until 00328 // we get a 'normal' key. 00329 case XK_Shift_L: case XK_Shift_R: *pmod = KKey::SHIFT; break; 00330 case XK_Control_L: case XK_Control_R: *pmod = KKey::CTRL; break; 00331 case XK_Alt_L: case XK_Alt_R: *pmod = KKey::ALT; break; 00332 // FIXME: check whether the Meta or Super key are for the Win modifier 00333 case XK_Meta_L: case XK_Meta_R: 00334 case XK_Super_L: case XK_Super_R: *pmod = KKey::WIN; break; 00335 case XK_Hyper_L: case XK_Hyper_R: 00336 case XK_Mode_switch: 00337 case XK_Num_Lock: 00338 case XK_Caps_Lock: 00339 break; 00340 default: 00341 return false; 00342 } 00343 return true; 00344 } 00345 00346 void KShortcutDialog::x11KeyPressEvent( XEvent* pEvent ) 00347 { 00348 KKeyNative keyNative( pEvent ); 00349 uint keyModX = keyNative.mod(); 00350 uint keySymX = keyNative.sym(); 00351 00352 m_mod = getModsFromModX( keyModX ); 00353 00354 if( keySymX ) { 00355 m_bRecording = true; 00356 00357 uint mod = 0; 00358 if( convertSymXToMod( keySymX, &mod ) ) { 00359 if( mod ) 00360 m_mod |= mod; 00361 } 00362 else 00363 keyPressed( KKey(keyNative) ); 00364 } 00365 updateShortcutDisplay(); 00366 } 00367 00368 void KShortcutDialog::x11KeyReleaseEvent( XEvent* pEvent ) 00369 { 00370 // We're only interested in the release of modifier keys, 00371 // and then only when it's for the first key in a sequence. 00372 if( m_bRecording && m_iKey == 0 ) { 00373 KKeyNative keyNative( pEvent ); 00374 uint keyModX = keyNative.mod(); 00375 uint keySymX = keyNative.sym(); 00376 00377 m_mod = getModsFromModX( keyModX ); 00378 00379 uint mod = 0; 00380 if( convertSymXToMod( keySymX, &mod ) && mod ) { 00381 m_mod &= ~mod; 00382 if( !m_mod ) 00383 m_bRecording = false; 00384 } 00385 updateShortcutDisplay(); 00386 } 00387 } 00388 00389 #endif // QT_WS_X11 00390 00391 void KShortcutDialog::keyPressed( KKey key ) 00392 { 00393 kdDebug(125) << "keyPressed: " << key.toString() << endl; 00394 00395 key.simplify(); 00396 if( m_bQtShortcut ) { 00397 key = key.keyCodeQt(); 00398 if( key.isNull() ) { 00399 // TODO: message box about key not able to be used as application shortcut 00400 } 00401 } 00402 00403 KKeySequence seq; 00404 if( m_iKey == 0 ) 00405 seq = key; 00406 else { 00407 // Remove modifiers 00408 key.init( key.sym(), 0 ); 00409 seq = m_shortcut.seq( m_iSeq ); 00410 seq.setKey( m_iKey, key ); 00411 } 00412 00413 m_shortcut.setSeq( m_iSeq, seq ); 00414 00415 m_mod = 0; 00416 if( m_adv->m_btnMultiKey->isChecked() && m_iKey < KKeySequence::MAX_KEYS - 1 ) 00417 m_iKey++; 00418 else { 00419 m_iKey = 0; 00420 m_bRecording = false; 00421 } 00422 00423 updateShortcutDisplay(); 00424 00425 if( !m_adv->m_btnMultiKey->isChecked() ) 00426 QTimer::singleShot(500, this, SLOT(accept())); 00427 } 00428 00429 #include "kshortcutdialog.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:27:31 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003