Ticket #9613: multikeybindings_v9.patch
File multikeybindings_v9.patch, 27.6 KB (added by , 13 years ago) |
---|
-
mythtv/libs/libmythtv/dbcheck.cpp
diff --git a/mythtv/libs/libmythtv/dbcheck.cpp b/mythtv/libs/libmythtv/dbcheck.cpp index ace4f6c..4ac238d 100644
a b tmp.constData(), 6225 6225 " description varchar(255) default NULL," 6226 6226 " keylist varchar(128) default NULL," 6227 6227 " hostname varchar(64) NOT NULL default ''," 6228 " multikey varchar(128) default NULL," 6228 6229 " PRIMARY KEY (destination,hostname)" 6229 6230 ");", 6230 6231 "CREATE TABLE keybindings (" … … tmp.constData(), 6233 6234 " description varchar(255) default NULL," 6234 6235 " keylist varchar(128) default NULL," 6235 6236 " hostname varchar(64) NOT NULL default ''," 6237 " multikey varchar(128) default NULL," 6236 6238 " PRIMARY KEY (`context`,`action`,hostname)" 6237 6239 ");", 6238 6240 "CREATE TABLE keyword (" -
mythtv/libs/libmythtv/tv_play.cpp
diff --git a/mythtv/libs/libmythtv/tv_play.cpp b/mythtv/libs/libmythtv/tv_play.cpp index 9f8cfde..43c1f72 100644
a b TV::TV(void) 892 892 endOfPlaybackTimerId(0), embedCheckTimerId(0), 893 893 endOfRecPromptTimerId(0), videoExitDialogTimerId(0), 894 894 pseudoChangeChanTimerId(0), speedChangeTimerId(0), 895 errorRecoveryTimerId(0), exitPlayerTimerId(0) 895 errorRecoveryTimerId(0), exitPlayerTimerId(0), 896 multikeyContext(new MultikeyContext()) 896 897 { 897 898 LOG(VB_GENERAL, LOG_INFO, LOC + "Creating TV object"); 898 899 ctorTime.start(); … … TV::~TV(void) 1244 1245 browsehelper = NULL; 1245 1246 } 1246 1247 1248 if (multikeyContext) 1249 { 1250 delete multikeyContext; 1251 multikeyContext = NULL; 1252 } 1253 1247 1254 LOG(VB_PLAYBACK, LOG_INFO, "TV::~TV() -- end"); 1248 1255 } 1249 1256 … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3384 3391 if (ignoreKeys) 3385 3392 { 3386 3393 handled = GetMythMainWindow()->TranslateKeyPress( 3387 "TV Playback", e, actions );3394 "TV Playback", e, actions, true, multikeyContext); 3388 3395 3389 3396 if (handled || actions.isEmpty()) 3397 { 3398 CommitMultikey(actx); 3390 3399 return true; 3400 } 3391 3401 3392 3402 bool esc = has_action("ESCAPE", actions) || 3393 3403 has_action("BACK", actions); … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3395 3405 bool play = has_action(ACTION_PLAY, actions); 3396 3406 3397 3407 if ((!esc || browsehelper->IsBrowsing()) && !pause && !play) 3408 { 3409 CommitMultikey(actx); 3398 3410 return false; 3411 } 3399 3412 } 3400 3413 3401 3414 OSD *osd = GetOSDLock(actx); … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3409 3422 if (editmode && !handled) 3410 3423 { 3411 3424 handled |= GetMythMainWindow()->TranslateKeyPress( 3412 "TV Editing", e, actions );3425 "TV Editing", e, actions, true, multikeyContext); 3413 3426 3414 3427 if (!handled) 3415 3428 { … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3453 3466 } 3454 3467 3455 3468 if (handled) 3469 { 3470 CommitMultikey(actx); 3456 3471 return true; 3472 } 3457 3473 3458 3474 // If text is already queued up, be more lax on what is ok. 3459 3475 // This allows hex teletext entry and minor channel entry. … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3465 3481 if (ok || txt=="_" || txt=="-" || txt=="#" || txt==".") 3466 3482 { 3467 3483 AddKeyToInputQueue(actx, txt.at(0).toLatin1()); 3484 CommitMultikey(actx, false); 3468 3485 return true; 3469 3486 } 3470 3487 } … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3475 3492 { 3476 3493 QStringList tt_actions; 3477 3494 handled = GetMythMainWindow()->TranslateKeyPress( 3478 "Teletext Menu", e, tt_actions );3495 "Teletext Menu", e, tt_actions, true, multikeyContext); 3479 3496 3480 3497 if (!handled && !tt_actions.isEmpty()) 3481 3498 { … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3484 3501 if (actx->player->HandleTeletextAction(tt_actions[i])) 3485 3502 { 3486 3503 actx->UnlockDeletePlayer(__FILE__, __LINE__); 3504 CommitMultikey(actx); 3487 3505 return true; 3488 3506 } 3489 3507 } … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3495 3513 { 3496 3514 QStringList itv_actions; 3497 3515 handled = GetMythMainWindow()->TranslateKeyPress( 3498 "TV Playback", e, itv_actions );3516 "TV Playback", e, itv_actions, true, multikeyContext); 3499 3517 3500 3518 if (!handled && !itv_actions.isEmpty()) 3501 3519 { … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3504 3522 if (actx->player->ITVHandleAction(itv_actions[i])) 3505 3523 { 3506 3524 actx->UnlockDeletePlayer(__FILE__, __LINE__); 3525 CommitMultikey(actx); 3507 3526 return true; 3508 3527 } 3509 3528 } … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3512 3531 actx->UnlockDeletePlayer(__FILE__, __LINE__); 3513 3532 3514 3533 handled = GetMythMainWindow()->TranslateKeyPress( 3515 "TV Playback", e, actions );3534 "TV Playback", e, actions, true, multikeyContext); 3516 3535 3517 3536 if (handled || actions.isEmpty()) 3537 { 3538 CommitMultikey(actx); 3518 3539 return true; 3540 } 3519 3541 3520 3542 handled = false; 3521 3543 … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3542 3564 #endif // DEBUG_ACTIONS 3543 3565 3544 3566 if (handled) 3567 { 3568 CommitMultikey(actx); 3545 3569 return true; 3570 } 3546 3571 3547 3572 if (!handled) 3548 3573 { … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3556 3581 { 3557 3582 AddKeyToInputQueue(actx, '0' + val); 3558 3583 handled = true; 3584 CommitMultikey(actx, false); 3559 3585 } 3560 3586 } 3561 3587 } … … bool TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e) 3563 3589 return true; 3564 3590 } 3565 3591 3592 void TV::CommitMultikey(PlayerContext *ctx, bool updateOSD) 3593 { 3594 MultikeyContext::MultikeyStatus status; 3595 QString prefix; 3596 multikeyContext->Commit(status, prefix); 3597 bool isMultikey = (QKeySequence(prefix).count() > 1); 3598 if (updateOSD) 3599 { 3600 switch (status) 3601 { 3602 case MultikeyContext::kMKnoPrefix: 3603 // clear the OSD text 3604 HideOSDWindow(ctx, "osd_input"); 3605 break; 3606 case MultikeyContext::kMKpartialMatch: 3607 SetOSDText(ctx, "osd_input", "osd_number_entry", 3608 prefix, kOSDTimeout_Med); 3609 break; 3610 case MultikeyContext::kMKfullMatch: 3611 // same as partial match but with short timeout 3612 if (isMultikey) 3613 SetOSDText(ctx, "osd_input", "osd_number_entry", 3614 prefix, kOSDTimeout_Short); 3615 break; 3616 case MultikeyContext::kMKbadMatch: 3617 // same as full match but with error text 3618 SetOSDText(ctx, "osd_input", "osd_number_entry", 3619 prefix + ": " + QObject::tr("Unknown key sequence"), 3620 kOSDTimeout_Short); 3621 break; 3622 } 3623 } 3624 } 3625 3566 3626 bool TV::BrowseHandleAction(PlayerContext *ctx, const QStringList &actions) 3567 3627 { 3568 3628 if (!browsehelper->IsBrowsing()) -
mythtv/libs/libmythtv/tv_play.h
diff --git a/mythtv/libs/libmythtv/tv_play.h b/mythtv/libs/libmythtv/tv_play.h index 1e04ab0..2892ffc 100644
a b using namespace std; 39 39 40 40 class QDateTime; 41 41 class OSD; 42 class MultikeyContext; 42 43 class RemoteEncoder; 43 44 class MythPlayer; 44 45 class DetectLetterbox; … … class MTV_PUBLIC TV : public QObject 355 356 void ClearInputQueues(const PlayerContext*, bool hideosd); 356 357 bool CommitQueuedInput(PlayerContext*); 357 358 bool ProcessSmartChannel(const PlayerContext*, QString&); 359 void CommitMultikey(PlayerContext*, bool updateOSD=true); 358 360 359 361 // query key queues 360 362 bool HasQueuedInput(void) const … … class MTV_PUBLIC TV : public QObject 818 820 TimerContextMap signalMonitorTimerId; 819 821 TimerContextMap tvchainUpdateTimerId; 820 822 823 MultikeyContext *multikeyContext; 824 821 825 public: 822 826 // Constants 823 827 static const int kInitFFRWSpeed; ///< 1x, default to normal speed -
mythtv/libs/libmythui/mythmainwindow.cpp
diff --git a/mythtv/libs/libmythui/mythmainwindow.cpp b/mythtv/libs/libmythui/mythmainwindow.cpp index d1ce2a2..03e39d9 100644
a b using namespace std; 80 80 81 81 #define LOC QString("MythMainWindow: ") 82 82 83 class MultikeyData 84 { 85 public: 86 void AddMultikeyMapping(const QString &multikey, QString action) 87 { 88 QKeySequence seq(multikey); 89 switch (seq.count()) 90 { 91 case 4: 92 ++multikeyPrefixes[QKeySequence(seq[0], seq[1], seq[2])]; 93 // fallthrough 94 case 3: 95 ++multikeyPrefixes[QKeySequence(seq[0], seq[1])]; 96 // fallthrough 97 case 2: 98 ++multikeyPrefixes[QKeySequence(seq[0])]; 99 // fallthrough 100 case 1: 101 multikeyActionMap[seq].append(action); 102 } 103 } 104 105 bool IsMultikeyPrefix(const QString &multikey) 106 { 107 return multikeyPrefixes.count(QKeySequence(multikey)); 108 } 109 110 bool GetMultikeyMapping(const QString &multikey, QStringList &actions) 111 { 112 QKeySequence seq(multikey); 113 if (multikeyActionMap.count(seq) > 0) 114 { 115 actions += multikeyActionMap[seq]; 116 return true; 117 } 118 return false; 119 } 120 121 void clear(void) 122 { 123 multikeyActionMap.clear(); 124 multikeyPrefixes.clear(); 125 } 126 127 private: 128 QMap<QKeySequence, QStringList> multikeyActionMap; 129 QMap<QKeySequence, int> multikeyPrefixes; 130 }; 131 83 132 class KeyContext 84 133 { 85 134 public: 86 135 void AddMapping(int key, QString action) 87 136 { 88 137 actionMap[key].append(action); 138 multiData.AddMultikeyMapping(QKeySequence(key).toString(), action); 89 139 } 90 140 91 141 bool GetMapping(int key, QStringList &actions) … … class KeyContext 99 149 } 100 150 101 151 QMap<int, QStringList> actionMap; 152 MultikeyData multiData; 102 153 }; 103 154 104 155 struct JumpData … … class MythMainWindowPrivate 210 261 QHash<QString, KeyContext *> keyContexts; 211 262 QMap<int, JumpData*> jumpMap; 212 263 QMap<QString, JumpData> destinationMap; 264 MultikeyData jumpMultikeyData; 213 265 QMap<QString, MPData> mediaPluginMap; 214 266 215 267 void (*exitmenucallback)(void); … … class MythMainWindowPrivate 258 310 bool m_pendingUpdate; 259 311 }; 260 312 313 // Returns false if the key couldn't be added (prefix too long). 314 bool MultikeyContext::AddKey(int key) 315 { 316 currentPrefix = oldPrefix; 317 bool result = true; 318 QKeySequence seq(currentPrefix); 319 int k1 = seq[0]; 320 int k2 = seq[1]; 321 int k3 = seq[2]; 322 int k4 = seq[3]; 323 if (k1 == 0) 324 k1 = key; 325 else if (k2 == 0) 326 k2 = key; 327 else if (k3 == 0) 328 k3 = key; 329 else if (k4 == 0) 330 k4 = key; 331 else 332 result = false; 333 if (result) 334 currentPrefix = QKeySequence(k1, k2, k3, k4).toString(); 335 return result; 336 } 337 261 338 // Make keynum in QKeyEvent be equivalent to what's in QKeySequence 262 339 int MythMainWindowPrivate::TranslateKeyNum(QKeyEvent* e) 263 340 { … … void MythMainWindow::ExitToMainMenu(void) 1436 1513 * \param e The keypress event to lookup. 1437 1514 * \param actions The QStringList that will contain the list of actions. 1438 1515 * \param allowJumps if true then jump points are allowed 1516 * \param prefixContext if non-NULL then multi-key bindings are allowed. 1439 1517 * 1440 1518 * \return true if the key event has been handled (the keypress was a jumpoint) 1441 1519 false if the caller should continue to handle keypress 1442 1520 */ 1443 1521 bool MythMainWindow::TranslateKeyPress(const QString &context, 1444 1522 QKeyEvent *e, QStringList &actions, 1445 bool allowJumps) 1523 bool allowJumps, 1524 MultikeyContext *prefixContext) 1446 1525 { 1447 1526 actions.clear(); 1448 1527 … … bool MythMainWindow::TranslateKeyPress(const QString &context, 1474 1553 } 1475 1554 1476 1555 int keynum = d->TranslateKeyNum(e); 1477 1478 QStringList localActions; 1479 if (allowJumps && (d->jumpMap.count(keynum) > 0) && 1480 (!d->jumpMap[keynum]->localAction.isEmpty()) && 1481 (d->keyContexts.value(context)) && 1482 (d->keyContexts.value(context)->GetMapping(keynum, localActions))) 1483 { 1484 if (localActions.contains(d->jumpMap[keynum]->localAction)) 1485 allowJumps = false; 1556 bool checkOnlyJumpPoints = false; 1557 bool wasEmpty = prefixContext ? prefixContext->GetPrefix().isEmpty() : true; 1558 bool noOverflow = prefixContext ? prefixContext->AddKey(keynum) : true; 1559 const QString singleKey = QKeySequence(keynum).toString(); 1560 const QString prefix = prefixContext ? prefixContext->GetPrefix() : singleKey; 1561 MultikeyContext::MultikeyStatus status; 1562 JumpData *singleKeyJump = NULL, *multiKeyJump = NULL; 1563 // There is a potential race condition where an input timeout 1564 // thread resets the context at the same time this code is 1565 // operating on it. 1566 QStringList singleKeyJumpActions, multiKeyJumpActions; 1567 QStringList singleKeyActions, multiKeyActions; 1568 KeyContext *kctx = d->keyContexts.value(context); 1569 KeyContext *gctx = d->keyContexts.value("Global"); 1570 1571 if (allowJumps) 1572 { 1573 // Find single-key jumppoint bindings. This is only used when 1574 // a multi-key sequence (regular or jumppoint) is aborted 1575 // mid-sequence with a single-key jump point. 1576 if (d->jumpMultikeyData.GetMultikeyMapping(singleKey, singleKeyJumpActions)) 1577 singleKeyJump = &d->destinationMap[singleKeyJumpActions[0]]; 1578 // Find multi-key jumppoint bindings. 1579 if (noOverflow && d->jumpMultikeyData.GetMultikeyMapping(prefix, multiKeyJumpActions)) 1580 multiKeyJump = &d->destinationMap[multiKeyJumpActions[0]]; 1581 } 1582 // Find regular bindings (both single- and multi-key) in the given 1583 // and global contexts. 1584 if (kctx) 1585 { 1586 if (noOverflow) 1587 kctx->multiData.GetMultikeyMapping(prefix, multiKeyActions); 1588 kctx->multiData.GetMultikeyMapping(singleKey, singleKeyActions); 1589 } 1590 if (gctx && context != "Global") 1591 { 1592 if (noOverflow) 1593 gctx->multiData.GetMultikeyMapping(prefix, multiKeyActions); 1594 gctx->multiData.GetMultikeyMapping(singleKey, singleKeyActions); 1595 } 1596 1597 // Disable the jump point if there is a corresponding local action 1598 // for the key sequence. 1599 if (multiKeyJump && 1600 !multiKeyJump->localAction.isEmpty() && 1601 multiKeyActions.contains(multiKeyJump->localAction)) 1602 { 1603 multiKeyJump = singleKeyJump = NULL; 1604 } 1605 if (singleKeyJump && 1606 !singleKeyJump->localAction.isEmpty() && 1607 singleKeyActions.contains(singleKeyJump->localAction)) 1608 { 1609 multiKeyJump = singleKeyJump = NULL; 1610 multiKeyActions = singleKeyActions; 1611 } 1612 1613 // Execute the jump point if there is one. 1614 if (multiKeyJump || (singleKeyJump && multiKeyActions.isEmpty())) 1615 { 1616 JumpData *jumpEntry = multiKeyJump ? multiKeyJump : singleKeyJump; 1617 if (!jumpEntry->exittomain && d->exitmenucallback == NULL) 1618 { 1619 if (prefixContext) 1620 prefixContext->SetStatus(MultikeyContext::kMKfullMatch); 1621 void (*callback)(void) = jumpEntry->callback; 1622 callback(); 1623 return true; 1624 } 1625 if (d->exitmenucallback == NULL) 1626 { 1627 if (prefixContext) 1628 prefixContext->SetStatus(MultikeyContext::kMKfullMatch); 1629 d->exitingtomain = true; 1630 d->exitmenucallback = jumpEntry->callback; 1631 QCoreApplication::postEvent( 1632 this, new QEvent(MythEvent::kExitToMainMenuEventType)); 1633 return true; 1634 } 1486 1635 } 1487 1636 1488 if (allowJumps && d->jumpMap.count(keynum) > 0 &&1489 !d->jumpMap[keynum]->exittomain && d->exitmenucallback == NULL)1637 // Handle a regular action if there is one. 1638 if (!multiKeyActions.isEmpty()) 1490 1639 { 1491 void (*callback)(void) = d->jumpMap[keynum]->callback; 1492 callback(); 1493 return true; 1640 if (prefixContext) 1641 prefixContext->SetStatus(MultikeyContext::kMKfullMatch); 1642 actions = multiKeyActions; 1643 return false; 1494 1644 } 1495 1645 1496 if (allowJumps &&1497 d->jumpMap.count(keynum) > 0 && d->exitmenucallback == NULL)1646 // No full match, so handle partial matches and bad matches. 1647 if (noOverflow) 1498 1648 { 1499 d->exitingtomain = true; 1500 d->exitmenucallback = d->jumpMap[keynum]->callback; 1501 QCoreApplication::postEvent( 1502 this, new QEvent(MythEvent::kExitToMainMenuEventType)); 1503 return true; 1649 // Check for a partial match. 1650 if ((kctx && kctx->multiData.IsMultikeyPrefix(prefix)) || 1651 (gctx && context != "Global" && gctx->multiData.IsMultikeyPrefix(prefix)) || 1652 (d->jumpMultikeyData.IsMultikeyPrefix(prefix))) 1653 { 1654 if (prefixContext) 1655 prefixContext->SetStatus(MultikeyContext::kMKpartialMatch); 1656 return false; 1657 } 1504 1658 } 1505 1506 if (d->keyContexts.value(context)) 1507 d->keyContexts.value(context)->GetMapping(keynum, actions); 1508 1509 if (context != "Global") 1510 d->keyContexts.value("Global")->GetMapping(keynum, actions); 1511 1659 if (prefixContext) 1660 prefixContext->SetStatus(wasEmpty ? MultikeyContext::kMKnoPrefix : 1661 MultikeyContext::kMKbadMatch); 1512 1662 return false; 1513 1663 } 1514 1664 … … void MythMainWindow::ClearKeyContext(const QString &context) 1533 1683 { 1534 1684 KeyContext *keycontext = d->keyContexts.value(context); 1535 1685 if (keycontext != NULL) 1686 { 1536 1687 keycontext->actionMap.clear(); 1688 keycontext->multiData.clear(); 1689 } 1537 1690 } 1538 1691 1539 1692 void MythMainWindow::BindKey(const QString &context, const QString &action, 1540 const QString &key )1693 const QString &key, const QString &multikey) 1541 1694 { 1542 1695 QKeySequence keyseq(key); 1543 1696 … … void MythMainWindow::BindKey(const QString &context, const QString &action, 1566 1719 if (action == "ESCAPE" && context == "Global" && i == 0) 1567 1720 d->escapekey = keynum; 1568 1721 } 1722 1723 QStringList multidummyaction(""); 1724 if (d->keyContexts.value(context)->multiData.GetMultikeyMapping(multikey, multidummyaction)) 1725 { 1726 LOG(VB_GENERAL, LOG_INFO, QString("Multikey %1 is bound to multiple actions " 1727 "in context %2.") 1728 .arg(multikey).arg(context)); 1729 } 1730 d->keyContexts.value(context)->multiData.AddMultikeyMapping(multikey, action); 1569 1731 } 1570 1732 1571 1733 void MythMainWindow::RegisterKey(const QString &context, const QString &action, 1572 1734 const QString &description, const QString &key) 1573 1735 { 1574 1736 QString keybind = key; 1737 QString multikeybind = ""; 1575 1738 1576 1739 MSqlQuery query(MSqlQuery::InitCon()); 1577 1740 1578 1741 if (d->m_useDB && query.isConnected()) 1579 1742 { 1580 query.prepare("SELECT keylist, description FROM keybindings WHERE "1743 query.prepare("SELECT keylist, description, multikey FROM keybindings WHERE " 1581 1744 "context = :CONTEXT AND action = :ACTION AND " 1582 1745 "hostname = :HOSTNAME ;"); 1583 1746 query.bindValue(":CONTEXT", context); … … void MythMainWindow::RegisterKey(const QString &context, const QString &action, 1588 1751 { 1589 1752 keybind = query.value(0).toString(); 1590 1753 QString db_description = query.value(1).toString(); 1754 multikeybind = query.value(2).toString(); 1591 1755 1592 1756 // Update keybinding description if changed 1593 1757 if (db_description != description) … … void MythMainWindow::RegisterKey(const QString &context, const QString &action, 1615 1779 else 1616 1780 { 1617 1781 QString inskey = keybind; 1782 QString insmultikey = multikeybind; 1618 1783 1619 1784 query.prepare("INSERT INTO keybindings (context, action, " 1620 "description, keylist, hostname ) VALUES "1785 "description, keylist, hostname, multikey) VALUES " 1621 1786 "( :CONTEXT, :ACTION, :DESCRIPTION, :KEYLIST, " 1622 ":HOSTNAME );");1787 ":HOSTNAME, :MULTIKEY );"); 1623 1788 query.bindValue(":CONTEXT", context); 1624 1789 query.bindValue(":ACTION", action); 1625 1790 query.bindValue(":DESCRIPTION", description); 1626 1791 query.bindValue(":KEYLIST", inskey); 1627 1792 query.bindValue(":HOSTNAME", GetMythDB()->GetHostName()); 1793 query.bindValue(":MULTIKEY", insmultikey); 1628 1794 1629 1795 if (!query.exec() && !(GetMythDB()->SuppressDBMessages())) 1630 1796 { … … void MythMainWindow::RegisterKey(const QString &context, const QString &action, 1633 1799 } 1634 1800 } 1635 1801 1636 BindKey(context, action, keybind );1802 BindKey(context, action, keybind, multikeybind); 1637 1803 } 1638 1804 1639 1805 QString MythMainWindow::GetKey(const QString &context, … … void MythMainWindow::ClearJump(const QString &destination) 1679 1845 } 1680 1846 1681 1847 1682 void MythMainWindow::BindJump(const QString &destination, const QString &key) 1848 void MythMainWindow::BindJump(const QString &destination, const QString &key, 1849 const QString &multikey) 1683 1850 { 1684 1851 /* make sure the jump point exists */ 1685 1852 if (d->destinationMap.find(destination) == d->destinationMap.end()) … … void MythMainWindow::BindJump(const QString &destination, const QString &key) 1704 1871 #endif 1705 1872 1706 1873 d->jumpMap[keynum] = &d->destinationMap[destination]; 1874 d->jumpMultikeyData.AddMultikeyMapping(QKeySequence(keynum).toString(), destination); 1707 1875 } 1708 1876 else 1709 1877 { … … void MythMainWindow::BindJump(const QString &destination, const QString &key) 1716 1884 LOG(VB_GENERAL, LOG_DEBUG, 1717 1885 QString("JumpPoint: %2 exists, no keybinding") .arg(destination)); 1718 1886 #endif 1887 1888 d->jumpMultikeyData.AddMultikeyMapping(multikey, destination); 1719 1889 } 1720 1890 1721 1891 void MythMainWindow::RegisterJump(const QString &destination, … … void MythMainWindow::RegisterJump(const QString &destination, 1724 1894 bool exittomain, QString localAction) 1725 1895 { 1726 1896 QString keybind = key; 1897 QString multikeybind = ""; 1727 1898 1728 1899 MSqlQuery query(MSqlQuery::InitCon()); 1729 1900 if (query.isConnected()) 1730 1901 { 1731 query.prepare("SELECT keylist FROM jumppoints WHERE "1902 query.prepare("SELECT keylist, multikey FROM jumppoints WHERE " 1732 1903 "destination = :DEST and hostname = :HOST ;"); 1733 1904 query.bindValue(":DEST", destination); 1734 1905 query.bindValue(":HOST", GetMythDB()->GetHostName()); … … void MythMainWindow::RegisterJump(const QString &destination, 1736 1907 if (query.exec() && query.next()) 1737 1908 { 1738 1909 keybind = query.value(0).toString(); 1910 multikeybind = query.value(1).toString(); 1739 1911 } 1740 1912 else 1741 1913 { 1742 1914 QString inskey = keybind; 1915 QString insmultikey = multikeybind; 1743 1916 1744 1917 query.prepare("INSERT INTO jumppoints (destination, description, " 1745 "keylist, hostname ) VALUES ( :DEST, :DESC, :KEYLIST, "1746 ":HOST );");1918 "keylist, hostname, multikey) VALUES ( :DEST, :DESC, :KEYLIST, " 1919 ":HOST, :MULTIKEY );"); 1747 1920 query.bindValue(":DEST", destination); 1748 1921 query.bindValue(":DESC", description); 1749 1922 query.bindValue(":KEYLIST", inskey); 1750 1923 query.bindValue(":HOST", GetMythDB()->GetHostName()); 1924 query.bindValue(":MULTIKEY", insmultikey); 1751 1925 1752 1926 if (!query.exec() || !query.isActive()) 1753 1927 { … … void MythMainWindow::RegisterJump(const QString &destination, 1760 1934 { callback, destination, description, exittomain, localAction }; 1761 1935 d->destinationMap[destination] = jd; 1762 1936 1763 BindJump(destination, keybind );1937 BindJump(destination, keybind, multikeybind); 1764 1938 } 1765 1939 1766 1940 void MythMainWindow::ClearAllJumps() -
mythtv/libs/libmythui/mythmainwindow.h
diff --git a/mythtv/libs/libmythui/mythmainwindow.h b/mythtv/libs/libmythui/mythmainwindow.h index 46ea69d..8abd2f2 100644
a b class MythPainterWindowVDPAU; 28 28 class MythPainterWindowD3D9; 29 29 class MythRender; 30 30 31 class MultikeyContext 32 { 33 public: 34 enum MultikeyStatus { 35 kMKnoPrefix, 36 kMKpartialMatch, 37 kMKfullMatch, 38 kMKbadMatch 39 }; 40 MultikeyContext(void) 41 : oldPrefix(""), currentPrefix(""), status(kMKnoPrefix) {} 42 void SetStatus(MultikeyStatus why) { status = why; } 43 const QString &GetPrefix(void) { return currentPrefix; } 44 bool AddKey(int key); 45 void Commit(MultikeyStatus &s, QString &prefix) { 46 prefix = currentPrefix; 47 s = status; 48 if (status != kMKpartialMatch) 49 { 50 currentPrefix = ""; 51 status = kMKnoPrefix; 52 } 53 oldPrefix = currentPrefix; 54 } 55 private: 56 QString oldPrefix; 57 QString currentPrefix; 58 MultikeyStatus status; 59 }; 60 31 61 class MUI_PUBLIC MythMainWindow : public QWidget 32 62 { 33 63 Q_OBJECT … … class MUI_PUBLIC MythMainWindow : public QWidget 49 79 MythScreenStack *GetStackAt(int pos); 50 80 51 81 bool TranslateKeyPress(const QString &context, QKeyEvent *e, 52 QStringList &actions, bool allowJumps = true) 82 QStringList &actions, bool allowJumps = true, 83 MultikeyContext *prefixContext = NULL) 53 84 MUNUSED_RESULT; 54 85 55 86 void ReloadKeys(void); 56 87 void ClearKey(const QString &context, const QString &action); 57 88 void ClearKeyContext(const QString &context); 58 89 void BindKey(const QString &context, const QString &action, 59 const QString &key );90 const QString &key, const QString &multikey); 60 91 void RegisterKey(const QString &context, const QString &action, 61 92 const QString &description, const QString &key); 62 93 QString GetKey(const QString &context, const QString &action) const; 63 94 64 95 void ClearJump(const QString &destination); 65 void BindJump(const QString &destination, const QString &key); 96 void BindJump(const QString &destination, const QString &key, 97 const QString &multikey); 66 98 void RegisterJump(const QString &destination, const QString &description, 67 99 const QString &key, void (*callback)(void), 68 100 bool exittomain = true, QString localAction = ""); -
mythtv/programs/mythfrontend/keybindings.cpp
diff --git a/mythtv/programs/mythfrontend/keybindings.cpp b/mythtv/programs/mythfrontend/keybindings.cpp index e15de26..d099923 100644
a b void KeyBindings::CommitAction(const ActionID &id) 283 283 } 284 284 285 285 GetMythMainWindow()->ClearKey(id.GetContext(), id.GetAction()); 286 GetMythMainWindow()->BindKey(id.GetContext(), id.GetAction(), keys );286 GetMythMainWindow()->BindKey(id.GetContext(), id.GetAction(), keys, ""); 287 287 } 288 288 289 289 /** \fn KeyBindings::CommitJumppoint(const ActionID&) … … void KeyBindings::CommitJumppoint(const ActionID &id) 312 312 } 313 313 314 314 GetMythMainWindow()->ClearJump(id.GetAction()); 315 GetMythMainWindow()->BindJump(id.GetAction(), keys); 315 // XXX- The following line causes the jumppoint editor to erase 316 // from memory (but not from the database) any existing multikey 317 // binding for the jumppoint. Fixing this would require further 318 // digging into action{,set}.{h,cpp}. 319 GetMythMainWindow()->BindJump(id.GetAction(), keys, ""); 316 320 } 317 321 318 322 /** \fn KeyBindings::CommitChanges(void)