
import win;
import key;
 
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_KEYBOARD_LL  = 13

var KBDLLHOOKSTRUCT = class{
    INT   vkCode;
    INT   scanCode;
    INT   flags;
    INT   time;
    INT dwExtraInfo;
}

var hasBeenEntered;
var LowLevelKeybdProc  = function( nCode, wParam, lParam){  
	if(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*/ ) { 
		hasBeenEntered = true;
		
    	var ll = KBDLLHOOKSTRUCT();
		ll = ..raw.convert(topointer(lParam),ll )
 	 
		if( ( type(owner.proc) == type.function)  &&  (owner.proc(wParam,ll.vkCode,ll.scanCode) )  )
			 	return 1;
					
		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 key  
	class hook{
	ctor(){
		var hinst = ::GetModuleHandle();  
		this._proc_c = ..raw.tostdcall( LowLevelKeybdProc,"int(int nCode, INT wParam, int lParam)",this) 
		
		var hhk = SetWindowsHookEx(WH_KEYBOARD_LL,this._proc_c,hinst,0);   
		this._hhk = hhk;
		
		//创建析构对象
   		this._gc = ..gcdata(
   			_gc = function(){  
   				this.close();
   			} 
   		)
   		
	}
	
	close  = function(){
		if(hhk){  
			UnhookWindowsHookEx(hhk);
			hhk  = null
			
		}
	}

   
}

/**intellisense()
key.hook() = 创建按键录制钩子
!hkkey.proc = @.proc=function(msg,vkcode,scancode){
	//录制回调函数 
    var kn = key.getName( vkcode );
    select(msg) {
    	case 0x100/*_WM_KEYDOWN*/ ,0x104/*_WM_SYSKEYDOWN*/{
    	    io.print("按下",kn)
    	}
    	case 0x101/*_WM_KEYUP*/,0x105/*_WM_SYSKEYUP*/{
    	    io.print("弹起",kn)
    	}  
    }   
	//return true;//取消按键 
}
!hkkey.close() = 释放按键录制钩子
?key.hook = !hkkey.
end intellisense**/
 