/*
 * SDLDRV USER driver functions
 *
 * Copyright 1998 Patrik Stridvall
 * Copyright 2002 TransGaming Technologies, Inc.
 */

#include "config.h"

#include "gdi.h"
#include "dinput.h"
#include "sdldrv.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(sdldrv);

static WORD sdl_keysym_to_win_vk[ SDLK_LAST + 1 ];
static WORD scancode_to_win_vk[ 0x100 ];

static void SDLDRV_send_mouse_event( HWND hwnd, DWORD flags, DWORD posX, DWORD posY,
                              DWORD data, DWORD time );

static void initialize_scancode_to_vk_tbl(void);
static void initialize_keysym_translation_tbl(void);

/***********************************************************************
 *		VkKeyScan (SDLDRV.@)
 */
WORD SDLDRV_VkKeyScan(CHAR cChar)
{
  TRACE("%c\n", cChar);
  return 0;
}

/***********************************************************************
 *              MapVirtualKey (SDLDRV.@)
 */
UINT16 SDLDRV_MapVirtualKey(UINT16 wCode, UINT16 wMapType)
{
  WORD wRetVal = 0;

  switch (wMapType) {
  case 0: /* VK -> scancode */
  {
    int i;

    /* Loop over all scancodes until we can find a mapping */
    for( i = 0; i < 255; i++ )
    {
      if( scancode_to_win_vk[ i ] == wCode )
      {
        wRetVal = i;
        break;
      }
    }

    if( i == 255 )
    {
      FIXME( "Need VK (%u) -> scancode conversion.\n", wCode );
    }

    TRACE( "(%u,%u -> %u)\n", wCode, wMapType, wRetVal );

    break;
  }

  case 1: /* scancode -> VK */
    wRetVal = scancode_to_win_vk[ wCode ];

    if( wRetVal == (WORD)255 )
    {
      FIXME( "Need scancode (%u) -> VK conversion.\n", wCode );
    }

    TRACE( "(%u,%u -> %u)\n", wCode, wMapType, wRetVal );

    break;

  default:
    FIXME("(%u,%u): stub\n", wCode, wMapType);
    break;
  }
  return wRetVal;
}

/***********************************************************************
 *		GetKeyNameText (SDLDRV.@)
 */
INT16 SDLDRV_GetKeyNameText( LONG lParam, LPSTR lpBuffer, INT16 nSize )
{
  if(lpBuffer && nSize)
    {
      *lpBuffer = 0;
    }
  return 0;
}

static
WORD sdldrv_virtkey_to_keysym( UINT virtKey )
{
  unsigned int i;
  WORD wSdlKey = (UINT)SDLK_LAST;

  for( i = (unsigned int)SDLK_FIRST; i < (unsigned int)SDLK_LAST; i++ )
  {
    if( sdl_keysym_to_win_vk[ i ] == virtKey )
    {
      break;
    }
  }

  if( i == (unsigned int)SDLK_LAST )
  {
    FIXME( "Need to map %u for  VK -> SDL keysym.\n", virtKey );
  }

  wSdlKey = i;

  TRACE("VK(%u) -> SDL(%u)\n", virtKey, wSdlKey);

  return wSdlKey;
}



/***********************************************************************
 *		ToUnicode (SDLDRV.@)
 * If the specified key is a dead key, the return value is -1. Otherwise,
 * it is one of the following values:
 * Value	Meaning
 * 0	The specified virtual key has no translation for the current state of the keyboard.
 * 1	One Windows character was copied to the buffer.
 * 2	Two characters were copied to the buffer. This usually happens when a
 *      dead-key character (accent or diacritic) stored in the keyboard layout cannot
 *      be composed with the specified virtual key to form a single character.
 */
INT SDLDRV_ToUnicode( UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
		      LPWSTR pwszBuff, int cchBuff, UINT flags )
{
  BOOL bCapitalize = FALSE;
  UINT wSdlKey;

  FIXME( "(%u, %u, %p, %p, %d, %u): not fully implemented\n",
         virtKey, scanCode, lpKeyState, pwszBuff, cchBuff, flags );

  /* Have we got any space to output what we need to? */
  if( cchBuff < 1 )
  {
    return 0;
  }

  /* Should do something about capitalization */
  if( lpKeyState[VK_LSHIFT] & 0x80 ||
      lpKeyState[VK_RSHIFT] & 0x80 ||
      lpKeyState[VK_CAPITAL] & 0x80 )
  {
    bCapitalize = TRUE;
  }

  /* FIXME: Try to translate any ascii character. Is this correct? Guess so... */

  /* Convert from the VK to the SDL keysym since they're in ascii */
  wSdlKey = sdldrv_virtkey_to_keysym( virtKey );
  if( wSdlKey == (UINT)SDLK_LAST )
    return 0; /* No translation! */

  /* Key pad numbers have different SDL representation */
  if( (wSdlKey >= SDLK_KP0) && (wSdlKey <= SDLK_KP9) )
  {
    wSdlKey -= (SDLK_KP0 - SDLK_0 );
  }

  if( (wSdlKey > SDLK_FIRST) && (wSdlKey <= SDLK_DELETE) )
  {
    char char_in_string[2] = { '\0', '\0' };

    /* SDL maps everything to lower case. See if we need to capitalize */
    if( bCapitalize )
    {
      char_in_string[0] = toupper(wSdlKey);
    }
    else
    {
      char_in_string[0] = (char)wSdlKey;
    }

    return MultiByteToWideChar( CP_ACP, 0, char_in_string, 1, pwszBuff, cchBuff );
  }

  return 0;
}

/***********************************************************************
 *		Beep (SDLDRV.@)
 */
void SDLDRV_Beep(void)
{
}

/***********************************************************************
 *		SetCursor (SDLDRV.@)
 */
void SDLDRV_SetCursor( struct tagCURSORICONINFO *lpCursor )
{
}

/***********************************************************************
 *              GetScreenSaveActive (SDLDRV.@)
 *
 * Returns the active status of the screen saver
 */
BOOL SDLDRV_GetScreenSaveActive(void)
{
    return FALSE;
}

/***********************************************************************
 *              SetScreenSaveActive (SDLDRV.@)
 *
 * Activate/Deactivate the screen saver
 */
void SDLDRV_SetScreenSaveActive(BOOL bActivate)
{
    FIXME("(%d): stub\n", bActivate);
}

/***********************************************************************
 *		AcquireClipboard (SDLDRV.@)
 */
void SDLDRV_AcquireClipboard(void)
{
}

/***********************************************************************
 *		ReleaseClipboard (SDLDRV.@)
 */
void SDLDRV_ReleaseClipboard(void)
{
}

/***********************************************************************
 *		SetClipboardData (SDLDRV.@)
 */
void SDLDRV_SetClipboardData(UINT wFormat)
{
}

/***********************************************************************
 *		GetClipboardData (SDLDRV.@)
 */
BOOL SDLDRV_GetClipboardData(UINT wFormat)
{
  return FALSE;
}

/***********************************************************************
 *		IsClipboardFormatAvailable (SDLDRV.@)
 */
BOOL SDLDRV_IsClipboardFormatAvailable(UINT wFormat)
{
  return FALSE;
}

/**************************************************************************
 *		RegisterClipboardFormat (SDLDRV.@)
 *
 * Registers a custom clipboard format
 * Returns: TRUE - new format registered, FALSE - Format already registered
 */
BOOL SDLDRV_RegisterClipboardFormat( LPCSTR FormatName )
{
  return TRUE;
}

/**************************************************************************
 *		IsSelectionOwner (SDLDRV.@)
 *
 * Returns: TRUE - We(WINE) own the selection, FALSE - Selection not owned by us
 */
BOOL SDLDRV_IsSelectionOwner(void)
{
  return FALSE;
}

static
void initialize_keysym_translation_tbl(void)
{
  unsigned int sdl_keysym;

  for( sdl_keysym = 0; sdl_keysym < (unsigned int)SDLK_LAST; sdl_keysym++ )
  {
     sdl_keysym_to_win_vk[sdl_keysym] = (WORD)255; /* 255 is not used in windows a valid virtual key in windows */
  }

  /* FIXME: Reorder these in SDL order */
  /* FIXME: This is not complete at this time */

  /* FIXME: How does SDL map a keyboard setup to the SDL keysym? Does this work for Dvorak and intl? */
  sdl_keysym_to_win_vk[SDLK_BACKSPACE] = VK_BACK;
  sdl_keysym_to_win_vk[SDLK_TAB] = VK_TAB;
  sdl_keysym_to_win_vk[SDLK_CLEAR] = VK_CLEAR;
  sdl_keysym_to_win_vk[SDLK_RETURN] = VK_RETURN;
  sdl_keysym_to_win_vk[SDLK_PAUSE] = VK_PAUSE;
  sdl_keysym_to_win_vk[SDLK_ESCAPE] = VK_ESCAPE;
  sdl_keysym_to_win_vk[SDLK_SPACE] = VK_SPACE;

  sdl_keysym_to_win_vk[SDLK_0] = VK_0;
  sdl_keysym_to_win_vk[SDLK_1] = VK_1;
  sdl_keysym_to_win_vk[SDLK_2] = VK_2;
  sdl_keysym_to_win_vk[SDLK_3] = VK_3;
  sdl_keysym_to_win_vk[SDLK_4] = VK_4;
  sdl_keysym_to_win_vk[SDLK_5] = VK_5;
  sdl_keysym_to_win_vk[SDLK_6] = VK_6;
  sdl_keysym_to_win_vk[SDLK_7] = VK_7;
  sdl_keysym_to_win_vk[SDLK_8] = VK_8;
  sdl_keysym_to_win_vk[SDLK_9] = VK_9;

  sdl_keysym_to_win_vk[SDLK_a] = VK_A;
  sdl_keysym_to_win_vk[SDLK_b] = VK_B;
  sdl_keysym_to_win_vk[SDLK_c] = VK_C;
  sdl_keysym_to_win_vk[SDLK_d] = VK_D;
  sdl_keysym_to_win_vk[SDLK_e] = VK_E;
  sdl_keysym_to_win_vk[SDLK_f] = VK_F;
  sdl_keysym_to_win_vk[SDLK_g] = VK_G;
  sdl_keysym_to_win_vk[SDLK_h] = VK_H;
  sdl_keysym_to_win_vk[SDLK_i] = VK_I;
  sdl_keysym_to_win_vk[SDLK_j] = VK_J;
  sdl_keysym_to_win_vk[SDLK_k] = VK_K;
  sdl_keysym_to_win_vk[SDLK_l] = VK_L;
  sdl_keysym_to_win_vk[SDLK_m] = VK_M;
  sdl_keysym_to_win_vk[SDLK_n] = VK_N;
  sdl_keysym_to_win_vk[SDLK_o] = VK_O;
  sdl_keysym_to_win_vk[SDLK_p] = VK_P;
  sdl_keysym_to_win_vk[SDLK_q] = VK_Q;
  sdl_keysym_to_win_vk[SDLK_r] = VK_R;
  sdl_keysym_to_win_vk[SDLK_s] = VK_S;
  sdl_keysym_to_win_vk[SDLK_t] = VK_T;
  sdl_keysym_to_win_vk[SDLK_u] = VK_U;
  sdl_keysym_to_win_vk[SDLK_v] = VK_V;
  sdl_keysym_to_win_vk[SDLK_w] = VK_W;
  sdl_keysym_to_win_vk[SDLK_x] = VK_X;
  sdl_keysym_to_win_vk[SDLK_y] = VK_Y;
  sdl_keysym_to_win_vk[SDLK_z] = VK_Z;

  sdl_keysym_to_win_vk[SDLK_F1] = VK_F1;
  sdl_keysym_to_win_vk[SDLK_F2] = VK_F2;
  sdl_keysym_to_win_vk[SDLK_F3] = VK_F3;
  sdl_keysym_to_win_vk[SDLK_F4] = VK_F4;
  sdl_keysym_to_win_vk[SDLK_F5] = VK_F5;
  sdl_keysym_to_win_vk[SDLK_F6] = VK_F6;
  sdl_keysym_to_win_vk[SDLK_F7] = VK_F7;
  sdl_keysym_to_win_vk[SDLK_F8] = VK_F8;
  sdl_keysym_to_win_vk[SDLK_F9] = VK_F9;
  sdl_keysym_to_win_vk[SDLK_F10] = VK_F10;
  sdl_keysym_to_win_vk[SDLK_F11] = VK_F11;
  sdl_keysym_to_win_vk[SDLK_F12] = VK_F12;
  sdl_keysym_to_win_vk[SDLK_F13] = VK_F13;
  sdl_keysym_to_win_vk[SDLK_F14] = VK_F14;
  sdl_keysym_to_win_vk[SDLK_F15] = VK_F15;
  /* There doesn't appear to be keysyms for > SDLK_F15 as there is in windows */

  sdl_keysym_to_win_vk[SDLK_UP]         = VK_UP;
  sdl_keysym_to_win_vk[SDLK_DOWN]       = VK_DOWN;
  sdl_keysym_to_win_vk[SDLK_LEFT]       = VK_LEFT;
  sdl_keysym_to_win_vk[SDLK_RIGHT]      = VK_RIGHT;
  sdl_keysym_to_win_vk[SDLK_LSHIFT]     = VK_LSHIFT;
  sdl_keysym_to_win_vk[SDLK_RSHIFT]     = VK_RSHIFT;
  sdl_keysym_to_win_vk[SDLK_LCTRL]      = VK_LCONTROL;
  sdl_keysym_to_win_vk[SDLK_RCTRL]      = VK_RCONTROL;
  sdl_keysym_to_win_vk[SDLK_LALT]       = VK_LMENU;
  sdl_keysym_to_win_vk[SDLK_RALT]       = VK_RMENU;
  sdl_keysym_to_win_vk[SDLK_CAPSLOCK]   = VK_CAPITAL;
  sdl_keysym_to_win_vk[SDLK_DELETE]     = VK_DELETE;

  sdl_keysym_to_win_vk[SDLK_KP0] = VK_NUMPAD0;
  sdl_keysym_to_win_vk[SDLK_KP1] = VK_NUMPAD1;
  sdl_keysym_to_win_vk[SDLK_KP2] = VK_NUMPAD2;
  sdl_keysym_to_win_vk[SDLK_KP3] = VK_NUMPAD3;
  sdl_keysym_to_win_vk[SDLK_KP4] = VK_NUMPAD4;
  sdl_keysym_to_win_vk[SDLK_KP5] = VK_NUMPAD5;
  sdl_keysym_to_win_vk[SDLK_KP6] = VK_NUMPAD6;
  sdl_keysym_to_win_vk[SDLK_KP7] = VK_NUMPAD7;
  sdl_keysym_to_win_vk[SDLK_KP8] = VK_NUMPAD8;
  sdl_keysym_to_win_vk[SDLK_KP9] = VK_NUMPAD9;
}

static
void initialize_scancode_to_vk_tbl(void)
{
  int sdl_scancode;

  for( sdl_scancode = 0;
       sdl_scancode < sizeof(scancode_to_win_vk)/sizeof(scancode_to_win_vk[0]);
       sdl_scancode++ )
  {
     scancode_to_win_vk[sdl_scancode] = (WORD)255; /* 255 is an invalid VK code */
  }

  scancode_to_win_vk[ DIK_ESCAPE ] = VK_ESCAPE;
  scancode_to_win_vk[ DIK_1 ] = VK_1;
  scancode_to_win_vk[ DIK_2 ] = VK_2;
  scancode_to_win_vk[ DIK_3 ] = VK_3;
  scancode_to_win_vk[ DIK_4 ] = VK_4;
  scancode_to_win_vk[ DIK_5 ] = VK_5;
  scancode_to_win_vk[ DIK_6 ] = VK_6;
  scancode_to_win_vk[ DIK_7 ] = VK_7;
  scancode_to_win_vk[ DIK_8 ] = VK_8;
  scancode_to_win_vk[ DIK_9 ] = VK_9;
  scancode_to_win_vk[ DIK_0 ] = VK_0;

  scancode_to_win_vk[ DIK_BACK ] = VK_BACK;
  scancode_to_win_vk[ DIK_TAB ] = VK_TAB;

  scancode_to_win_vk[ DIK_SPACE ] = VK_SPACE;

#if 0
  scancode_to_win_vk[ DIK_NUMPAD1 ] = VK_NUMPAD1;
  scancode_to_win_vk[ DIK_NUMPAD3 ] = VK_NUMPAD3;
  scancode_to_win_vk[ DIK_NUMPAD5 ] = VK_NUMPAD5;
  scancode_to_win_vk[ DIK_NUMPAD7 ] = VK_NUMPAD7;
  scancode_to_win_vk[ DIK_NUMPAD9 ] = VK_NUMPAD9;
#endif

  scancode_to_win_vk[ DIK_NUMPAD8 ] =
    scancode_to_win_vk[ DIK_UP ] = VK_UP;

  scancode_to_win_vk[ DIK_NUMPAD4 ] =
    scancode_to_win_vk[ DIK_LEFT ] = VK_LEFT;

  scancode_to_win_vk[ DIK_NUMPAD6 ] =
    scancode_to_win_vk[ DIK_RIGHT ] = VK_RIGHT;

  scancode_to_win_vk[ DIK_NUMPAD2 ] =
    scancode_to_win_vk[ DIK_DOWN ] = VK_DOWN;

  scancode_to_win_vk[ DIK_A ] = VK_A;
  scancode_to_win_vk[ DIK_B ] = VK_B;
  scancode_to_win_vk[ DIK_C ] = VK_C;
  scancode_to_win_vk[ DIK_D ] = VK_D;
  scancode_to_win_vk[ DIK_E ] = VK_E;
  scancode_to_win_vk[ DIK_F ] = VK_F;
  scancode_to_win_vk[ DIK_G ] = VK_G;
  scancode_to_win_vk[ DIK_H ] = VK_H;
  scancode_to_win_vk[ DIK_I ] = VK_I;
  scancode_to_win_vk[ DIK_J ] = VK_J;
  scancode_to_win_vk[ DIK_K ] = VK_K;
  scancode_to_win_vk[ DIK_L ] = VK_L;
  scancode_to_win_vk[ DIK_M ] = VK_M;
  scancode_to_win_vk[ DIK_N ] = VK_N;
  scancode_to_win_vk[ DIK_O ] = VK_O;
  scancode_to_win_vk[ DIK_P ] = VK_P;
  scancode_to_win_vk[ DIK_Q ] = VK_Q;
  scancode_to_win_vk[ DIK_R ] = VK_R;
  scancode_to_win_vk[ DIK_S ] = VK_S;
  scancode_to_win_vk[ DIK_T ] = VK_T;
  scancode_to_win_vk[ DIK_U ] = VK_U;
  scancode_to_win_vk[ DIK_V ] = VK_V;
  scancode_to_win_vk[ DIK_W ] = VK_W;
  scancode_to_win_vk[ DIK_X ] = VK_X;
  scancode_to_win_vk[ DIK_Y ] = VK_Y;
  scancode_to_win_vk[ DIK_Z ] = VK_Z;

  scancode_to_win_vk[ DIK_F1 ] = VK_F1;
  scancode_to_win_vk[ DIK_F2 ] = VK_F2;
  scancode_to_win_vk[ DIK_F3 ] = VK_F3;
  scancode_to_win_vk[ DIK_F4 ] = VK_F4;
  scancode_to_win_vk[ DIK_F5 ] = VK_F5;
  scancode_to_win_vk[ DIK_F6 ] = VK_F6;
  scancode_to_win_vk[ DIK_F7 ] = VK_F7;
  scancode_to_win_vk[ DIK_F8 ] = VK_F8;
  scancode_to_win_vk[ DIK_F9 ] = VK_F9;
  scancode_to_win_vk[ DIK_F10 ] = VK_F10;
  scancode_to_win_vk[ DIK_F11 ] = VK_F11;
  scancode_to_win_vk[ DIK_F12 ] = VK_F12;
  scancode_to_win_vk[ DIK_F13 ] = VK_F13;
  scancode_to_win_vk[ DIK_F14 ] = VK_F14;
  scancode_to_win_vk[ DIK_F15 ] = VK_F15;

  scancode_to_win_vk[ DIK_LMENU ] = VK_LMENU;
  scancode_to_win_vk[ DIK_RMENU ] = VK_RMENU;

  scancode_to_win_vk[ DIK_LSHIFT ] = VK_LSHIFT;
  scancode_to_win_vk[ DIK_RSHIFT ] = VK_RSHIFT;

}

/***********************************************************************
 *		SDLDRV_ProcessEvent
 */
void SDLDRV_ProcessEvent(SDL_Event* event)
{
  INPUT input;
  DWORD SDLmouse_flags;
  const DWORD dwPresentTime = GetTickCount();

  switch (event->type) {
  case SDL_KEYDOWN:
  case SDL_KEYUP:
    TRACE("keyboard (state=%d, keysym=%d, scancode=0x%02x)\n",
	  event->key.state, event->key.keysym.sym, event->key.keysym.scancode);

    /* FIXME: How does one indicate that this should generate a KEYDOWN rather than SYSKEYDOWN? */

    input.type = WINE_INTERNAL_INPUT_KEYBOARD;
    input.u.ki.wVk = sdl_keysym_to_win_vk[ event->key.keysym.sym ];
    input.u.ki.wScan = SDLDRV_MapVirtualKey( input.u.ki.wVk, 0 );
    input.u.ki.dwFlags = (event->key.state == SDL_PRESSED) ? 0 : KEYEVENTF_KEYUP;
    input.u.ki.time = dwPresentTime;
    input.u.ki.dwExtraInfo = 0;

    if( input.u.ki.wVk != 255 )
    {
      TRACE("vk=0x%04x\n", input.u.ki.wVk);
    }
    else
    {
      FIXME( "Need to translate keysym=%u\n", event->key.keysym.sym );
    }

    SendInput(1, &input, sizeof(input));

    break;

  case SDL_MOUSEBUTTONDOWN:
  {
    int SDLmouse_button = event->button.button;

    switch (SDLmouse_button) {
      case SDL_BUTTON_LEFT:
        SDLmouse_flags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
        break;
      case SDL_BUTTON_MIDDLE:
        SDLmouse_flags = MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_ABSOLUTE;
        break;
      case SDL_BUTTON_RIGHT:
        SDLmouse_flags = MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_ABSOLUTE;
        break;
      default:
        SDLmouse_flags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
        break;
    }

    SDLDRV_send_mouse_event( 0, SDLmouse_flags,
                             event->button.x, event->button.y,
                             0 /*SDLmouse_button*/, dwPresentTime );

    break;
  }

  case SDL_MOUSEBUTTONUP:
  {
    int SDLmouse_button = event->button.button;

    switch (SDLmouse_button)
    {
      case SDL_BUTTON_LEFT:
        SDLmouse_flags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
        break;
      case SDL_BUTTON_MIDDLE:
        SDLmouse_flags = MOUSEEVENTF_MIDDLEUP | MOUSEEVENTF_ABSOLUTE;
        break;
      case SDL_BUTTON_RIGHT:
        SDLmouse_flags = MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_ABSOLUTE;
        break;
      default:
        SDLmouse_flags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
        break;
    }

    SDLDRV_send_mouse_event( 0, SDLmouse_flags,
                             event->button.x, event->button.y,
                             0 /*SDLmouse_button*/, dwPresentTime );

    break;
  }

  case SDL_MOUSEMOTION:
    /* Since SDL mouse events are both relative and absolute, this enables us
     * to combine the mouse motion events by simply taking the most recent one
     * in the event queue and sending only that one as an absolute mouse move.
     */
    while( SDL_PeepEvents( event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK ) );

    SDLDRV_send_mouse_event( 0, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
                             event->motion.x, event->motion.y,
                             0, dwPresentTime );

    break;

  case SDL_QUIT:
    FIXME("quit\n");
    break;

  default:
    FIXME( "Unhandled SDL event %d\n", event->type );
    break;
  }
}

/***********************************************************************
 *		MsgWaitForMultipleObjectsEx (SDLDRV.@)
 */
DWORD SDLDRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
                                          DWORD timeout, DWORD mask, DWORD flags )
{
  SDL_Event event;

  if( SDL_PollEvent(&event)>0 ) {
    SDLDRV_ProcessEvent(&event);
    return WAIT_OBJECT_0 + count;
  }

  return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
                                   timeout, flags & MWMO_ALERTABLE );
}

/***********************************************************************
 *              send_mouse_event
 */
static
void SDLDRV_send_mouse_event( HWND hwnd, DWORD flags, DWORD posX, DWORD posY,
                              DWORD data, DWORD time )
{
    INPUT input;

    TRACE("(%04lX,%ld,%ld)\n", flags, posX, posY );

    if (flags & MOUSEEVENTF_ABSOLUTE)
    {
        int width  = GetSystemMetrics( SM_CXSCREEN );
        int height = GetSystemMetrics( SM_CYSCREEN );

        /* Relative mouse movements seem not to be scaled as absolute ones */
	/* FIXME: Is this right (ie it's just a cut/paste from x11) */
        posX = (((long)posX << 16) + width-1)  / width;
        posY = (((long)posY << 16) + height-1) / height;
    }

    input.type             = WINE_INTERNAL_INPUT_MOUSE;
    input.u.mi.dx          = posX;
    input.u.mi.dy          = posY;
    input.u.mi.mouseData   = data; /* for button events */
    input.u.mi.dwFlags     = flags;
    input.u.mi.time        = time;
    input.u.mi.dwExtraInfo = (ULONG_PTR)hwnd;

    SendInput( 1, &input, sizeof(input) );
}

extern
void SDLDRV_initialize_keyboard(void)
{
  /* Initialize our SDL keysym -> Windows VK translation table */
  initialize_keysym_translation_tbl();

  /* Initialize our scancode -> VK translation table */
  initialize_scancode_to_vk_tbl();

  /* FIXME: I suppose that the delay and interval values should be comming from a GetSystem*
   * type call. */
  SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
}
