00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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>
00028 #include <X11/keysymdef.h>
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 );
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
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
00160
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
00178 bool bLessOk;
00179
00180 if( m_shortcut.count() == 0 )
00181 bLessOk = true;
00182
00183 else if( m_shortcut.count() == 1 && m_shortcut.seq(0).count() <= 1 )
00184 bLessOk = true;
00185
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
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
00291 grabKeyboard();
00292 m_bGrab = true;
00293 }
00294
00295
00296 break;
00297 case XFocusOut:
00298 if (m_bGrab) {
00299
00300 releaseKeyboard();
00301 m_bGrab = false;
00302 }
00303
00304
00305 break;
00306 default:
00307
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
00327
00328
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
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
00371
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
00400 }
00401 }
00402
00403 KKeySequence seq;
00404 if( m_iKey == 0 )
00405 seq = key;
00406 else {
00407
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"