;-- TIME_STAMP   2024-01-02 15:58:13


#include <WinAPI.au3>
#include <WindowsConstants.au3>
OnAutoItExitRegister('OnAutoItExit')
;~ HotKeySet('^+q', '_Exit')  ; Strg+Shift+Q - during testing

Global $iSpeed = 3  ; Factor for multiplying the wheel steps
Global $INI = StringTrimRight(@ScriptFullPath, 4) & '.ini'
If FileExists($INI) Then
    $iSpeed = IniRead($INI, 'HScroll', 'speed', 3)
EndIf

Global $gSciTECmd
GUIRegisterMsg(74, "MY_WM_COPYDATA")  ; $WM_COPYDATA = 74

Global Const $HC_ACTION = 0
Global $hStub_MouseProc = DllCallbackRegister("_MouseProc", "long", "int;wparam;lparam")
Global $hmod = _WinAPI_GetModuleHandle(0)
Global $hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hStub_MouseProc), $hmod)

Global $hStub_KeyProc = DllCallbackRegister("_KeyProc", "long", "int;wparam;lparam")
Global $hHookKey = _WinAPI_SetWindowsHookEx($WH_KEYBOARD_LL, DllCallbackGetPtr($hStub_KeyProc), $hmod)
Global $gbShift = False, $gbCtrl = False

While True
	Sleep(50)
WEnd

Func _MouseProc($nCode, $wParam, $lParam)
	Local $tInfo, $wheelCount
	$tInfo = DllStructCreate("int X;int Y;dword mouseData;dword flags;dword time;ulong_ptr dwExtraInfo", $lParam)
    If $nCode < 0 Or _GetHwnd_SciTE() = Null Or $gbShift = False Then Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
    If $nCode = $HC_ACTION Then
		Switch $wParam
			Case $WM_MOUSEWHEEL
				$wheelCount = _WinAPI_HiWord($tInfo.mouseData)/120
                SendSciTE_Command('extender:dostring do editor:LineScroll(' & $wheelCount*$iSpeed*(-1) & ',0) end')
		EndSwitch
	EndIf
	Return _WinAPI_CallNextHookEx($hHook, $nCode, $wParam, $lParam)
EndFunc

Func _KeyProc($nCode, $wParam, $lParam)
    Local $tKEYHOOKS, $vkCode, $ID
    $tKEYHOOKS = DllStructCreate($tagKBDLLHOOKSTRUCT, $lParam)
    If $nCode < 0 Or _GetHwnd_SciTE() = Null Then Return _WinAPI_CallNextHookEx($hHookKey, $nCode, $wParam, $lParam)
	$vkCode = DllStructGetData($tKEYHOOKS, "vkCode")
    If $wParam = $WM_KEYDOWN Then
		If $vkCode = 0xA0 Or $vkCode = 0xA1 Then ; left or right shift-button pressed
			$gbShift = True
        ElseIf $vkCode = 0xA2 Or $vkCode = 0xA3 Then ; left or right ctrl-button pressed
            $gbCtrl = True
		EndIf
	Else
        Switch DllStructGetData($tKEYHOOKS, "flags")
			Case 0x80, 0x81 ; 0x80= UP for 'normal' keys and left pairs,  0x81= UP for right pairs
				If $vkCode = 0xA0 Or $vkCode = 0xA1 Then        ; LShift, RShift
                    $gbShift = False
                ElseIf $vkCode = 0xA2 Or $vkCode = 0xA3 Then    ; LCtrl, RCtrl
                    $gbCtrl = False
                EndIf
		EndSwitch
    EndIf
    Return _WinAPI_CallNextHookEx($hHookKey, $nCode, $wParam, $lParam)
EndFunc

Func _Exit()
	Exit
EndFunc

Func OnAutoItExit()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hStub_MouseProc)
    _WinAPI_UnhookWindowsHookEx($hHookKey)
    DllCallbackFree($hStub_KeyProc)
EndFunc   ;==>OnAutoItExit

Func _GetHwnd_SciTE()
    Local $hScite = WinGetHandle('[ACTIVE]')
    If _WinAPI_GetClassName($hScite) = 'SciTEWindow' Then
        Return $hScite
    Else
        Return SetError(1, 0, Null)
    EndIf
EndFunc

Func _GetHwndDirectorExtension()
	Local $hActive = WinGetHandle('[ACTIVE]')
	Local $PIDActive = WinGetProcess($hActive)
	Local $aExtension = WinList("DirectorExtension")
	Local $PIDExt
	For $i = 1 To $aExtension[0][0]
		$PIDExt = WinGetProcess($aExtension[$i][1])
		If $PIDExt = $PIDActive Then Return $aExtension[$i][1]
	Next
EndFunc

; by Jos
Func SendSciTE_Command($_sCmd, $Wait_For_Return_Info=0)
    Local $WM_COPYDATA = 74
    Local $Scite_hwnd = _GetHwndDirectorExtension()          ; Get SciTE DIrector Handle
    Local $My_Hwnd = GUICreate("AutoIt3-SciTE interface")    ; Create GUI to receive SciTE info
    Local $My_Dec_Hwnd = Dec(StringTrimLeft($My_Hwnd, 2))    ; Convert my Gui Handle to decimal
    $_sCmd = ":" & $My_Dec_Hwnd & ":" & $_sCmd               ; Add dec my gui handle to commandline to tell SciTE where to send the return info
    Local $CmdStruct = DllStructCreate('Char[' & StringLen($_sCmd) + 1 & ']')
    DllStructSetData($CmdStruct, 1, $_sCmd)
    Local $COPYDATA = DllStructCreate('Ptr;DWord;Ptr')
    DllStructSetData($COPYDATA, 1, 1)
    DllStructSetData($COPYDATA, 2, StringLen($_sCmd) + 1)
    DllStructSetData($COPYDATA, 3, DllStructGetPtr($CmdStruct))
	$gSciTECmd = ''
    DllCall('User32.dll', 'None', 'SendMessage', 'HWnd', $Scite_hwnd, _
            'Int', $WM_COPYDATA, 'HWnd', $My_Hwnd, _
            'Ptr', DllStructGetPtr($COPYDATA))
    GUIDelete($My_Hwnd)
	If $Wait_For_Return_Info Then
		Local $n = 0
		While $gSciTECmd = '' Or $n < 10
			Sleep(20)
			$n += 1
		WEnd
	EndIf
	Return $gSciTECmd
EndFunc   ;==>SendSciTE_Command

Func MY_WM_COPYDATA($hWnd, $msg, $wParam, $lParam)
	Local $COPYDATA = DllStructCreate('Ptr;DWord;Ptr', $lParam)
	Local $gSciTECmdLen = DllStructGetData($COPYDATA, 2)
    Local $CmdStruct = DllStructCreate('Char[' & $gSciTECmdLen+1 & ']',DllStructGetData($COPYDATA, 3))
	$gSciTECmd = StringLeft(DllStructGetData($CmdStruct, 1), $gSciTECmdLen)
EndFunc   ;==>MY_WM_COPYDATA