Here is a complete addon.
Press M to open and close the map.
While the map is open, press left-shift and left-control to go up and down the quests. It starts at the top, so you will need to use left-control to navigate to the first quest. Press tab to repeat the name and number of the quest.
While at a quest, press left-alt to hear the full description slowly, or right-alt to hear the objectives more quickly.
To be clear, you are not actually changing the game's selected quest when you use this code. It is simply navigating its own table. A more advanced version of this would probably integrate with the quest log to actually choose quests.
Lua Code:
local quests = {}
local questSelected = 1
local function speakText(spokenMessage, speed)
C_VoiceChat.StopSpeakingText()
C_VoiceChat.SpeakText(1, spokenMessage, Enum.VoiceTtsDestination.QueuedLocalPlayback, speed or 5, 100)
end
local function readCurrentTitle()
if quests[questSelected]["isHeader"] then
speakText(questSelected .. " is a header: " .. quests[questSelected]["title"])
else
speakText(questSelected .. " is " .. quests[questSelected]["title"])
end
end
local function readCurrentDescription()
if quests[questSelected]["isHeader"] then
speakText("Sorry, that is a header.")
else
speakText(quests[questSelected]["title"] .. ": " .. quests[questSelected]["description"], 2)
end
end
local function readCurrentObjectives()
if quests[questSelected]["isHeader"] then
speakText("Sorry, that is a header.")
else
speakText(quests[questSelected]["title"] .. ": " .. quests[questSelected]["objectives"], 4)
end
end
local function next()
if questSelected < #quests then
questSelected = questSelected + 1
else
questSelected = 1
end
readCurrentTitle()
end
local function prev()
if questSelected > 1 then
questSelected = questSelected - 1
else
questSelected = #quests
end
readCurrentTitle()
end
local function goto(i)
if not tonumber(i) then
i = 1
elseif i < 1 then
i = 1
elseif i > #quests then
i = #quests
end
questSelected = i
readCurrentTitle()
end
local frame = CreateFrame("Frame", nil, QuestMapFrame)
frame:RegisterEvent("QUEST_LOG_UPDATE")
frame:SetScript("OnEvent", function(__, event)
if event == "QUEST_LOG_UPDATE" and not QuestMapFrame.ignoreQuestLogUpdate and QuestMapFrame:IsShown() then
wipe(quests)
for i=1, C_QuestLog.GetNumQuestLogEntries() do
quests[i] = C_QuestLog.GetInfo(i)
if quests[i]["questID"] > 0 then
quests[i]["description"], quests[i]["objectives"] = GetQuestLogQuestText(i)
end
end
if questSelected > #quests then
questSelected = 1
end
readCurrentTitle()
end
end)
frame:EnableKeyboard(true)
frame:SetPropagateKeyboardInput(true)
frame:SetScript("OnKeyDown", function(__, key)
if key == "LSHIFT" then
prev()
elseif key == "LCTRL" then
next()
elseif key == "LALT" then
readCurrentDescription()
elseif key == "RALT" then
readCurrentObjectives()
elseif key == "TAB" then
readCurrentTitle()
end
end)
Edit: I wrote mine before you edited your post.