PageRenderTime 60ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/src/qt/qtbase/src/gui/kernel/qshortcutmap.cpp

https://gitlab.com/x33n/phantomjs
C++ | 707 lines | 465 code | 72 blank | 170 comment | 138 complexity | 711e85fd4803bb725eb8109b7addd3dc MD5 | raw file
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of the QtGui module of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "qshortcutmap_p.h"
  42. #include "private/qobject_p.h"
  43. #include "qkeysequence.h"
  44. #include "qdebug.h"
  45. #include "qevent.h"
  46. #include "qvector.h"
  47. #include "qcoreapplication.h"
  48. #include <private/qkeymapper_p.h>
  49. #include <algorithm>
  50. #ifndef QT_NO_SHORTCUT
  51. QT_BEGIN_NAMESPACE
  52. // To enable verbose output uncomment below
  53. //#define DEBUG_QSHORTCUTMAP
  54. /* \internal
  55. Entry data for QShortcutMap
  56. Contains:
  57. Keysequence for entry
  58. Pointer to parent owning the sequence
  59. */
  60. struct QShortcutEntry
  61. {
  62. QShortcutEntry()
  63. : keyseq(0), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(0), contextMatcher(0)
  64. {}
  65. QShortcutEntry(const QKeySequence &k)
  66. : keyseq(k), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(0), contextMatcher(0)
  67. {}
  68. QShortcutEntry(QObject *o, const QKeySequence &k, Qt::ShortcutContext c, int i, bool a, QShortcutMap::ContextMatcher m)
  69. : keyseq(k), context(c), enabled(true), autorepeat(a), id(i), owner(o), contextMatcher(m)
  70. {}
  71. bool correctContext() const { return contextMatcher(owner, context); }
  72. bool operator<(const QShortcutEntry &f) const
  73. { return keyseq < f.keyseq; }
  74. QKeySequence keyseq;
  75. Qt::ShortcutContext context;
  76. bool enabled : 1;
  77. bool autorepeat : 1;
  78. signed int id;
  79. QObject *owner;
  80. QShortcutMap::ContextMatcher contextMatcher;
  81. };
  82. #if 0 //ndef QT_NO_DEBUG_STREAM
  83. /*! \internal
  84. QDebug operator<< for easy debug output of the shortcut entries.
  85. */
  86. static QDebug &operator<<(QDebug &dbg, const QShortcutEntry *se) {
  87. if (!se)
  88. return dbg << "QShortcutEntry(0x0)";
  89. dbg.nospace()
  90. << "QShortcutEntry(" << se->keyseq
  91. << "), id(" << se->id << "), enabled(" << se->enabled << "), autorepeat(" << se->autorepeat
  92. << "), owner(" << se->owner << ')';
  93. return dbg.space();
  94. }
  95. #endif // QT_NO_DEBUGSTREAM
  96. /* \internal
  97. Private data for QShortcutMap
  98. */
  99. class QShortcutMapPrivate
  100. {
  101. Q_DECLARE_PUBLIC(QShortcutMap)
  102. public:
  103. QShortcutMapPrivate(QShortcutMap* parent)
  104. : q_ptr(parent), currentId(0), ambigCount(0), currentState(QKeySequence::NoMatch)
  105. {
  106. identicals.reserve(10);
  107. currentSequences.reserve(10);
  108. }
  109. QShortcutMap *q_ptr; // Private's parent
  110. QList<QShortcutEntry> sequences; // All sequences!
  111. int currentId; // Global shortcut ID number
  112. int ambigCount; // Index of last enabled ambiguous dispatch
  113. QKeySequence::SequenceMatch currentState;
  114. QVector<QKeySequence> currentSequences; // Sequence for the current state
  115. QVector<QKeySequence> newEntries;
  116. QKeySequence prevSequence; // Sequence for the previous identical match
  117. QVector<const QShortcutEntry*> identicals; // Last identical matches
  118. };
  119. /*! \internal
  120. QShortcutMap constructor.
  121. */
  122. QShortcutMap::QShortcutMap()
  123. : d_ptr(new QShortcutMapPrivate(this))
  124. {
  125. resetState();
  126. }
  127. /*! \internal
  128. QShortcutMap destructor.
  129. */
  130. QShortcutMap::~QShortcutMap()
  131. {
  132. }
  133. /*! \internal
  134. Adds a shortcut to the global map.
  135. Returns the id of the newly added shortcut.
  136. */
  137. int QShortcutMap::addShortcut(QObject *owner, const QKeySequence &key, Qt::ShortcutContext context, ContextMatcher matcher)
  138. {
  139. Q_ASSERT_X(owner, "QShortcutMap::addShortcut", "All shortcuts need an owner");
  140. Q_ASSERT_X(!key.isEmpty(), "QShortcutMap::addShortcut", "Cannot add keyless shortcuts to map");
  141. Q_D(QShortcutMap);
  142. QShortcutEntry newEntry(owner, key, context, --(d->currentId), true, matcher);
  143. QList<QShortcutEntry>::iterator it = std::upper_bound(d->sequences.begin(), d->sequences.end(), newEntry);
  144. d->sequences.insert(it, newEntry); // Insert sorted
  145. #if defined(DEBUG_QSHORTCUTMAP)
  146. qDebug().nospace()
  147. << "QShortcutMap::addShortcut(" << owner << ", "
  148. << key << ", " << context << ") = " << d->currentId;
  149. #endif
  150. return d->currentId;
  151. }
  152. /*! \internal
  153. Removes a shortcut from the global map.
  154. If \a owner is 0, all entries in the map with the key sequence specified
  155. is removed. If \a key is null, all sequences for \a owner is removed from
  156. the map. If \a id is 0, any identical \a key sequences owned by \a owner
  157. are removed.
  158. Returns the number of sequences removed from the map.
  159. */
  160. int QShortcutMap::removeShortcut(int id, QObject *owner, const QKeySequence &key)
  161. {
  162. Q_D(QShortcutMap);
  163. int itemsRemoved = 0;
  164. bool allOwners = (owner == 0);
  165. bool allKeys = key.isEmpty();
  166. bool allIds = id == 0;
  167. // Special case, remove everything
  168. if (allOwners && allKeys && id == 0) {
  169. itemsRemoved = d->sequences.size();
  170. d->sequences.clear();
  171. return itemsRemoved;
  172. }
  173. int i = d->sequences.size()-1;
  174. while (i>=0)
  175. {
  176. const QShortcutEntry &entry = d->sequences.at(i);
  177. int entryId = entry.id;
  178. if ((allOwners || entry.owner == owner)
  179. && (allIds || entry.id == id)
  180. && (allKeys || entry.keyseq == key)) {
  181. d->sequences.removeAt(i);
  182. ++itemsRemoved;
  183. }
  184. if (id == entryId)
  185. return itemsRemoved;
  186. --i;
  187. }
  188. #if defined(DEBUG_QSHORTCUTMAP)
  189. qDebug().nospace()
  190. << "QShortcutMap::removeShortcut(" << id << ", " << owner << ", "
  191. << key << ") = " << itemsRemoved;
  192. #endif
  193. return itemsRemoved;
  194. }
  195. /*! \internal
  196. Changes the enable state of a shortcut to \a enable.
  197. If \a owner is 0, all entries in the map with the key sequence specified
  198. is removed. If \a key is null, all sequences for \a owner is removed from
  199. the map. If \a id is 0, any identical \a key sequences owned by \a owner
  200. are changed.
  201. Returns the number of sequences which are matched in the map.
  202. */
  203. int QShortcutMap::setShortcutEnabled(bool enable, int id, QObject *owner, const QKeySequence &key)
  204. {
  205. Q_D(QShortcutMap);
  206. int itemsChanged = 0;
  207. bool allOwners = (owner == 0);
  208. bool allKeys = key.isEmpty();
  209. bool allIds = id == 0;
  210. int i = d->sequences.size()-1;
  211. while (i>=0)
  212. {
  213. QShortcutEntry entry = d->sequences.at(i);
  214. if ((allOwners || entry.owner == owner)
  215. && (allIds || entry.id == id)
  216. && (allKeys || entry.keyseq == key)) {
  217. d->sequences[i].enabled = enable;
  218. ++itemsChanged;
  219. }
  220. if (id == entry.id)
  221. return itemsChanged;
  222. --i;
  223. }
  224. #if defined(DEBUG_QSHORTCUTMAP)
  225. qDebug().nospace()
  226. << "QShortcutMap::setShortcutEnabled(" << enable << ", " << id << ", "
  227. << owner << ", " << key << ") = " << itemsChanged;
  228. #endif
  229. return itemsChanged;
  230. }
  231. /*! \internal
  232. Changes the auto repeat state of a shortcut to \a enable.
  233. If \a owner is 0, all entries in the map with the key sequence specified
  234. is removed. If \a key is null, all sequences for \a owner is removed from
  235. the map. If \a id is 0, any identical \a key sequences owned by \a owner
  236. are changed.
  237. Returns the number of sequences which are matched in the map.
  238. */
  239. int QShortcutMap::setShortcutAutoRepeat(bool on, int id, QObject *owner, const QKeySequence &key)
  240. {
  241. Q_D(QShortcutMap);
  242. int itemsChanged = 0;
  243. bool allOwners = (owner == 0);
  244. bool allKeys = key.isEmpty();
  245. bool allIds = id == 0;
  246. int i = d->sequences.size()-1;
  247. while (i>=0)
  248. {
  249. QShortcutEntry entry = d->sequences.at(i);
  250. if ((allOwners || entry.owner == owner)
  251. && (allIds || entry.id == id)
  252. && (allKeys || entry.keyseq == key)) {
  253. d->sequences[i].autorepeat = on;
  254. ++itemsChanged;
  255. }
  256. if (id == entry.id)
  257. return itemsChanged;
  258. --i;
  259. }
  260. #if defined(DEBUG_QSHORTCUTMAP)
  261. qDebug().nospace()
  262. << "QShortcutMap::setShortcutAutoRepeat(" << on << ", " << id << ", "
  263. << owner << ", " << key << ") = " << itemsChanged;
  264. #endif
  265. return itemsChanged;
  266. }
  267. /*! \internal
  268. Resets the state of the statemachine to NoMatch
  269. */
  270. void QShortcutMap::resetState()
  271. {
  272. Q_D(QShortcutMap);
  273. d->currentState = QKeySequence::NoMatch;
  274. clearSequence(d->currentSequences);
  275. }
  276. /*! \internal
  277. Returns the current state of the statemachine
  278. */
  279. QKeySequence::SequenceMatch QShortcutMap::state()
  280. {
  281. Q_D(QShortcutMap);
  282. return d->currentState;
  283. }
  284. /*! \internal
  285. Uses ShortcutOverride event to see if any widgets want to override
  286. the event. If not, uses nextState(QKeyEvent) to check for a grabbed
  287. Shortcut, and dispatchEvent() is found and identical.
  288. \sa nextState, dispatchEvent
  289. */
  290. bool QShortcutMap::tryShortcutEvent(QObject *o, QKeyEvent *e)
  291. {
  292. Q_D(QShortcutMap);
  293. if (e->key() == Qt::Key_unknown)
  294. return false;
  295. bool wasAccepted = e->isAccepted();
  296. bool wasSpontaneous = e->spont;
  297. if (d->currentState == QKeySequence::NoMatch) {
  298. ushort orgType = e->t;
  299. e->t = QEvent::ShortcutOverride;
  300. e->ignore();
  301. QCoreApplication::sendEvent(o, e);
  302. e->t = orgType;
  303. e->spont = wasSpontaneous;
  304. if (e->isAccepted()) {
  305. if (!wasAccepted)
  306. e->ignore();
  307. return false;
  308. }
  309. }
  310. QKeySequence::SequenceMatch result = nextState(e);
  311. bool stateWasAccepted = e->isAccepted();
  312. if (wasAccepted)
  313. e->accept();
  314. else
  315. e->ignore();
  316. int identicalMatches = d->identicals.count();
  317. switch(result) {
  318. case QKeySequence::NoMatch:
  319. return stateWasAccepted;
  320. case QKeySequence::ExactMatch:
  321. resetState();
  322. dispatchEvent(e);
  323. default:
  324. break;
  325. }
  326. // If nextState is QKeySequence::ExactMatch && identicals.count == 0
  327. // we've only found disabled shortcuts
  328. return identicalMatches > 0 || result == QKeySequence::PartialMatch;
  329. }
  330. /*! \internal
  331. Returns the next state of the statemachine
  332. If return value is SequenceMatch::ExactMatch, then a call to matches()
  333. will return a QObjects* list of all matching objects for the last matching
  334. sequence.
  335. */
  336. QKeySequence::SequenceMatch QShortcutMap::nextState(QKeyEvent *e)
  337. {
  338. Q_D(QShortcutMap);
  339. // Modifiers can NOT be shortcuts...
  340. if (e->key() >= Qt::Key_Shift &&
  341. e->key() <= Qt::Key_Alt)
  342. return d->currentState;
  343. QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
  344. // We start fresh each time..
  345. d->identicals.resize(0);
  346. result = find(e);
  347. if (result == QKeySequence::NoMatch && (e->modifiers() & Qt::KeypadModifier)) {
  348. // Try to find a match without keypad modifier
  349. QKeyEvent event = *e;
  350. event.setModifiers(e->modifiers() & ~Qt::KeypadModifier);
  351. result = find(&event);
  352. }
  353. if (result == QKeySequence::NoMatch && e->modifiers() & Qt::ShiftModifier) {
  354. // If Shift + Key_Backtab, also try Shift + Qt::Key_Tab
  355. if (e->key() == Qt::Key_Backtab) {
  356. QKeyEvent pe = QKeyEvent(e->type(), Qt::Key_Tab, e->modifiers(), e->text());
  357. result = find(&pe);
  358. }
  359. }
  360. // Should we eat this key press?
  361. if (d->currentState == QKeySequence::PartialMatch
  362. || (d->currentState == QKeySequence::ExactMatch && d->identicals.count()))
  363. e->accept();
  364. // Does the new state require us to clean up?
  365. if (result == QKeySequence::NoMatch)
  366. clearSequence(d->currentSequences);
  367. d->currentState = result;
  368. #if defined(DEBUG_QSHORTCUTMAP)
  369. qDebug().nospace() << "QShortcutMap::nextState(" << e << ") = " << result;
  370. #endif
  371. return result;
  372. }
  373. /*! \internal
  374. Determines if an enabled shortcut has a matcing key sequence.
  375. */
  376. bool QShortcutMap::hasShortcutForKeySequence(const QKeySequence &seq) const
  377. {
  378. Q_D(const QShortcutMap);
  379. QShortcutEntry entry(seq); // needed for searching
  380. QList<QShortcutEntry>::ConstIterator itEnd = d->sequences.constEnd();
  381. QList<QShortcutEntry>::ConstIterator it = std::lower_bound(d->sequences.constBegin(), itEnd, entry);
  382. for (;it != itEnd; ++it) {
  383. if (matches(entry.keyseq, (*it).keyseq) == QKeySequence::ExactMatch && (*it).correctContext() && (*it).enabled) {
  384. return true;
  385. }
  386. }
  387. //end of the loop: we didn't find anything
  388. return false;
  389. }
  390. /*! \internal
  391. Returns the next state of the statemachine, based
  392. on the new key event \a e.
  393. Matches are appended to the vector of identicals,
  394. which can be access through matches().
  395. \sa matches
  396. */
  397. QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e)
  398. {
  399. Q_D(QShortcutMap);
  400. if (!d->sequences.count())
  401. return QKeySequence::NoMatch;
  402. createNewSequences(e, d->newEntries);
  403. #if defined(DEBUG_QSHORTCUTMAP)
  404. qDebug() << "Possible shortcut key sequences:" << d->newEntries;
  405. #endif
  406. // Should never happen
  407. if (d->newEntries == d->currentSequences) {
  408. Q_ASSERT_X(e->key() != Qt::Key_unknown || e->text().length(),
  409. "QShortcutMap::find", "New sequence to find identical to previous");
  410. return QKeySequence::NoMatch;
  411. }
  412. // Looking for new identicals, scrap old
  413. d->identicals.resize(0);
  414. bool partialFound = false;
  415. bool identicalDisabledFound = false;
  416. QVector<QKeySequence> okEntries;
  417. int result = QKeySequence::NoMatch;
  418. for (int i = d->newEntries.count()-1; i >= 0 ; --i) {
  419. QShortcutEntry entry(d->newEntries.at(i)); // needed for searching
  420. QList<QShortcutEntry>::ConstIterator itEnd = d->sequences.constEnd();
  421. QList<QShortcutEntry>::ConstIterator it =
  422. std::lower_bound(d->sequences.constBegin(), itEnd, entry);
  423. int oneKSResult = QKeySequence::NoMatch;
  424. int tempRes = QKeySequence::NoMatch;
  425. do {
  426. if (it == itEnd)
  427. break;
  428. tempRes = matches(entry.keyseq, (*it).keyseq);
  429. oneKSResult = qMax(oneKSResult, tempRes);
  430. if (tempRes != QKeySequence::NoMatch && (*it).correctContext()) {
  431. if (tempRes == QKeySequence::ExactMatch) {
  432. if ((*it).enabled)
  433. d->identicals.append(&*it);
  434. else
  435. identicalDisabledFound = true;
  436. } else if (tempRes == QKeySequence::PartialMatch) {
  437. // We don't need partials, if we have identicals
  438. if (d->identicals.size())
  439. break;
  440. // We only care about enabled partials, so we don't consume
  441. // key events when all partials are disabled!
  442. partialFound |= (*it).enabled;
  443. }
  444. }
  445. ++it;
  446. // If we got a valid match on this run, there might still be more keys to check against,
  447. // so we'll loop once more. If we get NoMatch, there's guaranteed no more possible
  448. // matches in the shortcutmap.
  449. } while (tempRes != QKeySequence::NoMatch);
  450. // If the type of match improves (ergo, NoMatch->Partial, or Partial->Exact), clear the
  451. // previous list. If this match is equal or better than the last match, append to the list
  452. if (oneKSResult > result) {
  453. okEntries.clear();
  454. #if defined(DEBUG_QSHORTCUTMAP)
  455. qDebug() << "Found better match (" << d->newEntries << "), clearing key sequence list";
  456. #endif
  457. }
  458. if (oneKSResult && oneKSResult >= result) {
  459. okEntries << d->newEntries.at(i);
  460. #if defined(DEBUG_QSHORTCUTMAP)
  461. qDebug() << "Added ok key sequence" << d->newEntries;
  462. #endif
  463. }
  464. }
  465. if (d->identicals.size()) {
  466. result = QKeySequence::ExactMatch;
  467. } else if (partialFound) {
  468. result = QKeySequence::PartialMatch;
  469. } else if (identicalDisabledFound) {
  470. result = QKeySequence::ExactMatch;
  471. } else {
  472. clearSequence(d->currentSequences);
  473. result = QKeySequence::NoMatch;
  474. }
  475. if (result != QKeySequence::NoMatch)
  476. d->currentSequences = okEntries;
  477. #if defined(DEBUG_QSHORTCUTMAP)
  478. qDebug() << "Returning shortcut match == " << result;
  479. #endif
  480. return QKeySequence::SequenceMatch(result);
  481. }
  482. /*! \internal
  483. Clears \a seq to an empty QKeySequence.
  484. Same as doing (the slower)
  485. \snippet code/src_gui_kernel_qshortcutmap.cpp 0
  486. */
  487. void QShortcutMap::clearSequence(QVector<QKeySequence> &ksl)
  488. {
  489. ksl.clear();
  490. d_func()->newEntries.clear();
  491. }
  492. /*! \internal
  493. Alters \a seq to the new sequence state, based on the
  494. current sequence state, and the new key event \a e.
  495. */
  496. void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl)
  497. {
  498. Q_D(QShortcutMap);
  499. QList<int> possibleKeys = QKeyMapper::possibleKeys(e);
  500. int pkTotal = possibleKeys.count();
  501. if (!pkTotal)
  502. return;
  503. int ssActual = d->currentSequences.count();
  504. int ssTotal = qMax(1, ssActual);
  505. // Resize to possible permutations of the current sequence(s).
  506. ksl.resize(pkTotal * ssTotal);
  507. int index = ssActual ? d->currentSequences.at(0).count() : 0;
  508. for (int pkNum = 0; pkNum < pkTotal; ++pkNum) {
  509. for (int ssNum = 0; ssNum < ssTotal; ++ssNum) {
  510. int i = (pkNum * ssTotal) + ssNum;
  511. QKeySequence &curKsl = ksl[i];
  512. if (ssActual) {
  513. const QKeySequence &curSeq = d->currentSequences.at(ssNum);
  514. curKsl.setKey(curSeq[0], 0);
  515. curKsl.setKey(curSeq[1], 1);
  516. curKsl.setKey(curSeq[2], 2);
  517. curKsl.setKey(curSeq[3], 3);
  518. } else {
  519. curKsl.setKey(0, 0);
  520. curKsl.setKey(0, 1);
  521. curKsl.setKey(0, 2);
  522. curKsl.setKey(0, 3);
  523. }
  524. curKsl.setKey(possibleKeys.at(pkNum), index);
  525. }
  526. }
  527. }
  528. /*! \internal
  529. Basically the same function as QKeySequence::matches(const QKeySequence &seq) const
  530. only that is specially handles Key_hyphen as Key_Minus, as people mix these up all the time and
  531. they conceptually the same.
  532. */
  533. QKeySequence::SequenceMatch QShortcutMap::matches(const QKeySequence &seq1,
  534. const QKeySequence &seq2) const
  535. {
  536. uint userN = seq1.count(),
  537. seqN = seq2.count();
  538. if (userN > seqN)
  539. return QKeySequence::NoMatch;
  540. // If equal in length, we have a potential ExactMatch sequence,
  541. // else we already know it can only be partial.
  542. QKeySequence::SequenceMatch match = (userN == seqN
  543. ? QKeySequence::ExactMatch
  544. : QKeySequence::PartialMatch);
  545. for (uint i = 0; i < userN; ++i) {
  546. int userKey = seq1[i],
  547. sequenceKey = seq2[i];
  548. if ((userKey & Qt::Key_unknown) == Qt::Key_hyphen)
  549. userKey = (userKey & Qt::KeyboardModifierMask) | Qt::Key_Minus;
  550. if ((sequenceKey & Qt::Key_unknown) == Qt::Key_hyphen)
  551. sequenceKey = (sequenceKey & Qt::KeyboardModifierMask) | Qt::Key_Minus;
  552. if (userKey != sequenceKey)
  553. return QKeySequence::NoMatch;
  554. }
  555. return match;
  556. }
  557. /*! \internal
  558. Converts keyboard button states into modifier states
  559. */
  560. int QShortcutMap::translateModifiers(Qt::KeyboardModifiers modifiers)
  561. {
  562. int result = 0;
  563. if (modifiers & Qt::ShiftModifier)
  564. result |= Qt::SHIFT;
  565. if (modifiers & Qt::ControlModifier)
  566. result |= Qt::CTRL;
  567. if (modifiers & Qt::MetaModifier)
  568. result |= Qt::META;
  569. if (modifiers & Qt::AltModifier)
  570. result |= Qt::ALT;
  571. return result;
  572. }
  573. /*! \internal
  574. Returns the vector of QShortcutEntry's matching the last Identical state.
  575. */
  576. QVector<const QShortcutEntry*> QShortcutMap::matches() const
  577. {
  578. Q_D(const QShortcutMap);
  579. return d->identicals;
  580. }
  581. /*! \internal
  582. Dispatches QShortcutEvents to widgets who grabbed the matched key sequence.
  583. */
  584. void QShortcutMap::dispatchEvent(QKeyEvent *e)
  585. {
  586. Q_D(QShortcutMap);
  587. if (!d->identicals.size())
  588. return;
  589. const QKeySequence &curKey = d->identicals.at(0)->keyseq;
  590. if (d->prevSequence != curKey) {
  591. d->ambigCount = 0;
  592. d->prevSequence = curKey;
  593. }
  594. // Find next
  595. const QShortcutEntry *current = 0, *next = 0;
  596. int i = 0, enabledShortcuts = 0;
  597. while(i < d->identicals.size()) {
  598. current = d->identicals.at(i);
  599. if (current->enabled || !next){
  600. ++enabledShortcuts;
  601. if (enabledShortcuts > d->ambigCount + 1)
  602. break;
  603. next = current;
  604. }
  605. ++i;
  606. }
  607. d->ambigCount = (d->identicals.size() == i ? 0 : d->ambigCount + 1);
  608. // Don't trigger shortcut if we're autorepeating and the shortcut is
  609. // grabbed with not accepting autorepeats.
  610. if (!next || (e->isAutoRepeat() && !next->autorepeat))
  611. return;
  612. // Dispatch next enabled
  613. #if defined(DEBUG_QSHORTCUTMAP)
  614. qDebug().nospace()
  615. << "QShortcutMap::dispatchEvent(): Sending QShortcutEvent(\""
  616. << next->keyseq.toString() << "\", " << next->id << ", "
  617. << (bool)(enabledShortcuts>1) << ") to object(" << next->owner << ')';
  618. #endif
  619. QShortcutEvent se(next->keyseq, next->id, enabledShortcuts>1);
  620. QCoreApplication::sendEvent(const_cast<QObject *>(next->owner), &se);
  621. }
  622. /* \internal
  623. QShortcutMap dump function, only available when DEBUG_QSHORTCUTMAP is
  624. defined.
  625. */
  626. #if defined(Dump_QShortcutMap)
  627. void QShortcutMap::dumpMap() const
  628. {
  629. Q_D(const QShortcutMap);
  630. for (int i = 0; i < d->sequences.size(); ++i)
  631. qDebug().nospace() << &(d->sequences.at(i));
  632. }
  633. #endif
  634. QT_END_NAMESPACE
  635. #endif // QT_NO_SHORTCUT