• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kdeui

kshortcutdialog.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00017     Boston, MA 02110-1301, 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"

kdeui

Skip menu "kdeui"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal