Processing DBCS input from a keyboard

┌──────────────────────────────────────────────────────────────────────┐
│A WM_CHAR message contains either a SBCS character or a DBCS character│
│when the message queue code page is for DBCS.                         │
└──────────────────────────────────────────────────────────────────────┘

On OS/2 PM, a WM_CHAR message is sent to the window when an end user presses a key. When a SBCS character is conveyed, CHAR1FROMMP contains its character code and CHAR2FROMMP contains a null character (00H). When a DBCS character is conveyed, CHAR1FROMMP contains the first byte of its character code and CHAR2FROMMP contains the second byte of its character code.
WM_CHAR

The MP2 of WM_CHAR containing a double-byte character:

     ┌─────────┬─────────┬─────────┬─────────┐
     │         │         │ The 2nd │ The 1st │
     │         │         │ byte of │ byte of │
     │         │         │ a DBC   │ a DBCS  │
     └─────────┴─────────┴─────────┴─────────┘
BIT 31                  15                   0

The MP2 of WM_CHAR containing a single-byte character:

     ┌─────────┬─────────┬─────────┬─────────┐
     │         │         │         │         │
     │         │         │ 00      │ a SBC   │
     │         │         │         │         │
     └─────────┴─────────┴─────────┴─────────┘
BIT 31                  15                   0

The following is the structure of a code fragment which can correctly handle WM_CHAR messages containing either SBCS or DBCS characters.
Processing WM_CHAR message

   ...
case WM_CHAR:
    fs = SHORT1FROMMP(mp1);
    if( (fs & KC_KEYUP) == 0 ) {
       if( (fs & KC_CHAR) != 0 ) {
         if( CHAR2FROMMP(mp2) != 0 ) {
            /* WM_CHAR conveys a doubl-byte character */
            ...
         }
         else {
            /* WM_CHAR conveys a single-byte character */
            ...
         }
       }
       else if( (fs & KC_VIRTUALKEY) != 0 ) {
            /* Processing virtual keys */
            ...
       }
    }
    break;
   ...
┌──────────────────────────────────────────────────────────────────────┐
│The wchar_t data type is useful to handle mixed string as a normalized│
│format.                                                               │
└──────────────────────────────────────────────────────────────────────┘

Normalization is a method to represent both SBCS and DBCS characters in the same format. By this method, an application programmer does not need to distinguish DBCS from SBCS, because all characters are represented as a character, regardless of single-byte or double-byte.

The wchat_t data type is a C language data type used for normalization. The normalized format should be used as a process code. The conversion for normalization should be performed at input and output time. IBM SAA level 2 defines several functions for wchar_t string manipulation, which are available on IBM C/C++ Tools.

The following example shows how the WM_CHAR message is treated by using wchar_t. See the application does not check if the input is DBCS or SBCS.
Processing a WM_CHAR message with wchar_t(source: MISCEDIT.C)

   ...
#include <stdlib.h>
   ...
static BOOL isChar( MPARAM mp1, MPARAM mp2 );
static BOOL isKeyUp( MPARAM mp1 );
static wchar_t createChar( MPARAM mp );
   ...
MRESULT EXPENTRY editorWinProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
static BOOL flSpot = FALSE;     /* indicates if on-the-spot is performed */
   ...
   switch( msg )
   {
   ...
      case WM_CHAR:
        if( isKeyUp( mp1 ) == TRUE )  break;
   ...
        if( isChar( mp1, mp2 ) == TRUE )
        {
           if( curpos.usCharNum < MAX_KEY_IN )
           {
            long cx;
            wchar_t wc[2];

               wc[0] = currentLine->wcChars[curpos.usCharNum]
                     = createChar( mp2 );
   ...
           }
        }
   ...
}
/******************************************/
/* isxxx:                                 */
/*  Check routine for input key value.    */
/******************************************/
static BOOL isChar( MPARAM mp1, MPARAM mp2 )
{
   /* should check virtual key first */
   if( (SHORT1FROMMP( mp1 ) & KC_VIRTUALKEY) != 0 )
   {
      if( SHORT2FROMMP( mp2 ) == VK_SPACE )  return TRUE;   /* space key */
      else  return FALSE;
   }
   else return( (SHORT1FROMMP( mp1 ) & KC_CHAR) != 0 );
}
static BOOL isKeyUp( MPARAM mp1 )
{
   return( (SHORT1FROMMP( mp1 ) & KC_KEYUP) != 0 );
}
/*******************************************/
/* createChar:                             */
/*  create a wide character from a message */
/*  parameter specified by mp.             */
/*******************************************/
static wchar_t createChar( MPARAM mp )
{
 char temp[3];
 wchar_t wc;

   temp[0] = CHAR1FROMMP( mp );
   temp[1] = CHAR2FROMMP( mp );
   temp[2] = '\0';
   mbtowc( &wc, temp, MB_LEN_MAX );
   return( wc );
}


[Back: Allowing a user to perform on-the-spot conversion]
[Next: Processing DBCS strings]