Results 1 to 18 of 18

Thread: [RESOLVED] How to get Unicode char on IME window in VB6?

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Resolved [RESOLVED] How to get Unicode char on IME window in VB6?

    You just imagine you are doing an Editable Flexgrid or Grid type of UserControl...

    I have a Flexgrid. I add a textbox for text input.
    Double Click the Cell, the textbox will appear then I can typing my text without any problem. After typing, I press <Enter> key to move focus to next Cell (textbox will turn invisible,the text set to Cell of course) ,then press Alphabetic Key, before textbox1 turn visible, the Alphabetic KeyCode automatically goto invisible textbox,after that,the textbox appear.

    The problem is that I lost Unicode if the Alphabetic KeyCode represent Unicode on IME But English and numeric is always OK.

    The sequence logic is:

    Select a Cell by Mouse --> Press <Alphabetic Key> -->Bring out IME -->IME will appear word combinations ---> I choose the 1st then press <Enter> key --> the TextBox appearing with the word -->Textbox got focus already,I can typing what I want -->Press Enter key to finish typing--->Focus Move to Next Cell ---> Press <Alphabetic Key> ---...

    The problem is not vb6 textbox is non-unicode, VB6 textbox fully support Chinese/Japanese/Korean when OS is Chinese/Japanese/Korean
    The problem is how to get IME Unicode without using Textbox or RichEdit.

    I made a demo for simulation.
    1. Select your IME input Language except English, otherwise,IME window doesn't appear. I use Baidu input as IME. You can use MS IME.
    2. Click Picture1 to gain focus
    3. Typing Alphabetic Key, IME is appearing and IME windows got few word combinations. Choose one.
    4. Enter key to transfer text on IME to textbox.
    5. The word is suppose go to invisible textbox before visible.
    6. After textbox visible, I see my Unicode lost with question mark or weird characters.

    Refer to screenshot and demo project.

    You also can learn how to pisition IME window.

    Code:
    Select Case uMsg
        Case WM_IME_SETCONTEXT
             If Not wParam = 0 Then
                Dim flag As Boolean
                flag = ImmAssociateContextEx(lng_hWnd, 0, 16)
                If flag Then
                   Dim IntPtr As Long
                   IntPtr = ImmGetContext(lng_hWnd)
                   flag = ImmSetOpenStatus(IntPtr, True)
                End If
             End If
        Case WM_IME_STARTCOMPOSITION
                Dim hIMC As Long
                hIMC = ImmGetContext(lng_hWnd)
                Dim cf As COMPOSITIONFORM
                cf.dwStyle = 2
                cf.ptCurrentPos.X = Picture1.ScaleLeft + 3
                cf.ptCurrentPos.Y = Picture1.ScaleTop + Picture1.Height - 16
                ImmSetCompositionWindow hIMC, cf
        Case WM_IME_CHAR
             'Send IME Char to Picture1.KeyPress
             Picture1_KeyPress CUIntToInt(wParam And &HFFFF&)
            
        End Select
    Attached Images Attached Images    
    Attached Files Attached Files
    Last edited by Jonney; Jan 16th, 2015 at 11:43 PM.

  2. #2

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: How to Get IME Unicode Char

    In C#, it is very easy:
    Code:
    if (msg == 646) ‘WM_IME_CHAR
        {
           this.KeyPressEvent(this, new KeyPressEventArgs(Strings.ChrW(m.WParam.ToInt32())));
           return;
        }
    Last edited by Jonney; Jan 7th, 2015 at 05:29 AM.

  3. #3

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: How to get Unicode char on IME window in VB6?

    I used ImmGetCompositionString API but always get zero size. Any idea?

    Code:
    Private Const GCS_RESULTREADSTR As Long = &H200
    Private Const GCS_COMPSTR As Long = 8
    
    Private Declare Function ImmAssociateContextEx Lib "imm32.dll" (ByVal hwnd As Long, ByVal himc As Long, ByVal dwFlags As Long) As Long
    Private Declare Function ImmGetContext Lib "imm32.dll" (ByVal hwnd As Long) As Long
    Private Declare Function ImmSetOpenStatus Lib "imm32.dll" (ByVal himc As Long, ByVal b As Long) As Long
    Private Declare Function ImmSetCompositionWindow Lib "imm32.dll" (ByVal himc As Long, lpCompositionForm As COMPOSITIONFORM) As Long
    
    Private Const WM_KEYDOWN As Long = &H100
    Private Const WM_KEYUP As Long = &H101
    Private Const WM_CHAR As Long = &H102
    Private Const WM_UNICHAR As Long = &H109, UNICODE_NOCHAR As Long = &HFFFF&
    
    Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageW" (ByRef lpMsg As TMSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
    
    Public Declare Function ImmGetCompositionStringW Lib "imm32.dll" _
               (ByVal himc As Long, ByVal dw As Long, _
                ByRef lpv As Long, ByVal dw2 As Long) As Long
    Public Declare Function ImmReleaseContext Lib "imm32.dll" (ByVal hwnd As Long, ByVal himc As Long) As Long
    
    Public Function GetCompStr(lngTargetHwnd As Long) As String
    
      Dim lngICHwnd As Long
      Dim lngdwSize As Long
      Dim strBuffer As String
    
      lngICHwnd = ImmGetContext(lngTargetHwnd)
      
      If lngICHwnd <> 0 Then
        lngdwSize = ImmGetCompositionStringW(lngICHwnd, GCS_RESULTREADSTR, 0, 0)
        
        strBuffer = String$(lngdwSize + 1, vbNullChar)
        
        lngdwSize = ImmGetCompositionStringW(lngICHwnd, GCS_RESULTREADSTR, StrPtr(strBuffer), lngdwSize + 1)
        
        Call ImmReleaseContext(lngTargetHwnd, lngICHwnd)
        
        strBuffer = Left$(strBuffer, lngdwSize)
        GetCompStr = strBuffer
    
    End If
    
    End Function
    Edited: I cannot get this GetCompStr function to work properly at this moment. Will try later on.
    Last edited by Jonney; Jan 7th, 2015 at 10:45 PM.

  4. #4

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: How to get Unicode char on IME window in VB6?

    OK.
    After I use Krool's Subclasser, now I can get CORRECT Unicode Char. Very Strange. The Subclasser may internally turn Unicode to ANSI or failed to prevent Windows from UNICODE to ANSI conversion.

    @Krool
    @Lavolpe
    @Dr.Unicode
    @Tanner
    Last edited by Jonney; Jan 7th, 2015 at 10:57 PM.

  5. #5

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    After I change "Region and Language" setting from Chinese (PRC) to English (USA), I failed to get Unicode Char again with question marks.

  6. #6

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    In Krool's TextBoxW, since it is Unicode Window which created by CreateWindowExW, I can see wParam is Unicode Keycode in WM_CHAR and WM_IME_CHAR. But the UserControl and Form is ANSI window, how to get its assocoated IME Unicode Char? I saw wParam give keycode 63 (Question mark) in in WM_CHAR and WM_IME_CHAR. Window crash the unicode.

  7. #7
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Yes, there was a lot of discussion on this in Krool's Common Controls thread. A few different solutions were provided, but georgekar gave the simplest one - here is Krool's discussion of how he used georgekar's idea:

    http://www.vbforums.com/showthread.p...=1#post4786597

    WM_CHAR and WM_IME_CHAR are too late to recover the original Unicode character. You have to cache the value before WM_CHAR; otherwise VB's ANSI pump will eat it. (Between the WM_KEYDOWN/WM_IME_KEYDOWN events, and the WM_CHAR/WM_IME_CHAR events, VB's parent window gets a chance to preview the key data, so it can look for accelerator keypresses. That preview is what ruins Unicode data, because VB uses TranslateMessageA.)

    I think georgekar's solution could also be used for the IME window, but in the WM_IME_KEYDOWN event instead of WM_KEYDOWN. Use PeekMessage in the same way, to see the correct Unicode character value in WM_IME_KEYDOWN. Cache this value, then later, when WM_IME_CHAR happens, you can use the cached value to obtain the correct Unicode value, since you intercepted it before VB's ANSI message pump ruined it.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  8. #8

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Quote Originally Posted by Tanner_H View Post
    Yes, there was a lot of discussion on this in Krool's Common Controls thread. A few different solutions were provided, but georgekar gave the simplest one - here is Krool's discussion of how he used georgekar's idea:

    http://www.vbforums.com/showthread.p...=1#post4786597

    WM_CHAR and WM_IME_CHAR are too late to recover the original Unicode character. You have to cache the value before WM_CHAR; otherwise VB's ANSI pump will eat it. (Between the WM_KEYDOWN/WM_IME_KEYDOWN events, and the WM_CHAR/WM_IME_CHAR events, VB's parent window gets a chance to preview the key data, so it can look for accelerator keypresses. That preview is what ruins Unicode data, because VB uses TranslateMessageA.)

    I think georgekar's solution could also be used for the IME window, but in the WM_IME_KEYDOWN event instead of WM_KEYDOWN. Use PeekMessage in the same way, to see the correct Unicode character value in WM_IME_KEYDOWN. Cache this value, then later, when WM_IME_CHAR happens, you can use the cached value to obtain the correct Unicode value, since you intercepted it before VB's ANSI message pump ruined it.
    the subclasser failed to Intercept WM_IME_CHAR for some reason.

    I think the problem is more complicated than TextBoxW. Normal UC or Form is ANSI window in locale English 1033. I see wParam is always 63 in WM_IME_CHAR or WM_UNICHAR or WM_CHAR when I am typing Unicode. But in Krool's TextBoxW (the window createWindowExW) is unicode window, I can see wParam is Unicode Keycode in English locale 1033. PeekMessage technique in Krool's TextBoxW is useful only when we using Kazah keyboard.

    The same code in C# works with whatever locale either 1033 or 2052, since C# window is always Unicode. I guess.

  9. #9
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Does the subclasser successfully intercept WM_IME_KEYDOWN or WM_KEYDOWN?

    If it does, the PeekMessage technique should work.

    PeekMessage technique in Krool's TextBoxW is useful only when we using Kazah keyboard.
    The PeekMessageW technique is useful any time you are not receiving Unicode characters correctly. (The reason for not receiving the characters doesn't really matter.)

    PeekMessage is useful because it lets you see the matching WM_CHAR (or WM_IME_CHAR, if you modify the code) for a given keypress, before the message gets dispatched to VB. So if VB's message pump is removing the Unicode character, for any reason, PeekMessage lets you work around it.

    So my question is: if you subclass WM_IME_KEYDOWN or WM_KEYDOWN, and use PeekMessageW inside the wndProc to check for a WM_CHAR (or WM_IME_CHAR) value, does PeekMessageW return the correct Unicode value?
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  10. #10

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Quote Originally Posted by Tanner_H View Post
    Does the subclasser successfully intercept WM_IME_KEYDOWN or WM_KEYDOWN?

    If it does, the PeekMessage technique should work.



    The PeekMessageW technique is useful any time you are not receiving Unicode characters correctly. (The reason for not receiving the characters doesn't really matter.)

    PeekMessage is useful because it lets you see the matching WM_CHAR (or WM_IME_CHAR, if you modify the code) for a given keypress, before the message gets dispatched to VB. So if VB's message pump is removing the Unicode character, for any reason, PeekMessage lets you work around it.

    So my question is: if you subclass WM_IME_KEYDOWN or WM_KEYDOWN, and use PeekMessageW inside the wndProc to check for a WM_CHAR (or WM_IME_CHAR) value, does PeekMessageW return the correct Unicode value?
    I can't intercept WM_IME_KEYDOWN in UserControl Subclass procedure.
    I think my problem is that IME attached to ANSI UserControl window (Form/Picturebox are all ANSI window),so WM_IME_CHAR just give me wParam=63 always.
    We can easily simulated in locale =1033 (Language setting in English USA) by turning Krools TextBoxW into ANSI using CreateWindowExA API, then WM_IME_CHAR will give 63 always. (I haven't tried, but theory is here).

  11. #11

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Quote Originally Posted by Tanner_H View Post
    Does the subclasser successfully intercept WM_IME_KEYDOWN or WM_KEYDOWN?

    If it does, the PeekMessage technique should work.



    The PeekMessageW technique is useful any time you are not receiving Unicode characters correctly. (The reason for not receiving the characters doesn't really matter.)

    PeekMessage is useful because it lets you see the matching WM_CHAR (or WM_IME_CHAR, if you modify the code) for a given keypress, before the message gets dispatched to VB. So if VB's message pump is removing the Unicode character, for any reason, PeekMessage lets you work around it.

    So my question is: if you subclass WM_IME_KEYDOWN or WM_KEYDOWN, and use PeekMessageW inside the wndProc to check for a WM_CHAR (or WM_IME_CHAR) value, does PeekMessageW return the correct Unicode value?
    I can't intercept WM_IME_KEYDOWN at all in UserControl Subclass procedure. I falied to detect this message.

    I think my problem is that IME attached to ANSI UserControl window (Form/Picturebox are all ANSI window),so WM_IME_CHAR just give me wParam=63 always because VB6 will deal with ANSI type API instead of W type API internally (sorry,not accurate really). Unicode just lost.

    We can easily simulated in locale =1033 (Region and Language setting in English USA) by turning Krools TextBoxW into ANSI using CreateWindowExA API, then WM_IME_CHAR will give 63 always if we are typing Unicode. (I haven't tried, but theory is here).

  12. #12
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Thanks for clarifying, Jonney. I also tried the sample project you provided, and even after trying many things, I couldn't find a way to successfully trap WM_IME_KEYDOWN. I have no idea why that message isn't being captured. I think LaVolpe's suggestion in your other thread, to just use a temporary TextBoxW, is the best solution.

    For what it's worth, I did find some bugs in your ImmGetCompositionString code. Change the declaration to this:

    Code:
    Public Declare Function ImmGetCompositionStringW Lib "imm32.dll" (ByVal himc As Long, ByVal dw As Long, ByVal lpv As Long, ByVal dw2 As Long) As Long
    Whenever you pass a pointer directly to an API (StrPtr, VarPtr), you need to change the API parameter to be ByVal instead of ByRef.

    Another bug is this: when you pass 0 as the length to ImmGetCompositionString, so it will return the size of the string buffer, the buffer size is returned in bytes, not characters, and it doesn't include the null-terminating character. Because of this, you might find it easier to pass the function a byte array instead of a VB string, then convert the byte array after the API has filled it.

    However, even with these changes, I still don't get useful results from the function. It could possibly be an ANSI/Unicode issue, or maybe there is another bug I haven't caught...?
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  13. #13

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Quote Originally Posted by Tanner_H View Post
    Thanks for clarifying, Jonney. I also tried the sample project you provided, and even after trying many things, I couldn't find a way to successfully trap WM_IME_KEYDOWN. I have no idea why that message isn't being captured. I think LaVolpe's suggestion in your other thread, to just use a temporary TextBoxW, is the best solution.

    For what it's worth, I did find some bugs in your ImmGetCompositionString code. Change the declaration to this:

    Code:
    Public Declare Function ImmGetCompositionStringW Lib "imm32.dll" (ByVal himc As Long, ByVal dw As Long, ByVal lpv As Long, ByVal dw2 As Long) As Long
    Whenever you pass a pointer directly to an API (StrPtr, VarPtr), you need to change the API parameter to be ByVal instead of ByRef.

    Another bug is this: when you pass 0 as the length to ImmGetCompositionString, so it will return the size of the string buffer, the buffer size is returned in bytes, not characters, and it doesn't include the null-terminating character. Because of this, you might find it easier to pass the function a byte array instead of a VB string, then convert the byte array after the API has filled it.

    However, even with these changes, I still don't get useful results from the function. It could possibly be an ANSI/Unicode issue, or maybe there is another bug I haven't caught...?
    Thank you for follow-up.
    I tried many definitions for ImmGetCompositionStringW API but always return 0. The problem is that I can't intercept most IME Message except 3: WM_IME_SETCONTEXT,WM_IME_STARTCOMPOSITION and WM_IME_CHAR.

    I do believe it can be done, since there're thousand free INPUT methods in Asia except MS keyboard PinYin.

    Wondering I haven't seen any stuff in VB6. vbaccelerator and cyberActivex don't have such stuff.

    If you got time (don't spend much), you can do some research since you have much more knowledge on Hook... than me.

    I believe Github has many projects. e.g. https://github.com/trmmy/zenisynth/b...zs_x86hook.cpp

    Search "input methods" or "IME", we can get many results.

    Edited:
    Private Declare Function ImmGetDefaultIMEWnd Lib "imm32.dll" (ByVal hwnd As Long) As Long

    can return the hWnd of IME window.
    Last edited by Jonney; Jan 21st, 2015 at 07:51 PM.

  14. #14
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    According to Handling Unicode in an IME-Aware Application:

    Quote Originally Posted by MSDN
    Your applications should use RegisterClassW to cause the WM_CHAR and WM_IME_CHAR messages to retrieve Unicode characters instead of DBCS characters in the wParam parameter.
    So, as already suggested before, creating a Unicode Edit control is your best bet.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  15. #15
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Quote Originally Posted by Bonnie West View Post
    According to Handling Unicode in an IME-Aware Application:



    So, as already suggested before, creating a Unicode Edit control is your best bet.
    Not sure if that alone will solve the issue, since VBs Main-MessagePump is still ANSI...

    I have no issues here, to capture the IME-Char-Message directly (quite similar to the C#-code the OP was showing),
    when the (Unicode)SubClassing happens against an RC5-cWidgetform (which run on their own W-capable MessagePump).

    In that case no Extra-PeekMessageW-Tricks are necessary.

    Olaf

  16. #16

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Quote Originally Posted by Schmidt View Post
    Not sure if that alone will solve the issue, since VBs Main-MessagePump is still ANSI...

    I have no issues here, to capture the IME-Char-Message directly (quite similar to the C#-code the OP was showing),
    when the (Unicode)SubClassing happens against an RC5-cWidgetform (which run on their own W-capable MessagePump).

    In that case no Extra-PeekMessageW-Tricks are necessary.

    Olaf
    Not yet study to use RichCleint5 to build an UserControl in class (or module), if a demo is available, please give me so at I can try.

    The problem is VB6's UC is ANSI window, so if locale is 1033 (English), IME never give Unicode Char KeyCode when we intercept WM_IME_CHAR / WM_UNICHAR or WM_CHAR.
    Last edited by Jonney; Jan 23rd, 2015 at 04:27 AM.

  17. #17
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,454

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Quote Originally Posted by Jonney View Post
    Not yet study to use RichCleint5 to build an UserControl in class (or module), if a demo is available, please give me so at I can try.
    Just uploaded an RC5-based IME- and QR-CoDec-Demo into the Codebank:
    http://www.vbforums.com/showthread.p...ow-Positioning

    HTH

    Olaf

  18. #18

    Thread Starter
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] How to get Unicode char on IME window in VB6?

    Quote Originally Posted by Schmidt View Post
    Just uploaded an RC5-based IME- and QR-CoDec-Demo into the Codebank:
    http://www.vbforums.com/showthread.p...ow-Positioning

    HTH

    Olaf
    Take time to digest...

    Thanks. If you know direct way instead of dependence of RichClient, please teach me.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width