News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

WM_CHAR in dialogbox procedure

Started by jimg, August 30, 2017, 11:09:52 AM

Previous topic - Next topic

jimg

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?

jj2007

Hi Jim,
Can't help you without seeing complete code but you are not alone with your problem. Hope it helps...

sinsi

Does it have to be a dialog? Why not a simple RegisterClassEx/CreateWindowEx?
🍺🍺🍺

jj2007

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".

aw27

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

jimg

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.



jimg

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.


jj2007

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 ;)


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.

jimg

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.

aw27

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?

Vortex

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

jimg

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.

aw27

@jimg
I meant some program issuing it to prevent the screensaver from triggering.  :icon_rolleyes:

jimg

Oh.  Nope, screen saver kicks in when expected.   Hopefully it's not a keylogger or something.

aw27

So it is not a result of a simulated keystroke.   :(
And unfortunately is not easy to find the origin of windows messages.  :(