| # kdeui Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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"

This file is part of the documentation for kdeui Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:20:22 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003