//hook 鼠标钩子
import win; 
 
var SetWindowsHookEx = ::User32.api("SetWindowsHookExA","pointer(int idHook,pointer lpfn, pointer hmod,INT dwThreadId)");
var CallNextHookEx = ::User32.api("CallNextHookEx","int( POINTER hhk,int nCode,INT wParam,int lParam)");
var UnhookWindowsHookEx = ::User32.api("UnhookWindowsHookEx","int(pointer hhk)");
 
var WH_MOUSE_LL  = 14

MSLLHOOKSTRUCT = class{
    struct   pt ={int x;int y};
    INT   mouseData;
    INT   flags;
    INT   time;
    INT dwExtraInfo;
} 

var LowLevelMouseProc  = function( nCode, wParam, lParam){
	if(owner.hasBeenEntered){
		//MSDN:
		//Prevent the mouse event being sent to other hook procs and the window procedure.
		//Might not be what you want.
		return 1;
	}

	//MSDN:
	//The wParam and lParam parameters contain information about a keyboard message
	if (  ( nCode == 0/*_HC_ACTION*/ ) /**&& ( wParam != 0x200/*_WM_MOUSEMOVE*/ )**/ ) { 
		owner.hasBeenEntered = true;
		
    	var ll = MSLLHOOKSTRUCT();
		ll = ..raw.convert(topointer(lParam),ll ); 
		if( ( type(owner.proc) == type.function)  &&  (owner.proc(wParam,ll.pt.x,ll.pt.y,ll.mouseData) )  ){
			owner.hasBeenEntered = false;
			return 1;
		}
					
		owner.hasBeenEntered = false;
	}
  
  	//MSDN:
  	//If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 
  	//If nCode is greater than or equal to zero, and the hook procedure did not process the message,
  	//it is highly recommended that you call CallNextHookEx and return the value it returns; 
	return CallNextHookEx(owner._hhk, nCode, wParam, lParam); 
}

namespace mouse

class hook{
	ctor(){
   		var hinst = ::GetModuleHandle();  
   		this._proc_c = ..raw.tostdcall( LowLevelMouseProc,"int(int nCode, int wParam, int lParam)",this)
   		var hhk = SetWindowsHookEx(WH_MOUSE_LL,this._proc_c,hinst,0);  
	   	this._hhk = hhk;
	   	
	   	..table.add_gc(this,"close"); 
	}
	
	close  = function(){
		if(hhk){
			UnhookWindowsHookEx(hhk);
			hhk  = null
		}
	}
    
} 


/**intellisense()
key.hook = 鼠标钩子
mouse.hook() = 创建按键录制钩子
!hkmouse.proc = @.proc = function(msg,x,y,mouseData){
	//录制回调函数，若要钩住滚轮消息，MSDN上查具体的mouseData参数
    select(msg) {
    	case 0x201/*_WM_LBUTTONDOWN*/{
    	    io.print("左键按下",x,y)
    	}
    	case 0x202/*_WM_LBUTTONUP*/{
    	    io.print("左键弹起",x,y)
    	}  
    }   
	//return true;//取消按键 
}
!hkmouse.close() = 释放按键录制钩子
?mouse.hook = !hkmouse.
end intellisense**/
 