/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/12/01
/// 
/// @brief  DirectX DiretInput関係
/// 
/// ****************************************************************************


#include "CPL_DX_Input.h"

namespace CPL {
namespace DX {


// _____________________________________________________________________________
/// @brief Input:デフォルトコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Input::Input()
  : m_ptr_dinput( nullptr )
  , m_ptr_key_device( nullptr )
  , m_ptr_mouse_device( nullptr )
{
}


// _____________________________________________________________________________
/// @brief デストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Input::~Input()
{
  RELEASE( m_ptr_mouse_device );
  RELEASE( m_ptr_key_device );
  RELEASE( m_ptr_dinput );
}


// _____________________________________________________________________________
/// @brief DirectInput作成
/// 
/// @return DirectXのリターンコード(HRESULT型)を返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT Input::CreateInput()
{
  // DirectInputオブジェクトの作成
  return
    DirectInput8Create
      ( ::GetModuleHandle(nullptr)
      , DIRECTINPUT_VERSION
      , IID_IDirectInput8
      , (VOID**)&m_ptr_dinput
      , nullptr
      );
}


// _____________________________________________________________________________
/// @brief キーデバイスの作成
/// 
/// @param[in] in_hdl_window
///   : デバイスに関連付けられているウィンドウハンドルを指定します。\n
///   : SetCooperativeLevel関数に渡されます。
/// 
/// @return DirectXのリターンコード(HRESULT型)を返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT Input::CreateKeyDevice( _in<HWND> in_hdl_window )
{
  if( !m_ptr_dinput )
  {
    CPL_OUTPUT( SwS("CorePLi : DirectInputオブジェクトが作成されていません。\n") );
    return E_FAIL;
  }

  // DirectInputデバイス作成
  HRESULT hr = m_ptr_dinput->CreateDevice( GUID_SysKeyboard, &m_ptr_key_device, nullptr );
  if( FAILED( hr ) )
  {
    CPL_OUTPUT( SwS("CorePLi : DirectInputデバイスの作成に失敗しました。\n") );
    return E_FAIL;
  }

  // デバイスをキーボードに設定
  hr = m_ptr_key_device->SetDataFormat( &c_dfDIKeyboard );
  if( FAILED( hr ) )
  {
    CPL_OUTPUT( SwS("CorePLi : DirectInput : キーボードの設定に失敗しました。\n") );
    return hr;
  }

  // 強調レベルの設定
  hr = m_ptr_key_device->SetCooperativeLevel( in_hdl_window, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND );
  if( FAILED( hr ) )
  {
    CPL_OUTPUT( SwS("CorePLi : DirectInput : キーボードの協調レベルの設定に失敗しました。\n") );
    return hr;
  }

  // デバイスを取得
  hr = m_ptr_key_device->Acquire();
  if( FAILED( hr ) )
  {
    return hr;
  }

  return S_OK;
}


// _____________________________________________________________________________
/// @brief キー状態取得
/// 
/// @param[in] out_key_table
///   : キーの状態を格納するためのバイト配列[256]の先頭アドレスを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Input::KeyRead( BYTE out_key_table[256] )
{
  HRESULT hr = m_ptr_key_device->Acquire();
  if( hr == DI_OK  ||  hr == S_FALSE )
  {
    m_ptr_key_device->GetDeviceState( 256, out_key_table );
  }
}


// _____________________________________________________________________________
/// @brief マウスデバイス作成
/// 
/// @param[in] in_hdl_window
///   : デバイスに関連付けられているウィンドウハンドルを指定します。\n
///   : SetCooperativeLevel関数に渡されます。
/// 
/// @return DirectXのリターンコード(HRESULT型)を返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HRESULT Input::CreateMouseDevice( _in<HWND> in_hdl_window )
{
  if( !m_ptr_dinput )
  {
    CPL_OUTPUT( SwS("CorePLi : DirectInputオブジェクトが作成されていません。\n") );
    return E_FAIL;
  }

  // デバイス作成
  HRESULT hr = m_ptr_dinput->CreateDevice( GUID_SysMouse, &m_ptr_mouse_device, nullptr );
  if( FAILED( hr ) )
  {
    CPL_OUTPUT( SwS("CorePLi : DirectInputデバイスの作成に失敗しました。\n") );
    return hr;
  }

  // デバイスをマウスに設定
  hr = m_ptr_mouse_device->SetDataFormat( &c_dfDIMouse2 );
  if( FAILED( hr ) )
  {
    CPL_OUTPUT( SwS("CorePLi : DirectInput : マウスの設定に失敗しました。\n") );
    return hr;
  }

  // 強調レベルの設定
  hr = m_ptr_mouse_device->SetCooperativeLevel( in_hdl_window, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND );
  if( FAILED( hr ) )
  {
    CPL_OUTPUT( SwS("CorePLi : DirectInput : マウスの協調レベルの設定に失敗しました。\n") );
    return hr;
  }

  // デバイスの取得
  hr = m_ptr_mouse_device->Acquire();
  if( FAILED( hr ) )
  {
    return hr;
  }

  return S_OK;
}


// _____________________________________________________________________________
/// @brief マウス情報取得
/// 
/// @param[in] out_ptr_mouse_state
///   : 取得用のDIMOUSESTATE2オブジェクトのアドレスを指定します。
/// 
/// @return 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Input::MouseRead( DIMOUSESTATE2* out_ptr_mouse_state )
{
  HRESULT hr =
    m_ptr_mouse_device->GetDeviceState
      ( sizeof(DIMOUSESTATE2)
      , out_ptr_mouse_state
      );
  if( FAILED( hr ) )
  {
    m_ptr_mouse_device->Acquire();
  }
}


} // namespace DX
} // namespace CPL


