Option Explicit
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, _
ByVal hWnd As Long, _
ByVal Msg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Public Const GWL_WNDPROC = (-4)
Public Const WM_CHAR = &H102
Public Const WM_KEYUP = &H101
Public Const WM_KEYDOWN = &H100
Public Const WM_LBUTTONUP = &H202
Public Const EM_SETSEL = &HB1
Public Const EM_GETSEL = &HB0
Public Const VK_END = &H23
Public Const VK_BACK = &H8
Public Const VK_DELETE = &H2E
Public Const VK_ESCAPE = &H1B
Public Const VK_HOME = &H24
Public Const VK_RETURN = &HD
Public Const VK_RIGHT = &H27
Public Const VK_LEFT = &H25
Public Const VK_UP = &H26
Public Const VK_DOWN = &H28
Public hProcEditOld As Long
Public hEdit As Long
Public iStart As Long
'
'своя процедура обработки сообщение окну редактирования
Public Function SubWndProcEdit(ByVal hWnd As Long, _
ByVal uMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
On Error Resume Next
Dim bln As Boolean 'флаг, который если Истина, показывает, что нужно запускать обработку сообщения стандартной процедурой
Dim i1 As Long, i2 As Long
bln = False
Select Case uMsg
Case WM_CHAR 'был введен символ, мы допускаем ввод только цифр
If wParam < &H30 Or wParam > &H39 Then
bln = False
Else
bln = True 'вот они цифры! )))
End If
Case WM_KEYDOWN, WM_KEYUP
Select Case wParam
Case VK_HOME
'не позволим перемещаться за пределы редактируемого текста
bln = False
'Тут тоже не совсем верно работает, выделяется весь редактируемый текст, вместо простого перемещения курсора
SendMessage hEdit, EM_SETSEL, iStart, iStart
SubWndProcEdit = True
Case VK_LEFT, VK_BACK, VK_UP
'строго говоря BackSpace не работает, это относится к минусам )))
'проверяем текущее положение курсора
i1 = SendMessage(hEdit, EM_GETSEL, 0, i2) Mod (2 ^ 8)
'здесь попытка предотвратить перемещения курсора в нередактируемый текст
If i1 = iStart And i1 = i2 Then
bln = False
ElseIf (i1 <= iStart And i1 <> i2) Then
bln = False
Else
bln = True
End If
Case VK_END, VK_RIGHT, VK_DOWN, VK_DELETE, VK_ESCAPE, VK_RETURN
bln = True' эти клавиши обрабатываются как обычно
Case Else
'мы допускаем ввод только цифр
If wParam < &H30 Or wParam > &H39 Then
bln = False
Else
bln = True
End If
End Select
Case WM_LBUTTONUP
'здесь мы не знаем, где кликнули, вернее знаем, но не заморачиваемся: позволяем выполниться процедуре по умолчанию
SubWndProcEdit = CallWindowProc(hProcEditOld, hEdit, uMsg, wParam, lParam)
'и затем проверяем новое положение курсора, если в нередактируемом тексте - возврат к редактируемому
i1 = SendMessage(hEdit, EM_GETSEL, 0, i2) Mod (2 ^ 8)
If i1 <= iStart Then
bln = False
SendMessage hEdit, EM_SETSEL, iStart, iStart
End If
bln = False
Case Else
bln = True
'все остальные сообщения обрабатываются стандартно
End Select
'обязательно нужно вернуть значение
If bln Then
SubWndProcEdit = CallWindowProc(hProcEditOld, hEdit, uMsg, wParam, lParam)
Else
SubWndProcEdit = True
End If
End Function