kshortcut.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2001,2002 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 "kshortcut.h" 00021 #include "kkeynative.h" 00022 #include "kkeyserver.h" 00023 00024 #include <qevent.h> 00025 #include <qstringlist.h> 00026 00027 #include <kdebug.h> 00028 #include <kglobal.h> 00029 #include <klocale.h> 00030 #include <ksimpleconfig.h> 00031 00032 //---------------------------------------------------- 00033 00034 static KKey* g_pspec = 0; 00035 static KKeySequence* g_pseq = 0; 00036 static KShortcut* g_pcut = 0; 00037 00038 //---------------------------------------------------- 00039 // KKey 00040 //---------------------------------------------------- 00041 00042 KKey::KKey() { clear(); } 00043 KKey::KKey( uint key, uint modFlags ) { init( key, modFlags ); } 00044 KKey::KKey( int keyQt ) { init( keyQt ); } 00045 KKey::KKey( const QKeySequence& seq ) { init( seq ); } 00046 KKey::KKey( const QKeyEvent* pEvent ) { init( pEvent ); } 00047 KKey::KKey( const KKey& key ) { init( key ); } 00048 KKey::KKey( const QString& sKey ) { init( sKey ); } 00049 00050 KKey::~KKey() 00051 { 00052 } 00053 00054 void KKey::clear() 00055 { 00056 m_sym = 0; 00057 m_mod = 0; 00058 } 00059 00060 bool KKey::init( uint key, uint modFlags ) 00061 { 00062 m_sym = key; 00063 m_mod = modFlags; 00064 return true; 00065 } 00066 00067 bool KKey::init( int keyQt ) 00068 { 00069 //KKeyServer::Sym sym; 00070 00071 //if( sym.initQt( keyQt ) 00072 if( KKeyServer::keyQtToSym( keyQt, m_sym ) 00073 && KKeyServer::keyQtToMod( keyQt, m_mod ) ) 00074 return true; 00075 else { 00076 m_sym = 0; 00077 m_mod = 0; 00078 return false; 00079 } 00080 } 00081 00082 bool KKey::init( const QKeySequence& key ) 00083 { 00084 // TODO: if key.count() > 1, should we return failure? 00085 return init( (int) key ); 00086 } 00087 00088 bool KKey::init( const QKeyEvent* pEvent ) 00089 { 00090 int keyQt = pEvent->key(); 00091 if( pEvent->state() & Qt::ShiftButton ) keyQt |= Qt::SHIFT; 00092 if( pEvent->state() & Qt::ControlButton ) keyQt |= Qt::CTRL; 00093 if( pEvent->state() & Qt::AltButton ) keyQt |= Qt::ALT; 00094 if( pEvent->state() & Qt::MetaButton ) keyQt |= Qt::META; 00095 return init( keyQt ); 00096 } 00097 00098 bool KKey::init( const KKey& key ) 00099 { 00100 m_sym = key.m_sym; 00101 m_mod = key.m_mod; 00102 return true; 00103 } 00104 00105 bool KKey::init( const QString& sSpec ) 00106 { 00107 clear(); 00108 00109 QString sKey = sSpec.stripWhiteSpace(); 00110 if( sKey.startsWith( "default(" ) && sKey.endsWith( ")" ) ) 00111 sKey = sKey.mid( 8, sKey.length() - 9 ); 00112 // i.e., "Ctrl++" = "Ctrl+Plus" 00113 if( sKey.endsWith( "++" ) ) 00114 sKey = sKey.left( sKey.length() - 1 ) + "plus"; 00115 QStringList rgs = QStringList::split( '+', sKey, true ); 00116 00117 uint i; 00118 // Check for modifier keys first. 00119 for( i = 0; i < rgs.size(); i++ ) { 00120 QString s = rgs[i].lower(); 00121 if( s == "shift" ) m_mod |= KKey::SHIFT; 00122 else if( s == "ctrl" ) m_mod |= KKey::CTRL; 00123 else if( s == "alt" ) m_mod |= KKey::ALT; 00124 else if( s == "win" ) m_mod |= KKey::WIN; 00125 else if( s == "meta" ) m_mod |= KKey::WIN; 00126 else { 00127 uint m = KKeyServer::stringUserToMod( s ); 00128 if( m != 0 ) m_mod |= m; 00129 else break; 00130 } 00131 } 00132 // If there is one non-blank key left: 00133 if( (i == rgs.size() - 1 && !rgs[i].isEmpty()) ) { 00134 KKeyServer::Sym sym( rgs[i] ); 00135 m_sym = sym.m_sym; 00136 } 00137 00138 if( m_sym == 0 ) 00139 m_mod = 0; 00140 00141 kdDebug(125) << "KKey::init( \"" << sSpec << "\" ):" 00142 << " m_sym = " << QString::number(m_sym, 16) 00143 << ", m_mod = " << QString::number(m_mod, 16) << endl; 00144 00145 return m_sym != 0; 00146 } 00147 00148 bool KKey::isNull() const { return m_sym == 0; } 00149 uint KKey::sym() const { return m_sym; } 00150 uint KKey::modFlags() const { return m_mod; } 00151 00152 int KKey::compare( const KKey& spec ) const 00153 { 00154 if( m_sym != spec.m_sym ) 00155 return m_sym - spec.m_sym; 00156 if( m_mod != spec.m_mod ) 00157 return m_mod - spec.m_mod; 00158 return 0; 00159 } 00160 00161 int KKey::keyCodeQt() const 00162 { 00163 return KKeyNative( *this ).keyCodeQt(); 00164 } 00165 00166 QString KKey::toString() const 00167 { 00168 QString s; 00169 00170 s = KKeyServer::modToStringUser( m_mod ); 00171 if( !s.isEmpty() ) 00172 s += '+'; 00173 s += KKeyServer::Sym(m_sym).toString(); 00174 00175 return s; 00176 } 00177 00178 QString KKey::toStringInternal() const 00179 { 00180 //kdDebug(125) << "KKey::toStringInternal(): this = " << this 00181 // << " mod = " << QString::number(m_mod, 16) 00182 // << " key = " << QString::number(m_sym, 16) << endl; 00183 QString s; 00184 00185 s = KKeyServer::modToStringInternal( m_mod ); 00186 if( !s.isEmpty() ) 00187 s += '+'; 00188 s += KKeyServer::Sym(m_sym).toStringInternal(); 00189 return s; 00190 } 00191 00192 KKey& KKey::null() 00193 { 00194 if( !g_pspec ) 00195 g_pspec = new KKey; 00196 if( !g_pspec->isNull() ) 00197 g_pspec->clear(); 00198 return *g_pspec; 00199 } 00200 00201 QString KKey::modFlagLabel( ModFlag modFlag ) 00202 { 00203 return KKeyServer::modToStringUser( modFlag ); 00204 } 00205 00206 //--------------------------------------------------------------------- 00207 // KKeySequence 00208 //--------------------------------------------------------------------- 00209 00210 KKeySequence::KKeySequence() { clear(); } 00211 KKeySequence::KKeySequence( const QKeySequence& seq ) { init( seq ); } 00212 KKeySequence::KKeySequence( const KKey& key ) { init( key ); } 00213 KKeySequence::KKeySequence( const KKeySequence& seq ) { init( seq ); } 00214 KKeySequence::KKeySequence( const QString& s ) { init( s ); } 00215 00216 KKeySequence::~KKeySequence() 00217 { 00218 } 00219 00220 void KKeySequence::clear() 00221 { 00222 m_nKeys = 0; 00223 m_bTriggerOnRelease = false; 00224 } 00225 00226 bool KKeySequence::init( const QKeySequence& seq ) 00227 { 00228 clear(); 00229 if( !seq.isEmpty() ) { 00230 for( uint i = 0; i < seq.count(); i++ ) { 00231 m_rgvar[i].init( seq[i] ); 00232 if( m_rgvar[i].isNull() ) 00233 return false; 00234 } 00235 m_nKeys = seq.count(); 00236 m_bTriggerOnRelease = false; 00237 } 00238 return true; 00239 } 00240 00241 bool KKeySequence::init( const KKey& key ) 00242 { 00243 if( !key.isNull() ) { 00244 m_nKeys = 1; 00245 m_rgvar[0].init( key ); 00246 m_bTriggerOnRelease = false; 00247 } else 00248 clear(); 00249 return true; 00250 } 00251 00252 bool KKeySequence::init( const KKeySequence& seq ) 00253 { 00254 m_bTriggerOnRelease = false; 00255 m_nKeys = seq.m_nKeys; 00256 for( uint i = 0; i < m_nKeys; i++ ) { 00257 if( seq.m_rgvar[i].isNull() ) { 00258 kdDebug(125) << "KKeySequence::init( seq ): key[" << i << "] is null." << endl; 00259 m_nKeys = 0; 00260 return false; 00261 } 00262 m_rgvar[i] = seq.m_rgvar[i]; 00263 } 00264 return true; 00265 } 00266 00267 bool KKeySequence::init( const QString& s ) 00268 { 00269 m_bTriggerOnRelease = false; 00270 //kdDebug(125) << "KKeySequence::init( " << s << " )" << endl; 00271 QStringList rgs = QStringList::split( ',', s ); 00272 if( s == "none" || rgs.size() == 0 ) { 00273 clear(); 00274 return true; 00275 } else if( rgs.size() <= MAX_KEYS ) { 00276 m_nKeys = rgs.size(); 00277 for( uint i = 0; i < m_nKeys; i++ ) { 00278 m_rgvar[i].init( KKey(rgs[i]) ); 00279 //kdDebug(125) << "\t'" << rgs[i] << "' => " << m_rgvar[i].toStringInternal() << endl; 00280 } 00281 return true; 00282 } else { 00283 clear(); 00284 return false; 00285 } 00286 } 00287 00288 uint KKeySequence::count() const 00289 { 00290 return m_nKeys; 00291 } 00292 00293 const KKey& KKeySequence::key( uint i ) const 00294 { 00295 if( i < m_nKeys ) 00296 return m_rgvar[i]; 00297 else 00298 return KKey::null(); 00299 } 00300 00301 bool KKeySequence::isTriggerOnRelease() const 00302 { return m_bTriggerOnRelease; } 00303 00304 bool KKeySequence::setKey( uint iKey, const KKey& key ) 00305 { 00306 if( iKey <= m_nKeys && iKey < MAX_KEYS ) { 00307 m_rgvar[iKey].init( key ); 00308 if( iKey == m_nKeys ) 00309 m_nKeys++; 00310 return true; 00311 } else 00312 return false; 00313 } 00314 00315 bool KKeySequence::isNull() const 00316 { 00317 return m_nKeys == 0; 00318 } 00319 00320 bool KKeySequence::startsWith( const KKeySequence& seq ) const 00321 { 00322 if( m_nKeys < seq.m_nKeys ) 00323 return false; 00324 00325 for( uint i = 0; i < seq.m_nKeys; i++ ) { 00326 if( m_rgvar[i] != seq.m_rgvar[i] ) 00327 return false; 00328 } 00329 00330 return true; 00331 } 00332 00333 int KKeySequence::compare( const KKeySequence& seq ) const 00334 { 00335 for( uint i = 0; i < m_nKeys && i < seq.m_nKeys; i++ ) { 00336 int ret = m_rgvar[i].compare( seq.m_rgvar[i] ); 00337 if( ret != 0 ) 00338 return ret; 00339 } 00340 if( m_nKeys != seq.m_nKeys ) 00341 return m_nKeys - seq.m_nKeys; 00342 else 00343 return 0; 00344 } 00345 00346 QKeySequence KKeySequence::qt() const 00347 { 00348 int k[4] = { 0, 0, 0, 0 }; 00349 00350 for( uint i = 0; i < count(); i++ ) 00351 k[i] = KKeyNative(key(i)).keyCodeQt(); 00352 QKeySequence seq( k[0], k[1], k[2], k[3] ); 00353 return seq; 00354 } 00355 00356 int KKeySequence::keyCodeQt() const 00357 { 00358 return (count() == 1) ? KKeyNative(key(0)).keyCodeQt() : 0; 00359 } 00360 00361 QString KKeySequence::toString() const 00362 { 00363 if( m_nKeys < 1 ) return QString::null; 00364 00365 QString s; 00366 s = m_rgvar[0].toString(); 00367 for( uint i = 1; i < m_nKeys; i++ ) { 00368 s += ","; 00369 s += m_rgvar[i].toString(); 00370 } 00371 00372 return s; 00373 } 00374 00375 QString KKeySequence::toStringInternal() const 00376 { 00377 if( m_nKeys < 1 ) return QString::null; 00378 00379 QString s; 00380 s = m_rgvar[0].toStringInternal(); 00381 for( uint i = 1; i < m_nKeys; i++ ) { 00382 s += ","; 00383 s += m_rgvar[i].toStringInternal(); 00384 } 00385 00386 return s; 00387 } 00388 00389 KKeySequence& KKeySequence::null() 00390 { 00391 if( !g_pseq ) 00392 g_pseq = new KKeySequence; 00393 if( !g_pseq->isNull() ) 00394 g_pseq->clear(); 00395 return *g_pseq; 00396 } 00397 00398 //--------------------------------------------------------------------- 00399 // KShortcut 00400 //--------------------------------------------------------------------- 00401 00402 KShortcut::KShortcut() { clear(); } 00403 KShortcut::KShortcut( int keyQt ) { init( keyQt ); } 00404 KShortcut::KShortcut( const QKeySequence& key ) { init( key ); } 00405 KShortcut::KShortcut( const KKey& key ) { init( key ); } 00406 KShortcut::KShortcut( const KKeySequence& seq ) { init( seq ); } 00407 KShortcut::KShortcut( const KShortcut& cut ) { init( cut ); } 00408 KShortcut::KShortcut( const char* ps ) { init( QString(ps) ); } 00409 KShortcut::KShortcut( const QString& s ) { init( s ); } 00410 00411 KShortcut::~KShortcut() 00412 { 00413 } 00414 00415 void KShortcut::clear() 00416 { 00417 m_nSeqs = 0; 00418 } 00419 00420 bool KShortcut::init( int keyQt ) 00421 { 00422 if( keyQt ) { 00423 m_nSeqs = 1; 00424 m_rgseq[0].init( QKeySequence(keyQt) ); 00425 } else 00426 clear(); 00427 return true; 00428 } 00429 00430 bool KShortcut::init( const QKeySequence& key ) 00431 { 00432 m_nSeqs = 1; 00433 m_rgseq[0].init( key ); 00434 return true; 00435 } 00436 00437 bool KShortcut::init( const KKey& spec ) 00438 { 00439 m_nSeqs = 1; 00440 m_rgseq[0].init( spec ); 00441 return true; 00442 } 00443 00444 bool KShortcut::init( const KKeySequence& seq ) 00445 { 00446 m_nSeqs = 1; 00447 m_rgseq[0] = seq; 00448 return true; 00449 } 00450 00451 bool KShortcut::init( const KShortcut& cut ) 00452 { 00453 m_nSeqs = cut.m_nSeqs; 00454 for( uint i = 0; i < m_nSeqs; i++ ) 00455 m_rgseq[i] = cut.m_rgseq[i]; 00456 return true; 00457 } 00458 00459 bool KShortcut::init( const QString& s ) 00460 { 00461 bool bRet = true; 00462 QStringList rgs = QStringList::split( ';', s ); 00463 00464 if( s == "none" || rgs.size() == 0 ) 00465 clear(); 00466 else if( rgs.size() <= MAX_SEQUENCES ) { 00467 m_nSeqs = rgs.size(); 00468 for( uint i = 0; i < m_nSeqs; i++ ) { 00469 QString& sSeq = rgs[i]; 00470 if( sSeq.startsWith( "default(" ) ) 00471 sSeq = sSeq.mid( 8, sSeq.length() - 9 ); 00472 m_rgseq[i].init( sSeq ); 00473 //kdDebug(125) << "*\t'" << sSeq << "' => " << m_rgseq[i].toStringInternal() << endl; 00474 } 00475 } else { 00476 clear(); 00477 bRet = false; 00478 } 00479 00480 if( !s.isEmpty() ) { 00481 QString sDebug; 00482 QTextStream os( &sDebug, IO_WriteOnly ); 00483 os << "KShortcut::init( \"" << s << "\" ): "; 00484 for( uint i = 0; i < m_nSeqs; i++ ) { 00485 os << " m_rgseq[" << i << "]: "; 00486 KKeyServer::Variations vars; 00487 vars.init( m_rgseq[i].key(0), true ); 00488 for( uint j = 0; j < vars.count(); j++ ) 00489 os << QString::number(vars.m_rgkey[j].keyCodeQt(),16) << ','; 00490 } 00491 kdDebug(125) << sDebug << endl; 00492 } 00493 00494 return bRet; 00495 } 00496 00497 uint KShortcut::count() const 00498 { 00499 return m_nSeqs; 00500 } 00501 00502 const KKeySequence& KShortcut::seq( uint i ) const 00503 { 00504 return (i < m_nSeqs) ? m_rgseq[i] : KKeySequence::null(); 00505 } 00506 00507 int KShortcut::keyCodeQt() const 00508 { 00509 if( m_nSeqs >= 1 ) 00510 return m_rgseq[0].keyCodeQt(); 00511 return QKeySequence(); 00512 } 00513 00514 bool KShortcut::isNull() const 00515 { 00516 return m_nSeqs == 0; 00517 } 00518 00519 int KShortcut::compare( const KShortcut& cut ) const 00520 { 00521 for( uint i = 0; i < m_nSeqs && i < cut.m_nSeqs; i++ ) { 00522 int ret = m_rgseq[i].compare( cut.m_rgseq[i] ); 00523 if( ret != 0 ) 00524 return ret; 00525 } 00526 return m_nSeqs - cut.m_nSeqs; 00527 } 00528 00529 bool KShortcut::contains( const KKey& key ) const 00530 { 00531 return contains( KKeySequence(key) ); 00532 } 00533 00534 bool KShortcut::contains( const KKeyNative& keyNative ) const 00535 { 00536 KKey key = keyNative.key(); 00537 key.simplify(); 00538 00539 for( uint i = 0; i < count(); i++ ) { 00540 if( !m_rgseq[i].isNull() 00541 && m_rgseq[i].count() == 1 00542 && m_rgseq[i].key(0) == key ) 00543 return true; 00544 } 00545 return false; 00546 } 00547 00548 bool KShortcut::contains( const KKeySequence& seq ) const 00549 { 00550 for( uint i = 0; i < count(); i++ ) { 00551 if( !m_rgseq[i].isNull() && m_rgseq[i] == seq ) 00552 return true; 00553 } 00554 return false; 00555 } 00556 00557 bool KShortcut::setSeq( uint iSeq, const KKeySequence& seq ) 00558 { 00559 // TODO: check if seq is null, and act accordingly. 00560 if( iSeq <= m_nSeqs && iSeq < MAX_SEQUENCES ) { 00561 m_rgseq[iSeq] = seq; 00562 if( iSeq == m_nSeqs ) 00563 m_nSeqs++; 00564 return true; 00565 } else 00566 return false; 00567 } 00568 00569 void KShortcut::remove( const KKeySequence& seq ) 00570 { 00571 if (seq.isNull()) return; 00572 00573 for( uint iSeq = 0; iSeq < m_nSeqs; iSeq++ ) 00574 { 00575 if (m_rgseq[iSeq] == seq) 00576 { 00577 for( uint jSeq = iSeq + 1; jSeq < m_nSeqs; jSeq++) 00578 m_rgseq[jSeq-1] = m_rgseq[jSeq]; 00579 m_nSeqs--; 00580 } 00581 } 00582 } 00583 00584 bool KShortcut::append( const KKeySequence& seq ) 00585 { 00586 if( m_nSeqs < MAX_SEQUENCES ) { 00587 if( !seq.isNull() ) { 00588 m_rgseq[m_nSeqs] = seq; 00589 m_nSeqs++; 00590 } 00591 return true; 00592 } else 00593 return false; 00594 } 00595 00596 bool KShortcut::append( const KKey& spec ) 00597 { 00598 if( m_nSeqs < MAX_SEQUENCES ) { 00599 m_rgseq[m_nSeqs].init( spec ); 00600 m_nSeqs++; 00601 return true; 00602 } else 00603 return false; 00604 } 00605 00606 bool KShortcut::append( const KShortcut& cut ) 00607 { 00608 uint seqs = m_nSeqs, co = cut.count(); 00609 for( uint i=0; i<co; i++ ) { 00610 if (!contains(cut.seq(i))) seqs++; 00611 } 00612 if( seqs > MAX_SEQUENCES ) return false; 00613 00614 for( uint i=0; i<co; i++ ) { 00615 const KKeySequence& seq = cut.seq(i); 00616 if(!contains(seq)) { 00617 m_rgseq[m_nSeqs] = seq; 00618 m_nSeqs++; 00619 } 00620 } 00621 return true; 00622 } 00623 00624 KShortcut::operator QKeySequence () const 00625 { 00626 if( count() >= 1 ) 00627 return m_rgseq[0].qt(); 00628 else 00629 return QKeySequence(); 00630 } 00631 00632 QString KShortcut::toString() const 00633 { 00634 QString s; 00635 00636 for( uint i = 0; i < count(); i++ ) { 00637 s += m_rgseq[i].toString(); 00638 if( i < count() - 1 ) 00639 s += ';'; 00640 } 00641 00642 return s; 00643 } 00644 00645 QString KShortcut::toStringInternal( const KShortcut* pcutDefault ) const 00646 { 00647 QString s; 00648 00649 for( uint i = 0; i < count(); i++ ) { 00650 const KKeySequence& seq = m_rgseq[i]; 00651 if( pcutDefault && i < pcutDefault->count() && seq == (*pcutDefault).seq(i) ) { 00652 s += "default("; 00653 s += seq.toStringInternal(); 00654 s += ")"; 00655 } else 00656 s += seq.toStringInternal(); 00657 if( i < count() - 1 ) 00658 s += ';'; 00659 } 00660 00661 return s; 00662 } 00663 00664 KShortcut& KShortcut::null() 00665 { 00666 if( !g_pcut ) 00667 g_pcut = new KShortcut; 00668 if( !g_pcut->isNull() ) 00669 g_pcut->clear(); 00670 return *g_pcut; 00671 }