From 83e8c2ecdeba601dc057db6587c6ca5bde79d31b Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Sat, 3 Nov 2018 23:26:27 -0400 Subject: [PATCH 1/6] reorganize --- extensions/CMakeLists.txt | 10 +++--- .../{ => bingtranslate}/bingtranslate.cpp | 31 ++++++++++++++----- .../{ => copyclipboard}/copyclipboard.cpp | 4 +-- .../{ => extranewlines}/extranewlines.cpp | 2 +- .../{ => removerepeat}/removerepeat.cpp | 2 +- 5 files changed, 32 insertions(+), 17 deletions(-) rename extensions/{ => bingtranslate}/bingtranslate.cpp (79%) rename extensions/{ => copyclipboard}/copyclipboard.cpp (79%) rename extensions/{ => extranewlines}/extranewlines.cpp (86%) rename extensions/{ => removerepeat}/removerepeat.cpp (98%) diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt index 08e4295..b9aed40 100644 --- a/extensions/CMakeLists.txt +++ b/extensions/CMakeLists.txt @@ -4,9 +4,9 @@ find_qt5(Core Widgets) cmake_policy(SET CMP0037 OLD) -add_library(Remove\ Repetition SHARED removerepeat.cpp extensionimpl.cpp) -add_library(Copy\ to\ Clipboard SHARED copyclipboard.cpp extensionimpl.cpp) -add_library(Bing\ Translate SHARED bingtranslate.cpp extensionimpl.cpp) -add_library(Extra\ Newlines SHARED extranewlines.cpp extensionimpl.cpp) +add_library(Bing\ Translate SHARED bingtranslate/bingtranslate.cpp extensionimpl.cpp) +add_library(Copy\ to\ Clipboard SHARED copyclipboard/copyclipboard.cpp extensionimpl.cpp) +add_library(Extra\ Newlines SHARED extranewlines/extranewlines.cpp extensionimpl.cpp) +add_library(Remove\ Repetition SHARED removerepeat/removerepeat.cpp extensionimpl.cpp) -target_link_libraries(Bing\ Translate winhttp.lib Qt5::Widgets) +target_link_libraries(Bing\ Translate winhttp Qt5::Widgets) diff --git a/extensions/bingtranslate.cpp b/extensions/bingtranslate/bingtranslate.cpp similarity index 79% rename from extensions/bingtranslate.cpp rename to extensions/bingtranslate/bingtranslate.cpp index 3a10fe3..a1580c1 100644 --- a/extensions/bingtranslate.cpp +++ b/extensions/bingtranslate/bingtranslate.cpp @@ -1,5 +1,8 @@ -#include "extension.h" +#include "../extension.h" #include +#include +#include +#include #include #include #include @@ -81,13 +84,13 @@ std::wstring Translate(std::wstring text, std::wstring& translateFrom, std::wstr static HINTERNET internet = NULL; if (!internet) internet = WinHttpOpen(L"Mozilla/5.0 Textractor", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, 0); - char buffer[10000] = {}; - WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, buffer, 10000, NULL, NULL); + char utf8[10000] = {}; + WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, utf8, 10000, NULL, NULL); text.clear(); - for (int i = 0; buffer[i];) + for (int i = 0; utf8[i];) { wchar_t utf8char[3] = {}; - swprintf_s<3>(utf8char, L"%02X", (int)(unsigned char)buffer[i++]); + swprintf_s<3>(utf8char, L"%02X", (unsigned)utf8[i++]); text += L"%" + std::wstring(utf8char); } @@ -123,10 +126,22 @@ std::wstring Translate(std::wstring text, std::wstring& translateFrom, std::wstr bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo) { - if (sentenceInfo["hook address"] == -1 || sentenceInfo["current select"] != 1) return false; + if (sentenceInfo["hook address"] == -1) return false; - std::wstring translation; - std::wstring translateFrom; + { + static std::mutex m; + static std::vector requestTimes; + std::lock_guard l(m); + requestTimes.push_back(GetTickCount()); + requestTimes.erase(std::remove_if(requestTimes.begin(), requestTimes.end(), [&](DWORD requestTime) { return GetTickCount() - requestTime > 60 * 1000; }), requestTimes.end()); + if (!sentenceInfo["current select"] && requestTimes.size() > 30) + { + sentence += L"\r\nToo many translation requests: refuse to make more."; + return true; + } + } + + std::wstring translation, translateFrom; Translate(sentence, translateFrom, translateTo); translation = Translate(sentence, translateFrom, translateTo); for (auto& c : translation) if (c == L'\\') c = 0x200b; diff --git a/extensions/copyclipboard.cpp b/extensions/copyclipboard/copyclipboard.cpp similarity index 79% rename from extensions/copyclipboard.cpp rename to extensions/copyclipboard/copyclipboard.cpp index 9b344f8..ee421a3 100644 --- a/extensions/copyclipboard.cpp +++ b/extensions/copyclipboard/copyclipboard.cpp @@ -1,8 +1,8 @@ -#include "extension.h" +#include "../extension.h" bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo) { - if (sentenceInfo["current select"] == 1 && sentenceInfo["hook address"] != -1) + if (sentenceInfo["current select"] && sentenceInfo["hook address"] != -1) { HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (sentence.size() + 2) * sizeof(wchar_t)); memcpy(GlobalLock(hMem), sentence.c_str(), (sentence.size() + 2) * sizeof(wchar_t)); diff --git a/extensions/extranewlines.cpp b/extensions/extranewlines/extranewlines.cpp similarity index 86% rename from extensions/extranewlines.cpp rename to extensions/extranewlines/extranewlines.cpp index d0fb344..8e0555d 100644 --- a/extensions/extranewlines.cpp +++ b/extensions/extranewlines/extranewlines.cpp @@ -1,4 +1,4 @@ -#include "extension.h" +#include "../extension.h" bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo) { diff --git a/extensions/removerepeat.cpp b/extensions/removerepeat/removerepeat.cpp similarity index 98% rename from extensions/removerepeat.cpp rename to extensions/removerepeat/removerepeat.cpp index 544649b..0def122 100644 --- a/extensions/removerepeat.cpp +++ b/extensions/removerepeat/removerepeat.cpp @@ -1,4 +1,4 @@ -#include "extension.h" +#include "../extension.h" #include #include From 1ca9b3c8e6e2c64f4c77f7750243d40e728746f2 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Sat, 3 Nov 2018 23:26:53 -0400 Subject: [PATCH 2/6] readd google translate --- deploy.ps1 | 10 +- .../googletranslate/googletranslate.cpp | 204 ++++++++++++++++++ 2 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 extensions/googletranslate/googletranslate.cpp diff --git a/deploy.ps1 b/deploy.ps1 index 63d3bbf..6a1edef 100644 --- a/deploy.ps1 +++ b/deploy.ps1 @@ -7,10 +7,11 @@ Compress-Archive -Force -DestinationPath Textractor -Path @( "Qt5Gui.dll", "Qt5Widgets.dll", "vnrhook.dll", - "Remove Repetition.dll", - "Copy to Clipboard.dll", "Bing Translate.dll", + "Copy to Clipboard.dll", "Extra Newlines.dll", + "Google Translate.dll", + "Remove Repetition.dll", "Extensions.txt" ) @@ -23,9 +24,10 @@ Compress-Archive -Force -DestinationPath Textractor -Path @( "Qt5Gui.dll", "Qt5Widgets.dll", "vnrhook.dll", - "Remove Repetition.dll", - "Copy to Clipboard.dll", "Bing Translate.dll", + "Copy to Clipboard.dll", "Extra Newlines.dll", + "Google Translate.dll", + "Remove Repetition.dll", "Extensions.txt" ) \ No newline at end of file diff --git a/extensions/googletranslate/googletranslate.cpp b/extensions/googletranslate/googletranslate.cpp new file mode 100644 index 0000000..6791697 --- /dev/null +++ b/extensions/googletranslate/googletranslate.cpp @@ -0,0 +1,204 @@ +#include "../extension.h" +#include +#include +#include +#include +#include +#include +#include +#include + +QStringList languages +{ + "English: en", + "Afrikaans: af", + "Arabic: ar", + "Albanian: sq", + "Belarusian: be", + "Bengali: bn", + "Bosnian: bs", + "Bulgarian: bg", + "Catalan: ca", + "Chinese(Simplified): zh-CH", + "Chinese(Traditional): zh-TW", + "Croatian: hr", + "Czech: cs", + "Danish: da", + "Dutch: nl", + "Esperanto: eo", + "Estonian: et", + "Filipino: tl", + "Finnish: fi", + "French: fr", + "Galician: gl", + "German: de", + "Greek: el", + "Hebrew: iw", + "Hindi: hi", + "Hungarian: hu", + "Icelandic: is", + "Indonesian: id", + "Irish: ga", + "Italian: it", + "Japanese: ja", + "Klingon: tlh", + "Korean: ko", + "Latin: la", + "Latvian: lv", + "Lithuanian: lt", + "Macedonian: mk", + "Malay: ms", + "Maltese: mt", + "Norwegian: no", + "Persian: fa", + "Polish: pl", + "Portuguese: pt", + "Romanian: ro", + "Russian: ru", + "Serbian: sr", + "Slovak: sk", + "Slovenian: sl", + "Somali: so", + "Spanish: es", + "Swahili: sw", + "Swedish: sv", + "Thai: th", + "Turkish: tr", + "Ukranian: uk", + "Urdu: ur", + "Vietnamese: vi", + "Welsh: cy", + "Yiddish: yi", + "Zulu: zu" +}; + +std::wstring translateTo; + +BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + { + QTimer::singleShot(0, [] + { + translateTo = QInputDialog::getItem(nullptr, "Select Language", "What language should Google translate to?", languages, 0, false).split(" ")[1].toStdWString(); + }); + } + break; + case DLL_PROCESS_DETACH: + { + } + break; + } + return TRUE; +} + +std::wstring GetTranslationUri(std::wstring text, unsigned TKK) +{ + // If no TKK available, use this uri. Can't use too much or google will detect unauthorized access. + if (!TKK) return L"/translate_a/single?client=gtx&dt=ld&dt=rm&dt=t&tl=" + translateTo + L"&q=" + text; + + // Artikash 8/19/2018: reverse engineered from translate.google.com + char utf8[10000] = {}; + WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, utf8, 10000, NULL, NULL); + + unsigned a = (unsigned)(_time64(NULL) / 3600), b = a; // <- the first part of TKK + for (int i = 0; utf8[i];) + { + a += (unsigned)utf8[i++]; + a += a << 10; + a ^= a >> 6; + } + a += a << 3; + a ^= a >> 11; + a += a << 15; + a ^= TKK; + a %= 1000000; + b ^= a; + + text.clear(); + for (int i = 0; utf8[i];) + { + wchar_t utf8char[3] = {}; + swprintf_s<3>(utf8char, L"%02X", (unsigned)utf8[i++]); + text += L"%" + std::wstring(utf8char); + } + + return L"/translate_a/single?client=t&dt=ld&dt=rm&dt=t&tl=" + translateTo + L"&tk=" + std::to_wstring(a) + L"." + std::to_wstring(b) + L"&q=" + text; +} + +bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo) +{ + static HINTERNET internet = NULL; + if (!internet) internet = WinHttpOpen(L"Mozilla/5.0 Textractor", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, 0); + static unsigned TKK = 0; + + if (sentenceInfo["hook address"] == -1) return false; + + { + static std::mutex m; + static std::vector requestTimes; + std::lock_guard l(m); + requestTimes.push_back(GetTickCount()); + requestTimes.erase(std::remove_if(requestTimes.begin(), requestTimes.end(), [&](DWORD requestTime) { return GetTickCount() - requestTime > 60 * 1000; }), requestTimes.end()); + if (!sentenceInfo["current select"] && requestTimes.size() > 30) + { + sentence += L"\r\nToo many translation requests: refuse to make more."; + return true; + } + } + + std::wstring translation; + if (internet) + { + if (!TKK) + if (HINTERNET connection = WinHttpConnect(internet, L"translate.google.com", INTERNET_DEFAULT_HTTPS_PORT, 0)) + { + if (HINTERNET request = WinHttpOpenRequest(connection, L"GET", L"/", NULL, NULL, NULL, WINHTTP_FLAG_SECURE)) + { + if (WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, NULL)) + { + DWORD bytesRead; + char buffer[100000] = {}; // Google Translate page is ~64kb + WinHttpReceiveResponse(request, NULL); + WinHttpReadData(request, buffer, 100000, &bytesRead); + if (strstr(buffer, "a\\x3d")) TKK = strtoll(strstr(buffer, "a\\x3d") + 5, nullptr, 10) + strtoll(strstr(buffer, "b\\x3d") + 5, nullptr, 10); + else TKK = strtoll(strstr(buffer, "TKK") + 12, nullptr, 10); + } + WinHttpCloseHandle(request); + } + WinHttpCloseHandle(connection); + } + + if (HINTERNET connection = WinHttpConnect(internet, L"translate.google.com", INTERNET_DEFAULT_HTTPS_PORT, 0)) + { + if (HINTERNET request = WinHttpOpenRequest(connection, L"GET", GetTranslationUri(sentence, TKK).c_str(), NULL, NULL, NULL, WINHTTP_FLAG_ESCAPE_DISABLE | WINHTTP_FLAG_SECURE)) + { + if (WinHttpSendRequest(request, NULL, 0, NULL, 0, 0, NULL)) + { + DWORD bytesRead; + char buffer[10000] = {}; + WinHttpReceiveResponse(request, NULL); + WinHttpReadData(request, buffer, 10000, &bytesRead); + // Response formatted as JSON: starts with '[[["' + if (buffer[0] == '[') + { + wchar_t wbuffer[10000] = {}; + MultiByteToWideChar(CP_UTF8, 0, buffer, -1, wbuffer, 10000); + std::wstring response(wbuffer); + for (std::wsmatch results; std::regex_search(response, results, std::wregex(L"\\[\"(.*?)\",[n\"]")); response = results.suffix().str()) + translation += std::wstring(results[1]) + L" "; + for (auto& c : translation) if (c == L'\\') c = 0x200b; + } + } + WinHttpCloseHandle(request); + } + WinHttpCloseHandle(connection); + } + } + + if (translation == L"") translation = L"Error while translating."; + sentence += L"\r\n" + translation; + return true; +} \ No newline at end of file From 66d02a7bf07e303c15d30298409c13367fc3d9de Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Sat, 3 Nov 2018 23:58:52 -0400 Subject: [PATCH 3/6] add regex filter --- deploy.ps1 | 2 ++ extensions/CMakeLists.txt | 4 ++++ extensions/regexfilter/regexfilter.cpp | 31 ++++++++++++++++++++++++++ extensions/regexfilter/window.cpp | 21 +++++++++++++++++ extensions/regexfilter/window.h | 30 +++++++++++++++++++++++++ extensions/regexfilter/window.ui | 26 +++++++++++++++++++++ 6 files changed, 114 insertions(+) create mode 100644 extensions/regexfilter/regexfilter.cpp create mode 100644 extensions/regexfilter/window.cpp create mode 100644 extensions/regexfilter/window.h create mode 100644 extensions/regexfilter/window.ui diff --git a/deploy.ps1 b/deploy.ps1 index 6a1edef..f7b662a 100644 --- a/deploy.ps1 +++ b/deploy.ps1 @@ -11,6 +11,7 @@ Compress-Archive -Force -DestinationPath Textractor -Path @( "Copy to Clipboard.dll", "Extra Newlines.dll", "Google Translate.dll", + "Regex Filter.dll", "Remove Repetition.dll", "Extensions.txt" ) @@ -28,6 +29,7 @@ Compress-Archive -Force -DestinationPath Textractor -Path @( "Copy to Clipboard.dll", "Extra Newlines.dll", "Google Translate.dll", + "Regex Filter.dll", "Remove Repetition.dll", "Extensions.txt" ) \ No newline at end of file diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt index b9aed40..8a301dc 100644 --- a/extensions/CMakeLists.txt +++ b/extensions/CMakeLists.txt @@ -7,6 +7,10 @@ cmake_policy(SET CMP0037 OLD) add_library(Bing\ Translate SHARED bingtranslate/bingtranslate.cpp extensionimpl.cpp) add_library(Copy\ to\ Clipboard SHARED copyclipboard/copyclipboard.cpp extensionimpl.cpp) add_library(Extra\ Newlines SHARED extranewlines/extranewlines.cpp extensionimpl.cpp) +add_library(Google\ Translate SHARED googletranslate/googletranslate.cpp extensionimpl.cpp) +add_library(Regex\ Filter SHARED regexfilter/regexfilter.cpp regexfilter/window.cpp extensionimpl.cpp) add_library(Remove\ Repetition SHARED removerepeat/removerepeat.cpp extensionimpl.cpp) target_link_libraries(Bing\ Translate winhttp Qt5::Widgets) +target_link_libraries(Google\ Translate winhttp Qt5::Widgets) +target_link_libraries(Regex\ Filter Qt5::Widgets) diff --git a/extensions/regexfilter/regexfilter.cpp b/extensions/regexfilter/regexfilter.cpp new file mode 100644 index 0000000..ac79e03 --- /dev/null +++ b/extensions/regexfilter/regexfilter.cpp @@ -0,0 +1,31 @@ +#include "../extension.h" +#include "window.h" +#include + +Window* w = nullptr; + +BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + { + QTimer::singleShot(0, [] { (w = new Window)->show(); }); + } + break; + case DLL_PROCESS_DETACH: + { + delete w; + } + break; + } + return TRUE; +} + +bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo) +{ + if (w == nullptr) return false; + std::lock_guard l(w->locker); + sentence = std::regex_replace(sentence, w->regex, L""); + return true; +} \ No newline at end of file diff --git a/extensions/regexfilter/window.cpp b/extensions/regexfilter/window.cpp new file mode 100644 index 0000000..105dc02 --- /dev/null +++ b/extensions/regexfilter/window.cpp @@ -0,0 +1,21 @@ +#include "window.h" +#include "ui_window.h" + +Window::Window(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::Window) +{ + ui->setupUi(this); +} + +Window::~Window() +{ + delete ui; +} + +void Window::on_regexInput_textEdited(const QString& newRegex) +{ + std::lock_guard lock(locker); + try { regex = newRegex.toStdWString(); } + catch (...) {} +} diff --git a/extensions/regexfilter/window.h b/extensions/regexfilter/window.h new file mode 100644 index 0000000..274bb1e --- /dev/null +++ b/extensions/regexfilter/window.h @@ -0,0 +1,30 @@ +#ifndef WINDOW_H +#define WINDOW_H + +#include +#include +#include +#include + +namespace Ui +{ + class Window; +} + +class Window : public QMainWindow +{ + Q_OBJECT + +public: + explicit Window(QWidget *parent = nullptr); + ~Window(); + + Ui::Window* ui; + std::mutex locker; + std::wregex regex; + +private slots: + void on_regexInput_textEdited(const QString& regex); +}; + +#endif // WINDOW_H diff --git a/extensions/regexfilter/window.ui b/extensions/regexfilter/window.ui new file mode 100644 index 0000000..c52e297 --- /dev/null +++ b/extensions/regexfilter/window.ui @@ -0,0 +1,26 @@ + + + Window + + + + 0 + 0 + 350 + 80 + + + + Regex Filter + + + + + + + + + + + + From 1d90787564299bfb419f73a4129c0af51ee4cf18 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Sun, 4 Nov 2018 01:15:34 -0400 Subject: [PATCH 4/6] casting does not work like i thought it did --- extensions/bingtranslate/bingtranslate.cpp | 2 +- extensions/googletranslate/googletranslate.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/bingtranslate/bingtranslate.cpp b/extensions/bingtranslate/bingtranslate.cpp index a1580c1..6135444 100644 --- a/extensions/bingtranslate/bingtranslate.cpp +++ b/extensions/bingtranslate/bingtranslate.cpp @@ -90,7 +90,7 @@ std::wstring Translate(std::wstring text, std::wstring& translateFrom, std::wstr for (int i = 0; utf8[i];) { wchar_t utf8char[3] = {}; - swprintf_s<3>(utf8char, L"%02X", (unsigned)utf8[i++]); + swprintf_s<3>(utf8char, L"%02X", (int)(unsigned char)utf8[i++]); text += L"%" + std::wstring(utf8char); } diff --git a/extensions/googletranslate/googletranslate.cpp b/extensions/googletranslate/googletranslate.cpp index 6791697..4ac05e5 100644 --- a/extensions/googletranslate/googletranslate.cpp +++ b/extensions/googletranslate/googletranslate.cpp @@ -106,7 +106,7 @@ std::wstring GetTranslationUri(std::wstring text, unsigned TKK) unsigned a = (unsigned)(_time64(NULL) / 3600), b = a; // <- the first part of TKK for (int i = 0; utf8[i];) { - a += (unsigned)utf8[i++]; + a += (unsigned char)utf8[i++]; a += a << 10; a ^= a >> 6; } @@ -121,7 +121,7 @@ std::wstring GetTranslationUri(std::wstring text, unsigned TKK) for (int i = 0; utf8[i];) { wchar_t utf8char[3] = {}; - swprintf_s<3>(utf8char, L"%02X", (unsigned)utf8[i++]); + swprintf_s<3>(utf8char, L"%02X", (int)(unsigned char)utf8[i++]); text += L"%" + std::wstring(utf8char); } From d88900aa4602008f035d2027c2b84c03103bf4f3 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Sun, 4 Nov 2018 01:20:38 -0400 Subject: [PATCH 5/6] make dialog smaller --- extensions/regexfilter/window.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/regexfilter/window.ui b/extensions/regexfilter/window.ui index c52e297..14766ee 100644 --- a/extensions/regexfilter/window.ui +++ b/extensions/regexfilter/window.ui @@ -7,7 +7,7 @@ 0 0 350 - 80 + 50 From 49dc067492566bf018b6bea0f030eab823f7cecf Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Sun, 4 Nov 2018 01:41:39 -0400 Subject: [PATCH 6/6] update readme for new project architecture --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 137c2b9..549e966 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,13 @@ ## Overview -**Textractor** (a.k.a. NextHooker) is an open-source 32 bit* text hooker for Windows/Wine based off of [ITHVNR](http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine). +**Textractor** (a.k.a. NextHooker) is an open-source x86/x64 text hooker for Windows/Wine based off of [ITHVNR](http://www.hongfire.com/forum/showthread.php/438331-ITHVNR-ITH-with-the-VNR-engine). ![How it looks](https://media.discordapp.net/attachments/330538905072041994/486629608456847360/unknown.png?width=1083&height=353) -*Compatible with 64 bit operating systems. 64 bit version with very limited functionality available on request. - ## Downloads -Releases of Textractor can be found [here](https://github.com/Artikash/Textractor/releases).
-Additional extensions for Textractor can be found [here](https://github.com/Artikash/Extensions/releases). +Releases of Textractor can be found [here](https://github.com/Artikash/Textractor/releases). Previous releases of ITHVNR can be found [here](https://github.com/mireado/ITHVNR/releases). @@ -27,7 +24,7 @@ Previous releases of ITHVNR can be found [here](https://github.com/mireado/ITHVN ## Extensions See my [Example Extension project](https://github.com/Artikash/ExampleExtension) to see how to build an extension.
-See the extensions folder and my [Extensions project](https://github.com/Artikash/Extensions) for examples of what extensions can do. +See the extensions folder for examples of what extensions can do. ## Contributing @@ -45,7 +42,8 @@ The host (see GUI/host folder) injects vnrhook.dll (created from the vnrhook fol Host writes to hostPipe, vnrhook writes to hookPipe.
vnrhook waits for the pipe to be connected, then injects a few instructions into any text outputting functions (e.g. TextOut, GetGlyphOutline) that cause their input to be sent through the pipe.
Additional information about hooks is shared through a file view (a.k.a. section object) that is mapped to a reference to the TextHook class.
-The text that the host receives through the pipe is then processed a little before being dispatched back to the GUI and displayed. +The text that the host receives through the pipe is then processed a little before being dispatched back to the GUI.
+Finally, the GUI dispatches the text to extensions before displaying it. ## Developers