#include <Misc.au3>
#include <GUIEdit.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Local $wValidKey_8 = 0
For $i = 48 To 57
Assign("wValidKey_" & $i, 0)
Next
Local $fIsReading = 0, $fIsWriting = 0
$hEC = DllCallbackRegister("_EditProcedure", "int", "hWnd;uint;wparam;lparam")
$pEC = DllCallbackGetPtr($hEC)
$hGUI = GUICreate("Test", 150, 80)
$iiTest = GUICtrlCreateInput("", 20, 20, 110, 20)
$hOEC = _WinAPI_SetWindowLong(GUICtrlGetHandle(-1), -4, $pEC)
GUISetState()
Do
Until GUIGetMsg() = -3
GUIDelete($hGUI)
DllCallbackFree($hEC)
Func _EditProcedure($hWnd, $iMsg, $iwParam, $ilParam)
Local $sString, $sVal, $iX, $iY, $iPosition, $aSel
Switch $iMsg
Case $WM_PASTE ; 粘贴时发送的消息。
Return 0 ; 返回任意值,以切断消息的继续传递。
Case $WM_CUT ; 剪切时发送的消息。
Return 0 ; 返回任意值,以切断消息的继续传递。
Case $WM_SETTEXT ; ControlSetText、GUICtrlSetData发送的消息。
; 判断是否是GUICtrlSetData发送,否则切断消息传递。
If $fIsWriting = 0 Then Return 0
Case $WM_GETTEXT ; ControlGetText 、GUICtrlRead发送的消息。
; 判断此消息是否由GUICtrlRead发送,否则返回任意值以切断消息传递。
If $fIsReading = 0 Then Return 0
Case $WM_CHAR ; ControlSend、Send、以及由人手物理输入时发送的消息。
; WM_CHAR消息中, $iwParam 参数设为按下的键的ASCII码。
; 用Chr($iwParam) 可以将ASCII转换为实际输入的字符。
; 判断是否是输入了数字或者退格符。
If Not IsDeclared("wValidKey_" & $iwParam) Then Return 0
; 判断按键是否处于按下状态,若是则可以说明是通过物理输入的。
; 否则,可以断定此消息是由ControlSend、Send发送。
If (_IsPressed(Hex($iwParam, 2)) Or _IsPressed(Hex($iwParam + 0x30, 2))) = 0 Then
Return 0
EndIf
; 获取插入符在input框的位置。
_GetCaretPos($iX, $iY)
$iPosition = _GUICtrlEdit_CharFromPos($hWnd, $iX, $iY)
$iPosition = $iPosition[0]
$fIsReading = 1 ; 设置为1,表示$WM_GETTEXT消息是由GUICtrlRead发送的。
$sString = GUICtrlRead($iiTest) ; 读取input框中现有的内容,不包含此时输入的字符。
$fIsReading = 0 ; $fIsReading为0时,表示$WM_GETTEXT是由其他外在程序发送的。
$aSel = _GUICtrlEdit_GetSel($hWnd)
If $iwParam = 8 Then ; 判断按键是否为退格。
If ($aSel[1] - $aSel[0]) Then
$sVal = StringLeft($sString, $aSel[0]) & StringRight($sString, StringLen($sString) - $aSel[1])
Else
$sVal &= StringLeft($sString, $iPosition - 1)
$sVal &= StringRight($sString, StringLen($sString) - $iPosition)
EndIf
Else
If ($aSel[1] - $aSel[0]) Then
$sString = StringLeft($sString, $aSel[0]) & StringRight($sString, StringLen($sString) - $aSel[1])
EndIf
$sVal &= StringLeft($sString, $iPosition) & Chr($iwParam)
$sVal &= StringRight($sString, StringLen($sString) - $iPosition)
EndIf
; 此时$sVal的值为 input框中现有的内容,另加,此时输入的字符。
; 如果input框现有内容为12,插入符在1与2之间,此时按下的键为3,$sVal的值为132。
; 判断首位是否为0。
If StringRegExp($sVal, "^0+") Then
$sVal = StringRegExpReplace($sVal, "^0+", "")
$fIsWriting = 1
GUICtrlSetData($iiTest, $sVal)
$fIsWriting = 0
_GUICtrlEdit_SetSel($hWnd, 0, 0)
; _EditProcedure($hWnd, $WM_CHAR, 8, 0)
Return 0
EndIf
; 判断是否在1-50之间。
If ($sVal <> "") And (Number($sVal) < 1 Or Number($sVal) > 50) Then Return 0
EndSwitch
; 继续消息的传递。
Return _WinAPI_CallWindowProc($hOEC, $hWnd, $iMsg, $iwParam, $ilParam)
EndFunc ;==>_EditProcedure
Func _GetCaretPos(ByRef $iX, ByRef $iY)
Local $tXY
$tXY = DllStructCreate("long X;long Y")
DllCall("User32.dll", "int", "GetCaretPos", "ptr", DllStructGetPtr($tXY))
$iX = DllStructGetData($tXY, "X")
$iY = DllStructGetData($tXY, "Y")
$tXY = 0
EndFunc ;==>_GetCaretPos