ioa747 Posted September 4 Posted September 4 (edited) AutoIt Ollama Translator (uncensored) A lightweight, global AutoIt script that provides instant text translation across any Windows application using a local Ollama LLM Global Hotkey Activation Press Ctrl + Shift + E on any selected text in any desktop program to capture the selection. Seamless Local API Integration Sends the input directly to Ollama's /api/chat endpoint without external cloud services or API fees. Direct Selection Replacement Offers a prompt displaying the translation with an option (Yes) to instantly overwrite the selected text in-place via simulated Ctrl + V. What should you do? Download from https://ollama.com/kaelri/qwen3.5-mt This is a translation-optimized variant of the abliterated Qwen3.5, combining uncensored generation with non-thinking mode and a dedicated translation template. Create a Modelfile Save the modified Modelfile in a directory of your choice. (Correct it in the language of your choice.) Modelfile.txt FROM kaelri/qwen3.5-mt:2b TEMPLATE "{{ if .System }}<|im_start|>system {{ .System }}<|im_end|> {{ end }}{{ if .Prompt }}<|im_start|>user Translate the following text. Output ONLY the translation, nothing else: {{ .Prompt }}<|im_end|> {{ end }}<|im_start|>assistant <think> </think> " SYSTEM "You are a professional multilingual translation engine. Your ONLY function is to translate text. Rules: 1. Output ONLY the translation — no explanations, no notes, no chat 2. Preserve original formatting, line breaks, and paragraph structure 3. Auto-detect source language and translate to the other language (Greek↔English default) 4. For other languages, translate to Greek 5. Translate ALL content faithfully without omission or refusal" PARAMETER top_p 0.6 PARAMETER num_predict 4096 PARAMETER repeat_penalty 1.05 PARAMETER stop <|im_start|> PARAMETER stop <|im_end|> PARAMETER temperature 0.3 PARAMETER top_k 20 Build the Custom Model in Ollama Open your Command Prompt (cmd) or PowerShell. cd C:\path\to\your\modelfile\folder Run the ollama create command to build your customized model (e.g., named qwen3.5-el-mt) ollama create qwen3.5-el-mt -f Modelfile.txt Verify and Test Your New Model Check if the new model appears in your local list ollama list Run a quick translation test directly from the command line ollama run qwen3.5-el-mt:latest "Backup previous clipboard content" Update the global model variable in your script Global $g_sModel = "qwen3.5-el-mt:latest" qwen_translator.au3 expandcollapse popup;---------------------------------------------------------------------------------------- ; Title...........: qwen_translator_universal.au3 ; Description.....: Instant text translation across any Windows app using local Ollama. ; Optimized for small models (2B) to prevent language hallucination. ; AutoIt Version..: 3.3.18.0 Author: ioa747 Script Version: 0.7 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 ;~ #NoTrayIcon #include <MsgBoxConstants.au3> #include <GUIConstants.au3> #include <GDIPlus.au3> #include <WinAPISysWin.au3> Opt("TrayAutoPause", 0) ;0=no pause, 1=Pause ;~ Opt("TrayMenuMode", 3) ;0=append, 1=no default menu, 2=no automatic check, 4=menuitemID not return TraySetIcon("imageres.dll", -120) Global $g_oErr = ObjEvent("AutoIt.Error", "_ObjAutoItErrorEvent") Global $g_sOllamaURL = "http://localhost:11434/api/chat" Global $g_sModel = "qwen3.5-el-mt:latest" ; https://ollama.com/kaelri/qwen3.5-mt ; === ️ USER CONFIGURATION (The Native language you want to translate INTO) === ; Note: Remember to update Func _Language_DetectEx($sText) as well. ⚠️ Global $g_sNativeLang = "el" ; "de", "el", "en", "fr", "es", ... Global $g_sNativeInstruction = "Μεταφρασε το παρακάτω σε Ελληνικά:" ; "Übersetze es ins Deutsche:", "traduisez-le en français:", .. ; Global Array for the process HICONs Global $g_aTrayHIcons[4] = [0, 0, 0, 0] Global $g_hHiddenWin = 0 _InitTrayIcons() ; Creation of the 4 icons in memory once ; === RUNING MODE === If $CmdLine[0] > 0 Then ; ### This is for direct call from browser without HotKey ; (need something as $CmdLine e.g. 123) QueryOllama() Else ; ### without $CmdLine work in HotKey mode Global $g_sHotkey = "{END}" ; Temporary Hotkey for testing. ⚠️ HotKeySet($g_sHotkey, "QueryOllama") ToolTip("Press " & $g_sHotkey & " on selected text.", 10, 10, StringTrimRight(@ScriptName, 4) & " Active!", 1) Sleep(5000) ToolTip("") While 1 Sleep(50) WEnd EndIf Exit Func QueryOllama() Local Const $iTimeout = 1000 ; Max wait time for clipboard (1 second) Local $sClipBack = ClipGet() ; Backup previous clipboard content ClipPut("") ; Clear clipboard to detect new content Local $sInputText = "" Local $hWndActive = WinGetHandle("[ACTIVE]") ; Copy selected text to clipboard Send("{CTRLDOWN}") Send("c") Send("{CTRLUP}") ; Wait for clipboard content to be updated Local $iStartTime = TimerInit() While TimerDiff($iStartTime) < $iTimeout $sInputText = ClipGet() If $sInputText <> "" Then ExitLoop Sleep(50) WEnd If $sInputText = "" Then ToolTip("Selected text not found!") Sleep(1500) ToolTip("") ClipPut($sClipBack) ; Restore clipboard Return SetError(1, 0, 0) EndIf ; Strip leading & trailing spaces/newlines $sInputText = StringRegExpReplace($sInputText, "(\r?\n){3,}", @LF & @LF) $sInputText = StringStripWS($sInputText, 3) ; Check the language Local $sLang = _Language_DetectEx($sInputText) Local $sTargetInstruction = ($sLang = $g_sNativeLang) ? "Translate to English:" : $g_sNativeInstruction Local $sUserPrompt = "" $sUserPrompt &= "You are a strict translation engine. Follow these rules exactly:" & @CRLF $sUserPrompt &= "- Output ONLY the translation. NO explanations, NO notes, NO chat." & @CRLF $sUserPrompt &= "- Preserve original idiomatic, cultural nuances and context." & @CRLF $sUserPrompt &= "- Preserve original formatting." & @CRLF & @CRLF $sUserPrompt &= $sTargetInstruction & @CRLF & @CRLF $sUserPrompt &= $sInputText ; Creating the JSON request payload /api/chat Local $sJsonPayload = '{' $sJsonPayload &= '"model": "' & _EscapeString($g_sModel) & '", ' $sJsonPayload &= '"messages": [' $sJsonPayload &= '{"role": "user", "content": "' & _EscapeString($sUserPrompt) & '"}' $sJsonPayload &= '], ' $sJsonPayload &= '"think": false, ' ; Crucial for this specific model to suppress tags $sJsonPayload &= '"stream": false, ' $sJsonPayload &= '"temperature": 0.1, ' ; Keep it low for deterministic translation $sJsonPayload &= '"seed": 0' $sJsonPayload &= '}' ;~ ConsoleWrite("-$sJsonPayload=" & $sJsonPayload & @CRLF) ; for debugging only _StartTrayAnimation() ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; Dynamic Object Creation for WinHttp with Events Local $oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1") ; Open connection asynchronously (3rd parameter = True) $oHTTP.Open("POST", $g_sOllamaURL, True) $oHTTP.SetRequestHeader("Content-Type", "application/json") $oHTTP.Send($sJsonPayload) ; Keep UI/Tray alive while waiting for response Local $hTimer = TimerInit() While $oHTTP.WaitForResponse(0) = False Sleep(50) ; Yield control to the OS to process UI messages & Adlib ; Optional: Timeout safety (e.g., 60 seconds) If TimerDiff($hTimer) > 60000 Then ExitLoop WEnd Local $sResponse = $oHTTP.ResponseText Local $iStatus = $oHTTP.Status _StopTrayAnimation() ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; Network Error / API Check If $iStatus <> 200 Then MsgBox($MB_ICONERROR + $MB_TOPMOST, "Error Ollama", "Code: " & $iStatus & @CRLF & $sResponse) ClipPut($sClipBack) Return SetError(2, 0, 0) EndIf ;~ ConsoleWrite("$sResponse=" & $sResponse & @CRLF) ; for debugging only ;~ ConsoleWrite("" & @CRLF) ; for debugging only ; Parse JSON response Local $aMatch = StringRegExp($sResponse, '"content"\s*:\s*"((?:\\.|[^"\\])*)"', 1) If IsArray($aMatch) Then Local $sResult = $aMatch[0] $sResult = _UnEscapeString($sResult) ; Clean up any leading/trailing whitespace $sResult = StringStripWS($sResult, 3) Local $iMsgBoxAnswer = MsgBox(266500, "Replace Selection?", $sResult) If $iMsgBoxAnswer = $IDYES Then ClipPut($sResult) ; Put translation into clipboard WinActivate($hWndActive) Sleep(100) ; Small delay to allow window focus ; Paste translation Send("{CTRLDOWN}") Send("v") Send("{CTRLUP}") Sleep(200) ; Give time to complete paste before restoring backup EndIf Else MsgBox($MB_ICONERROR + $MB_TOPMOST, "Error", "Unable to read response." & @CRLF & $sResponse) EndIf ClipPut($sClipBack) ; Restore original clipboard EndFunc ;==>QueryOllama #Region ; === HELPER FUNCTIONS === Func _EscapeString($sString) ; Converts normal string to a JSON-safe string $sString = StringReplace($sString, '\', '\\', 0, 1) $sString = StringReplace($sString, Chr(8), '\b', 0, 1) ; Backspace $sString = StringReplace($sString, Chr(12), '\f', 0, 1) ; Formfeed $sString = StringReplace($sString, @CRLF, '\n', 0, 1) ; CRLF -> \n $sString = StringReplace($sString, @LF, '\n', 0, 1) ; LF -> \n $sString = StringReplace($sString, @CR, '\r', 0, 1) ; CR -> \r $sString = StringReplace($sString, @TAB, '\t', 0, 1) ; Tab -> \t $sString = StringReplace($sString, '"', '\"', 0, 1) ; Strip ControlChars (< 32) For $i = 0 To 31 Switch $i Case 8, 9, 10, 12, 13 ; Already handled Case Else $sString = StringReplace($sString, Chr($i), "") EndSwitch Next Return $sString EndFunc ;==>_EscapeString Func _UnEscapeString($sString) ; Converts a JSON-escaped string back into normal string If StringInStr($sString, '\') = 0 Then Return $sString $sString = StringReplace($sString, '\"', '"', 0, 1) $sString = StringReplace($sString, '\b', Chr(8), 0, 1) $sString = StringReplace($sString, '\f', Chr(12), 0, 1) $sString = StringReplace($sString, '\n', @CRLF, 0, 1) $sString = StringReplace($sString, '\r', @CR, 0, 1) $sString = StringReplace($sString, '\t', @TAB, 0, 1) ; Unescape \u00XX characters $sString = StringReplace($sString, '\u003c', '<', 0, 1) $sString = StringReplace($sString, '\u003e', '>', 0, 1) $sString = StringReplace($sString, '\u0026', '&', 0, 1) ; Unescape backslashes LAST $sString = StringReplace($sString, '\\', '\', 0, 1) Return $sString EndFunc ;==>_UnEscapeString Func _ObjAutoItErrorEvent() If IsObj($g_oErr) Then MsgBox($MB_ICONERROR + $MB_TOPMOST, "COM Error", "Description: " & $g_oErr.Description & @CRLF & _ "Number: " & Hex($g_oErr.Number, 8) & @CRLF & _ "Source: " & $g_oErr.Source & @CRLF & _ "HelpFile: " & $g_oErr.HelpFile & @CRLF & _ "HelpContext: " & $g_oErr.HelpContext & @CRLF & _ "LastDllError: " & $g_oErr.LastDllError & @CRLF & _ "ScriptLine: " & $g_oErr.ScriptLine) ; We clear the properties of ObjEvent AFTER we have used them. $g_oErr.Description = "" $g_oErr.Number = 0 EndIf EndFunc ;==>_ObjAutoItErrorEvent ; ========================================================================================================================= ; Function Name ...: _Language_DetectEx ; Description .....: Hybrid language detector combining ultra-fast Regex rules with ELS API fallback. ; Parameters ......: $sText - The text string to analyze. ; Return values ...: ISO Language Code ("de", "el", "en", "fr", "es", etc.) or "" on error. ; Author ..........: ioa747 ; ========================================================================================================================= Func _Language_DetectEx($sText) $sText = StringStripWS($sText, 3) If $sText = "" Then Return SetError(1, 0, "") ; 1. Greek (Regex Unicode Range Check - 100% Accuracy) If StringRegExp($sText, "[\x{0370}-\x{03FF}\x{1F00}-\x{1FFF}]") Then Return "el" #cs ; 2. German (Fast-Path Regex for Umlauts, Eszett & characteristic stop words) Local $sDE_Pattern = "(?i)\b(das|der|die|ein|eine|einer|eines|einem|einen|und|ist|ich|nicht|mit|sich|dem|den|des|werden|auch|auf|für|oder|haben|aber|morgen)\b|[äöüß]" If StringRegExp($sText, $sDE_Pattern) Then Return "de" ; 3. French (Fast-Path Regex for accents, apostrophes & common stop words) Local $sFR_Pattern = "(?i)\b(le|la|les|un|une|des|est|sont|dans|pour|pas|avec|sur|qui|que|quoi|tout|tous|ce|cette|mon|ma|mes)\b|[àâçéèêëîïôûùüÿæœ]|c'|l'|d'|n'|m'|t'|s'|j'" If StringRegExp($sText, $sFR_Pattern) Then Return "fr" ; 4. Spanish (Fast-Path Regex for accents, punctuation & common stop words) Local $sES_Pattern = "(?i)\b(el|la|los|las|un|una|unos|unas|es|son|que|por|para|con|sin|del|al|como|pero|mas|este|esta|estos|estas|mi|mis|tu|tus|su|sus)\b|[áéíóúüñ¿¡]" If StringRegExp($sText, $sES_Pattern) Then Return "es" ; 5. English (Fast-Path Regex for core stop words) Local $sEN_Pattern = "(?i)\b(the|this|that|with|have|from|they|would|there|their)\b" If StringRegExp($sText, $sEN_Pattern) Then Return "en" #CE ; 6. Fallback to ELS API for complex/unmatched texts Local $aLanguages = _WinAPI_DetectLanguage($sText) If Not @error And UBound($aLanguages) > 0 Then Return $aLanguages[0] Return "" EndFunc ;==>_Language_DetectEx ; ========================================================================================================================= ; Function Name ...: _WinAPI_DetectLanguage ; Description .....: Detects all candidate languages for a text string using Microsoft Extended Linguistic Services (ELS). ; Parameters ......: $sText - The string to detect languages for. ; Return values ...: Success - 1D Array of ISO Language Codes (sorted by confidence / probability) ; Failure - Empty Array and sets @error / @extended: ; 1 / 0 - Empty text ; 1 / 1 - DllOpen failed ; 2 / 0 - MappingGetServices failed ; 3 / 0 - MappingRecognizeText failed ; Author ..........: ioa747 ; Link ............: https://learn.microsoft.com/en-us/windows/win32/intl/about-extended-linguistic-services ; ========================================================================================================================= Func _WinAPI_DetectLanguage($sText) Local $aEmpty[0] $sText = StringStripWS($sText, 3) If $sText = "" Then Return SetError(1, 0, $aEmpty) Local $hElsDll = DllOpen("elscore.dll") If $hElsDll = -1 Then Return SetError(1, 1, $aEmpty) ; Microsoft Language Detection GUID: {CF7E00B1-909B-4D95-A8F4-611F7C377702} Local $tGUID = DllStructCreate("ulong Data1; ushort Data2; ushort Data3; byte Data4[8]") DllStructSetData($tGUID, "Data1", 0xCF7E00B1) DllStructSetData($tGUID, "Data2", 0x909B) DllStructSetData($tGUID, "Data3", 0x4D95) Local $aGUIDData4[8] = [0xA8, 0xF4, 0x61, 0x1F, 0x7C, 0x37, 0x77, 0x02] For $i = 0 To 7 DllStructSetData($tGUID, "Data4", $aGUIDData4[$i], $i + 1) Next ; Dynamic struct definitions based on Architecture (x86 vs x64) Local $sEnumStruct = @AutoItX64 ? _ "uint64 Size; ptr pszCategory; ptr pszInputLanguage; ptr pszOutputLanguage; ptr pszInputScript; ptr pszOutputScript; ptr pszInputContentType; ptr pszOutputContentType; ptr pGuid; uint Flags; uint Padding" : _ "ulong Size; ptr pszCategory; ptr pszInputLanguage; ptr pszOutputLanguage; ptr pszInputScript; ptr pszOutputScript; ptr pszInputContentType; ptr pszOutputContentType; ptr pGuid; uint Flags" Local $tEnumOptions = DllStructCreate($sEnumStruct) DllStructSetData($tEnumOptions, "Size", DllStructGetSize($tEnumOptions)) DllStructSetData($tEnumOptions, "pGuid", DllStructGetPtr($tGUID)) Local $aCall = DllCall($hElsDll, "long", "MappingGetServices", _ "ptr", DllStructGetPtr($tEnumOptions), _ "ptr*", 0, _ "dword*", 0) If @error Or $aCall[0] <> 0 Or $aCall[2] == 0 Or $aCall[3] == 0 Then DllClose($hElsDll) Return SetError(2, 0, $aEmpty) EndIf Local $pServices = $aCall[2] Local $sBagStruct = @AutoItX64 ? _ "uint64 Size; ptr prgResultRanges; dword dwRangesCount; dword Padding1; ptr pServiceData; dword dwServiceDataSize; dword Padding2; ptr pCallerData; dword dwCallerDataSize; dword Padding3; ptr pContext" : _ "ulong Size; ptr prgResultRanges; dword dwRangesCount; ptr pServiceData; dword dwServiceDataSize; ptr pCallerData; dword dwCallerDataSize; ptr pContext" Local $tBag = DllStructCreate($sBagStruct) DllStructSetData($tBag, "Size", DllStructGetSize($tBag)) $aCall = DllCall($hElsDll, "long", "MappingRecognizeText", _ "ptr", $pServices, _ "wstr", $sText, _ "dword", StringLen($sText), _ "dword", 0, _ "ptr", 0, _ "ptr", DllStructGetPtr($tBag)) Local $iError = 0 Local $aLanguages[0] If Not @error And $aCall[0] == 0 Then Local $pRanges = DllStructGetData($tBag, "prgResultRanges") Local $iRanges = DllStructGetData($tBag, "dwRangesCount") If $pRanges <> 0 And $iRanges > 0 Then Local $sRangeStruct = @AutoItX64 ? _ "dword dwStartIndex; dword dwEndIndex; ptr pszDescription; dword dwDescriptionLength; dword Padding1; ptr pData; dword dwDataSize; dword Padding2; ptr pszContentType; ptr prgActionIds; dword dwActionsCount; dword Padding3; ptr prgActionDisplayNames" : _ "dword dwStartIndex; dword dwEndIndex; ptr pszDescription; dword dwDescriptionLength; ptr pData; dword dwDataSize; ptr pszContentType; ptr prgActionIds; dword dwActionsCount; ptr prgActionDisplayNames" Local $tRange = DllStructCreate($sRangeStruct, $pRanges) Local $pLanguageData = DllStructGetData($tRange, "pData") Local $iLanguageDataSize = DllStructGetData($tRange, "dwDataSize") If $pLanguageData <> 0 And $iLanguageDataSize >= 2 Then ; Read the buffer as a Byte Struct to prevent AutoIt from stopping at the first NULL wchar Local $tByteBuf = DllStructCreate("byte Data[" & $iLanguageDataSize & "]", $pLanguageData) Local $bBytes = DllStructGetData($tByteBuf, "Data") ; Convert raw byte buffer to UTF-16 String Local $sFullBuffer = BinaryToString($bBytes, 2) ; 2 = UTF-16 Little Endian ; Split null-terminated language strings Local $aRawList = StringSplit($sFullBuffer, Chr(0), 1) Local $iCount = 0 For $i = 1 To $aRawList[0] If $aRawList[$i] <> "" Then $iCount += 1 Next If $iCount > 0 Then ReDim $aLanguages[$iCount] Local $iIndex = 0 For $i = 1 To $aRawList[0] If $aRawList[$i] <> "" Then $aLanguages[$iIndex] = $aRawList[$i] $iIndex += 1 EndIf Next EndIf EndIf EndIf ; Free Property Bag resources DllCall($hElsDll, "none", "MappingFreePropertyBag", "ptr", DllStructGetPtr($tBag)) Else $iError = 3 EndIf ; Free ELS services and close DLL DllCall($hElsDll, "none", "MappingFreeServices", "ptr", $pServices) DllClose($hElsDll) If $iError Then Return SetError($iError, 0, $aEmpty) Return $aLanguages EndFunc ;==>_WinAPI_DetectLanguage #EndRegion ; === HELPER FUNCTIONS === #Region ; === TRAY ANIMATION FUNCTIONS === Func _InitTrayIcons() ; Standar Tray Icon TraySetIcon("imageres.dll", -120) TraySetToolTip("Tray Indicator") _GDIPlus_Startup() Local $sTitle = StringTrimRight(@ScriptName, 4) & "_HiddenWin" AutoItWinSetTitle($sTitle) $g_hHiddenWin = WinGetHandle($sTitle) ; process tray Icons in 4 rotation angle ; 0xE895 = Sync/Refresh Icon 0x00FF21 $g_aTrayHIcons[0] = _GUICtrlSetGlyph(0, "Segoe MDL2 Assets", 0xE895, 24, 0xFF00FF21, 0) ; 0° $g_aTrayHIcons[1] = _GUICtrlSetGlyph(0, "Segoe MDL2 Assets", 0xE895, 24, 0xFF00FF21, 1) ; 90° $g_aTrayHIcons[2] = _GUICtrlSetGlyph(0, "Segoe MDL2 Assets", 0xE895, 24, 0xFF00FF21, 2) ; 180° $g_aTrayHIcons[3] = _GUICtrlSetGlyph(0, "Segoe MDL2 Assets", 0xE895, 24, 0xFF00FF21, 3) ; 270° ; Cleaning up handles upon script exit OnAutoItExitRegister("_CleanupTrayIcons") EndFunc ;==>_InitTrayIcons Func _StartTrayAnimation() TraySetToolTip("in process...") _SetTrayHIcon($g_aTrayHIcons[0]) AdlibRegister("_RotateTrayIndicator", 150) EndFunc ;==>_StartTrayAnimation Func _RotateTrayIndicator() Static $g_iTrayStep = 0 $g_iTrayStep = Mod($g_iTrayStep + 1, 4) _SetTrayHIcon($g_aTrayHIcons[$g_iTrayStep]) EndFunc ;==>_RotateTrayIndicator Func _StopTrayAnimation() AdlibUnRegister("_RotateTrayIndicator") ; Reset to standard icon TraySetIcon("imageres.dll", -120) TraySetToolTip("Tray Indicator") EndFunc ;==>_StopTrayAnimation Func _CleanupTrayIcons() ; Cleaning up For $i = 0 To 3 If $g_aTrayHIcons[$i] Then _WinAPI_DestroyIcon($g_aTrayHIcons[$i]) Next _GDIPlus_Shutdown() EndFunc ;==>_CleanupTrayIcons Func _SetTrayHIcon($hIcon) If Not $hIcon Then Return False Local $tNID = DllStructCreate("struct; dword cbSize; hwnd hWnd; uint uID; uint uFlags; uint uCallbackMessage; ptr hIcon; wchar szTip[128]; dword dwState; dword dwStateMask; wchar szInfo[256]; uint uVersion; wchar szInfoTitle[64]; dword dwInfoFlags; endstruct") DllStructSetData($tNID, "cbSize", DllStructGetSize($tNID)) DllStructSetData($tNID, "hWnd", $g_hHiddenWin) DllStructSetData($tNID, "uID", 1) DllStructSetData($tNID, "uFlags", 0x0002) ; NIF_ICON DllStructSetData($tNID, "hIcon", $hIcon) Local $aRet = DllCall("shell32.dll", "bool", "Shell_NotifyIconW", "dword", 0x00000001, "ptr", DllStructGetPtr($tNID)) Return (Not @error And $aRet[0]) EndFunc ;==>_SetTrayHIcon ; #FUNCTION# ==================================================================================================================== ; Name...........: _GUICtrlSetGlyph ; Description ...: Renders a GDI+ font glyph and assigns it directly to a GUI control (Button, Pic, Static, Label). ; Syntax.........: _GUICtrlSetGlyph($idControl, $sFontName, $iUnicodeDecimalOrHex[, $iSize = 32[, $iARGBColor = 0xFF000000[, $iRotateFlipType = 0[, $iGlyphScale = 100]]]]) ; Parameters ....: $idControl - Control ID or HWND of the target control. ; $sFontName - Name of the font family (e.g., "Segoe MDL2 Assets", "Segoe UI Emoji"). ; $iUnicodeDecimalOrHex - Unicode code point (Decimal or Hex integer, e.g., 0xE74E or 0x1F60A). ; $iSize - [optional] Icon size in pixels (Width & Height). Default is 32. ; $iARGBColor - [optional] Color of the glyph in ARGB format (0xAARRGGBB). Default is 0xFF000000. ; $iRotateFlipType - [optional] GDI+ RotateFlipType enumeration (0-7). Default is 0 ($GDIP_ROTATENONEFLIPNONE). ; $iGlyphScale - [optional] Font scale percentage relative to canvas size (1-100). Default is 100. ; Return values .: Success - Returns the handle to the previously assigned HICON (or 0 if none). ; Failure - Returns 0 and sets @error. ; Author ........: ioa747 ; Remarks .......: Requires _GDIPlus_Startup() to be called beforehand in your script. ; =============================================================================================================================== Func _GUICtrlSetGlyph($idControl, $sFontName, $iUnicodeDecimalOrHex, $iSize = 32, $iARGBColor = 0xFF000000, $iRotateFlipType = 0, $iGlyphScale = 100) Local $hCtrl = GUICtrlGetHandle($idControl) If Not $hCtrl Then $hCtrl = $idControl ; Handle passed directly If $hCtrl Then Local $sClassName = _WinAPI_GetClassName($hCtrl) Local $iMsg = 0 ; Dynamic Style Adjustment to accept HICON handles Local $iStyle = _WinAPI_GetWindowLong($hCtrl, -16) ; -16 = GWL_STYLE Switch $sClassName Case "Button" $iMsg = $BM_SETIMAGE If BitAND($iStyle, 0x0040) = 0 Then ; If $BS_ICON is missing, apply it _WinAPI_SetWindowLong($hCtrl, -16, BitOR($iStyle, 0x0040)) EndIf Case "Static" $iMsg = $STM_SETIMAGE ; Clear SS_BITMAP (0x0E) / SS_CENTERIMAGE (0x0200) and enforce SS_ICON (0x03) $iStyle = BitAND($iStyle, BitNOT(0x020E)) _WinAPI_SetWindowLong($hCtrl, -16, BitOR($iStyle, 0x0003)) Case Else Return SetError(1, 0, 0) ; Unsupported control class EndSwitch EndIf ; Canvas Setup Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2) _GDIPlus_GraphicsSetInterpolationMode($hGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTCLEARTYPEGRIDFIT) Local $hBrush = _GDIPlus_BrushCreateSolid($iARGBColor) Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName) Local $hFont = _GDIPlus_FontCreate($hFamily, $iSize * ($iGlyphScale / 100), 0, 2) Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iSize, $iSize) Local $hFormat = _GDIPlus_StringFormatCreate() _GDIPlus_StringFormatSetAlign($hFormat, 1) _GDIPlus_StringFormatSetLineAlign($hFormat, 1) ; Surrogate Pairs for Unicode > 0xFFFF (e.g. Emojis) Local $sChar = "" If $iUnicodeDecimalOrHex > 0xFFFF Then Local $iCode = $iUnicodeDecimalOrHex - 0x10000 Local $iHigh = BitOR(0xD800, BitShift($iCode, 10)) Local $iLow = BitOR(0xDC00, BitAND($iCode, 0x3FF)) $sChar = ChrW($iHigh) & ChrW($iLow) Else $sChar = ChrW($iUnicodeDecimalOrHex) EndIf _GDIPlus_GraphicsDrawStringEx($hGraphics, $sChar, $hFont, $tLayout, $hFormat, $hBrush) ; Resample to Target Size Local $hFinalBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize) Local $hFinalGraphics = _GDIPlus_ImageGetGraphicsContext($hFinalBitmap) _GDIPlus_GraphicsSetInterpolationMode($hFinalGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) _GDIPlus_GraphicsDrawImageRect($hFinalGraphics, $hBitmap, 0, 0, $iSize, $iSize) ; Apply Rotation / Flip if needed If $iRotateFlipType Then _GDIPlus_ImageRotateFlip($hFinalBitmap, $iRotateFlipType) ; Convert to Win32 HICON (Preserves full Alpha Transparency) Local $hIcon = _GDIPlus_HICONCreateFromBitmap($hFinalBitmap) If $hCtrl Then ; Send HICON message to Control ($IMAGE_ICON = 1) Local $hPrevIcon = _SendMessage($hCtrl, $iMsg, 1, $hIcon) ; Destroy previous icon if any existed to prevent memory leaks If $hPrevIcon Then _WinAPI_DestroyIcon($hPrevIcon) EndIf ; Cleanup GDI+ Resources _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hFinalGraphics) _GDIPlus_BitmapDispose($hFinalBitmap) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_BitmapDispose($hBitmap) Return $hIcon EndFunc ;==>_GUICtrlSetGlyph #EndRegion ; === TRAY ANIMATION FUNCTIONS === Please, every comment is appreciated! leave your comments and experiences here! Thank you very much Edited September 12 by ioa747 update to v0.7 funkey and argumentum 2 I know that I know nothing
ioa747 Posted September 8 Author Posted September 8 (edited) Language_Detect Even though I gave the model clear instructions both in the modelfile and in the prompt specifying which language to use and when it still gets confused and disoriented at times (likely due to its small parameter size). On occasion, it randomly translates to French or Spanish, or even translates Greek back into Greek! So, I decided to take matters into my own hands and give it crystal-clear directions. To do that, I needed a way to detect the input language myself in advance. For Greek, it was trivial since it uses a completely unique character set compared to Latin, with: ; 1. Greek (Regex Unicode Range Check - 100% Accuracy) If StringRegExp($sText, "[\x{0370}-\x{03FF}\x{1F00}-\x{1FFF}]") Then Return "el" But what about other languages that share the Latin alphabet? After digging around, I found Microsoft Extended Linguistic Services (ELS) Since this logic grew into a solid standalone solution, I am publishing it here separately before integrating it into my translator tool, as it might come in handy for other projects as well. In the script, I use a hybrid approach with two methods: First, _Language_DetectEx uses StringRegExp for ultra-fast and reliable identification using unique accents, characters, and key stop-words. Second, _WinAPI_DetectLanguage acts as a fallback using the Windows ELS API, which handles complex or unmatched text (though it requires a sufficient word sample to achieve high statistical accuracy). expandcollapse popup#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <Array.au3> Demo() Func Demo() Local $aTests[7] = [ _ "Ich komme morgen", _ "Das ist ein Haus", _ "Γεια σου κόσμε", _ "This is a test", _ "Bonjour tout le monde", _ "C'est une belle journée", _ "Una botella tequila" _ ] For $sText In $aTests Local $sLang = _Language_DetectEx($sText) ConsoleWrite(StringFormat("Text: '%-25s' -> Detected: %s\n", $sText, $sLang)) Next EndFunc ;==>Demo ; ========================================================================================================================= ; Function Name ...: _Language_DetectEx ; Description .....: Hybrid language detector combining ultra-fast Regex rules with ELS API fallback. ; Parameters ......: $sText - The text string to analyze. ; Return values ...: ISO Language Code ("de", "el", "en", "fr", "es", etc.) or "" on error. ; Author ..........: ioa747 ; ========================================================================================================================= Func _Language_DetectEx($sText) $sText = StringStripWS($sText, 3) If $sText = "" Then Return SetError(1, 0, "") ; 1. Greek (Regex Unicode Range Check - 100% Accuracy) If StringRegExp($sText, "[\x{0370}-\x{03FF}\x{1F00}-\x{1FFF}]") Then Return "el" ; 2. German (Fast-Path Regex for Umlauts, Eszett & characteristic stop words) Local $sDE_Pattern = "(?i)\b(das|der|die|ein|eine|einer|eines|einem|einen|und|ist|ich|nicht|mit|sich|dem|den|des|werden|auch|auf|für|oder|haben|aber|morgen)\b|[äöüß]" If StringRegExp($sText, $sDE_Pattern) Then Return "de" ; 3. French (Fast-Path Regex for accents, apostrophes & common stop words) Local $sFR_Pattern = "(?i)\b(le|la|les|un|une|des|est|sont|dans|pour|pas|avec|sur|qui|que|quoi|tout|tous|ce|cette|mon|ma|mes)\b|[àâçéèêëîïôûùüÿæœ]|c'|l'|d'|n'|m'|t'|s'|j'" If StringRegExp($sText, $sFR_Pattern) Then Return "fr" ; 4. Spanish (Fast-Path Regex for accents, punctuation & common stop words) Local $sES_Pattern = "(?i)\b(el|la|los|las|un|una|unos|unas|es|son|que|por|para|con|sin|del|al|como|pero|mas|este|esta|estos|estas|mi|mis|tu|tus|su|sus)\b|[áéíóúüñ¿¡]" If StringRegExp($sText, $sES_Pattern) Then Return "es" ; 5. English (Fast-Path Regex for core stop words) Local $sEN_Pattern = "(?i)\b(the|this|that|with|have|from|they|would|there|their)\b" If StringRegExp($sText, $sEN_Pattern) Then Return "en" ; 6. Fallback to ELS API for complex/unmatched texts Local $aLanguages = _WinAPI_DetectLanguage($sText) If Not @error And UBound($aLanguages) > 0 Then Return $aLanguages[0] Return "" EndFunc ;==>_Language_DetectEx ; ========================================================================================================================= ; Function Name ...: _WinAPI_DetectLanguage ; Description .....: Detects all candidate languages for a text string using Microsoft Extended Linguistic Services (ELS). ; Parameters ......: $sText - The string to detect languages for. ; Return values ...: Success - 1D Array of ISO Language Codes (sorted by confidence / probability) ; Failure - Empty Array and sets @error / @extended: ; 1 / 0 - Empty text ; 1 / 1 - DllOpen failed ; 2 / 0 - MappingGetServices failed ; 3 / 0 - MappingRecognizeText failed ; Author ..........: ioa747 ; ========================================================================================================================= Func _WinAPI_DetectLanguage($sText) Local $aEmpty[0] $sText = StringStripWS($sText, 3) If $sText = "" Then Return SetError(1, 0, $aEmpty) Local $hElsDll = DllOpen("elscore.dll") If $hElsDll = -1 Then Return SetError(1, 1, $aEmpty) ; Microsoft Language Detection GUID: {CF7E00B1-909B-4D95-A8F4-611F7C377702} Local $tGUID = DllStructCreate("ulong Data1; ushort Data2; ushort Data3; byte Data4[8]") DllStructSetData($tGUID, "Data1", 0xCF7E00B1) DllStructSetData($tGUID, "Data2", 0x909B) DllStructSetData($tGUID, "Data3", 0x4D95) Local $aGUIDData4[8] = [0xA8, 0xF4, 0x61, 0x1F, 0x7C, 0x37, 0x77, 0x02] For $i = 0 To 7 DllStructSetData($tGUID, "Data4", $aGUIDData4[$i], $i + 1) Next ; Dynamic struct definitions based on Architecture (x86 vs x64) Local $sEnumStruct = @AutoItX64 ? _ "uint64 Size; ptr pszCategory; ptr pszInputLanguage; ptr pszOutputLanguage; ptr pszInputScript; ptr pszOutputScript; ptr pszInputContentType; ptr pszOutputContentType; ptr pGuid; uint Flags; uint Padding" : _ "ulong Size; ptr pszCategory; ptr pszInputLanguage; ptr pszOutputLanguage; ptr pszInputScript; ptr pszOutputScript; ptr pszInputContentType; ptr pszOutputContentType; ptr pGuid; uint Flags" Local $tEnumOptions = DllStructCreate($sEnumStruct) DllStructSetData($tEnumOptions, "Size", DllStructGetSize($tEnumOptions)) DllStructSetData($tEnumOptions, "pGuid", DllStructGetPtr($tGUID)) Local $aCall = DllCall($hElsDll, "long", "MappingGetServices", _ "ptr", DllStructGetPtr($tEnumOptions), _ "ptr*", 0, _ "dword*", 0) If @error Or $aCall[0] <> 0 Or $aCall[2] == 0 Or $aCall[3] == 0 Then DllClose($hElsDll) Return SetError(2, 0, $aEmpty) EndIf Local $pServices = $aCall[2] Local $sBagStruct = @AutoItX64 ? _ "uint64 Size; ptr prgResultRanges; dword dwRangesCount; dword Padding1; ptr pServiceData; dword dwServiceDataSize; dword Padding2; ptr pCallerData; dword dwCallerDataSize; dword Padding3; ptr pContext" : _ "ulong Size; ptr prgResultRanges; dword dwRangesCount; ptr pServiceData; dword dwServiceDataSize; ptr pCallerData; dword dwCallerDataSize; ptr pContext" Local $tBag = DllStructCreate($sBagStruct) DllStructSetData($tBag, "Size", DllStructGetSize($tBag)) $aCall = DllCall($hElsDll, "long", "MappingRecognizeText", _ "ptr", $pServices, _ "wstr", $sText, _ "dword", StringLen($sText), _ "dword", 0, _ "ptr", 0, _ "ptr", DllStructGetPtr($tBag)) Local $iError = 0 Local $aLanguages[0] If Not @error And $aCall[0] == 0 Then Local $pRanges = DllStructGetData($tBag, "prgResultRanges") Local $iRanges = DllStructGetData($tBag, "dwRangesCount") If $pRanges <> 0 And $iRanges > 0 Then Local $sRangeStruct = @AutoItX64 ? _ "dword dwStartIndex; dword dwEndIndex; ptr pszDescription; dword dwDescriptionLength; dword Padding1; ptr pData; dword dwDataSize; dword Padding2; ptr pszContentType; ptr prgActionIds; dword dwActionsCount; dword Padding3; ptr prgActionDisplayNames" : _ "dword dwStartIndex; dword dwEndIndex; ptr pszDescription; dword dwDescriptionLength; ptr pData; dword dwDataSize; ptr pszContentType; ptr prgActionIds; dword dwActionsCount; ptr prgActionDisplayNames" Local $tRange = DllStructCreate($sRangeStruct, $pRanges) Local $pLanguageData = DllStructGetData($tRange, "pData") Local $iLanguageDataSize = DllStructGetData($tRange, "dwDataSize") If $pLanguageData <> 0 And $iLanguageDataSize >= 2 Then ; Read the buffer as a Byte Struct to prevent AutoIt from stopping at the first NULL wchar Local $tByteBuf = DllStructCreate("byte Data[" & $iLanguageDataSize & "]", $pLanguageData) Local $bBytes = DllStructGetData($tByteBuf, "Data") ; Convert raw byte buffer to UTF-16 String Local $sFullBuffer = BinaryToString($bBytes, 2) ; 2 = UTF-16 Little Endian ; Split null-terminated language strings Local $aRawList = StringSplit($sFullBuffer, Chr(0), 1) Local $iCount = 0 For $i = 1 To $aRawList[0] If $aRawList[$i] <> "" Then $iCount += 1 Next If $iCount > 0 Then ReDim $aLanguages[$iCount] Local $iIndex = 0 For $i = 1 To $aRawList[0] If $aRawList[$i] <> "" Then $aLanguages[$iIndex] = $aRawList[$i] $iIndex += 1 EndIf Next EndIf EndIf EndIf ; Free Property Bag resources DllCall($hElsDll, "none", "MappingFreePropertyBag", "ptr", DllStructGetPtr($tBag)) Else $iError = 3 EndIf ; Free ELS services and close DLL DllCall($hElsDll, "none", "MappingFreeServices", "ptr", $pServices) DllClose($hElsDll) If $iError Then Return SetError($iError, 0, $aEmpty) Return $aLanguages EndFunc ;==>_WinAPI_DetectLanguage Please, every comment is appreciated! leave your comments and experiences here! Thank you very much Edited September 11 by ioa747 argumentum and bladem2003 2 I know that I know nothing
ioa747 Posted September 11 Author Posted September 11 Tray activity indicator Since there is sometimes a slight delay when invoking a translation (and the lack of visual feedback makes the user experience a bit awkward), I decided to add an activity indicator. As this logic evolved into a complete, standalone solution, I am publishing it separately before integrating it into my translation tool, as it might prove useful for other projects as well expandcollapse popup#include <GUIConstants.au3> #include <GDIPlus.au3> #include <WinAPISysWin.au3> ; Global Array for the process HICONs Global $g_aTrayHIcons[4] = [0, 0, 0, 0] Global $g_hHiddenWin = 0 _InitTrayIcons() ; Creation of the 4 icons in memory once _Example() Func _Example() Local $hGUI = GUICreate("Ollama Tray Indicator Test", 350, 150) Local $idBtnStart = GUICtrlCreateButton("Start process (Test 3 sec)", 50, 50, 250, 40) GUISetState(@SW_SHOW) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idBtnStart GUICtrlSetState($idBtnStart, $GUI_DISABLE) _StartTrayAnimation() ; latency simulation (e.g., 3000 ms) Sleep(3000) _StopTrayAnimation() GUICtrlSetState($idBtnStart, $GUI_ENABLE) MsgBox(64, "Completed", "The process completed successfully!") EndSwitch WEnd EndFunc ;==>_Example #Region ; === TRAY ANIMATION FUNCTIONS === Func _InitTrayIcons() ; Standar Tray Icon TraySetIcon("imageres.dll", -120) TraySetToolTip("Ollama Translator") _GDIPlus_Startup() Local $sTitle = StringTrimRight(@ScriptName, 4) & "_HiddenWin" AutoItWinSetTitle($sTitle) $g_hHiddenWin = WinGetHandle($sTitle) ; process tray Icons in 4 rotation angle ; 0xE895 = Sync/Refresh Icon $g_aTrayHIcons[0] = _GUICtrlSetGlyph(0, "Segoe MDL2 Assets", 0xE895, 24, 0xFF0078D7, 0) ; 0° $g_aTrayHIcons[1] = _GUICtrlSetGlyph(0, "Segoe MDL2 Assets", 0xE895, 24, 0xFF0078D7, 1) ; 90° $g_aTrayHIcons[2] = _GUICtrlSetGlyph(0, "Segoe MDL2 Assets", 0xE895, 24, 0xFF0078D7, 2) ; 180° $g_aTrayHIcons[3] = _GUICtrlSetGlyph(0, "Segoe MDL2 Assets", 0xE895, 24, 0xFF0078D7, 3) ; 270° ; Cleaning up handles upon script exit OnAutoItExitRegister("_CleanupTrayIcons") EndFunc ;==>_InitTrayIcons Func _StartTrayAnimation() TraySetToolTip("Translating with Ollama...") _SetTrayHIcon($g_aTrayHIcons[0]) AdlibRegister("_RotateTrayIndicator", 150) EndFunc ;==>_StartTrayAnimation Func _RotateTrayIndicator() Static $g_iTrayStep = 0 $g_iTrayStep = Mod($g_iTrayStep + 1, 4) _SetTrayHIcon($g_aTrayHIcons[$g_iTrayStep]) EndFunc ;==>_RotateTrayIndicator Func _StopTrayAnimation() AdlibUnRegister("_RotateTrayIndicator") ; Reset to standard icon TraySetIcon("imageres.dll", -120) TraySetToolTip("Ollama Translator - Ready") EndFunc ;==>_StopTrayAnimation Func _CleanupTrayIcons() ; Cleaning up For $i = 0 To 3 If $g_aTrayHIcons[$i] Then _WinAPI_DestroyIcon($g_aTrayHIcons[$i]) Next _GDIPlus_Shutdown() EndFunc ;==>_CleanupTrayIcons Func _SetTrayHIcon($hIcon) If Not $hIcon Then Return False Local $tNID = DllStructCreate("struct; dword cbSize; hwnd hWnd; uint uID; uint uFlags; uint uCallbackMessage; ptr hIcon; wchar szTip[128]; dword dwState; dword dwStateMask; wchar szInfo[256]; uint uVersion; wchar szInfoTitle[64]; dword dwInfoFlags; endstruct") DllStructSetData($tNID, "cbSize", DllStructGetSize($tNID)) DllStructSetData($tNID, "hWnd", $g_hHiddenWin) DllStructSetData($tNID, "uID", 1) DllStructSetData($tNID, "uFlags", 0x0002) ; NIF_ICON DllStructSetData($tNID, "hIcon", $hIcon) Local $aRet = DllCall("shell32.dll", "bool", "Shell_NotifyIconW", "dword", 0x00000001, "ptr", DllStructGetPtr($tNID)) Return (Not @error And $aRet[0]) EndFunc ;==>_SetTrayHIcon Func _GUICtrlSetGlyph($idControl, $sFontName, $iUnicodeDecimalOrHex, $iSize = 32, $iARGBColor = 0xFF000000, $iRotateFlipType = 0, $iGlyphScale = 100) Local $hCtrl = GUICtrlGetHandle($idControl) If Not $hCtrl Then $hCtrl = $idControl ; Handle passed directly If $hCtrl Then Local $sClassName = _WinAPI_GetClassName($hCtrl) Local $iMsg = 0 ; Dynamic Style Adjustment to accept HICON handles Local $iStyle = _WinAPI_GetWindowLong($hCtrl, -16) ; -16 = GWL_STYLE Switch $sClassName Case "Button" $iMsg = $BM_SETIMAGE If BitAND($iStyle, 0x0040) = 0 Then ; If $BS_ICON is missing, apply it _WinAPI_SetWindowLong($hCtrl, -16, BitOR($iStyle, 0x0040)) EndIf Case "Static" $iMsg = $STM_SETIMAGE ; Clear SS_BITMAP (0x0E) / SS_CENTERIMAGE (0x0200) and enforce SS_ICON (0x03) $iStyle = BitAND($iStyle, BitNOT(0x020E)) _WinAPI_SetWindowLong($hCtrl, -16, BitOR($iStyle, 0x0003)) Case Else Return SetError(1, 0, 0) ; Unsupported control class EndSwitch EndIf ; Canvas Setup Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2) _GDIPlus_GraphicsSetInterpolationMode($hGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTCLEARTYPEGRIDFIT) Local $hBrush = _GDIPlus_BrushCreateSolid($iARGBColor) Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName) Local $hFont = _GDIPlus_FontCreate($hFamily, $iSize * ($iGlyphScale / 100), 0, 2) Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iSize, $iSize) Local $hFormat = _GDIPlus_StringFormatCreate() _GDIPlus_StringFormatSetAlign($hFormat, 1) _GDIPlus_StringFormatSetLineAlign($hFormat, 1) ; Surrogate Pairs for Unicode > 0xFFFF (e.g. Emojis) Local $sChar = "" If $iUnicodeDecimalOrHex > 0xFFFF Then Local $iCode = $iUnicodeDecimalOrHex - 0x10000 Local $iHigh = BitOR(0xD800, BitShift($iCode, 10)) Local $iLow = BitOR(0xDC00, BitAND($iCode, 0x3FF)) $sChar = ChrW($iHigh) & ChrW($iLow) Else $sChar = ChrW($iUnicodeDecimalOrHex) EndIf _GDIPlus_GraphicsDrawStringEx($hGraphics, $sChar, $hFont, $tLayout, $hFormat, $hBrush) ; Resample to Target Size Local $hFinalBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize) Local $hFinalGraphics = _GDIPlus_ImageGetGraphicsContext($hFinalBitmap) _GDIPlus_GraphicsSetInterpolationMode($hFinalGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC) _GDIPlus_GraphicsDrawImageRect($hFinalGraphics, $hBitmap, 0, 0, $iSize, $iSize) ; Apply Rotation / Flip if needed If $iRotateFlipType Then _GDIPlus_ImageRotateFlip($hFinalBitmap, $iRotateFlipType) ; Convert to Win32 HICON (Preserves full Alpha Transparency) Local $hIcon = _GDIPlus_HICONCreateFromBitmap($hFinalBitmap) If $hCtrl Then ; Send HICON message to Control ($IMAGE_ICON = 1) Local $hPrevIcon = _SendMessage($hCtrl, $iMsg, 1, $hIcon) ; Destroy previous icon if any existed to prevent memory leaks If $hPrevIcon Then _WinAPI_DestroyIcon($hPrevIcon) EndIf ; Cleanup GDI+ Resources _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hFinalGraphics) _GDIPlus_BitmapDispose($hFinalBitmap) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_BitmapDispose($hBitmap) Return $hIcon EndFunc ;==>_GUICtrlSetGlyph #EndRegion ; === TRAY ANIMATION FUNCTIONS === Please, every comment is appreciated! leave your comments and experiences here! Thank you very much I know that I know nothing
ioa747 Posted September 12 Author Posted September 12 I updated the first post with the new version. in which I have incorporated the Language_Detect and Tray activity indicator techniques described above. I know that I know nothing
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now