jjryu 2009. 1. 21. 01:02
#define _STLP_NEW_PLATFORM_SDK 1

#include <windows.h>
#include <dinput.h>
#include <stdio.h>
#include <dsound.h>

char                    c_szClassName[] = "사운드출력" ;

HINSTANCE                g_hInst ;
BOOL                    g_bPaused = TRUE ;

LPDIRECTINPUT            g_lpDirectInput ;
LPDIRECTINPUTDEVICE        g_lpKeyboard ;
char                    g_szText[1024] = "00" ;
int                        X_pos, Y_pos ;

#define KEYDOWN(State,KeyID)    (State[KeyID] & 0x80)

#ifdef DS
#define NUM_SOUNDS        5

#define SPACE            0
#define LEFT            1
#define RIGHT            2
#define UP                3
#define DOWN            4

HWND                    g_hWnd = NULL ;

LPDIRECTSOUND            g_lpDirectSound = NULL ;
LPDIRECTSOUNDBUFFER        g_lpSoundBuffer[NUM_SOUNDS] ;

#ifdef _3DS
LPDIRECTSOUND3DLISTENER    g_lpDirectSound3dListener ;
LPDIRECTSOUNDBUFFER        g_lpDirectSoundBuffer ;
LPDIRECTSOUND3DBUFFER    g_lp3DSoundBuffer[NUM_SOUNDS] ;
#endif

#pragma pack(1)
struct WaveHeader
{
    BYTE        RIFF[4];          // "RIFF"
    DWORD       dwSize;           // Size of data to follow
    BYTE        WAVE[4];          // "WAVE"
    BYTE        fmt_[4];          // "fmt "
    DWORD       dw16;             // 16
    WORD        wOne_0;           // 1
    WORD        wChnls;           // Number of Channels
    DWORD       dwSRate;          // Sample Rate
    DWORD       BytesPerSec;      // Sample Rate
    WORD        wBlkAlign;        // 1
    WORD        BitsPerSample;    // Sample size
    BYTE        DATA[4];          // "DATA"
    DWORD       dwDSize;          // Number of Samples
};
#pragma pack()

#ifdef _3DS

//----------------------------------------------------------------------
//
// Function     : CreateSoundBuffer3D()
//
// Purpose      : Creates a 3D sound buffer and returns the sound buffer
//
//----------------------------------------------------------------------
/****************************************************************************
 *
 *      CreateSoundBuffer3D
 *
 *      3D 사운드 버퍼를 생성하고 그 값을 리턴한다.
 *
 ****************************************************************************/

IDirectSoundBuffer *CreateSoundBuffer3D ()
{
    IDirectSoundBuffer    *lpDirectSoundBuffer = NULL ;
    DSBUFFERDESC        dsbDesc = {0} ;
    HRESULT                hResult ;

    ZeroMemory (&dsbDesc, sizeof (DSBUFFERDESC)) ;

    dsbDesc.dwSize  = sizeof (dsbDesc) ;
    dsbDesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER ;
    dsbDesc.dwBufferBytes = 0 ;

    hResult = g_lpDirectSound->CreateSoundBuffer
                    (&dsbDesc, &lpDirectSoundBuffer, NULL) ;

    if (hResult != DS_OK)
        lpDirectSoundBuffer = NULL ;

    return lpDirectSoundBuffer ;
}

#endif

/****************************************************************************
 *
 *      PlaySoundDS
 *
 *      DirectSound를 이용하여 사운드를 출력시킨다.
 *
 ****************************************************************************/

BOOL PlaySoundDS (DWORD dwSound, D3DVECTOR d3dvPos, DWORD dwFlags)
{
    HRESULT    hResult ;
    DWORD    dwStatus ;

    if (dwSound >= NUM_SOUNDS)
        return FALSE ;

    if (g_lpSoundBuffer[dwSound])
    {
        hResult = g_lpSoundBuffer[dwSound]->GetStatus (&dwStatus) ;

        if (hResult != DS_OK)
        {
            MessageBox (g_hWnd, "GetStatus 에러", "사운드출력", MB_OK) ;
            return FALSE;
        }

        if ((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING)
        {

#ifdef _3DS

            hResult = g_lp3DSoundBuffer[dwSound]->SetPosition
                (d3dvPos.x, d3dvPos.y, d3dvPos.z, DS3D_IMMEDIATE) ;

            if (hResult != DS_OK)
            {
                MessageBox (g_hWnd, "SetPosition 에러", "사운드출력", MB_OK) ;
                return FALSE;
            }

#endif

            hResult = g_lpSoundBuffer[dwSound]->Play (0, 0, dwFlags) ;

            if (hResult != DS_OK)
            {
                MessageBox (g_hWnd, "Play 에러", "사운드출력", MB_OK) ;
                return FALSE;
            }
        }
    }

    return TRUE ;
}

/****************************************************************************
 *
 *      OutputSound
 *
 *      Sound를 출력한다.
 *
 ****************************************************************************/

void OutputSound (DWORD dwSound)
{
    D3DVECTOR d3dvPos ;

    d3dvPos.x = D3DVAL(0) ;
    d3dvPos.y = D3DVAL(0) ;
    d3dvPos.z = D3DVAL(0) ;

    PlaySoundDS (dwSound, d3dvPos, NULL) ;
}

/****************************************************************************
 *
 *      ReadData
 *
 *      웨이브(*.wav) 화일로부터 데이타를 읽어들인다.
 *
 ****************************************************************************/

BOOL ReadData (LPDIRECTSOUNDBUFFER lpSoundBuffer,
               FILE* pFile, DWORD dwSize, DWORD dwPos)
{
    LPVOID    lpData1 ;
    DWORD    dwData1Size ;
    LPVOID    lpData2 ;
    DWORD    dwData2Size ;
    HRESULT    hResult ;

    if (dwPos != 0xffffffff)
    {
        if (fseek (pFile, dwPos, SEEK_SET) != 0)
        {
            return FALSE ;
        }
    }

    hResult = lpSoundBuffer->Lock (0, dwSize, &lpData1, &dwData1Size,
                        &lpData2, &dwData2Size, DSBLOCK_FROMWRITECURSOR);

    if (hResult != DS_OK)
    {
        MessageBox (g_hWnd, "Lock 에러", "사운드출력", MB_OK) ;
        return FALSE;
    }

    if (dwData1Size > 0)
    {
        if (fread (lpData1, dwData1Size, 1, pFile) != 1)
        {
            char holder[256] ;

            wsprintf (holder, "Data1 : %d, dwdata: %d, pFile: %d",
                                            lpData1, dwData1Size, pFile) ;
            MessageBox (g_hWnd, holder, "사운드출력", MB_OK) ;

            return FALSE ;
        }
    }

    if (dwData2Size > 0)
    {
        if (fread (lpData2, dwData2Size, 1, pFile) != 1)
        {
            MessageBox (g_hWnd, "fread::lpData2 에러", "사운드출력", MB_OK) ;
            return FALSE ;
        }
    }
    
    hResult = lpSoundBuffer->Unlock (lpData1, dwData1Size, lpData2, dwData2Size) ;

    if (hResult != DS_OK)
    {
        MessageBox (g_hWnd, "Unlock 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

    return TRUE ;
}

/****************************************************************************
 *
 *      CreateSoundBuffer
 *
 *      DirectSound 버퍼를 생성한다.
 *
 ****************************************************************************/

BOOL CreateSoundBuffer (DWORD dwBuf, DWORD dwBufSize, DWORD dwFreq,
                        DWORD dwBitsPerSample, DWORD dwBlkAlign, BOOL bStereo)
{
    PCMWAVEFORMAT    pcmwf ;
    DSBUFFERDESC    dsbdesc ;
    HRESULT            hResult ;
    
    memset (&pcmwf, 0, sizeof (PCMWAVEFORMAT)) ;

    pcmwf.wf.wFormatTag            = WAVE_FORMAT_PCM ;
    pcmwf.wf.nChannels            = bStereo ? 2 : 1 ;
    pcmwf.wf.nSamplesPerSec        = dwFreq ;
    pcmwf.wf.nBlockAlign        = (WORD)dwBlkAlign ;
    pcmwf.wf.nAvgBytesPerSec    = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign ;
    pcmwf.wBitsPerSample        = (WORD)dwBitsPerSample ;

    memset (&dsbdesc, 0, sizeof (DSBUFFERDESC)) ;
    
    dsbdesc.dwSize                = sizeof (DSBUFFERDESC) ;
    dsbdesc.dwFlags                = 0 ;
#ifdef _3DS
    dsbdesc.dwFlags                = DSBCAPS_CTRL3D ;
#else
    dsbdesc.dwFlags                |= DSBCAPS_STATIC ;
    dsbdesc.dwFlags                |= DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2 ;
#endif
    dsbdesc.dwBufferBytes        = dwBufSize ;
    dsbdesc.lpwfxFormat            = (LPWAVEFORMATEX)&pcmwf ;

    hResult = g_lpDirectSound->CreateSoundBuffer
                    (&dsbdesc, &g_lpSoundBuffer[dwBuf], NULL) ;

    if (hResult != DS_OK)
    {
        MessageBox (g_hWnd, "CreateSoundBuffer 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

#ifdef _3DS
    hResult = g_lpSoundBuffer[dwBuf]->QueryInterface
        (IID_IDirectSound3DBuffer, (void**) &g_lp3DSoundBuffer[dwBuf]) ;

    if (hResult != DS_OK)
    {
        MessageBox (g_hWnd, "QueryInterface<-CreateSoundBuffer 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

#endif

    return TRUE ;
}

/****************************************************************************
 *
 *      CreateSoundBufferFromWaveFile
 *
 *      웨이브(.wav)화일읽 읽어들여와 DirectSound 버퍼를 생성한다.
 *
 ****************************************************************************/

BOOL CreateBufferFromWaveFile (char* FileName, DWORD dwBuf)
{
    WaveHeader    wavHdr;
    DWORD        dwSize ;
    BOOL        bStereo ;
    FILE        *pFile ;
        
    pFile = fopen (FileName,"rb") ;

    if (pFile == NULL)
        return FALSE ;

    if (fread (&wavHdr, sizeof (wavHdr), 1, pFile) != 1)
    {
        fclose (pFile) ;
        return NULL ;
    }

    dwSize  = wavHdr.dwDSize ;
    bStereo = wavHdr.wChnls > 1 ? TRUE : FALSE ;

    if (!CreateSoundBuffer (dwBuf, dwSize, wavHdr.dwSRate,
                wavHdr.BitsPerSample, wavHdr.wBlkAlign, bStereo))
    {
        fclose (pFile) ;
        return FALSE ;
    }

    if (!ReadData (g_lpSoundBuffer[dwBuf], pFile, dwSize, sizeof (wavHdr)))
    {
        fclose (pFile) ;
        return FALSE ;
    }

    fclose (pFile) ;

    return TRUE ;
}

#endif

/****************************************************************************
 *
 *      DirectInput_Init
 *
 *      DirectInput에 대한 초기화를 수행한다.
 *
 *        다음 순서대로 함수를 호출한다.
 *
 *      DirectInputCreate
 *      IDirectInput::CreateDevice
 *      IDirectInputDevice::SetDataFormat
 *      IDirectInputDevice::SetCooperativeLevel
 *
 ****************************************************************************/

BOOL DirectInput_Init (HWND hwnd)
{
    HRESULT hResult ;

    hResult = DirectInputCreate (g_hInst, DIRECTINPUT_VERSION, &g_lpDirectInput, NULL) ;

    if (hResult != DI_OK)
    {
        MessageBox (hwnd, "DirectInputCreate 에러", "키보드입력", MB_OK) ;
        return FALSE ;
    }

    hResult = g_lpDirectInput->CreateDevice (GUID_SysKeyboard, &g_lpKeyboard, NULL) ;

    if (hResult != DI_OK)
    {
        MessageBox (hwnd, "CreateDevice 에러", "키보드입력", MB_OK) ;
        return FALSE ;
    }

    hResult = g_lpKeyboard->SetDataFormat (&c_dfDIKeyboard) ;

    if (hResult != DI_OK)
    {
        MessageBox (hwnd, "SetDataFormat 에러", "키보드입력", MB_OK) ;
        return FALSE ;
    }

    hResult = g_lpKeyboard->SetCooperativeLevel
                (hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND) ;

    if (hResult != DI_OK)
    {
        MessageBox (hwnd, "SetCooperativeLevel 에러", "키보드입력", MB_OK) ;
        return FALSE ;
    }
#ifdef DS

    hResult = DirectSoundCreate (NULL, &g_lpDirectSound, NULL) ;

    if (hResult != DS_OK)
    {
        MessageBox (hwnd, "DirectSoundCreate 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

    g_lpDirectSound->SetCooperativeLevel (hwnd, DSSCL_NORMAL) ;

    if (hResult != DS_OK)
    {
        MessageBox (hwnd, "SetCooperativeLevel 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

#ifdef _3DS

    g_lpDirectSoundBuffer = CreateSoundBuffer3D () ;

    if (g_lpDirectSoundBuffer == NULL)
    {
        MessageBox (hwnd, "CreateSoundBuffer3D 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

    hResult = g_lpDirectSoundBuffer->QueryInterface
                (IID_IDirectSound3DListener, (void**) &g_lpDirectSound3dListener) ;

    if (hResult != DS_OK)
    {
        MessageBox (hwnd, "QueryInterface 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

    g_lpDirectSound3dListener->SetRolloffFactor ((FLOAT).01,DS3D_DEFERRED) ;
    g_lpDirectSound3dListener->SetOrientation (-D3DVAL(1), D3DVAL(0),
            D3DVAL(0), D3DVAL(0), D3DVAL(1), D3DVAL(0), DS3D_DEFERRED) ;
    g_lpDirectSound3dListener->CommitDeferredSettings () ;

#endif

    for (int i = 0; i < NUM_SOUNDS; i ++)
    {
        g_lpSoundBuffer[i] = NULL ;
    }

    if (!CreateBufferFromWaveFile ("SPACE.WAV", SPACE))
    {
        MessageBox (hwnd, "CreateBufferFromWaveFile (SPACE) 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

    if (!CreateBufferFromWaveFile ("LEFT.WAV", LEFT))
    {
        MessageBox (hwnd, "CreateBufferFromWaveFile (LEFT) 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

    if (!CreateBufferFromWaveFile ("RIGHT.WAV", RIGHT))
    {
        MessageBox (hwnd, "CreateBufferFromWaveFile (RIGHT) 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

    if (!CreateBufferFromWaveFile ("UP.WAV", UP))
    {
        MessageBox (hwnd, "CreateBufferFromWaveFile (UP) 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

    if (!CreateBufferFromWaveFile ("DOWN.WAV", DOWN))
    {
        MessageBox (hwnd, "CreateBufferFromWaveFile (DOWN) 에러", "사운드출력", MB_OK) ;
        return FALSE ;
    }

#endif

    return TRUE ;
}

/****************************************************************************
 *
 *      DirectInput_End
 *
 *      프로그램의 종료시 생성된 DirectInput 객체들을 해제시킨다.
 *
 ****************************************************************************/

void DirectInput_End (void)
{
    if (g_lpKeyboard)
    {
        g_lpKeyboard->Unacquire () ;
        g_lpKeyboard->Release () ;
        g_lpKeyboard = NULL ;
    }
    if (g_lpDirectInput)
    {
        g_lpDirectInput->Release () ;
        g_lpDirectInput = NULL ;
    }

#ifdef DS

    for (int i=0; i<NUM_SOUNDS; i++)
    {
        if (g_lpSoundBuffer[i])
        {
            g_lpSoundBuffer[i]->Release () ;
            g_lpSoundBuffer[i] = NULL ;
        }
    }

#ifdef _3DS

    for (i=0; i<NUM_SOUNDS; i++)
    {
        if (g_lp3DSoundBuffer[i])
        {
            g_lp3DSoundBuffer[i]->Release () ;
            g_lp3DSoundBuffer[i] = NULL ;
        }
    }

    if (g_lpDirectSound3dListener)
    {
        g_lpDirectSound3dListener->Release () ;
        g_lpDirectSound3dListener = NULL ;
    }

    if (g_lpDirectSoundBuffer)
    {
        g_lpDirectSoundBuffer->Release () ;
        g_lpDirectSoundBuffer = NULL ;
    }

#endif

    if (g_lpDirectSound)
    {
        g_lpDirectSound->Release () ;
        g_lpDirectSound = NULL ;
    }

#endif
}

/****************************************************************************
 *
 *      OnPaint
 *
 *      현재 눌려진 키보드의 상태를 화면상에 보여준다.
 *
 ****************************************************************************/

LRESULT OnPaint (HWND hwnd)
{
    PAINTSTRUCT ps;
    
    HDC hdc = BeginPaint (hwnd, &ps) ;

    if (hdc)
    {
        ExtTextOut (hdc, X_pos, Y_pos, ETO_OPAQUE, &ps.rcPaint, g_szText,
                        lstrlen(g_szText), NULL) ;

        EndPaint (hwnd, &ps) ;
    }

    return 0 ;
}

/****************************************************************************
 *
 *      CheckRect
 *
 *      현재 x와 y의 좌표가 윈도우를 벗어났는가 확인하고
 *
 *       x와 y의 위치에 키보드 상태를 출력하도록 한다.
 *
 ****************************************************************************/

void CheckRect (HWND hwnd, int *X_pos, int *Y_pos, char *szBuf)
{
    RECT rect ;

    GetClientRect (hwnd, &rect) ;

    if (*X_pos < 0)
        *X_pos = 0 ;
    if (*Y_pos < 0)
        *Y_pos = 0 ;
    if (*X_pos > rect.right-10)
        *X_pos = rect.right-10 ;
    if (*Y_pos > rect.bottom-10)
        *Y_pos = rect.bottom-10 ;

    lstrcpy (g_szText, szBuf) ;
    InvalidateRect (hwnd, NULL, TRUE) ;
}

/****************************************************************************
 *
 *      KeyInput
 *
 *      현재 입력된 키보드의 상태를 확인한다.
 *
 ****************************************************************************/

void KeyInput (HWND hwnd)
{
    if (g_lpKeyboard)
    {
        BYTE KeyState[256] ;
        HRESULT hResult ;

        for (;;)
        {
            hResult = g_lpKeyboard->GetDeviceState (sizeof (KeyState), &KeyState) ;

            if (hResult == DIERR_INPUTLOST)
            {
                hResult = g_lpKeyboard->Acquire () ;

                if (hResult != DI_OK)
                {
                    break ;
                }
            }
            else
                break ;
        }

        if (hResult == DI_OK)
        {
            char szBuf[1024] ;

            // 아래 있는 모든 if문을 else if 형태로 묶으면
            // 키보드 동시입력을 지원하지 못하게 된다.
            // 그러므로 동시에 입력되도록 if 문으로
            // 각각의 키를 매순간 모두 비교해야 한다.

            if (KEYDOWN(KeyState, DIK_RIGHT))
            {
                lstrcpy (szBuf, "Right") ;
                X_pos+=10 ;

                CheckRect (hwnd, &X_pos, &Y_pos, szBuf) ;
#ifdef DS
                OutputSound (RIGHT) ;
#endif
            }
            else if (KEYDOWN(KeyState, DIK_LEFT))
            {
                lstrcpy (szBuf, "Left") ;
                X_pos-=10 ;

                CheckRect (hwnd, &X_pos, &Y_pos, szBuf) ;
#ifdef DS
                OutputSound (LEFT) ;
#endif
            }

            if (KEYDOWN(KeyState, DIK_UP))
            {
                lstrcpy (szBuf, "Up") ;
                Y_pos-=10 ;

                CheckRect (hwnd, &X_pos, &Y_pos, szBuf) ;
#ifdef DS
                OutputSound (UP) ;
#endif
            }
            else if (KEYDOWN(KeyState, DIK_DOWN))
            {
                lstrcpy (szBuf, "Down") ;
                Y_pos+=10 ;

                CheckRect (hwnd, &X_pos, &Y_pos, szBuf) ;
#ifdef DS
                OutputSound (DOWN) ;
#endif
            }

            if (KEYDOWN(KeyState, DIK_ESCAPE))
            {
                lstrcpy (szBuf, "Esc") ;
                lstrcpy (g_szText, szBuf) ;
                InvalidateRect (hwnd, NULL, TRUE) ;
            }

            if (KEYDOWN(KeyState, DIK_SPACE))
            {
                lstrcpy (szBuf, "SPACE") ;
                lstrcpy (g_szText, szBuf) ;
                InvalidateRect (hwnd, NULL, TRUE) ;
#ifdef DS
                OutputSound (SPACE) ;
#endif
            }

            if (KEYDOWN(KeyState, DIK_LSHIFT))
            {
                lstrcpy (szBuf, "LShift") ;
                lstrcpy (g_szText, szBuf) ;
                InvalidateRect (hwnd, NULL, TRUE) ;
            }

            if (KEYDOWN(KeyState, DIK_RSHIFT))
            {
                lstrcpy (szBuf, "RShift") ;
                lstrcpy (g_szText, szBuf) ;
                InvalidateRect (hwnd, NULL, TRUE) ;
            }
        }
    }
}

/****************************************************************************
 *
 *      SyncAcquire
 *
 *      g_bPaused의 상태에 따라서 Acquire ()를 호출할 것인지
 *
 *      Unacquire ()를 호출할 것인지를 결정한다.
 *
 ****************************************************************************/

void SyncAcquire (HWND hwnd)
{
    if (g_bPaused)
    {
        if (g_lpKeyboard)
            g_lpKeyboard->Unacquire () ;
    }
    else
    {
        if (g_lpKeyboard)
            g_lpKeyboard->Acquire () ;
    }
}

/****************************************************************************
 *
 *      WndProc
 *
 *      윈도우로 입력되는 메세지들을 처리하는 부분
 *
 ****************************************************************************/

LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_PAINT:
            return OnPaint (hwnd) ;

        case WM_ACTIVATE:
            if (wParam == WA_INACTIVE)
                g_bPaused = TRUE ;
            else
                g_bPaused = FALSE ;

            SyncAcquire (hwnd) ;
            break;

        case WM_DESTROY:
            PostQuitMessage (0) ;
            break;
    }

    return DefWindowProc (hwnd, msg, wParam, lParam) ;
}

/****************************************************************************
 *
 *      AppInit
 *
 *      윈도우의 생성시 필요한 값들을 초기화한다.
 *
 ****************************************************************************/

HWND AppInit (HINSTANCE hinst, int nCmdShow)
{
    g_hInst = hinst ;

    WNDCLASS wc ;

    wc.hCursor        = LoadCursor (0, IDC_ARROW) ;
    wc.hIcon          = LoadIcon (NULL, MAKEINTRESOURCE(IDI_APPLICATION)) ;
    wc.lpszMenuName   = NULL ;
    wc.lpszClassName  = c_szClassName ;
    wc.hbrBackground  = 0 ;
    wc.hInstance      = hinst ;
    wc.style          = 0 ;
    wc.lpfnWndProc    = WndProc ;
    wc.cbClsExtra     = 0 ;
    wc.cbWndExtra     = 0 ;

    if (!RegisterClass (&wc))
    {
        return NULL ;
    }

    HWND hwnd = CreateWindow (
                        c_szClassName,
                        "사운드 입력",
                        WS_OVERLAPPEDWINDOW,
                        CW_USEDEFAULT, CW_USEDEFAULT,
                        CW_USEDEFAULT, CW_USEDEFAULT,
                        NULL,
                        NULL,
                        g_hInst,
                        0
                        ) ;

    g_hWnd = hwnd ;

    if (!DirectInput_Init (hwnd))
    {
        DestroyWindow (hwnd) ;
        return NULL ;
    }

    ShowWindow (hwnd, nCmdShow) ;

    return hwnd ;
}

/****************************************************************************
 *
 *      WinMain
 *
 *      윈도우즈의 메인함수.
 *
 ****************************************************************************/

int PASCAL WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
{
    MSG msg ;
    
    HWND hwnd = AppInit (hinst, nCmdShow) ;

    msg.wParam = 0 ;
    X_pos = Y_pos = 0 ;

    if (hwnd)
    {

        for (;;)
        {
            if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
            {
                if (msg.message == WM_QUIT)
                {
                    break;
                }
                else
                {
                    TranslateMessage (&msg) ;
                    DispatchMessage (&msg) ;
                }
            }
            else if (g_bPaused)
            {
                WaitMessage () ;
            }
            else
            {
                KeyInput (hwnd) ;
            }
        }
    }

    DirectInput_End () ;

    return msg.wParam ;
}