local ffi = require "ffi" local encoding = require "accessibility.vendor.love2talk.encoding" ffi.cdef[[ void Tolk_Load(); void Tolk_Output(const char *s, bool interrupt); void Tolk_Silence(); void Tolk_Speak(const char *s, bool interrupt); void Tolk_Braille(const char *s, bool interrupt); void Tolk_TrySAPI(bool try); void Tolk_PreferSAPI(bool prefer); const wchar_t * Tolk_DetectScreenReader(); bool Tolk_HasSpeech(); bool Tolk_HasBraille(); bool Tolk_IsSpeaking();]] -- LOCAL MODIFICATION: load Tolk from the mod's own lib/ directory. -- -- ffi.load() goes through the Windows loader, which does not know about LOVE's -- virtual filesystem. Upstream relies on Tolk.dll sitting next to love.exe, which -- needs admin rights to arrange. Instead we resolve the real OS path via -- love.filesystem.getSource() and load by absolute path. -- -- Tolk.dll in turn loads the screen-reader clients (nvdaControllerClient64.dll, -- SAAPI64.dll) itself, and those go through the normal search order — so we must -- also add our directory to the DLL search path via SetDllDirectory, or Tolk would -- load but find no screen reader and silently fall back to SAPI. local function loadTolk() local ok, source = pcall(function() return love.filesystem.getSource() end) if ok and source then local libDir = source .. "\\accessibility\\lib" pcall(function() ffi.cdef [[ int SetDllDirectoryA(const char *lpPathName); ]] ffi.C.SetDllDirectoryA(libDir) end) local loaded, handle = pcall(ffi.load, libDir .. "\\Tolk.dll") if loaded then return handle end end -- Fall back to the normal search order: next to love.exe, or on PATH. return ffi.load("Tolk") end local tolk = loadTolk() tolk.Tolk_Load() local function output(s, interrupt) interrupt=interrupt or false tolk.Tolk_Output(encoding.to_utf16(s), interrupt) end local function speak(s, interrupt) interrupt=interrupt or false tolk.Tolk_Speak(encoding.to_utf16(s), interrupt) end local function braille(s) tolk.Tolk_Braille(encoding.to_utf16(s)) end local function silence() tolk.Tolk_Silence() end local function trySAPI(try) tolk.Tolk_TrySAPI(try) end local function preferSAPI(prefer) tolk.Tolk_PreferSAPI(prefer) end local function isSpeaking() return tolk.Tolk_IsSpeaking() end local function detectScreenReader() --todo, need to convert the returned value to something Lua likes end local function hasSpeech() return tolk.Tolk_HasSpeech() end local function hasBraille() return tolk.Tolk_HasBraille() end return { output=output, speak=speak, braille=braille, silence=silence, isSpeaking=isSpeaking, trySAPI=trySAPI, preferSAPI=preferSAPI, detectScreenReader=detectScreenReader, hasSpeech=hasSpeech, hasBraille=hasBraille}