I threw together a quickie dialog using DialogBoxIndirectParam. I just wanted some specialized keyboard input for a program I am working on.
There are no controls on the dialog, I am just handling everything directly in the dialog code.
The dialogbox procedure does not receive the WM_CHAR message.
The only useful message to get keyboard input is the WM_KEYDOWN message.
I tried returning DLGC_WANTCHARS or DLGC_WANTALLKEYS in response to the WM_GETDLGCODE message, but still no WM_CHAR message.
Normally the WM_CHAR message would be sent as the result of the TranslateMessage function, but that is not really for use within a dialog and didn't work.
I finally kludeged a workaround with the code:
.elseif eax==WM_KEYDOWN
.data?
kbs db 256 dup (?)
chout dd ?
.code
mov edx,lParam
shr edx,16
and edx,0ffh
mov chout,0
invoke GetKeyboardState,addr kbs
invoke ToAscii,wParam,edx,addr kbs,addr chout,0
; ascii character returned in chout
but I'm thinking there is probably a much cleaner way to get the ascii character from the keyboard. I don't want to use an edit control which causes more trouble than it solves in my particular circumstance.
Any suggestions?
Hi Jim,
Can't help you without seeing complete code but you are not alone (https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/47926-why-no-wm_char-handling-in-sdk-modal-dialog) with your problem. Hope it helps...
Does it have to be a dialog? Why not a simple RegisterClassEx/CreateWindowEx?
Quote from: jimg on August 30, 2017, 11:09:52 AMThere are no controls on the dialog, I am just handling everything directly in the dialog code.... I don't want to use an edit control which causes more trouble than it solves in my particular circumstance.
If there was an edit control, subclassing would work, see attachment: The edit field doesn't accept chars between "e" and "z".
With the information you provided I can only suggest that you pick the WM_CHAR from the main loop and send it to the dialog with a:
invoke SendMessage, myDialogHwnd, msg.message, msg.wParam, msg.lParam
Thanks for the responses. I thought this might have been simple enough that someone would have immediately known a solution.
When I can get the whole mess more presentable, I'll post the source.
Sinsi: Yes, I could have just done a full windows with translate message. I just tend to go the simple route when possible. Quickie dialogs have served me well before this.
Aw27: I'm not getting WM_CHAR messages any where else while the modal dialog is running. The main is also a dialog so I don't have message loop. Perhaps that may be the only other solution.
JJ: Originally I started with subclassed edits but the code started getting out of hand and misbehaving. I rewrote with the simple dialog and ended up with about one fourth the code and it's a lot simpler and faster.
I do have one additional question for now, which I'll embed here where no one will see it.
I am getting a periodic character 252 in the WM_KEYDOWN message. Anyone know what this is? Microsoft just says it's unknown and reserved. I'm guessing some kind of keyboard heartbeat.
JJ-
Thanks for that link. After working through it, it's amazing how it parallels my process over the last two days. (And what a surprise to see a post by Hutch in the middle :) )
I guess my above solution wasn't so bad after all.
Quote from: jimg on August 31, 2017, 12:33:32 AM(And what a surprise to see a post by Hutch in the middle :) )
He was still young then ;)
(https://forum.powerbasic.com/core/image.php?userid=187&thumb=1&dateline=1455377628)
Implementing a subclassed edit is IMHO remarkably simple, just create it in WM_INITDIALOG. Here is the subclass:
SubEdit proc hwnd, uMsg, wParam, lParam
.if uMsg==WM_CHAR
.if wParam>="e" && wParam<="z"
return 0 ; to suppress the message
.endif
.endif
invoke CallWindowProc, opEdit, hwnd, uMsg, wParam, lParam
ret
SubEdit endp
Look for opEdit in the source posted above.
Yes, done it many times (like in the ascii table prog I posted not too long ago).
In this case, because I was juggling a few things at once, it just got real messy real fast, so I backed off and tried a "simpler" approach.
Quote from: jimg on August 31, 2017, 12:04:06 AM
I don't have message loop.
Iczelion inspiration? :biggrin:
Quote
I am getting a periodic character 252 in the WM_KEYDOWN message
Do you have a screensaver?
Hi jimg,
I tried to simulate your design by creating an invisible edit control. The subclass procedure does the job.
Your method based on GetKeyboardState is better. Quick and practical.
include DlgBoxWmchar.inc
.data
DlgBox db 'DLGBOX',0
capt db 'Info',0
format1 db 'You pressed %c',0
.data?
pOldEditBox dd ?
hEdit dd ?
buffer db 16 dup(?)
.code
start:
invoke GetModuleHandle,0
xor ecx,ecx
invoke DialogBoxParam,eax,ADDR DlgBox,ecx,\
ADDR DlgProc,ecx
invoke ExitProcess,eax
DlgProc PROC hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.IF uMsg==WM_INITDIALOG
invoke GetDlgItem,hWnd,IDC_EDIT
mov hEdit,eax
invoke SetWindowLong,eax,GWL_WNDPROC,\
ADDR SubclassProc
mov pOldEditBox,eax
.ELSEIF uMsg==WM_CLOSE
invoke EndDialog,hWnd,0
.ELSE
xor eax,eax
ret
.ENDIF
mov eax,1
ret
DlgProc ENDP
SubclassProc PROC hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.IF uMsg==WM_CHAR
invoke wsprintf,ADDR buffer,ADDR format1,wParam
invoke MessageBox,0,ADDR buffer,ADDR capt,MB_OK
xor eax,eax
ret
.ENDIF
invoke CallWindowProc,pOldEditBox,hWnd,uMsg,\
wParam,lParam
ret
SubclassProc ENDP
END start
Thanks Vortex :)
AW: I get the character exactly every 10 seconds. I have a screensaver, but I don't think that is it. Just something weird about my machine. Doesn't happen on my other computers.
@jimg
I meant some program issuing it to prevent the screensaver from triggering. :icon_rolleyes:
Oh. Nope, screen saver kicks in when expected. Hopefully it's not a keylogger or something.
So it is not a result of a simulated keystroke. :(
And unfortunately is not easy to find the origin of windows messages. :(
John (Sinsi) has the right answer - create a window with a WndProc
for dialog windows, the OS provides the actual WndProc and sends only
messages they felt were pertinent to the DlgProc, handling the rest internally
by the way, i see your 7366 post count, JJ
trying to sneak up on me, eh ? :P
Quote from: dedndave on September 01, 2017, 01:15:40 AMtrying to sneak up on me, eh ? :P
I think everybody will be happy if you accept the challenge, Dave - keep posting :P
Dave!
Haven't seen a post from you in a while :)
So, since I really wanted a modal window, I kept at it.
I went looking for a way to get the keyboard input directly. Looked up how to do a hook, something I haven't tried since dos days.
Found SetWindowsHook, but also found you could hook much more than just the keyboard, including the messages!
Hooked the messages and sure enough, I finally got WM_CHAR. As a bonus, I now got the cursor keys in the WM_KEYDOWN which I was not getting in the modal dialog.
Simple code:
in init:
inv GetCurrentThreadId
inv SetWindowsHookEx,WH_MSGFILTER,addr MyMessageHook,0,eax
mov hHook,eax
hook proc:
MyMessageHook proc code,wParam,lParam
.if code==MSGF_DIALOGBOX
mov ecx,lParam
mov eax,[ecx].MSG.message
.if eax==WM_CHAR
invoke SendMessage,hInputSearchDialog,eax,[ecx].MSG.wParam,[ecx].MSG.lParam
.endif
.endif
inv CallNextHookEx, hHook, code, wParam, lParam
ret
MyMessageHook endp
At exit:
invoke UnhookWindowsHookEx, hHook
Easy, and gives me everything I wanted :bgrin:
Quote from: dedndave on September 01, 2017, 01:15:40 AM
John (Sinsi) has the right answer - create a window with a WndProc
for dialog windows, the OS provides the actual WndProc and sends only
messages they felt were pertinent to the DlgProc, handling the rest internally
by the way, i see your 7366 post count, JJ
trying to sneak up on me, eh ? :P
Hello Dave
keep posting ! :t