How do you "capture" the enter key when the user hits enter when typing into an edit control?
I think subclassing would work, but was hoping for a simpler way.
If its a single-line edit control then use either your main window procedure (WM_KEYDOWN or WM_CHAR) or your edit control's window procedure.
If its multiline make sure you don't have the ES_WANTRETURN style set and do the same as above.
If it's in a dialog (rather than a window) it's probably easier, but I don't use dialogs so you'll need to wait on someone else.
zooba,
Thanks for the quick response!
Quote
If its a single-line edit control then use either your main window procedure (WM_KEYDOWN or WM_CHAR) or your edit control's window procedure.
I don't seem to be getting the WM_CHAR event.
Quote from: msmith on January 13, 2006, 04:22:49 AM
I don't seem to be getting the WM_CHAR event.
You'll only get WM_CHAR if you have TranslateMessage in your message loop and it's working correctly.
I see the problem, at least in part.
My event handler "directs" events based on the argument that contains the handle. I now see that WM_CHAR does not supply a handle argument.
It looks like I have to keep track of which control has focus in order to use the WM_CHAR message. Do you know of an easy way to do this?
Also, I need to be able to change focus based on the Tab key.
Quote from: msmith on January 13, 2006, 04:54:05 AMIt looks like I have to keep track of which control has focus in order to use the WM_CHAR message. Do you know of an easy way to do this?
GetFocus function
Quote from: msmith on January 13, 2006, 04:54:05 AMAlso, I need to be able to change focus based on the Tab key.
Put IsDialogMessage in your message loop and ensure your controls have WS_TABSTOP set.
Thanks again.
Now I have something to work with. Trying these things takes longer than one might expect because this is compiler generated code, so I have to modify the compiler to generate the new code, compile the compiler, and then use a test program to test it.
I think I can just use GetFocus to supply the handle and go from there.
Once I am able to capture this event, I assume I should check for the "ENTER" code and "take" the event for myself, and to pass the event if it is not an ENTER. Is this correct?
It still is not working.
Here are some code snippets from the event handler.
cmp ebx,WM_CHAR
je !wmChar
.
.
.
!wmChar:
mov [!PassKbdEvent],0
invoke GetFocus
cmp eax,0
je !DefWndProc
invoke GetWindowLong,eax,GWL_USERDATA
cmp eax,0
je !DefWndProc
mov esi,eax
mov eax,[esi+ArrayOffs]
mov [ArrayIndex],eax
mov eax,[esi+evKeyStruckOffs]
cmp eax,0
je !DefWndProc
call dword eax
cmp [!PassKbdEvent],0
jne !DefWndProc
xor eax,eax
jmp !Finish
GWL_USERDATA for each control contains the address of a descriptor for that control which holds event dispatch pointers and other key info. In the case shown, [esi+evKeyStruckOffs] holds the dispatch address for the event.
PS
I changed the code above temporarily to:
!wmChar:
call txt1_keystruck
xor eax,eax
jmp !Finish
I now get the event when the edit box does not have focus, but not when it does.
I think you'll want to step through this code with a debugger to make sure your descriptor contains the correct values in the correct places.
Also you'll want to make sure that a WM_CHAR event is sent for enter inside an edit control. It's entirely possible that the control is absorbing it based on it's style (not 100% sure on this).
With the small code segment at the bottom, the descriptor is out of the picture.
It appears that the control IS absorbing the WM_CHAR events.
In that case you'll need to set up a window proc for the edit control. This isn't as hard as it sounds, and since you've got a descriptor system already working you just need to allocate space in there for the old window proc (or somewhere common to all edit controls):
invoke GetWindowLong, hEdit, GWL_USERDATA
mov esi, eax
invoke SetWindowLong, hEdit, GWL_WNDPROC, OFFSET EditProc
mov [esi+OldWndProcOffs], eax
Then all the edit proc needs to do is check for a specific message and pass everything else to CallWindowProc (not DefWindowProc). :U
zooba,
Thanks again for all of your help and advice.
In my original post is said:
Quote
How do you "capture" the enter key when the user hits enter when typing into an edit control?
I think subclassing would work, but was hoping for a simpler way.
In fact, I tried this earlier today and it works as expected.
The problem is that I can't expect my compiler customers to do this. Some of them either don't know or don't care what an API is. They want to code their application, not low level stuff like this.
The goal of the compiler is to give the user the power of a good compiler such as PowerBASIC or c, but with the simplicity of VB. The ability to go to the nuts and bolts level such as API calls in anline asm is there, but is is intended only for those who WANT to use it, not HAVE to.
I may automatically create a separate window process (invisibly) whenever the user creates a single line edit, and add some intuitive support statements to use it.
One the bright side, by having a separate window process for each edit box, there is no doubt about the handle and no need to use GetHandle.
Here's the code:
txt1_intercept:
; LN:27 if wmsg=$102 then
cmp [wmsg],258
jne _Lbl5
; LN:29 if wparam=$0d then
cmp [wparam],13
jne _Lbl6
; LN:30 gosub b1_command
call b1_command
; LN:31 end if
_Lbl6:
; LN:32 end if
_Lbl5:
; LN:33 passinterceptevent
mov [!PassInterceptEvent],1
; LN:34 end event
ret
As you can see, the compiler can output asm with the BASIC lines as comments.
I'm not sure I can see the exact problem you're having. Perhaps you could post some sample input and output for your compiler?
zooba,
I'm not having a problem. The code I just posted works fine.
I just hate for a customer to have to go this far "under the hood" to do the job.
Quote from: msmith on January 14, 2006, 02:11:04 AM
I just hate for a customer to have to go this far "under the hood" to do the job.
There shouldn't be any need for the customer to do this. If the compiler-generated code calls user defined events isn't it just a matter of calling one of these events from a different place?
The customer has to do an "INTERCEPTON" for each edit control and then write an event handler for each one.
So presumably there's some code that the customer doesn't write which calls their interception code. Can't you have another window procedure for the edit control which passes Enter key presses to the customer's code?
zooba
The procedure the customer does right now is:
1) create control
This does a CreateWindowEx and fills in the descriptor with key things like Handle, control type, ID, status, etc. and nulls all of the event dispatch addresses. It also saves the default WindowProc.
2) Does an INTERCEPTON for that control (if it desired to intercept events intended for the control). This overwrites the Proc in the Handle using a SetWindowLong
3) Writes an intercept event of the form:
ControlName.INTERCEPT
UserCode (In this case checks wmsg to see if is a WM_CHAR and if it is, checks wparam for a ENTER code. If it is, the proper button event is called))
PASSEVENT (if the user wants to allow normal processing of the event, otherwise this is omitted causing a 0 to be returned)
END EVENT
For the normal case of doing an event:
1) Create control (ExitButton for example)
2) Write event
ExitButton.COMMAND
END
END EVENT
The compiler automatically stores the ExitButton.COMMAND dispatch address in the descriptor and the event handler automatically checks the entry in the descriptor for a 0, in which case not event is called. Otherwise it calls the address stored in the descriptor in the Command Dispatch entry.
I hope this answers your question, and thanks again for all the help.
Yes, it does answer my question. :wink
I've been so interested because it appears very similar to my current project, a runtime library (http://www.masmforum.com/simple/index.php?topic=3148.30) for MASM to hide a lot of the API details in macros and procedures :bg