The MASM Forum

General => The Campus => Topic started by: jimg on August 30, 2017, 11:09:52 AM

Title: WM_CHAR in dialogbox procedure
Post by: jimg on August 30, 2017, 11:09:52 AM
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?
Title: Re: WM_CHAR in dialogbox procedure
Post by: jj2007 on August 30, 2017, 05:18:22 PM
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...
Title: Re: WM_CHAR in dialogbox procedure
Post by: sinsi on August 30, 2017, 05:26:31 PM
Does it have to be a dialog? Why not a simple RegisterClassEx/CreateWindowEx?
Title: Re: WM_CHAR in dialogbox procedure
Post by: jj2007 on August 30, 2017, 06:13:33 PM
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".
Title: Re: WM_CHAR in dialogbox procedure
Post by: aw27 on August 30, 2017, 06:56:26 PM
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
Title: Re: WM_CHAR in dialogbox procedure
Post by: jimg on August 31, 2017, 12:04:06 AM
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.


Title: Re: WM_CHAR in dialogbox procedure
Post by: jimg on August 31, 2017, 12:33:32 AM
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.

Title: Re: WM_CHAR in dialogbox procedure
Post by: jj2007 on August 31, 2017, 01:01:38 AM
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.
Title: Re: WM_CHAR in dialogbox procedure
Post by: jimg on August 31, 2017, 02:46:23 AM
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.
Title: Re: WM_CHAR in dialogbox procedure
Post by: aw27 on August 31, 2017, 03:22:21 AM
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?
Title: Re: WM_CHAR in dialogbox procedure
Post by: Vortex on August 31, 2017, 03:26:12 AM
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
Title: Re: WM_CHAR in dialogbox procedure
Post by: jimg on August 31, 2017, 04:06:36 AM
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.
Title: Re: WM_CHAR in dialogbox procedure
Post by: aw27 on August 31, 2017, 05:03:34 AM
@jimg
I meant some program issuing it to prevent the screensaver from triggering.  :icon_rolleyes:
Title: Re: WM_CHAR in dialogbox procedure
Post by: jimg on August 31, 2017, 07:10:29 AM
Oh.  Nope, screen saver kicks in when expected.   Hopefully it's not a keylogger or something.
Title: Re: WM_CHAR in dialogbox procedure
Post by: aw27 on August 31, 2017, 11:16:48 AM
So it is not a result of a simulated keystroke.   :(
And unfortunately is not easy to find the origin of windows messages.  :(
Title: Re: WM_CHAR in dialogbox procedure
Post by: 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
Title: Re: WM_CHAR in dialogbox procedure
Post by: jj2007 on September 01, 2017, 02:02:19 AM
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
Title: Re: WM_CHAR in dialogbox procedure
Post by: jimg on September 01, 2017, 03:08:25 AM
Dave!

Haven't seen a post from you in a while :)
Title: Re: WM_CHAR in dialogbox procedure
Post by: jimg on September 01, 2017, 03:19:36 AM
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:
Title: Re: WM_CHAR in dialogbox procedure
Post by: RuiLoureiro on September 01, 2017, 04:02:12 AM
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