build system update
-fix win32 folders from being excluded
This commit is contained in:
parent
96732f9346
commit
dd0b1d103e
|
|
@ -23,7 +23,6 @@ mono_crash.*
|
|||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/System/Time.hpp>
|
||||
#include <SFML/System/Win32/SleepImpl.hpp>
|
||||
#include <SFML/System/Win32/WindowsHeader.hpp>
|
||||
|
||||
#include <mmsystem.h>
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
void sleepImpl(Time time)
|
||||
{
|
||||
// Get the minimum supported timer resolution on this system
|
||||
static const UINT periodMin = []
|
||||
{
|
||||
TIMECAPS tc;
|
||||
timeGetDevCaps(&tc, sizeof(TIMECAPS));
|
||||
return tc.wPeriodMin;
|
||||
}();
|
||||
|
||||
// Set the timer resolution to the minimum for the Sleep call
|
||||
timeBeginPeriod(periodMin);
|
||||
|
||||
// Wait...
|
||||
::Sleep(static_cast<DWORD>(time.asMilliseconds()));
|
||||
|
||||
// Reset the timer resolution back to the system default
|
||||
timeEndPeriod(periodMin);
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Config.hpp>
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class Time;
|
||||
}
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Windows implementation of sf::Sleep
|
||||
///
|
||||
/// \param time Time to sleep
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void sleepImpl(Time time);
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINDOWS
|
||||
#define _WIN32_WINDOWS 0x0501 // NOLINT(bugprone-reserved-identifier)
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
|
||||
#ifndef WINVER
|
||||
#define WINVER 0x0501
|
||||
#endif
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE 1
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE 1 // NOLINT(bugprone-reserved-identifier)
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/Win32/ClipboardImpl.hpp>
|
||||
#include <SFML/Window/Win32/Utils.hpp>
|
||||
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/String.hpp>
|
||||
#include <SFML/System/Win32/WindowsHeader.hpp>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
String ClipboardImpl::getString()
|
||||
{
|
||||
String text;
|
||||
|
||||
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
|
||||
{
|
||||
err() << "Failed to get the clipboard data in Unicode format: " << getErrorString(GetLastError()) << std::endl;
|
||||
return text;
|
||||
}
|
||||
|
||||
if (!OpenClipboard(nullptr))
|
||||
{
|
||||
err() << "Failed to open the Win32 clipboard: " << getErrorString(GetLastError()) << std::endl;
|
||||
return text;
|
||||
}
|
||||
|
||||
HANDLE clipboardHandle = GetClipboardData(CF_UNICODETEXT);
|
||||
|
||||
if (!clipboardHandle)
|
||||
{
|
||||
err() << "Failed to get Win32 handle for clipboard content: " << getErrorString(GetLastError()) << std::endl;
|
||||
CloseClipboard();
|
||||
return text;
|
||||
}
|
||||
|
||||
text = String(static_cast<wchar_t*>(GlobalLock(clipboardHandle)));
|
||||
GlobalUnlock(clipboardHandle);
|
||||
|
||||
CloseClipboard();
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ClipboardImpl::setString(const String& text)
|
||||
{
|
||||
if (!OpenClipboard(nullptr))
|
||||
{
|
||||
err() << "Failed to open the Win32 clipboard: " << getErrorString(GetLastError()) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EmptyClipboard())
|
||||
{
|
||||
err() << "Failed to empty the Win32 clipboard: " << getErrorString(GetLastError()) << std::endl;
|
||||
CloseClipboard();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a Win32-compatible string
|
||||
const std::size_t stringSize = (text.getSize() + 1) * sizeof(WCHAR);
|
||||
if (const HANDLE stringHandle = GlobalAlloc(GMEM_MOVEABLE, stringSize))
|
||||
{
|
||||
std::memcpy(GlobalLock(stringHandle), text.toWideString().data(), stringSize);
|
||||
GlobalUnlock(stringHandle);
|
||||
SetClipboardData(CF_UNICODETEXT, stringHandle);
|
||||
}
|
||||
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class String;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Give access to the system clipboard
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class ClipboardImpl
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the content of the clipboard as string data
|
||||
///
|
||||
/// This function returns the content of the clipboard
|
||||
/// as a string. If the clipboard does not contain string
|
||||
/// it returns an empty sf::String object.
|
||||
///
|
||||
/// \return Current content of the clipboard
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static String getString();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the content of the clipboard as string data
|
||||
///
|
||||
/// This function sets the content of the clipboard as a
|
||||
/// string.
|
||||
///
|
||||
/// \param text sf::String object containing the data to be sent
|
||||
/// to the clipboard
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void setString(const String& text);
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/Win32/CursorImpl.hpp>
|
||||
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/Win32/WindowsHeader.hpp>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
CursorImpl::~CursorImpl()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool CursorImpl::loadFromPixels(const std::uint8_t* pixels, Vector2u size, Vector2u hotspot)
|
||||
{
|
||||
release();
|
||||
|
||||
// Create the bitmap that will hold our color data
|
||||
auto bitmapHeader = BITMAPV5HEADER();
|
||||
bitmapHeader.bV5Size = sizeof(BITMAPV5HEADER);
|
||||
bitmapHeader.bV5Width = static_cast<LONG>(size.x);
|
||||
bitmapHeader.bV5Height = -static_cast<LONG>(size.y); // Negative indicates origin is in upper-left corner
|
||||
bitmapHeader.bV5Planes = 1;
|
||||
bitmapHeader.bV5BitCount = 32;
|
||||
bitmapHeader.bV5Compression = BI_BITFIELDS;
|
||||
bitmapHeader.bV5RedMask = 0x00ff0000;
|
||||
bitmapHeader.bV5GreenMask = 0x0000ff00;
|
||||
bitmapHeader.bV5BlueMask = 0x000000ff;
|
||||
bitmapHeader.bV5AlphaMask = 0xff000000;
|
||||
|
||||
std::uint32_t* bitmapData = nullptr;
|
||||
|
||||
HDC screenDC = GetDC(nullptr);
|
||||
HBITMAP color = CreateDIBSection(screenDC,
|
||||
reinterpret_cast<const BITMAPINFO*>(&bitmapHeader),
|
||||
DIB_RGB_COLORS,
|
||||
reinterpret_cast<void**>(&bitmapData),
|
||||
nullptr,
|
||||
0);
|
||||
ReleaseDC(nullptr, screenDC);
|
||||
|
||||
if (!color)
|
||||
{
|
||||
err() << "Failed to create cursor color bitmap" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill our bitmap with the cursor color data
|
||||
// We'll have to swap the red and blue channels here
|
||||
std::uint32_t* bitmapOffset = bitmapData;
|
||||
for (std::size_t remaining = size.x * size.y; remaining > 0; --remaining, pixels += 4)
|
||||
{
|
||||
*bitmapOffset++ = static_cast<std::uint32_t>((pixels[3] << 24) | (pixels[0] << 16) | (pixels[1] << 8) | pixels[2]);
|
||||
}
|
||||
|
||||
// Create a dummy mask bitmap (it won't be used)
|
||||
HBITMAP mask = CreateBitmap(static_cast<int>(size.x), static_cast<int>(size.y), 1, 1, nullptr);
|
||||
|
||||
if (!mask)
|
||||
{
|
||||
DeleteObject(color);
|
||||
err() << "Failed to create cursor mask bitmap" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the structure that describes our cursor
|
||||
auto cursorInfo = ICONINFO();
|
||||
cursorInfo.fIcon = FALSE; // This is a cursor and not an icon
|
||||
cursorInfo.xHotspot = hotspot.x;
|
||||
cursorInfo.yHotspot = hotspot.y;
|
||||
cursorInfo.hbmColor = color;
|
||||
cursorInfo.hbmMask = mask;
|
||||
|
||||
// Create the cursor
|
||||
m_cursor = reinterpret_cast<HCURSOR>(CreateIconIndirect(&cursorInfo));
|
||||
m_systemCursor = false;
|
||||
|
||||
// The data has been copied into the cursor, so get rid of these
|
||||
DeleteObject(color);
|
||||
DeleteObject(mask);
|
||||
|
||||
if (m_cursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
err() << "Failed to create cursor from bitmaps" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool CursorImpl::loadFromSystem(Cursor::Type type)
|
||||
{
|
||||
release();
|
||||
|
||||
LPCTSTR shape = nullptr;
|
||||
|
||||
// clang-format off
|
||||
switch (type)
|
||||
{
|
||||
case Cursor::Type::Arrow: shape = IDC_ARROW; break;
|
||||
case Cursor::Type::ArrowWait: shape = IDC_APPSTARTING; break;
|
||||
case Cursor::Type::Wait: shape = IDC_WAIT; break;
|
||||
case Cursor::Type::Text: shape = IDC_IBEAM; break;
|
||||
case Cursor::Type::Hand: shape = IDC_HAND; break;
|
||||
case Cursor::Type::SizeHorizontal: shape = IDC_SIZEWE; break;
|
||||
case Cursor::Type::SizeVertical: shape = IDC_SIZENS; break;
|
||||
case Cursor::Type::SizeTopLeftBottomRight: shape = IDC_SIZENWSE; break;
|
||||
case Cursor::Type::SizeBottomLeftTopRight: shape = IDC_SIZENESW; break;
|
||||
case Cursor::Type::SizeLeft: shape = IDC_SIZEWE; break;
|
||||
case Cursor::Type::SizeRight: shape = IDC_SIZEWE; break;
|
||||
case Cursor::Type::SizeTop: shape = IDC_SIZENS; break;
|
||||
case Cursor::Type::SizeBottom: shape = IDC_SIZENS; break;
|
||||
case Cursor::Type::SizeTopLeft: shape = IDC_SIZENWSE; break;
|
||||
case Cursor::Type::SizeBottomRight: shape = IDC_SIZENWSE; break;
|
||||
case Cursor::Type::SizeBottomLeft: shape = IDC_SIZENESW; break;
|
||||
case Cursor::Type::SizeTopRight: shape = IDC_SIZENESW; break;
|
||||
case Cursor::Type::SizeAll: shape = IDC_SIZEALL; break;
|
||||
case Cursor::Type::Cross: shape = IDC_CROSS; break;
|
||||
case Cursor::Type::Help: shape = IDC_HELP; break;
|
||||
case Cursor::Type::NotAllowed: shape = IDC_NO; break;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// Get the shared system cursor and make sure not to destroy it
|
||||
m_cursor = LoadCursor(nullptr, shape);
|
||||
m_systemCursor = true;
|
||||
|
||||
if (m_cursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
err() << "Could not create copy of a system cursor" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void CursorImpl::release()
|
||||
{
|
||||
if (m_cursor && !m_systemCursor)
|
||||
{
|
||||
DestroyCursor(static_cast<HCURSOR>(m_cursor));
|
||||
m_cursor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/Cursor.hpp>
|
||||
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Win32 implementation of Cursor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class CursorImpl
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
/// Refer to sf::Cursor::Cursor().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CursorImpl() = default;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
/// Refer to sf::Cursor::~Cursor().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~CursorImpl();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Deleted copy constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CursorImpl(const CursorImpl&) = delete;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Deleted copy assignment
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
CursorImpl& operator=(const CursorImpl&) = delete;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a cursor with the provided image
|
||||
///
|
||||
/// Refer to sf::Cursor::createFromPixels().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool loadFromPixels(const std::uint8_t* pixels, Vector2u size, Vector2u hotspot);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a native system cursor
|
||||
///
|
||||
/// Refer to sf::Cursor::createFromSystem().
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool loadFromSystem(Cursor::Type type);
|
||||
|
||||
private:
|
||||
friend class WindowImplWin32;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Release the cursor, if we have loaded one.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void release();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
void* m_cursor{}; // Type erasure via `void*` is used here to avoid depending on `windows.h`
|
||||
bool m_systemCursor{};
|
||||
};
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,757 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/InputImpl.hpp>
|
||||
#include <SFML/Window/Window.hpp>
|
||||
|
||||
#include <SFML/System/EnumArray.hpp>
|
||||
#include <SFML/System/String.hpp>
|
||||
#include <SFML/System/Win32/WindowsHeader.hpp>
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
sf::priv::EnumArray<sf::Keyboard::Key, sf::Keyboard::Scancode, sf::Keyboard::KeyCount> keyToScancodeMapping; ///< Mapping from Key to Scancode
|
||||
sf::priv::EnumArray<sf::Keyboard::Scancode, sf::Keyboard::Key, sf::Keyboard::ScancodeCount> scancodeToKeyMapping; ///< Mapping from Scancode to Key
|
||||
|
||||
sf::Keyboard::Key virtualKeyToSfKey(UINT virtualKey)
|
||||
{
|
||||
// clang-format off
|
||||
switch (virtualKey)
|
||||
{
|
||||
case 'A': return sf::Keyboard::Key::A;
|
||||
case 'B': return sf::Keyboard::Key::B;
|
||||
case 'C': return sf::Keyboard::Key::C;
|
||||
case 'D': return sf::Keyboard::Key::D;
|
||||
case 'E': return sf::Keyboard::Key::E;
|
||||
case 'F': return sf::Keyboard::Key::F;
|
||||
case 'G': return sf::Keyboard::Key::G;
|
||||
case 'H': return sf::Keyboard::Key::H;
|
||||
case 'I': return sf::Keyboard::Key::I;
|
||||
case 'J': return sf::Keyboard::Key::J;
|
||||
case 'K': return sf::Keyboard::Key::K;
|
||||
case 'L': return sf::Keyboard::Key::L;
|
||||
case 'M': return sf::Keyboard::Key::M;
|
||||
case 'N': return sf::Keyboard::Key::N;
|
||||
case 'O': return sf::Keyboard::Key::O;
|
||||
case 'P': return sf::Keyboard::Key::P;
|
||||
case 'Q': return sf::Keyboard::Key::Q;
|
||||
case 'R': return sf::Keyboard::Key::R;
|
||||
case 'S': return sf::Keyboard::Key::S;
|
||||
case 'T': return sf::Keyboard::Key::T;
|
||||
case 'U': return sf::Keyboard::Key::U;
|
||||
case 'V': return sf::Keyboard::Key::V;
|
||||
case 'W': return sf::Keyboard::Key::W;
|
||||
case 'X': return sf::Keyboard::Key::X;
|
||||
case 'Y': return sf::Keyboard::Key::Y;
|
||||
case 'Z': return sf::Keyboard::Key::Z;
|
||||
case '0': return sf::Keyboard::Key::Num0;
|
||||
case '1': return sf::Keyboard::Key::Num1;
|
||||
case '2': return sf::Keyboard::Key::Num2;
|
||||
case '3': return sf::Keyboard::Key::Num3;
|
||||
case '4': return sf::Keyboard::Key::Num4;
|
||||
case '5': return sf::Keyboard::Key::Num5;
|
||||
case '6': return sf::Keyboard::Key::Num6;
|
||||
case '7': return sf::Keyboard::Key::Num7;
|
||||
case '8': return sf::Keyboard::Key::Num8;
|
||||
case '9': return sf::Keyboard::Key::Num9;
|
||||
case VK_ESCAPE: return sf::Keyboard::Key::Escape;
|
||||
case VK_LCONTROL: return sf::Keyboard::Key::LControl;
|
||||
case VK_LSHIFT: return sf::Keyboard::Key::LShift;
|
||||
case VK_LMENU: return sf::Keyboard::Key::LAlt;
|
||||
case VK_LWIN: return sf::Keyboard::Key::LSystem;
|
||||
case VK_RCONTROL: return sf::Keyboard::Key::RControl;
|
||||
case VK_RSHIFT: return sf::Keyboard::Key::RShift;
|
||||
case VK_RMENU: return sf::Keyboard::Key::RAlt;
|
||||
case VK_RWIN: return sf::Keyboard::Key::RSystem;
|
||||
case VK_APPS: return sf::Keyboard::Key::Menu;
|
||||
case VK_OEM_4: return sf::Keyboard::Key::LBracket;
|
||||
case VK_OEM_6: return sf::Keyboard::Key::RBracket;
|
||||
case VK_OEM_1: return sf::Keyboard::Key::Semicolon;
|
||||
case VK_OEM_COMMA: return sf::Keyboard::Key::Comma;
|
||||
case VK_OEM_PERIOD: return sf::Keyboard::Key::Period;
|
||||
case VK_OEM_7: return sf::Keyboard::Key::Apostrophe;
|
||||
case VK_OEM_2: return sf::Keyboard::Key::Slash;
|
||||
case VK_OEM_5: return sf::Keyboard::Key::Backslash;
|
||||
case VK_OEM_3: return sf::Keyboard::Key::Grave;
|
||||
case VK_OEM_PLUS: return sf::Keyboard::Key::Equal;
|
||||
case VK_OEM_MINUS: return sf::Keyboard::Key::Hyphen;
|
||||
case VK_SPACE: return sf::Keyboard::Key::Space;
|
||||
case VK_RETURN: return sf::Keyboard::Key::Enter;
|
||||
case VK_BACK: return sf::Keyboard::Key::Backspace;
|
||||
case VK_TAB: return sf::Keyboard::Key::Tab;
|
||||
case VK_PRIOR: return sf::Keyboard::Key::PageUp;
|
||||
case VK_NEXT: return sf::Keyboard::Key::PageDown;
|
||||
case VK_END: return sf::Keyboard::Key::End;
|
||||
case VK_HOME: return sf::Keyboard::Key::Home;
|
||||
case VK_INSERT: return sf::Keyboard::Key::Insert;
|
||||
case VK_DELETE: return sf::Keyboard::Key::Delete;
|
||||
case VK_ADD: return sf::Keyboard::Key::Add;
|
||||
case VK_SUBTRACT: return sf::Keyboard::Key::Subtract;
|
||||
case VK_MULTIPLY: return sf::Keyboard::Key::Multiply;
|
||||
case VK_DIVIDE: return sf::Keyboard::Key::Divide;
|
||||
case VK_LEFT: return sf::Keyboard::Key::Left;
|
||||
case VK_RIGHT: return sf::Keyboard::Key::Right;
|
||||
case VK_UP: return sf::Keyboard::Key::Up;
|
||||
case VK_DOWN: return sf::Keyboard::Key::Down;
|
||||
case VK_NUMPAD0: return sf::Keyboard::Key::Numpad0;
|
||||
case VK_NUMPAD1: return sf::Keyboard::Key::Numpad1;
|
||||
case VK_NUMPAD2: return sf::Keyboard::Key::Numpad2;
|
||||
case VK_NUMPAD3: return sf::Keyboard::Key::Numpad3;
|
||||
case VK_NUMPAD4: return sf::Keyboard::Key::Numpad4;
|
||||
case VK_NUMPAD5: return sf::Keyboard::Key::Numpad5;
|
||||
case VK_NUMPAD6: return sf::Keyboard::Key::Numpad6;
|
||||
case VK_NUMPAD7: return sf::Keyboard::Key::Numpad7;
|
||||
case VK_NUMPAD8: return sf::Keyboard::Key::Numpad8;
|
||||
case VK_NUMPAD9: return sf::Keyboard::Key::Numpad9;
|
||||
case VK_F1: return sf::Keyboard::Key::F1;
|
||||
case VK_F2: return sf::Keyboard::Key::F2;
|
||||
case VK_F3: return sf::Keyboard::Key::F3;
|
||||
case VK_F4: return sf::Keyboard::Key::F4;
|
||||
case VK_F5: return sf::Keyboard::Key::F5;
|
||||
case VK_F6: return sf::Keyboard::Key::F6;
|
||||
case VK_F7: return sf::Keyboard::Key::F7;
|
||||
case VK_F8: return sf::Keyboard::Key::F8;
|
||||
case VK_F9: return sf::Keyboard::Key::F9;
|
||||
case VK_F10: return sf::Keyboard::Key::F10;
|
||||
case VK_F11: return sf::Keyboard::Key::F11;
|
||||
case VK_F12: return sf::Keyboard::Key::F12;
|
||||
case VK_F13: return sf::Keyboard::Key::F13;
|
||||
case VK_F14: return sf::Keyboard::Key::F14;
|
||||
case VK_F15: return sf::Keyboard::Key::F15;
|
||||
case VK_PAUSE: return sf::Keyboard::Key::Pause;
|
||||
default: return sf::Keyboard::Key::Unknown;
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
int sfKeyToVirtualKey(sf::Keyboard::Key key)
|
||||
{
|
||||
// clang-format off
|
||||
switch (key)
|
||||
{
|
||||
case sf::Keyboard::Key::A: return 'A';
|
||||
case sf::Keyboard::Key::B: return 'B';
|
||||
case sf::Keyboard::Key::C: return 'C';
|
||||
case sf::Keyboard::Key::D: return 'D';
|
||||
case sf::Keyboard::Key::E: return 'E';
|
||||
case sf::Keyboard::Key::F: return 'F';
|
||||
case sf::Keyboard::Key::G: return 'G';
|
||||
case sf::Keyboard::Key::H: return 'H';
|
||||
case sf::Keyboard::Key::I: return 'I';
|
||||
case sf::Keyboard::Key::J: return 'J';
|
||||
case sf::Keyboard::Key::K: return 'K';
|
||||
case sf::Keyboard::Key::L: return 'L';
|
||||
case sf::Keyboard::Key::M: return 'M';
|
||||
case sf::Keyboard::Key::N: return 'N';
|
||||
case sf::Keyboard::Key::O: return 'O';
|
||||
case sf::Keyboard::Key::P: return 'P';
|
||||
case sf::Keyboard::Key::Q: return 'Q';
|
||||
case sf::Keyboard::Key::R: return 'R';
|
||||
case sf::Keyboard::Key::S: return 'S';
|
||||
case sf::Keyboard::Key::T: return 'T';
|
||||
case sf::Keyboard::Key::U: return 'U';
|
||||
case sf::Keyboard::Key::V: return 'V';
|
||||
case sf::Keyboard::Key::W: return 'W';
|
||||
case sf::Keyboard::Key::X: return 'X';
|
||||
case sf::Keyboard::Key::Y: return 'Y';
|
||||
case sf::Keyboard::Key::Z: return 'Z';
|
||||
case sf::Keyboard::Key::Num0: return '0';
|
||||
case sf::Keyboard::Key::Num1: return '1';
|
||||
case sf::Keyboard::Key::Num2: return '2';
|
||||
case sf::Keyboard::Key::Num3: return '3';
|
||||
case sf::Keyboard::Key::Num4: return '4';
|
||||
case sf::Keyboard::Key::Num5: return '5';
|
||||
case sf::Keyboard::Key::Num6: return '6';
|
||||
case sf::Keyboard::Key::Num7: return '7';
|
||||
case sf::Keyboard::Key::Num8: return '8';
|
||||
case sf::Keyboard::Key::Num9: return '9';
|
||||
case sf::Keyboard::Key::Escape: return VK_ESCAPE;
|
||||
case sf::Keyboard::Key::LControl: return VK_LCONTROL;
|
||||
case sf::Keyboard::Key::LShift: return VK_LSHIFT;
|
||||
case sf::Keyboard::Key::LAlt: return VK_LMENU;
|
||||
case sf::Keyboard::Key::LSystem: return VK_LWIN;
|
||||
case sf::Keyboard::Key::RControl: return VK_RCONTROL;
|
||||
case sf::Keyboard::Key::RShift: return VK_RSHIFT;
|
||||
case sf::Keyboard::Key::RAlt: return VK_RMENU;
|
||||
case sf::Keyboard::Key::RSystem: return VK_RWIN;
|
||||
case sf::Keyboard::Key::Menu: return VK_APPS;
|
||||
case sf::Keyboard::Key::LBracket: return VK_OEM_4;
|
||||
case sf::Keyboard::Key::RBracket: return VK_OEM_6;
|
||||
case sf::Keyboard::Key::Semicolon: return VK_OEM_1;
|
||||
case sf::Keyboard::Key::Comma: return VK_OEM_COMMA;
|
||||
case sf::Keyboard::Key::Period: return VK_OEM_PERIOD;
|
||||
case sf::Keyboard::Key::Apostrophe: return VK_OEM_7;
|
||||
case sf::Keyboard::Key::Slash: return VK_OEM_2;
|
||||
case sf::Keyboard::Key::Backslash: return VK_OEM_5;
|
||||
case sf::Keyboard::Key::Grave: return VK_OEM_3;
|
||||
case sf::Keyboard::Key::Equal: return VK_OEM_PLUS;
|
||||
case sf::Keyboard::Key::Hyphen: return VK_OEM_MINUS;
|
||||
case sf::Keyboard::Key::Space: return VK_SPACE;
|
||||
case sf::Keyboard::Key::Enter: return VK_RETURN;
|
||||
case sf::Keyboard::Key::Backspace: return VK_BACK;
|
||||
case sf::Keyboard::Key::Tab: return VK_TAB;
|
||||
case sf::Keyboard::Key::PageUp: return VK_PRIOR;
|
||||
case sf::Keyboard::Key::PageDown: return VK_NEXT;
|
||||
case sf::Keyboard::Key::End: return VK_END;
|
||||
case sf::Keyboard::Key::Home: return VK_HOME;
|
||||
case sf::Keyboard::Key::Insert: return VK_INSERT;
|
||||
case sf::Keyboard::Key::Delete: return VK_DELETE;
|
||||
case sf::Keyboard::Key::Add: return VK_ADD;
|
||||
case sf::Keyboard::Key::Subtract: return VK_SUBTRACT;
|
||||
case sf::Keyboard::Key::Multiply: return VK_MULTIPLY;
|
||||
case sf::Keyboard::Key::Divide: return VK_DIVIDE;
|
||||
case sf::Keyboard::Key::Left: return VK_LEFT;
|
||||
case sf::Keyboard::Key::Right: return VK_RIGHT;
|
||||
case sf::Keyboard::Key::Up: return VK_UP;
|
||||
case sf::Keyboard::Key::Down: return VK_DOWN;
|
||||
case sf::Keyboard::Key::Numpad0: return VK_NUMPAD0;
|
||||
case sf::Keyboard::Key::Numpad1: return VK_NUMPAD1;
|
||||
case sf::Keyboard::Key::Numpad2: return VK_NUMPAD2;
|
||||
case sf::Keyboard::Key::Numpad3: return VK_NUMPAD3;
|
||||
case sf::Keyboard::Key::Numpad4: return VK_NUMPAD4;
|
||||
case sf::Keyboard::Key::Numpad5: return VK_NUMPAD5;
|
||||
case sf::Keyboard::Key::Numpad6: return VK_NUMPAD6;
|
||||
case sf::Keyboard::Key::Numpad7: return VK_NUMPAD7;
|
||||
case sf::Keyboard::Key::Numpad8: return VK_NUMPAD8;
|
||||
case sf::Keyboard::Key::Numpad9: return VK_NUMPAD9;
|
||||
case sf::Keyboard::Key::F1: return VK_F1;
|
||||
case sf::Keyboard::Key::F2: return VK_F2;
|
||||
case sf::Keyboard::Key::F3: return VK_F3;
|
||||
case sf::Keyboard::Key::F4: return VK_F4;
|
||||
case sf::Keyboard::Key::F5: return VK_F5;
|
||||
case sf::Keyboard::Key::F6: return VK_F6;
|
||||
case sf::Keyboard::Key::F7: return VK_F7;
|
||||
case sf::Keyboard::Key::F8: return VK_F8;
|
||||
case sf::Keyboard::Key::F9: return VK_F9;
|
||||
case sf::Keyboard::Key::F10: return VK_F10;
|
||||
case sf::Keyboard::Key::F11: return VK_F11;
|
||||
case sf::Keyboard::Key::F12: return VK_F12;
|
||||
case sf::Keyboard::Key::F13: return VK_F13;
|
||||
case sf::Keyboard::Key::F14: return VK_F14;
|
||||
case sf::Keyboard::Key::F15: return VK_F15;
|
||||
case sf::Keyboard::Key::Pause: return VK_PAUSE;
|
||||
default: return 0;
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
WORD sfScanToWinScan(sf::Keyboard::Scancode code)
|
||||
{
|
||||
// Convert an SFML scancode to a Windows scancode
|
||||
// Reference: https://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx
|
||||
// clang-format off
|
||||
switch (code)
|
||||
{
|
||||
case sf::Keyboard::Scan::A: return 0x1E;
|
||||
case sf::Keyboard::Scan::B: return 0x30;
|
||||
case sf::Keyboard::Scan::C: return 0x2E;
|
||||
case sf::Keyboard::Scan::D: return 0x20;
|
||||
case sf::Keyboard::Scan::E: return 0x12;
|
||||
case sf::Keyboard::Scan::F: return 0x21;
|
||||
case sf::Keyboard::Scan::G: return 0x22;
|
||||
case sf::Keyboard::Scan::H: return 0x23;
|
||||
case sf::Keyboard::Scan::I: return 0x17;
|
||||
case sf::Keyboard::Scan::J: return 0x24;
|
||||
case sf::Keyboard::Scan::K: return 0x25;
|
||||
case sf::Keyboard::Scan::L: return 0x26;
|
||||
case sf::Keyboard::Scan::M: return 0x32;
|
||||
case sf::Keyboard::Scan::N: return 0x31;
|
||||
case sf::Keyboard::Scan::O: return 0x18;
|
||||
case sf::Keyboard::Scan::P: return 0x19;
|
||||
case sf::Keyboard::Scan::Q: return 0x10;
|
||||
case sf::Keyboard::Scan::R: return 0x13;
|
||||
case sf::Keyboard::Scan::S: return 0x1F;
|
||||
case sf::Keyboard::Scan::T: return 0x14;
|
||||
case sf::Keyboard::Scan::U: return 0x16;
|
||||
case sf::Keyboard::Scan::V: return 0x2F;
|
||||
case sf::Keyboard::Scan::W: return 0x11;
|
||||
case sf::Keyboard::Scan::X: return 0x2D;
|
||||
case sf::Keyboard::Scan::Y: return 0x15;
|
||||
case sf::Keyboard::Scan::Z: return 0x2C;
|
||||
|
||||
case sf::Keyboard::Scan::Num1: return 0x02;
|
||||
case sf::Keyboard::Scan::Num2: return 0x03;
|
||||
case sf::Keyboard::Scan::Num3: return 0x04;
|
||||
case sf::Keyboard::Scan::Num4: return 0x05;
|
||||
case sf::Keyboard::Scan::Num5: return 0x06;
|
||||
case sf::Keyboard::Scan::Num6: return 0x07;
|
||||
case sf::Keyboard::Scan::Num7: return 0x08;
|
||||
case sf::Keyboard::Scan::Num8: return 0x09;
|
||||
case sf::Keyboard::Scan::Num9: return 0x0A;
|
||||
case sf::Keyboard::Scan::Num0: return 0x0B;
|
||||
|
||||
case sf::Keyboard::Scan::Enter: return 0x1C;
|
||||
case sf::Keyboard::Scan::Escape: return 0x01;
|
||||
case sf::Keyboard::Scan::Backspace: return 0x0E;
|
||||
case sf::Keyboard::Scan::Tab: return 0x0F;
|
||||
case sf::Keyboard::Scan::Space: return 0x39;
|
||||
case sf::Keyboard::Scan::Hyphen: return 0x0C;
|
||||
case sf::Keyboard::Scan::Equal: return 0x0D;
|
||||
case sf::Keyboard::Scan::LBracket: return 0x1A;
|
||||
case sf::Keyboard::Scan::RBracket: return 0x1B;
|
||||
case sf::Keyboard::Scan::Backslash: return 0x2B;
|
||||
case sf::Keyboard::Scan::Semicolon: return 0x27;
|
||||
case sf::Keyboard::Scan::Apostrophe: return 0x28;
|
||||
case sf::Keyboard::Scan::Grave: return 0x29;
|
||||
case sf::Keyboard::Scan::Comma: return 0x33;
|
||||
case sf::Keyboard::Scan::Period: return 0x34;
|
||||
case sf::Keyboard::Scan::Slash: return 0x35;
|
||||
|
||||
case sf::Keyboard::Scan::F1: return 0x3B;
|
||||
case sf::Keyboard::Scan::F2: return 0x3C;
|
||||
case sf::Keyboard::Scan::F3: return 0x3D;
|
||||
case sf::Keyboard::Scan::F4: return 0x3E;
|
||||
case sf::Keyboard::Scan::F5: return 0x3F;
|
||||
case sf::Keyboard::Scan::F6: return 0x40;
|
||||
case sf::Keyboard::Scan::F7: return 0x41;
|
||||
case sf::Keyboard::Scan::F8: return 0x42;
|
||||
case sf::Keyboard::Scan::F9: return 0x43;
|
||||
case sf::Keyboard::Scan::F10: return 0x44;
|
||||
case sf::Keyboard::Scan::F11: return 0x57;
|
||||
case sf::Keyboard::Scan::F12: return 0x58;
|
||||
case sf::Keyboard::Scan::F13: return 0x64;
|
||||
case sf::Keyboard::Scan::F14: return 0x65;
|
||||
case sf::Keyboard::Scan::F15: return 0x66;
|
||||
case sf::Keyboard::Scan::F16: return 0x67;
|
||||
case sf::Keyboard::Scan::F17: return 0x68;
|
||||
case sf::Keyboard::Scan::F18: return 0x69;
|
||||
case sf::Keyboard::Scan::F19: return 0x6A;
|
||||
case sf::Keyboard::Scan::F20: return 0x6B;
|
||||
case sf::Keyboard::Scan::F21: return 0x6C;
|
||||
case sf::Keyboard::Scan::F22: return 0x6D;
|
||||
case sf::Keyboard::Scan::F23: return 0x6E;
|
||||
case sf::Keyboard::Scan::F24: return 0x76;
|
||||
|
||||
case sf::Keyboard::Scan::CapsLock: return 0x3A;
|
||||
case sf::Keyboard::Scan::PrintScreen: return 0xE037;
|
||||
case sf::Keyboard::Scan::ScrollLock: return 0x46;
|
||||
case sf::Keyboard::Scan::Pause: return 0x45;
|
||||
case sf::Keyboard::Scan::Insert: return 0xE052;
|
||||
case sf::Keyboard::Scan::Home: return 0xE047;
|
||||
case sf::Keyboard::Scan::PageUp: return 0xE049;
|
||||
case sf::Keyboard::Scan::Delete: return 0xE053;
|
||||
case sf::Keyboard::Scan::End: return 0xE04F;
|
||||
case sf::Keyboard::Scan::PageDown: return 0xE051;
|
||||
case sf::Keyboard::Scan::Right: return 0xE04D;
|
||||
case sf::Keyboard::Scan::Left: return 0xE04B;
|
||||
case sf::Keyboard::Scan::Down: return 0xE050;
|
||||
case sf::Keyboard::Scan::Up: return 0xE048;
|
||||
case sf::Keyboard::Scan::NumLock: return 0xE045;
|
||||
|
||||
case sf::Keyboard::Scan::NumpadDivide: return 0xE035;
|
||||
case sf::Keyboard::Scan::NumpadMultiply: return 0x37;
|
||||
case sf::Keyboard::Scan::NumpadMinus: return 0x4A;
|
||||
case sf::Keyboard::Scan::NumpadPlus: return 0x4E;
|
||||
case sf::Keyboard::Scan::NumpadEqual: return 0x7E;
|
||||
case sf::Keyboard::Scan::NumpadEnter: return 0xE01C;
|
||||
case sf::Keyboard::Scan::NumpadDecimal: return 0x53;
|
||||
|
||||
case sf::Keyboard::Scan::Numpad1: return 0x4F;
|
||||
case sf::Keyboard::Scan::Numpad2: return 0x50;
|
||||
case sf::Keyboard::Scan::Numpad3: return 0x51;
|
||||
case sf::Keyboard::Scan::Numpad4: return 0x4B;
|
||||
case sf::Keyboard::Scan::Numpad5: return 0x4C;
|
||||
case sf::Keyboard::Scan::Numpad6: return 0x4D;
|
||||
case sf::Keyboard::Scan::Numpad7: return 0x47;
|
||||
case sf::Keyboard::Scan::Numpad8: return 0x48;
|
||||
case sf::Keyboard::Scan::Numpad9: return 0x49;
|
||||
case sf::Keyboard::Scan::Numpad0: return 0x52;
|
||||
|
||||
case sf::Keyboard::Scan::NonUsBackslash: return 0x56;
|
||||
// No known scancode for Keyboard::Scan::Application
|
||||
// No known scancode for Keyboard::Scan::Execute
|
||||
// No known scancode for Keyboard::Scan::ModeChange
|
||||
case sf::Keyboard::Scan::Help: return 0xE061;
|
||||
case sf::Keyboard::Scan::Menu: return 0xE05D;
|
||||
case sf::Keyboard::Scan::Select: return 0xE01E;
|
||||
// No known scancode for Keyboard::Scan::Redo
|
||||
// No known scancode for Keyboard::Scan::Undo
|
||||
// No known scancode for Keyboard::Scan::Cut
|
||||
// No known scancode for Keyboard::Scan::Copy
|
||||
// No known scancode for Keyboard::Scan::Paste
|
||||
|
||||
case sf::Keyboard::Scan::VolumeMute: return 0xE020;
|
||||
case sf::Keyboard::Scan::VolumeUp: return 0xE02E;
|
||||
case sf::Keyboard::Scan::VolumeDown: return 0xE02C;
|
||||
case sf::Keyboard::Scan::MediaPlayPause: return 0xE022;
|
||||
case sf::Keyboard::Scan::MediaStop: return 0xE024;
|
||||
case sf::Keyboard::Scan::MediaNextTrack: return 0xE019;
|
||||
case sf::Keyboard::Scan::MediaPreviousTrack: return 0xE010;
|
||||
|
||||
case sf::Keyboard::Scan::LControl: return 0x1D;
|
||||
case sf::Keyboard::Scan::LShift: return 0x2A;
|
||||
case sf::Keyboard::Scan::LAlt: return 0x38;
|
||||
case sf::Keyboard::Scan::LSystem: return 0xE05B;
|
||||
case sf::Keyboard::Scan::RControl: return 0xE01D;
|
||||
case sf::Keyboard::Scan::RShift: return 0x36;
|
||||
case sf::Keyboard::Scan::RAlt: return 0xE038;
|
||||
case sf::Keyboard::Scan::RSystem: return 0xE05C;
|
||||
|
||||
case sf::Keyboard::Scan::Back: return 0xE06A;
|
||||
case sf::Keyboard::Scan::Forward: return 0xE069;
|
||||
case sf::Keyboard::Scan::Refresh: return 0xE067;
|
||||
case sf::Keyboard::Scan::Stop: return 0xE068;
|
||||
case sf::Keyboard::Scan::Search: return 0xE065;
|
||||
case sf::Keyboard::Scan::Favorites: return 0xE066;
|
||||
case sf::Keyboard::Scan::HomePage: return 0xE030;
|
||||
|
||||
case sf::Keyboard::Scan::LaunchApplication1: return 0xE06B;
|
||||
case sf::Keyboard::Scan::LaunchApplication2: return 0xE021;
|
||||
case sf::Keyboard::Scan::LaunchMail: return 0xE06C;
|
||||
case sf::Keyboard::Scan::LaunchMediaSelect: return 0xE06D;
|
||||
|
||||
// Unable to map to a scancode
|
||||
default: return 0x0;
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
WORD sfScanToWinScanExtended(sf::Keyboard::Scancode code)
|
||||
{
|
||||
// Convert an SFML scancode to a Windows scancode
|
||||
// Reference: https://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx
|
||||
// clang-format off
|
||||
switch (code)
|
||||
{
|
||||
case sf::Keyboard::Scan::PrintScreen: return 55 | 0xE100;
|
||||
case sf::Keyboard::Scan::Insert: return 82 | 0xE100;
|
||||
case sf::Keyboard::Scan::Home: return 71 | 0xE100;
|
||||
case sf::Keyboard::Scan::PageUp: return 73 | 0xE100;
|
||||
case sf::Keyboard::Scan::Delete: return 83 | 0xE100;
|
||||
case sf::Keyboard::Scan::End: return 79 | 0xE100;
|
||||
case sf::Keyboard::Scan::PageDown: return 81 | 0xE100;
|
||||
case sf::Keyboard::Scan::Right: return 77 | 0xE100;
|
||||
case sf::Keyboard::Scan::Left: return 75 | 0xE100;
|
||||
case sf::Keyboard::Scan::Down: return 80 | 0xE100;
|
||||
case sf::Keyboard::Scan::Up: return 72 | 0xE100;
|
||||
case sf::Keyboard::Scan::NumLock: return 69 | 0xE100;
|
||||
case sf::Keyboard::Scan::NumpadEnter: return 28 | 0xE100;
|
||||
case sf::Keyboard::Scan::NumpadDivide: return 53 | 0xE100;
|
||||
case sf::Keyboard::Scan::Help: return 97 | 0xE100;
|
||||
case sf::Keyboard::Scan::Menu: return 93 | 0xE100;
|
||||
case sf::Keyboard::Scan::Select: return 30 | 0xE100;
|
||||
case sf::Keyboard::Scan::VolumeMute: return 32 | 0xE100;
|
||||
case sf::Keyboard::Scan::VolumeUp: return 46 | 0xE100;
|
||||
case sf::Keyboard::Scan::VolumeDown: return 44 | 0xE100;
|
||||
case sf::Keyboard::Scan::MediaPlayPause: return 34 | 0xE100;
|
||||
case sf::Keyboard::Scan::MediaStop: return 36 | 0xE100;
|
||||
case sf::Keyboard::Scan::MediaNextTrack: return 25 | 0xE100;
|
||||
case sf::Keyboard::Scan::MediaPreviousTrack: return 16 | 0xE100;
|
||||
case sf::Keyboard::Scan::LSystem: return 91 | 0xE100;
|
||||
case sf::Keyboard::Scan::RControl: return 29 | 0xE100;
|
||||
case sf::Keyboard::Scan::RAlt: return 56 | 0xE100;
|
||||
case sf::Keyboard::Scan::RSystem: return 92 | 0xE100;
|
||||
case sf::Keyboard::Scan::Back: return 106 | 0xE100;
|
||||
case sf::Keyboard::Scan::Forward: return 105 | 0xE100;
|
||||
case sf::Keyboard::Scan::Refresh: return 103 | 0xE100;
|
||||
case sf::Keyboard::Scan::Stop: return 104 | 0xE100;
|
||||
case sf::Keyboard::Scan::Search: return 101 | 0xE100;
|
||||
case sf::Keyboard::Scan::Favorites: return 102 | 0xE100;
|
||||
case sf::Keyboard::Scan::HomePage: return 48 | 0xE100;
|
||||
case sf::Keyboard::Scan::LaunchApplication1: return 107 | 0xE100;
|
||||
case sf::Keyboard::Scan::LaunchApplication2: return 33 | 0xE100;
|
||||
case sf::Keyboard::Scan::LaunchMail: return 108 | 0xE100;
|
||||
case sf::Keyboard::Scan::LaunchMediaSelect: return 109 | 0xE100;
|
||||
|
||||
// Use non-extended mapping
|
||||
default: return sfScanToWinScan(code);
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
UINT sfScanToVirtualKey(sf::Keyboard::Scancode code)
|
||||
{
|
||||
const WORD winScancode = sfScanToWinScan(code);
|
||||
|
||||
// Manually map non-extended key codes
|
||||
// clang-format off
|
||||
switch (code)
|
||||
{
|
||||
case sf::Keyboard::Scan::Numpad0: return VK_NUMPAD0;
|
||||
case sf::Keyboard::Scan::Numpad1: return VK_NUMPAD1;
|
||||
case sf::Keyboard::Scan::Numpad2: return VK_NUMPAD2;
|
||||
case sf::Keyboard::Scan::Numpad3: return VK_NUMPAD3;
|
||||
case sf::Keyboard::Scan::Numpad4: return VK_NUMPAD4;
|
||||
case sf::Keyboard::Scan::Numpad5: return VK_NUMPAD5;
|
||||
case sf::Keyboard::Scan::Numpad6: return VK_NUMPAD6;
|
||||
case sf::Keyboard::Scan::Numpad7: return VK_NUMPAD7;
|
||||
case sf::Keyboard::Scan::Numpad8: return VK_NUMPAD8;
|
||||
case sf::Keyboard::Scan::Numpad9: return VK_NUMPAD9;
|
||||
case sf::Keyboard::Scan::NumpadMinus: return VK_SUBTRACT;
|
||||
case sf::Keyboard::Scan::NumpadDecimal: return VK_DECIMAL;
|
||||
case sf::Keyboard::Scan::NumpadDivide: return VK_DIVIDE;
|
||||
case sf::Keyboard::Scan::Pause: return VK_PAUSE;
|
||||
case sf::Keyboard::Scan::RControl: return VK_RCONTROL;
|
||||
case sf::Keyboard::Scan::RAlt: return VK_RMENU;
|
||||
default: return MapVirtualKey(winScancode, MAPVK_VSC_TO_VK_EX);
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
std::optional<sf::String> sfScanToConsumerKeyName(sf::Keyboard::Scancode code)
|
||||
{
|
||||
// Convert an SFML scancode to a Windows consumer keyboard key name
|
||||
// Reference: https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input#keystroke-messages
|
||||
// clang-format off
|
||||
switch (code)
|
||||
{
|
||||
case sf::Keyboard::Scan::MediaNextTrack: return "Next Track";
|
||||
case sf::Keyboard::Scan::MediaPreviousTrack: return "Previous Track";
|
||||
case sf::Keyboard::Scan::MediaStop: return "Stop";
|
||||
case sf::Keyboard::Scan::MediaPlayPause: return "Play/Pause";
|
||||
case sf::Keyboard::Scan::VolumeMute: return "Mute";
|
||||
case sf::Keyboard::Scan::VolumeUp: return "Volume Increment";
|
||||
case sf::Keyboard::Scan::VolumeDown: return "Volume Decrement";
|
||||
case sf::Keyboard::Scan::LaunchMediaSelect: return "Consumer Control Configuration";
|
||||
case sf::Keyboard::Scan::LaunchMail: return "Email Reader";
|
||||
case sf::Keyboard::Scan::LaunchApplication2: return "Calculator";
|
||||
case sf::Keyboard::Scan::LaunchApplication1: return "Local Machine Browser";
|
||||
case sf::Keyboard::Scan::Search: return "Search";
|
||||
case sf::Keyboard::Scan::HomePage: return "Home";
|
||||
case sf::Keyboard::Scan::Back: return "Back";
|
||||
case sf::Keyboard::Scan::Forward: return "Forward";
|
||||
case sf::Keyboard::Scan::Stop: return "Stop";
|
||||
case sf::Keyboard::Scan::Refresh: return "Refresh";
|
||||
case sf::Keyboard::Scan::Favorites: return "Bookmarks";
|
||||
|
||||
// Not a consumer key
|
||||
default: return std::nullopt;
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
/// Ensure the mappings are generated from/to Key and Scancode.
|
||||
void ensureMappings()
|
||||
{
|
||||
static bool isMappingInitialized = false;
|
||||
|
||||
if (isMappingInitialized)
|
||||
return;
|
||||
|
||||
// Phase 1: Initialize mappings with default values
|
||||
keyToScancodeMapping.fill(sf::Keyboard::Scan::Unknown);
|
||||
scancodeToKeyMapping.fill(sf::Keyboard::Key::Unknown);
|
||||
|
||||
// Phase 2: Translate scancode to virtual code to key names
|
||||
for (unsigned int i = 0; i < sf::Keyboard::ScancodeCount; ++i)
|
||||
{
|
||||
const auto scan = static_cast<sf::Keyboard::Scancode>(i);
|
||||
const UINT virtualKey = sfScanToVirtualKey(scan);
|
||||
const sf::Keyboard::Key key = virtualKeyToSfKey(virtualKey);
|
||||
if (key != sf::Keyboard::Key::Unknown && keyToScancodeMapping[key] == sf::Keyboard::Scan::Unknown)
|
||||
keyToScancodeMapping[key] = scan;
|
||||
scancodeToKeyMapping[scan] = key;
|
||||
}
|
||||
|
||||
isMappingInitialized = true;
|
||||
}
|
||||
|
||||
bool isValidScancode(sf::Keyboard::Scancode code)
|
||||
{
|
||||
return code > sf::Keyboard::Scan::Unknown && static_cast<unsigned int>(code) < sf::Keyboard::ScancodeCount;
|
||||
}
|
||||
|
||||
bool isValidKey(sf::Keyboard::Key key)
|
||||
{
|
||||
return key > sf::Keyboard::Key::Unknown && static_cast<unsigned int>(key) < sf::Keyboard::KeyCount;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace sf::priv::InputImpl
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
bool isKeyPressed(Keyboard::Key key)
|
||||
{
|
||||
const int virtualKey = sfKeyToVirtualKey(key);
|
||||
return (GetAsyncKeyState(virtualKey) & 0x8000) != 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool isKeyPressed(Keyboard::Scancode code)
|
||||
{
|
||||
const UINT virtualKey = sfScanToVirtualKey(code);
|
||||
return (GetAsyncKeyState(static_cast<int>(virtualKey)) & KF_UP) != 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Keyboard::Key localize(Keyboard::Scancode code)
|
||||
{
|
||||
if (!isValidScancode(code))
|
||||
return Keyboard::Key::Unknown;
|
||||
|
||||
ensureMappings();
|
||||
|
||||
return scancodeToKeyMapping[code];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Keyboard::Scancode delocalize(Keyboard::Key key)
|
||||
{
|
||||
if (!isValidKey(key))
|
||||
return Keyboard::Scan::Unknown;
|
||||
|
||||
ensureMappings();
|
||||
|
||||
return keyToScancodeMapping[key];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
String getDescription(Keyboard::Scancode code)
|
||||
{
|
||||
// Try to translate the scan code to a consumer key
|
||||
if (const auto consumerKeyName = sfScanToConsumerKeyName(code))
|
||||
return *consumerKeyName;
|
||||
|
||||
WORD winCode = sfScanToWinScanExtended(code);
|
||||
std::array<WCHAR, 1024> name{};
|
||||
|
||||
// Remap F13-F23 to values supported by GetKeyNameText
|
||||
if ((winCode >= 0x64) && (winCode <= 0x6E))
|
||||
winCode += 0x18;
|
||||
// Remap F24 to value supported by GetKeyNameText
|
||||
if (winCode == 0x76)
|
||||
winCode = 0x87;
|
||||
|
||||
if (GetKeyNameText(winCode << 16, name.data(), static_cast<int>(name.size())) > 0)
|
||||
return name.data();
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void setVirtualKeyboardVisible(bool /*visible*/)
|
||||
{
|
||||
// Not applicable
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool isMouseButtonPressed(Mouse::Button button)
|
||||
{
|
||||
int virtualKey = 0;
|
||||
switch (button)
|
||||
{
|
||||
case Mouse::Button::Left:
|
||||
virtualKey = GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON;
|
||||
break;
|
||||
case Mouse::Button::Right:
|
||||
virtualKey = GetSystemMetrics(SM_SWAPBUTTON) ? VK_LBUTTON : VK_RBUTTON;
|
||||
break;
|
||||
case Mouse::Button::Middle:
|
||||
virtualKey = VK_MBUTTON;
|
||||
break;
|
||||
case Mouse::Button::Extra1:
|
||||
virtualKey = VK_XBUTTON1;
|
||||
break;
|
||||
case Mouse::Button::Extra2:
|
||||
virtualKey = VK_XBUTTON2;
|
||||
break;
|
||||
default:
|
||||
virtualKey = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return (GetAsyncKeyState(virtualKey) & 0x8000) != 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i getMousePosition()
|
||||
{
|
||||
POINT point;
|
||||
GetCursorPos(&point);
|
||||
return {point.x, point.y};
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i getMousePosition(const WindowBase& relativeTo)
|
||||
{
|
||||
if (const WindowHandle handle = relativeTo.getNativeHandle())
|
||||
{
|
||||
POINT point;
|
||||
GetCursorPos(&point);
|
||||
ScreenToClient(handle, &point);
|
||||
return {point.x, point.y};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void setMousePosition(Vector2i position)
|
||||
{
|
||||
SetCursorPos(position.x, position.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void setMousePosition(Vector2i position, const WindowBase& relativeTo)
|
||||
{
|
||||
if (const WindowHandle handle = relativeTo.getNativeHandle())
|
||||
{
|
||||
POINT point = {position.x, position.y};
|
||||
ClientToScreen(handle, &point);
|
||||
SetCursorPos(point.x, point.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool isTouchDown(unsigned int /*finger*/)
|
||||
{
|
||||
// Not applicable
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i getTouchPosition(unsigned int /*finger*/)
|
||||
{
|
||||
// Not applicable
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i getTouchPosition(unsigned int /*finger*/, const WindowBase& /*relativeTo*/)
|
||||
{
|
||||
// Not applicable
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace sf::priv::InputImpl
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,227 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/System/EnumArray.hpp>
|
||||
#include <SFML/System/Win32/WindowsHeader.hpp>
|
||||
|
||||
#include <dinput.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Windows implementation of joysticks
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class JoystickImpl
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global initialization of the joystick module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void initialize();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global cleanup of the joystick module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void cleanup();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a joystick is currently connected
|
||||
///
|
||||
/// \param index Index of the joystick to check
|
||||
///
|
||||
/// \return `true` if the joystick is connected, `false` otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isConnected(unsigned int index);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable lazy enumeration updates
|
||||
///
|
||||
/// \param status Whether to rely on windows triggering enumeration updates
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void setLazyUpdates(bool status);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the connection status of all joysticks
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void updateConnections();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Open the joystick
|
||||
///
|
||||
/// \param index Index assigned to the joystick
|
||||
///
|
||||
/// \return `true` on success, `false` on failure
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] bool open(unsigned int index);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Close the joystick
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void close();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the joystick capabilities
|
||||
///
|
||||
/// \return Joystick capabilities
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] JoystickCaps getCapabilities() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the joystick identification
|
||||
///
|
||||
/// \return Joystick identification
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] Joystick::Identification getIdentification() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the joystick and get its new state
|
||||
///
|
||||
/// \return Joystick state
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] JoystickState update();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global initialization of the joystick module (DInput)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void initializeDInput();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global cleanup of the joystick module (DInput)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void cleanupDInput();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a joystick is currently connected (DInput)
|
||||
///
|
||||
/// \param index Index of the joystick to check
|
||||
///
|
||||
/// \return `true` if the joystick is connected, `false` otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isConnectedDInput(unsigned int index);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the connection status of all joysticks (DInput)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void updateConnectionsDInput();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Open the joystick (DInput)
|
||||
///
|
||||
/// \param index Index assigned to the joystick
|
||||
///
|
||||
/// \return `true` on success, `false` on failure
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] bool openDInput(unsigned int index);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Close the joystick (DInput)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void closeDInput();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the joystick capabilities (DInput)
|
||||
///
|
||||
/// \return Joystick capabilities
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] JoystickCaps getCapabilitiesDInput() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the joystick and get its new state (DInput, Buffered)
|
||||
///
|
||||
/// \return Joystick state
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] JoystickState updateDInputBuffered();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the joystick and get its new state (DInput, Polled)
|
||||
///
|
||||
/// \return Joystick state
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] JoystickState updateDInputPolled();
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Device enumeration callback function passed to EnumDevices in updateConnections
|
||||
///
|
||||
/// \param deviceInstance Device object instance
|
||||
/// \param userData User data (unused)
|
||||
///
|
||||
/// \return DIENUM_CONTINUE to continue enumerating devices or DIENUM_STOP to stop
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static BOOL CALLBACK deviceEnumerationCallback(const DIDEVICEINSTANCE* deviceInstance, void* userData);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Device object enumeration callback function passed to EnumObjects in open
|
||||
///
|
||||
/// \param deviceObjectInstance Device object instance
|
||||
/// \param userData User data (pointer to our JoystickImpl object)
|
||||
///
|
||||
/// \return DIENUM_CONTINUE to continue enumerating objects or DIENUM_STOP to stop
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static BOOL CALLBACK deviceObjectEnumerationCallback(const DIDEVICEOBJECTINSTANCE* deviceObjectInstance, void* userData);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int m_index{}; //!< Index of the joystick
|
||||
JOYCAPS m_caps{}; //!< Joystick capabilities
|
||||
IDirectInputDevice8W* m_device{}; //!< DirectInput 8.x device
|
||||
DIDEVCAPS m_deviceCaps{}; //!< DirectInput device capabilities
|
||||
EnumArray<Joystick::Axis, int, Joystick::AxisCount> m_axes{}; //!< Offsets to the bytes containing the axes states, -1 if not available
|
||||
std::array<int, Joystick::ButtonCount> m_buttons{}; //!< Offsets to the bytes containing the button states, -1 if not available
|
||||
Joystick::Identification m_identification; //!< Joystick identification
|
||||
JoystickState m_state; //!< Buffered joystick state
|
||||
bool m_buffered{}; //!< `true` if the device uses buffering, `false` if the device uses polling
|
||||
};
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/SensorImpl.hpp>
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
void SensorImpl::initialize()
|
||||
{
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SensorImpl::cleanup()
|
||||
{
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SensorImpl::isAvailable(Sensor::Type /*sensor*/)
|
||||
{
|
||||
// TODO: not implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SensorImpl::open(Sensor::Type /*sensor*/)
|
||||
{
|
||||
// TODO: not implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SensorImpl::close()
|
||||
{
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector3f SensorImpl::update()
|
||||
{
|
||||
// TODO: not implemented
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SensorImpl::setEnabled(bool /*enabled*/)
|
||||
{
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/Sensor.hpp>
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Windows implementation of sensors
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SensorImpl
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global initialization of the sensor module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void initialize();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Perform the global cleanup of the sensor module
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void cleanup();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if a sensor is available
|
||||
///
|
||||
/// \param sensor Sensor to check
|
||||
///
|
||||
/// \return `true` if the sensor is available, `false` otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isAvailable(Sensor::Type sensor);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Open the sensor
|
||||
///
|
||||
/// \param sensor Type of the sensor
|
||||
///
|
||||
/// \return `true` on success, `false` on failure
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] bool open(Sensor::Type sensor);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Close the sensor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void close();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the sensor and get its new value
|
||||
///
|
||||
/// \return Sensor value
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] Vector3f update();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable the sensor
|
||||
///
|
||||
/// \param enabled `true` to enable, `false` to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setEnabled(bool enabled);
|
||||
};
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/System/String.hpp>
|
||||
#include <SFML/System/Win32/WindowsHeader.hpp>
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
inline std::string getErrorString(DWORD error)
|
||||
{
|
||||
PTCHAR buffer = nullptr;
|
||||
if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
nullptr,
|
||||
error,
|
||||
0,
|
||||
reinterpret_cast<PTCHAR>(&buffer),
|
||||
0,
|
||||
nullptr) == 0)
|
||||
{
|
||||
return "Unknown error.";
|
||||
}
|
||||
|
||||
const sf::String message = buffer;
|
||||
LocalFree(buffer);
|
||||
return message.toAnsiString();
|
||||
}
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/VideoModeImpl.hpp>
|
||||
|
||||
#include <SFML/System/Win32/WindowsHeader.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
|
||||
{
|
||||
std::vector<VideoMode> modes;
|
||||
|
||||
// Enumerate all available video modes for the primary display adapter
|
||||
DEVMODE win32Mode;
|
||||
win32Mode.dmSize = sizeof(win32Mode);
|
||||
win32Mode.dmDriverExtra = 0;
|
||||
for (int count = 0; EnumDisplaySettings(nullptr, static_cast<DWORD>(count), &win32Mode); ++count)
|
||||
{
|
||||
// Convert to sf::VideoMode
|
||||
const VideoMode mode({win32Mode.dmPelsWidth, win32Mode.dmPelsHeight}, win32Mode.dmBitsPerPel);
|
||||
|
||||
// Add it only if it is not already in the array
|
||||
if (std::find(modes.begin(), modes.end(), mode) == modes.end())
|
||||
modes.push_back(mode);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VideoMode VideoModeImpl::getDesktopMode()
|
||||
{
|
||||
DEVMODE win32Mode;
|
||||
win32Mode.dmSize = sizeof(win32Mode);
|
||||
win32Mode.dmDriverExtra = 0;
|
||||
EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &win32Mode);
|
||||
|
||||
return VideoMode({win32Mode.dmPelsWidth, win32Mode.dmPelsHeight}, win32Mode.dmBitsPerPel);
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/VulkanImpl.hpp>
|
||||
|
||||
#include <SFML/System/Win32/WindowsHeader.hpp>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define VK_USE_PLATFORM_WIN32_KHR
|
||||
#define VK_NO_PROTOTYPES
|
||||
#include <vulkan.h>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
struct VulkanLibraryWrapper
|
||||
{
|
||||
~VulkanLibraryWrapper()
|
||||
{
|
||||
if (library)
|
||||
FreeLibrary(library);
|
||||
}
|
||||
|
||||
// Try to load the library and all the required entry points
|
||||
bool loadLibrary()
|
||||
{
|
||||
if (library)
|
||||
return true;
|
||||
|
||||
library = LoadLibraryA("vulkan-1.dll");
|
||||
|
||||
if (!library)
|
||||
return false;
|
||||
|
||||
if (!loadEntryPoint(vkGetInstanceProcAddr, "vkGetInstanceProcAddr"))
|
||||
{
|
||||
FreeLibrary(library);
|
||||
library = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!loadEntryPoint(vkEnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties"))
|
||||
{
|
||||
FreeLibrary(library);
|
||||
library = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!loadEntryPoint(vkEnumerateInstanceExtensionProperties, "vkEnumerateInstanceExtensionProperties"))
|
||||
{
|
||||
FreeLibrary(library);
|
||||
library = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool loadEntryPoint(T& entryPoint, const char* name)
|
||||
{
|
||||
entryPoint = reinterpret_cast<T>(reinterpret_cast<void*>(GetProcAddress(library, name)));
|
||||
|
||||
return entryPoint != nullptr;
|
||||
}
|
||||
|
||||
HMODULE library{};
|
||||
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr{};
|
||||
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{};
|
||||
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties{};
|
||||
};
|
||||
|
||||
VulkanLibraryWrapper wrapper;
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VulkanImpl::isAvailable(bool requireGraphics)
|
||||
{
|
||||
static bool checked = false;
|
||||
static bool computeAvailable = false;
|
||||
static bool graphicsAvailable = false;
|
||||
|
||||
if (!checked)
|
||||
{
|
||||
checked = true;
|
||||
|
||||
// Check if the library is available
|
||||
computeAvailable = wrapper.loadLibrary();
|
||||
|
||||
// To check for instance extensions we don't need to differentiate between graphics and compute
|
||||
graphicsAvailable = computeAvailable;
|
||||
|
||||
if (graphicsAvailable)
|
||||
{
|
||||
// Retrieve the available instance extensions
|
||||
std::vector<VkExtensionProperties> extensionProperties;
|
||||
|
||||
std::uint32_t extensionCount = 0;
|
||||
|
||||
wrapper.vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
||||
|
||||
extensionProperties.resize(extensionCount);
|
||||
|
||||
wrapper.vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensionProperties.data());
|
||||
|
||||
// Check if the necessary extensions are available
|
||||
bool hasVkKhrSurface = false;
|
||||
bool hasVkKhrPlatformSurface = false;
|
||||
|
||||
for (const VkExtensionProperties& properties : extensionProperties)
|
||||
{
|
||||
if (std::string_view(properties.extensionName) == VK_KHR_SURFACE_EXTENSION_NAME)
|
||||
{
|
||||
hasVkKhrSurface = true;
|
||||
}
|
||||
else if (std::string_view(properties.extensionName) == VK_KHR_WIN32_SURFACE_EXTENSION_NAME)
|
||||
{
|
||||
hasVkKhrPlatformSurface = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasVkKhrSurface || !hasVkKhrPlatformSurface)
|
||||
graphicsAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (requireGraphics)
|
||||
return graphicsAvailable;
|
||||
|
||||
return computeAvailable;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VulkanFunctionPointer VulkanImpl::getFunction(const char* name)
|
||||
{
|
||||
if (!isAvailable(false))
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<VulkanFunctionPointer>(GetProcAddress(wrapper.library, name));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const std::vector<const char*>& VulkanImpl::getGraphicsRequiredInstanceExtensions()
|
||||
{
|
||||
static const std::vector<const char*> extensions{VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME};
|
||||
return extensions;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VulkanImpl::createVulkanSurface(const VkInstance& instance,
|
||||
WindowHandle windowHandle,
|
||||
VkSurfaceKHR& surface,
|
||||
const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
if (!isAvailable())
|
||||
return false;
|
||||
|
||||
// Make a copy of the instance handle since we get it passed as a reference
|
||||
VkInstance inst = instance;
|
||||
|
||||
auto vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(
|
||||
wrapper.vkGetInstanceProcAddr(inst, "vkCreateWin32SurfaceKHR"));
|
||||
|
||||
if (!vkCreateWin32SurfaceKHR)
|
||||
return false;
|
||||
|
||||
VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = VkWin32SurfaceCreateInfoKHR();
|
||||
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
surfaceCreateInfo.hinstance = GetModuleHandleA(nullptr);
|
||||
surfaceCreateInfo.hwnd = windowHandle;
|
||||
|
||||
return vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, allocator, &surface) == VK_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,849 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/ContextSettings.hpp>
|
||||
#include <SFML/Window/VideoMode.hpp>
|
||||
#include <SFML/Window/Win32/Utils.hpp>
|
||||
#include <SFML/Window/Win32/WglContext.hpp>
|
||||
#include <SFML/Window/WindowImpl.hpp>
|
||||
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/String.hpp>
|
||||
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// We check for this definition in order to avoid multiple definitions of GLAD
|
||||
// entities during unity builds of SFML.
|
||||
#ifndef SF_GLAD_WGL_IMPLEMENTATION_INCLUDED
|
||||
#define SF_GLAD_WGL_IMPLEMENTATION_INCLUDED
|
||||
#define SF_GLAD_WGL_IMPLEMENTATION
|
||||
#include <glad/wgl.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace WglContextImpl
|
||||
{
|
||||
// Some drivers are bugged and don't track the current HDC/HGLRC properly
|
||||
// In order to deactivate successfully, we need to track it ourselves as well
|
||||
thread_local sf::priv::WglContext* currentContext(nullptr);
|
||||
|
||||
|
||||
// We use a different loader for wgl functions since we load them directly from OpenGL32.dll
|
||||
sf::GlFunctionPointer getOpenGl32Function(const char* name)
|
||||
{
|
||||
static const HMODULE module = GetModuleHandleA("OpenGL32.dll");
|
||||
|
||||
if (module)
|
||||
return reinterpret_cast<sf::GlFunctionPointer>(GetProcAddress(module, reinterpret_cast<LPCSTR>(name)));
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ensureInit()
|
||||
{
|
||||
static bool initialized = false;
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
|
||||
gladLoadWGL(nullptr, getOpenGl32Function);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ensureExtensionsInit(HDC deviceContext)
|
||||
{
|
||||
static bool initialized = false;
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
|
||||
// We don't check the return value since the extension
|
||||
// flags are cleared even if loading fails
|
||||
gladLoadWGL(deviceContext, sf::priv::WglContext::getFunction);
|
||||
}
|
||||
}
|
||||
} // namespace WglContextImpl
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace sf::priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
WglContext::WglContext(WglContext* shared) : WglContext(shared, ContextSettings{}, {1u, 1u})
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
WglContext::WglContext(WglContext* shared, const ContextSettings& settings, const WindowImpl& owner, unsigned int bitsPerPixel)
|
||||
{
|
||||
WglContextImpl::ensureInit();
|
||||
|
||||
// Save the creation settings
|
||||
m_settings = settings;
|
||||
|
||||
// Create the rendering surface from the owner window
|
||||
createSurface(owner.getNativeHandle(), bitsPerPixel);
|
||||
|
||||
// Create the context
|
||||
createContext(shared);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
WglContext::WglContext(WglContext* shared, const ContextSettings& settings, Vector2u size)
|
||||
{
|
||||
WglContextImpl::ensureInit();
|
||||
|
||||
// Save the creation settings
|
||||
m_settings = settings;
|
||||
|
||||
// Create the rendering surface (window or pbuffer if supported)
|
||||
createSurface(shared, size, VideoMode::getDesktopMode().bitsPerPixel);
|
||||
|
||||
// Create the context
|
||||
createContext(shared);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
WglContext::~WglContext()
|
||||
{
|
||||
// Notify unshared OpenGL resources of context destruction
|
||||
cleanupUnsharedResources();
|
||||
|
||||
// Destroy the OpenGL context
|
||||
if (m_context)
|
||||
{
|
||||
if (WglContextImpl::currentContext == this)
|
||||
{
|
||||
if (wglMakeCurrent(m_deviceContext, nullptr) == TRUE)
|
||||
WglContextImpl::currentContext = nullptr;
|
||||
}
|
||||
|
||||
wglDeleteContext(m_context);
|
||||
}
|
||||
|
||||
// Destroy the device context
|
||||
if (m_deviceContext)
|
||||
{
|
||||
if (m_pbuffer)
|
||||
{
|
||||
wglReleasePbufferDCARB(m_pbuffer, m_deviceContext);
|
||||
wglDestroyPbufferARB(m_pbuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReleaseDC(m_window, m_deviceContext);
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the window if we own it
|
||||
if (m_window && m_ownsWindow)
|
||||
DestroyWindow(m_window);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
GlFunctionPointer WglContext::getFunction(const char* name)
|
||||
{
|
||||
if (WglContextImpl::currentContext == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// If we are using the generic GDI implementation, skip to loading directly from OpenGL32.dll since it doesn't support extensions
|
||||
if (!WglContextImpl::currentContext->m_isGeneric)
|
||||
{
|
||||
auto address = reinterpret_cast<GlFunctionPointer>(wglGetProcAddress(reinterpret_cast<LPCSTR>(name)));
|
||||
|
||||
if (address)
|
||||
{
|
||||
// Test whether the returned value is a valid error code
|
||||
auto errorCode = reinterpret_cast<std::ptrdiff_t>(address);
|
||||
|
||||
if ((errorCode != -1) && (errorCode != 1) && (errorCode != 2) && (errorCode != 3))
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
return WglContextImpl::getOpenGl32Function(name);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool WglContext::makeCurrent(bool current)
|
||||
{
|
||||
if (!m_deviceContext || !m_context)
|
||||
return false;
|
||||
|
||||
if (wglMakeCurrent(m_deviceContext, current ? m_context : nullptr) == FALSE)
|
||||
{
|
||||
err() << "Failed to " << (current ? "activate" : "deactivate")
|
||||
<< " OpenGL context: " << getErrorString(GetLastError()) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
WglContextImpl::currentContext = (current ? this : nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WglContext::display()
|
||||
{
|
||||
if (m_deviceContext && m_context)
|
||||
SwapBuffers(m_deviceContext);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WglContext::setVerticalSyncEnabled(bool enabled)
|
||||
{
|
||||
// Make sure that extensions are initialized
|
||||
WglContextImpl::ensureExtensionsInit(m_deviceContext);
|
||||
|
||||
if (SF_GLAD_WGL_EXT_swap_control)
|
||||
{
|
||||
if (wglSwapIntervalEXT(enabled) == FALSE)
|
||||
err() << "Setting vertical sync failed: " << getErrorString(GetLastError()) << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
{
|
||||
// wglSwapIntervalEXT not supported
|
||||
err() << "Setting vertical sync not supported" << std::endl;
|
||||
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPixel, const ContextSettings& settings, bool pbuffer)
|
||||
{
|
||||
// Selecting a pixel format can be an expensive process on some implementations
|
||||
// Since the same pixel format should always be selected for a specific combination of inputs
|
||||
// we can cache the result of the lookup instead of having to perform it multiple times for the same inputs
|
||||
struct PixelFormatCacheEntry
|
||||
{
|
||||
unsigned int bitsPerPixel{};
|
||||
unsigned int depthBits{};
|
||||
unsigned int stencilBits{};
|
||||
unsigned int antiAliasingLevel{};
|
||||
bool pbuffer{};
|
||||
int bestFormat{};
|
||||
};
|
||||
|
||||
static std::mutex cacheMutex;
|
||||
static std::vector<PixelFormatCacheEntry> pixelFormatCache;
|
||||
|
||||
// Check if we have already previously found a pixel format for
|
||||
// the current inputs and return it if one has been previously found
|
||||
{
|
||||
const std::lock_guard lock(cacheMutex);
|
||||
|
||||
for (const auto& entry : pixelFormatCache)
|
||||
{
|
||||
if (bitsPerPixel == entry.bitsPerPixel && settings.depthBits == entry.depthBits &&
|
||||
settings.stencilBits == entry.stencilBits && settings.antiAliasingLevel == entry.antiAliasingLevel &&
|
||||
pbuffer == entry.pbuffer)
|
||||
return entry.bestFormat;
|
||||
}
|
||||
}
|
||||
|
||||
WglContextImpl::ensureInit();
|
||||
|
||||
// Find a suitable pixel format -- first try with wglChoosePixelFormatARB
|
||||
int bestFormat = 0;
|
||||
if (SF_GLAD_WGL_ARB_pixel_format)
|
||||
{
|
||||
// Define the basic attributes we want for our window
|
||||
static constexpr std::array intAttributes =
|
||||
{WGL_DRAW_TO_WINDOW_ARB,
|
||||
GL_TRUE,
|
||||
WGL_SUPPORT_OPENGL_ARB,
|
||||
GL_TRUE,
|
||||
WGL_DOUBLE_BUFFER_ARB,
|
||||
GL_TRUE,
|
||||
WGL_PIXEL_TYPE_ARB,
|
||||
WGL_TYPE_RGBA_ARB,
|
||||
0,
|
||||
0};
|
||||
|
||||
// Check how many formats are supporting our requirements
|
||||
std::array<int, 512> formats{};
|
||||
UINT nbFormats = 0; // We must initialize to 0 otherwise broken drivers might fill with garbage in the following call
|
||||
const bool isValid = wglChoosePixelFormatARB(deviceContext,
|
||||
intAttributes.data(),
|
||||
nullptr,
|
||||
static_cast<UINT>(formats.size()),
|
||||
formats.data(),
|
||||
&nbFormats) != FALSE;
|
||||
|
||||
if (!isValid)
|
||||
err() << "Failed to enumerate pixel formats: " << getErrorString(GetLastError()) << std::endl;
|
||||
|
||||
// Get the best format among the returned ones
|
||||
if (isValid && (nbFormats > 0))
|
||||
{
|
||||
int bestScore = 0x7FFFFFFF;
|
||||
for (UINT i = 0; i < nbFormats; ++i)
|
||||
{
|
||||
// Extract the components of the current format
|
||||
std::array<int, 7> values{};
|
||||
static constexpr std::array attributes =
|
||||
{WGL_RED_BITS_ARB,
|
||||
WGL_GREEN_BITS_ARB,
|
||||
WGL_BLUE_BITS_ARB,
|
||||
WGL_ALPHA_BITS_ARB,
|
||||
WGL_DEPTH_BITS_ARB,
|
||||
WGL_STENCIL_BITS_ARB,
|
||||
WGL_ACCELERATION_ARB};
|
||||
|
||||
if (wglGetPixelFormatAttribivARB(deviceContext,
|
||||
formats[i],
|
||||
PFD_MAIN_PLANE,
|
||||
static_cast<UINT>(values.size()),
|
||||
attributes.data(),
|
||||
values.data()) == FALSE)
|
||||
{
|
||||
err() << "Failed to retrieve pixel format information: " << getErrorString(GetLastError()) << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
std::array sampleValues = {0, 0};
|
||||
if (SF_GLAD_WGL_ARB_multisample)
|
||||
{
|
||||
static constexpr std::array sampleAttributes = {WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB};
|
||||
|
||||
if (wglGetPixelFormatAttribivARB(deviceContext,
|
||||
formats[i],
|
||||
PFD_MAIN_PLANE,
|
||||
static_cast<UINT>(sampleAttributes.size()),
|
||||
sampleAttributes.data(),
|
||||
sampleValues.data()) == FALSE)
|
||||
{
|
||||
err() << "Failed to retrieve pixel format multisampling information: "
|
||||
<< getErrorString(GetLastError()) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int sRgbCapableValue = 0;
|
||||
if (SF_GLAD_WGL_ARB_framebuffer_sRGB || SF_GLAD_WGL_EXT_framebuffer_sRGB)
|
||||
{
|
||||
const int sRgbCapableAttribute = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
|
||||
|
||||
if (wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 1, &sRgbCapableAttribute, &sRgbCapableValue) ==
|
||||
FALSE)
|
||||
{
|
||||
err() << "Failed to retrieve pixel format sRGB capability information: "
|
||||
<< getErrorString(GetLastError()) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pbuffer)
|
||||
{
|
||||
static constexpr std::array pbufferAttributes = {WGL_DRAW_TO_PBUFFER_ARB};
|
||||
|
||||
int pbufferValue = 0;
|
||||
|
||||
if (wglGetPixelFormatAttribivARB(deviceContext,
|
||||
formats[i],
|
||||
PFD_MAIN_PLANE,
|
||||
static_cast<UINT>(pbufferAttributes.size()),
|
||||
pbufferAttributes.data(),
|
||||
&pbufferValue) == FALSE)
|
||||
{
|
||||
err() << "Failed to retrieve pixel format pbuffer information: " << getErrorString(GetLastError())
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pbufferValue != GL_TRUE)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Evaluate the current configuration
|
||||
const int color = values[0] + values[1] + values[2] + values[3];
|
||||
const int score = evaluateFormat(bitsPerPixel,
|
||||
settings,
|
||||
color,
|
||||
values[4],
|
||||
values[5],
|
||||
sampleValues[0] ? sampleValues[1] : 0,
|
||||
values[6] == WGL_FULL_ACCELERATION_ARB,
|
||||
sRgbCapableValue == TRUE);
|
||||
|
||||
// Keep it if it's better than the current best
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestScore = score;
|
||||
bestFormat = formats[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find a pixel format with ChoosePixelFormat, if wglChoosePixelFormatARB is not supported
|
||||
// ChoosePixelFormat doesn't support pbuffers
|
||||
if ((bestFormat == 0) && !pbuffer)
|
||||
{
|
||||
// Setup a pixel format descriptor from the rendering settings
|
||||
PIXELFORMATDESCRIPTOR descriptor;
|
||||
ZeroMemory(&descriptor, sizeof(descriptor));
|
||||
descriptor.nSize = sizeof(descriptor);
|
||||
descriptor.nVersion = 1;
|
||||
descriptor.iLayerType = PFD_MAIN_PLANE;
|
||||
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
descriptor.iPixelType = PFD_TYPE_RGBA;
|
||||
descriptor.cColorBits = static_cast<BYTE>(bitsPerPixel);
|
||||
descriptor.cDepthBits = static_cast<BYTE>(settings.depthBits);
|
||||
descriptor.cStencilBits = static_cast<BYTE>(settings.stencilBits);
|
||||
descriptor.cAlphaBits = bitsPerPixel == 32 ? 8 : 0;
|
||||
|
||||
// Get the pixel format that best matches our requirements
|
||||
bestFormat = ChoosePixelFormat(deviceContext, &descriptor);
|
||||
}
|
||||
|
||||
// If we get this far, the format wasn't found in the cache so add it here
|
||||
{
|
||||
const std::lock_guard lock(cacheMutex);
|
||||
|
||||
pixelFormatCache.emplace_back(
|
||||
PixelFormatCacheEntry{bitsPerPixel, settings.depthBits, settings.stencilBits, settings.antiAliasingLevel, pbuffer, bestFormat});
|
||||
}
|
||||
|
||||
return bestFormat;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WglContext::setDevicePixelFormat(unsigned int bitsPerPixel)
|
||||
{
|
||||
const int bestFormat = selectBestPixelFormat(m_deviceContext, bitsPerPixel, m_settings);
|
||||
|
||||
if (bestFormat == 0)
|
||||
{
|
||||
err() << "Failed to find a suitable pixel format for device context: " << getErrorString(GetLastError()) << '\n'
|
||||
<< "Cannot create OpenGL context" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract the depth and stencil bits from the chosen format
|
||||
PIXELFORMATDESCRIPTOR actualFormat;
|
||||
actualFormat.nSize = sizeof(actualFormat);
|
||||
actualFormat.nVersion = 1;
|
||||
DescribePixelFormat(m_deviceContext, bestFormat, sizeof(actualFormat), &actualFormat);
|
||||
|
||||
// Set the chosen pixel format
|
||||
if (SetPixelFormat(m_deviceContext, bestFormat, &actualFormat) == FALSE)
|
||||
{
|
||||
err() << "Failed to set pixel format for device context: " << getErrorString(GetLastError()) << '\n'
|
||||
<< "Cannot create OpenGL context" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WglContext::updateSettingsFromPixelFormat()
|
||||
{
|
||||
const int format = GetPixelFormat(m_deviceContext);
|
||||
|
||||
if (format == 0)
|
||||
{
|
||||
err() << "Failed to get selected pixel format: " << getErrorString(GetLastError()) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PIXELFORMATDESCRIPTOR actualFormat;
|
||||
actualFormat.nSize = sizeof(actualFormat);
|
||||
actualFormat.nVersion = 1;
|
||||
|
||||
if (DescribePixelFormat(m_deviceContext, format, sizeof(actualFormat), &actualFormat) == 0)
|
||||
{
|
||||
err() << "Failed to retrieve pixel format information: " << getErrorString(GetLastError()) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Detect if we are running using the generic GDI implementation and warn
|
||||
if (actualFormat.dwFlags & PFD_GENERIC_FORMAT)
|
||||
{
|
||||
m_isGeneric = true;
|
||||
|
||||
err() << "Warning: Detected \"Microsoft Corporation GDI Generic\" OpenGL implementation" << std::endl;
|
||||
|
||||
// Detect if the generic GDI implementation is not accelerated
|
||||
if (!(actualFormat.dwFlags & PFD_GENERIC_ACCELERATED))
|
||||
err() << "Warning: The \"Microsoft Corporation GDI Generic\" OpenGL implementation is not "
|
||||
"hardware-accelerated"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if (SF_GLAD_WGL_ARB_pixel_format)
|
||||
{
|
||||
static constexpr std::array attributes = {WGL_DEPTH_BITS_ARB, WGL_STENCIL_BITS_ARB};
|
||||
std::array<int, 2> values{};
|
||||
|
||||
if (wglGetPixelFormatAttribivARB(m_deviceContext,
|
||||
format,
|
||||
PFD_MAIN_PLANE,
|
||||
static_cast<UINT>(attributes.size()),
|
||||
attributes.data(),
|
||||
values.data()) == TRUE)
|
||||
{
|
||||
m_settings.depthBits = static_cast<unsigned int>(values[0]);
|
||||
m_settings.stencilBits = static_cast<unsigned int>(values[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Failed to retrieve pixel format information: " << getErrorString(GetLastError()) << std::endl;
|
||||
m_settings.depthBits = actualFormat.cDepthBits;
|
||||
m_settings.stencilBits = actualFormat.cStencilBits;
|
||||
}
|
||||
|
||||
if (SF_GLAD_WGL_ARB_multisample)
|
||||
{
|
||||
static constexpr std::array sampleAttributes = {WGL_SAMPLE_BUFFERS_ARB, WGL_SAMPLES_ARB};
|
||||
std::array<int, 2> sampleValues{};
|
||||
|
||||
if (wglGetPixelFormatAttribivARB(m_deviceContext,
|
||||
format,
|
||||
PFD_MAIN_PLANE,
|
||||
static_cast<UINT>(sampleAttributes.size()),
|
||||
sampleAttributes.data(),
|
||||
sampleValues.data()) == TRUE)
|
||||
{
|
||||
m_settings.antiAliasingLevel = static_cast<unsigned int>(sampleValues[0] ? sampleValues[1] : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Failed to retrieve pixel format multisampling information: " << getErrorString(GetLastError())
|
||||
<< std::endl;
|
||||
m_settings.antiAliasingLevel = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings.antiAliasingLevel = 0;
|
||||
}
|
||||
|
||||
if (SF_GLAD_WGL_ARB_framebuffer_sRGB || SF_GLAD_WGL_EXT_framebuffer_sRGB)
|
||||
{
|
||||
static constexpr std::array sRgbCapableAttribute = {WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB};
|
||||
int sRgbCapableValue = 0;
|
||||
|
||||
if (wglGetPixelFormatAttribivARB(m_deviceContext,
|
||||
format,
|
||||
PFD_MAIN_PLANE,
|
||||
static_cast<UINT>(sRgbCapableAttribute.size()),
|
||||
sRgbCapableAttribute.data(),
|
||||
&sRgbCapableValue) == TRUE)
|
||||
{
|
||||
m_settings.sRgbCapable = (sRgbCapableValue == TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Failed to retrieve pixel format sRGB capability information: " << getErrorString(GetLastError())
|
||||
<< std::endl;
|
||||
m_settings.sRgbCapable = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings.sRgbCapable = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings.depthBits = actualFormat.cDepthBits;
|
||||
m_settings.stencilBits = actualFormat.cStencilBits;
|
||||
m_settings.antiAliasingLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WglContext::createSurface(WglContext* shared, Vector2u size, unsigned int bitsPerPixel)
|
||||
{
|
||||
// Check if the shared context already exists and pbuffers are supported
|
||||
if (shared && shared->m_deviceContext && SF_GLAD_WGL_ARB_pbuffer)
|
||||
{
|
||||
const int bestFormat = selectBestPixelFormat(shared->m_deviceContext, bitsPerPixel, m_settings, true);
|
||||
|
||||
if (bestFormat > 0)
|
||||
{
|
||||
static constexpr std::array attributes = {0, 0};
|
||||
|
||||
m_pbuffer = wglCreatePbufferARB(shared->m_deviceContext,
|
||||
bestFormat,
|
||||
static_cast<int>(size.x),
|
||||
static_cast<int>(size.y),
|
||||
attributes.data());
|
||||
|
||||
if (m_pbuffer)
|
||||
{
|
||||
m_window = shared->m_window;
|
||||
m_deviceContext = wglGetPbufferDCARB(m_pbuffer);
|
||||
|
||||
if (!m_deviceContext)
|
||||
{
|
||||
err() << "Failed to retrieve pixel buffer device context: " << getErrorString(GetLastError())
|
||||
<< std::endl;
|
||||
|
||||
wglDestroyPbufferARB(m_pbuffer);
|
||||
m_pbuffer = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Failed to create pixel buffer: " << getErrorString(GetLastError()) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If pbuffers are not available we use a hidden window as the off-screen surface to draw to
|
||||
if (!m_deviceContext)
|
||||
{
|
||||
// We can't create a memory DC, the resulting context wouldn't be compatible
|
||||
// with other contexts and thus wglShareLists would always fail
|
||||
|
||||
// Create the hidden window
|
||||
m_window = CreateWindowA("STATIC",
|
||||
"",
|
||||
WS_POPUP | WS_DISABLED,
|
||||
0,
|
||||
0,
|
||||
static_cast<int>(size.x),
|
||||
static_cast<int>(size.y),
|
||||
nullptr,
|
||||
nullptr,
|
||||
GetModuleHandle(nullptr),
|
||||
nullptr);
|
||||
ShowWindow(m_window, SW_HIDE);
|
||||
m_deviceContext = GetDC(m_window);
|
||||
|
||||
m_ownsWindow = true;
|
||||
|
||||
// Set the pixel format of the device context
|
||||
setDevicePixelFormat(bitsPerPixel);
|
||||
}
|
||||
|
||||
// Update context settings from the selected pixel format
|
||||
updateSettingsFromPixelFormat();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WglContext::createSurface(HWND window, unsigned int bitsPerPixel)
|
||||
{
|
||||
m_window = window;
|
||||
m_deviceContext = GetDC(window);
|
||||
|
||||
// Set the pixel format of the device context
|
||||
setDevicePixelFormat(bitsPerPixel);
|
||||
|
||||
// Update context settings from the selected pixel format
|
||||
updateSettingsFromPixelFormat();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WglContext::createContext(WglContext* shared)
|
||||
{
|
||||
// We can't create an OpenGL context if we don't have a DC
|
||||
if (!m_deviceContext)
|
||||
return;
|
||||
|
||||
// Get a working copy of the context settings
|
||||
const ContextSettings settings = m_settings;
|
||||
|
||||
// Get the context to share display lists with
|
||||
HGLRC sharedContext = shared ? shared->m_context : nullptr;
|
||||
|
||||
// Create the OpenGL context -- first try using wglCreateContextAttribsARB
|
||||
while (!m_context && m_settings.majorVersion)
|
||||
{
|
||||
if (SF_GLAD_WGL_ARB_create_context)
|
||||
{
|
||||
std::vector<int> attributes;
|
||||
|
||||
// Check if the user requested a specific context version (anything > 1.1)
|
||||
if ((m_settings.majorVersion > 1) || ((m_settings.majorVersion == 1) && (m_settings.minorVersion > 1)))
|
||||
{
|
||||
attributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
|
||||
attributes.push_back(static_cast<int>(m_settings.majorVersion));
|
||||
attributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
|
||||
attributes.push_back(static_cast<int>(m_settings.minorVersion));
|
||||
}
|
||||
|
||||
// Check if setting the profile is supported
|
||||
if (SF_GLAD_WGL_ARB_create_context_profile)
|
||||
{
|
||||
const int profile = (m_settings.attributeFlags & ContextSettings::Core)
|
||||
? WGL_CONTEXT_CORE_PROFILE_BIT_ARB
|
||||
: WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
|
||||
const int debug = (m_settings.attributeFlags & ContextSettings::Debug) ? WGL_CONTEXT_DEBUG_BIT_ARB : 0;
|
||||
|
||||
attributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
|
||||
attributes.push_back(profile);
|
||||
attributes.push_back(WGL_CONTEXT_FLAGS_ARB);
|
||||
attributes.push_back(debug);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_settings.attributeFlags & ContextSettings::Core) ||
|
||||
(m_settings.attributeFlags & ContextSettings::Debug))
|
||||
err() << "Selecting a profile during context creation is not supported,"
|
||||
<< "disabling compatibility and debug" << std::endl;
|
||||
|
||||
m_settings.attributeFlags = ContextSettings::Default;
|
||||
}
|
||||
|
||||
// Append the terminating 0
|
||||
attributes.push_back(0);
|
||||
attributes.push_back(0);
|
||||
|
||||
if (sharedContext)
|
||||
{
|
||||
static std::recursive_mutex mutex;
|
||||
const std::lock_guard lock(mutex);
|
||||
|
||||
if (WglContextImpl::currentContext == shared)
|
||||
{
|
||||
if (wglMakeCurrent(shared->m_deviceContext, nullptr) == FALSE)
|
||||
{
|
||||
err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError())
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
WglContextImpl::currentContext = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the context
|
||||
m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, attributes.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
// If wglCreateContextAttribsARB is not supported, there is no need to keep trying
|
||||
break;
|
||||
}
|
||||
|
||||
// If we couldn't create the context, first try disabling flags,
|
||||
// then lower the version number and try again -- stop at 0.0
|
||||
// Invalid version numbers will be generated by this algorithm (like 3.9), but we really don't care
|
||||
if (!m_context)
|
||||
{
|
||||
if (m_settings.attributeFlags != ContextSettings::Default)
|
||||
{
|
||||
m_settings.attributeFlags = ContextSettings::Default;
|
||||
}
|
||||
else if (m_settings.minorVersion > 0)
|
||||
{
|
||||
// If the minor version is not 0, we decrease it and try again
|
||||
--m_settings.minorVersion;
|
||||
|
||||
m_settings.attributeFlags = settings.attributeFlags;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the minor version is 0, we decrease the major version
|
||||
--m_settings.majorVersion;
|
||||
m_settings.minorVersion = 9;
|
||||
|
||||
m_settings.attributeFlags = settings.attributeFlags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If wglCreateContextAttribsARB failed, use wglCreateContext
|
||||
if (!m_context)
|
||||
{
|
||||
// set the context version to 1.1 (arbitrary) and disable flags
|
||||
m_settings.majorVersion = 1;
|
||||
m_settings.minorVersion = 1;
|
||||
m_settings.attributeFlags = ContextSettings::Default;
|
||||
|
||||
m_context = wglCreateContext(m_deviceContext);
|
||||
if (!m_context)
|
||||
{
|
||||
err() << "Failed to create an OpenGL context for this window: " << getErrorString(GetLastError()) << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Share this context with others
|
||||
if (sharedContext)
|
||||
{
|
||||
// wglShareLists doesn't seem to be thread-safe
|
||||
static std::recursive_mutex mutex;
|
||||
const std::lock_guard lock(mutex);
|
||||
|
||||
if (WglContextImpl::currentContext == shared)
|
||||
{
|
||||
if (wglMakeCurrent(shared->m_deviceContext, nullptr) == FALSE)
|
||||
{
|
||||
err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError())
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
WglContextImpl::currentContext = nullptr;
|
||||
}
|
||||
|
||||
if (wglShareLists(sharedContext, m_context) == FALSE)
|
||||
err() << "Failed to share the OpenGL context: " << getErrorString(GetLastError()) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are the shared context, initialize extensions now
|
||||
// This enables us to re-create the shared context using extensions if we need to
|
||||
if (!shared && m_context)
|
||||
{
|
||||
makeCurrent(true);
|
||||
WglContextImpl::ensureExtensionsInit(m_deviceContext);
|
||||
makeCurrent(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/Window/GlContext.hpp>
|
||||
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
|
||||
#include <glad/wgl.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
struct ContextSettings;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
class WindowImpl;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Windows (WGL) implementation of OpenGL contexts
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class WglContext : public GlContext
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a new default context
|
||||
///
|
||||
/// \param shared Context to share the new one with (can be a null pointer)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
WglContext(WglContext* shared);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a new context attached to a window
|
||||
///
|
||||
/// \param shared Context to share the new one with
|
||||
/// \param settings Creation parameters
|
||||
/// \param owner Pointer to the owner window
|
||||
/// \param bitsPerPixel Pixel depth, in bits per pixel
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
WglContext(WglContext* shared, const ContextSettings& settings, const WindowImpl& owner, unsigned int bitsPerPixel);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a new context that embeds its own rendering target
|
||||
///
|
||||
/// \param shared Context to share the new one with
|
||||
/// \param settings Creation parameters
|
||||
/// \param size Back buffer width and height, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
WglContext(WglContext* shared, const ContextSettings& settings, Vector2u size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~WglContext() override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the address of an OpenGL function
|
||||
///
|
||||
/// \param name Name of the function to get the address of
|
||||
///
|
||||
/// \return Address of the OpenGL function, 0 on failure
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static GlFunctionPointer getFunction(const char* name);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Activate the context as the current target for rendering
|
||||
///
|
||||
/// \param current Whether to make the context current or no longer current
|
||||
///
|
||||
/// \return `true` on success, `false` if any error happened
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool makeCurrent(bool current) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Display what has been rendered to the context so far
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void display() override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable vertical synchronization
|
||||
///
|
||||
/// Activating vertical synchronization will limit the number
|
||||
/// of frames displayed to the refresh rate of the monitor.
|
||||
/// This can avoid some visual artifacts, and limit the framerate
|
||||
/// to a good value (but not constant across different computers).
|
||||
///
|
||||
/// \param enabled: `true` to enable v-sync, `false` to deactivate
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setVerticalSyncEnabled(bool enabled) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Select the best pixel format for a given set of settings
|
||||
///
|
||||
/// \param deviceContext Device context
|
||||
/// \param bitsPerPixel Pixel depth, in bits per pixel
|
||||
/// \param settings Requested context settings
|
||||
/// \param pbuffer Whether the pixel format should support pbuffers
|
||||
///
|
||||
/// \return The best pixel format
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static int selectBestPixelFormat(HDC deviceContext,
|
||||
unsigned int bitsPerPixel,
|
||||
const ContextSettings& settings,
|
||||
bool pbuffer = false);
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the pixel format of the device context
|
||||
///
|
||||
/// \param bitsPerPixel Pixel depth, in bits per pixel
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setDevicePixelFormat(unsigned int bitsPerPixel);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update the context settings from the selected pixel format
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void updateSettingsFromPixelFormat();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the context's drawing surface
|
||||
///
|
||||
/// \param shared Shared context (can be a null pointer)
|
||||
/// \param size Back buffer width and height, in pixels
|
||||
/// \param bitsPerPixel Pixel depth, in bits per pixel
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void createSurface(WglContext* shared, Vector2u size, unsigned int bitsPerPixel);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the context's drawing surface from an existing window
|
||||
///
|
||||
/// \param window Window handle of the owning window
|
||||
/// \param bitsPerPixel Pixel depth, in bits per pixel
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void createSurface(HWND window, unsigned int bitsPerPixel);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the context
|
||||
///
|
||||
/// \param shared Context to share the new one with (can be a null pointer)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void createContext(WglContext* shared);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
HWND m_window{}; //!< Window to which the context is attached
|
||||
HPBUFFERARB m_pbuffer{}; //!< Handle to a pbuffer if one was created
|
||||
HDC m_deviceContext{}; //!< Device context associated to the context
|
||||
HGLRC m_context{}; //!< OpenGL context
|
||||
bool m_ownsWindow{}; //!< Do we own the target window?
|
||||
bool m_isGeneric{}; //!< Is this context provided by the generic GDI implementation?
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
} // namespace sf
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,315 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Window/Keyboard.hpp>
|
||||
#include <SFML/Window/WindowEnums.hpp>
|
||||
#include <SFML/Window/WindowHandle.hpp>
|
||||
#include <SFML/Window/WindowImpl.hpp>
|
||||
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include <SFML/System/Win32/WindowsHeader.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class String;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Windows implementation of WindowImpl
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class WindowImplWin32 : public WindowImpl
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct the window implementation from an existing control
|
||||
///
|
||||
/// \param handle Platform-specific handle of the control
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
WindowImplWin32(WindowHandle handle);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the window implementation
|
||||
///
|
||||
/// \param mode Video mode to use
|
||||
/// \param title Title of the window
|
||||
/// \param style Window style
|
||||
/// \param state Window state
|
||||
/// \param settings Additional settings for the underlying OpenGL context
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
WindowImplWin32(VideoMode mode, const String& title, std::uint32_t style, State state, const ContextSettings& settings);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~WindowImplWin32() override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the OS-specific handle of the window
|
||||
///
|
||||
/// \return Handle of the window
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] WindowHandle getNativeHandle() const override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the position of the window
|
||||
///
|
||||
/// \return Position of the window, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] Vector2i getPosition() const override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the position of the window on screen
|
||||
///
|
||||
/// \param position New position of the window, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setPosition(Vector2i position) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the client size of the window
|
||||
///
|
||||
/// \return Size of the window, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] Vector2u getSize() const override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the size of the rendering region of the window
|
||||
///
|
||||
/// \param size New size, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setSize(Vector2u size) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the title of the window
|
||||
///
|
||||
/// \param title New title
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setTitle(const String& title) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the window's icon
|
||||
///
|
||||
/// \param size Icon's width and height, in pixels
|
||||
/// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setIcon(Vector2u size, const std::uint8_t* pixels) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Show or hide the window
|
||||
///
|
||||
/// \param visible `true` to show, `false` to hide
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setVisible(bool visible) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Show or hide the mouse cursor
|
||||
///
|
||||
/// \param visible `true` to show, `false` to hide
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setMouseCursorVisible(bool visible) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Grab or release the mouse cursor
|
||||
///
|
||||
/// \param grabbed `true` to enable, `false` to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setMouseCursorGrabbed(bool grabbed) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the displayed cursor to a native system cursor
|
||||
///
|
||||
/// \param cursor Native system cursor type to display
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setMouseCursor(const CursorImpl& cursor) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable automatic key-repeat
|
||||
///
|
||||
/// \param enabled `true` to enable, `false` to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setKeyRepeatEnabled(bool enabled) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Request the current window to be made the active
|
||||
/// foreground window
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void requestFocus() override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check whether the window has the input focus
|
||||
///
|
||||
/// \return `true` if window has focus, `false` otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] bool hasFocus() const override;
|
||||
|
||||
protected:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Process incoming events from the operating system
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void processEvents() override;
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Register the window class
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void registerWindowClass();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Switch to fullscreen mode
|
||||
///
|
||||
/// \param mode Video mode to switch to
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void switchToFullscreen(const VideoMode& mode);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Free all the graphical resources attached to the window
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void cleanup();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Process a Win32 event
|
||||
///
|
||||
/// \param message Message to process
|
||||
/// \param wParam First parameter of the event
|
||||
/// \param lParam Second parameter of the event
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void processEvent(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enables or disables tracking for the mouse cursor leaving the window
|
||||
///
|
||||
/// \param track `true` to enable, `false` to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setTracking(bool track);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Grab or release the mouse cursor
|
||||
///
|
||||
/// This is not to be confused with setMouseCursorGrabbed.
|
||||
/// Here m_cursorGrabbed is not modified; it is used,
|
||||
/// for example, to release the cursor when switching to
|
||||
/// another application.
|
||||
///
|
||||
/// \param grabbed `true` to enable, `false` to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void grabCursor(bool grabbed);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Convert content size to window size including window chrome
|
||||
///
|
||||
/// \param size Size to convert
|
||||
///
|
||||
/// \return Converted size including window chrome
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2i contentSizeToWindowSize(Vector2u size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Convert a Win32 virtual key code to a SFML key code
|
||||
///
|
||||
/// \param key Virtual key code to convert
|
||||
/// \param flags Additional flags
|
||||
///
|
||||
/// \return SFML key code corresponding to the key
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static Keyboard::Key virtualKeyCodeToSF(WPARAM key, LPARAM flags);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Function called whenever one of our windows receives a message
|
||||
///
|
||||
/// \param handle Win32 handle of the window
|
||||
/// \param message Message received
|
||||
/// \param wParam First parameter of the message
|
||||
/// \param lParam Second parameter of the message
|
||||
///
|
||||
/// \return `true` to discard the event after it has been processed
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static LRESULT CALLBACK globalOnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Convert a Win32 scancode to an sfml scancode
|
||||
///
|
||||
/// \param flags input flags
|
||||
///
|
||||
/// \return SFML scancode corresponding to the key
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static Keyboard::Scancode toScancode(WPARAM wParam, LPARAM lParam);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
HWND m_handle{}; //!< Win32 handle of the window
|
||||
LONG_PTR m_callback{}; //!< Stores the original event callback function of the control
|
||||
bool m_cursorVisible{true}; //!< Is the cursor visible or hidden?
|
||||
HCURSOR m_lastCursor{
|
||||
LoadCursor(nullptr, IDC_ARROW)}; //!< Last cursor used -- this data is not owned by the window and is required to be always valid
|
||||
HICON m_icon{}; //!< Custom icon assigned to the window
|
||||
bool m_keyRepeatEnabled{true}; //!< Automatic key-repeat state for keydown events
|
||||
Vector2u m_lastSize; //!< The last handled size of the window
|
||||
bool m_resizing{}; //!< Is the window being resized?
|
||||
char16_t m_surrogate{}; //!< First half of the surrogate pair, in case we're receiving a Unicode character in two events
|
||||
bool m_mouseInside{}; //!< Mouse is inside the window?
|
||||
bool m_fullscreen{}; //!< Is the window fullscreen?
|
||||
bool m_cursorGrabbed{}; //!< Is the mouse cursor trapped?
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
Loading…
Reference in New Issue