mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Added config overlay
This commit is contained in:
parent
fb6555523f
commit
199d434f29
@ -5,14 +5,13 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
std::map<std::string, unsigned> createMapping(const std::vector<std::string>& enumNames)
|
||||
std::vector<std::pair<std::string, unsigned>> createMapping(const std::vector<std::string>& enumNames)
|
||||
{
|
||||
std::map<std::string, unsigned> mapping;
|
||||
std::vector<std::pair<std::string, unsigned>> mapping;
|
||||
unsigned i = 0;
|
||||
for (const auto& name : enumNames)
|
||||
{
|
||||
|
||||
mapping[name] = i;
|
||||
mapping.push_back({ name, i });
|
||||
++i;
|
||||
}
|
||||
return mapping;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <Config/Parser.h>
|
||||
#include <Config/Setting.h>
|
||||
@ -13,17 +14,23 @@ namespace Config
|
||||
public:
|
||||
Value get() const { return m_value; }
|
||||
|
||||
protected:
|
||||
MappedSetting(const std::string& name, const std::string& default, const std::map<std::string, Value>& valueMapping)
|
||||
: Setting(name, default)
|
||||
, m_value{}
|
||||
, m_valueMapping(valueMapping)
|
||||
virtual std::vector<std::string> getDefaultValueStrings() override
|
||||
{
|
||||
}
|
||||
if (m_defaultValueStrings.empty())
|
||||
{
|
||||
auto prevValue = m_value;
|
||||
auto prevParam = m_param;
|
||||
for (const auto& pair : m_valueMapping)
|
||||
{
|
||||
m_value = pair.second;
|
||||
m_param = getParamInfo().default;
|
||||
m_defaultValueStrings.push_back(getValueStr());
|
||||
}
|
||||
m_value = prevValue;
|
||||
m_param = prevParam;
|
||||
|
||||
virtual std::string getParamStr() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return m_defaultValueStrings;
|
||||
}
|
||||
|
||||
virtual std::string getValueStr() const override
|
||||
@ -32,60 +39,39 @@ namespace Config
|
||||
{
|
||||
if (pair.second == m_value)
|
||||
{
|
||||
std::string param(getParamStr());
|
||||
if (!param.empty())
|
||||
const auto paramInfo = getParamInfo();
|
||||
if (!paramInfo.name.empty())
|
||||
{
|
||||
param = '(' + param + ')';
|
||||
return pair.first + '(' + std::to_string(paramInfo.current) + ')';
|
||||
}
|
||||
return pair.first + param;
|
||||
return pair.first;
|
||||
}
|
||||
}
|
||||
throw ParsingError("MappedSetting::getValueStr(): value not found in mapping");
|
||||
}
|
||||
|
||||
virtual void setDefaultParam(const Value& /*value*/)
|
||||
protected:
|
||||
MappedSetting(const std::string& name, const std::string& default,
|
||||
const std::vector<std::pair<std::string, Value>>& valueMapping)
|
||||
: Setting(name, default)
|
||||
, m_value{}
|
||||
, m_valueMapping(valueMapping)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void setValue(const std::string& value) override
|
||||
{
|
||||
std::string val(value);
|
||||
std::string param;
|
||||
auto parenPos = value.find('(');
|
||||
if (std::string::npos != parenPos)
|
||||
{
|
||||
val = value.substr(0, parenPos);
|
||||
param = value.substr(parenPos + 1);
|
||||
if (param.length() < 2 || param.back() != ')')
|
||||
{
|
||||
throw ParsingError("invalid value: '" + value + "'");
|
||||
}
|
||||
param = param.substr(0, param.length() - 1);
|
||||
}
|
||||
|
||||
auto it = m_valueMapping.find(val);
|
||||
auto it = std::find_if(m_valueMapping.begin(), m_valueMapping.end(),
|
||||
[&](const auto& v) { return v.first == value; });
|
||||
if (it == m_valueMapping.end())
|
||||
{
|
||||
throw ParsingError("invalid value: '" + value + "'");
|
||||
}
|
||||
|
||||
if (param.empty())
|
||||
{
|
||||
m_value = it->second;
|
||||
setDefaultParam(it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
setValue(it->second, param);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void setValue(const Value& /*value*/, const std::string& param)
|
||||
{
|
||||
throw ParsingError("invalid parameter: '" + param + "'");
|
||||
m_value = it->second;
|
||||
}
|
||||
|
||||
Value m_value;
|
||||
const std::map<std::string, Value> m_valueMapping;
|
||||
const std::vector<std::pair<std::string, Value>> m_valueMapping;
|
||||
std::vector<std::string> m_defaultValueStrings;
|
||||
};
|
||||
}
|
||||
|
@ -138,10 +138,26 @@ namespace Config
|
||||
name.insert(name.end(), maxNameLength - name.length(), ' ');
|
||||
std::string source(setting.second.getSource());
|
||||
source.insert(source.end(), maxSourceLength - source.length(), ' ');
|
||||
Compat::Log() << " [" << source << "] " << name << " = " << setting.second.getValueAsString();
|
||||
Compat::Log() << " [" << source << "] " << name << " = " << setting.second.getValueStr();
|
||||
}
|
||||
}
|
||||
|
||||
int parseInt(const std::string& value, int min, int max)
|
||||
{
|
||||
if (value.empty() || std::string::npos != value.find_first_not_of("+-0123456789") ||
|
||||
std::string::npos != value.substr(1).find_first_of("+-"))
|
||||
{
|
||||
throw ParsingError("not a valid integer: '" + value + "'");
|
||||
}
|
||||
|
||||
int result = std::strtol(value.c_str(), nullptr, 10);
|
||||
if (result < min || result > max)
|
||||
{
|
||||
throw ParsingError("integer out of range: '" + value + "'");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SIZE parseResolution(const std::string& value)
|
||||
{
|
||||
try
|
||||
@ -149,14 +165,7 @@ namespace Config
|
||||
auto pos = value.find('x');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
SIZE resolution = {};
|
||||
resolution.cx = parseUnsigned(value.substr(0, pos));
|
||||
resolution.cy = parseUnsigned(value.substr(pos + 1));
|
||||
if (0 != resolution.cx && resolution.cx <= 65535 &&
|
||||
0 != resolution.cy && resolution.cy <= 65535)
|
||||
{
|
||||
return resolution;
|
||||
}
|
||||
return { parseInt(value.substr(0, pos), 1, MAXUINT16), parseInt(value.substr(pos + 1), 1, MAXUINT16) };
|
||||
}
|
||||
}
|
||||
catch (ParsingError&)
|
||||
@ -166,21 +175,22 @@ namespace Config
|
||||
throw ParsingError("invalid resolution: '" + value + "'");
|
||||
}
|
||||
|
||||
unsigned parseUnsigned(const std::string& value)
|
||||
{
|
||||
if (value.empty() || std::string::npos != value.find_first_not_of("0123456789"))
|
||||
{
|
||||
throw ParsingError("not an unsigned integer: '" + value + "'");
|
||||
}
|
||||
return std::strtoul(value.c_str(), nullptr, 10);
|
||||
}
|
||||
|
||||
void registerSetting(Setting& setting)
|
||||
{
|
||||
const auto& name = setting.getName();
|
||||
getSettings().emplace(name, setting);
|
||||
}
|
||||
|
||||
std::string removeParam(const std::string& value)
|
||||
{
|
||||
auto paramPos = value.find('(');
|
||||
if (paramPos != std::string::npos)
|
||||
{
|
||||
return value.substr(0, paramPos);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string trim(const std::string& str)
|
||||
{
|
||||
auto result(str);
|
||||
|
@ -20,8 +20,9 @@ namespace Config
|
||||
{
|
||||
void loadAllConfigFiles(const std::filesystem::path& processPath);
|
||||
SIZE parseResolution(const std::string& value);
|
||||
unsigned parseUnsigned(const std::string& value);
|
||||
int parseInt(const std::string& value, int min, int max);
|
||||
void registerSetting(Setting& setting);
|
||||
std::string removeParam(const std::string& value);
|
||||
std::string trim(const std::string& str);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@
|
||||
namespace Config
|
||||
{
|
||||
Setting::Setting(const std::string& name, const std::string& default)
|
||||
: m_name(name)
|
||||
: m_param(0)
|
||||
, m_name(name)
|
||||
, m_default(default)
|
||||
{
|
||||
Parser::registerSetting(*this);
|
||||
@ -15,9 +16,65 @@ namespace Config
|
||||
set("default", "default");
|
||||
}
|
||||
|
||||
void Setting::set(const std::string& value)
|
||||
{
|
||||
if ("default" == value)
|
||||
{
|
||||
set(m_default);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string val(value);
|
||||
std::string param;
|
||||
auto parenPos = value.find('(');
|
||||
if (std::string::npos != parenPos)
|
||||
{
|
||||
val = Parser::trim(value.substr(0, parenPos));
|
||||
param = value.substr(parenPos + 1);
|
||||
if (param.back() != ')')
|
||||
{
|
||||
throw ParsingError("invalid value: '" + value + "'");
|
||||
}
|
||||
param = Parser::trim(param.substr(0, param.length() - 1));
|
||||
}
|
||||
|
||||
setValue(val);
|
||||
|
||||
try
|
||||
{
|
||||
m_param = getParamInfo().default;
|
||||
if (!param.empty())
|
||||
{
|
||||
setParam(param);
|
||||
}
|
||||
}
|
||||
catch (const ParsingError& e)
|
||||
{
|
||||
throw ParsingError(Parser::removeParam(getValueStr()) + ": " + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void Setting::set(const std::string& value, const std::string& source)
|
||||
{
|
||||
setValue("default" == value ? m_default : value);
|
||||
set(value);
|
||||
m_source = source;
|
||||
}
|
||||
|
||||
void Setting::setParam(const std::string& param)
|
||||
{
|
||||
const auto paramInfo = getParamInfo();
|
||||
if (paramInfo.name.empty())
|
||||
{
|
||||
throw ParsingError("parameters are not allowed");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_param = Parser::parseInt(param, paramInfo.min, paramInfo.max);
|
||||
}
|
||||
catch (const ParsingError&)
|
||||
{
|
||||
throw ParsingError("invalid parameter value: '" + param + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Config
|
||||
{
|
||||
class Setting
|
||||
{
|
||||
public:
|
||||
struct ParamInfo
|
||||
{
|
||||
std::string name;
|
||||
int min;
|
||||
int max;
|
||||
int default;
|
||||
int current;
|
||||
};
|
||||
|
||||
Setting(const std::string& name, const std::string& default);
|
||||
|
||||
Setting(const Setting&) = delete;
|
||||
@ -14,18 +24,26 @@ namespace Config
|
||||
Setting& operator=(const Setting&) = delete;
|
||||
Setting& operator=(Setting&&) = delete;
|
||||
|
||||
virtual std::vector<std::string> getDefaultValueStrings() { return {}; }
|
||||
virtual ParamInfo getParamInfo() const { return {}; }
|
||||
virtual std::string getValueStr() const = 0;
|
||||
|
||||
const std::string& getName() const { return m_name; }
|
||||
int getParam() const { return m_param; }
|
||||
const std::string& getSource() const { return m_source; }
|
||||
std::string getValueAsString() const { return getValueStr(); }
|
||||
|
||||
void reset();
|
||||
void set(const std::string& value);
|
||||
void set(const std::string& value, const std::string& source);
|
||||
|
||||
protected:
|
||||
virtual std::string getValueStr() const = 0;
|
||||
virtual void setValue(const std::string& value) = 0;
|
||||
|
||||
int m_param;
|
||||
|
||||
private:
|
||||
void setParam(const std::string& param);
|
||||
|
||||
std::string m_name;
|
||||
std::string m_default;
|
||||
std::string m_source;
|
||||
|
@ -15,33 +15,16 @@ namespace Config
|
||||
{"msaa4x", D3DDDIMULTISAMPLE_4_SAMPLES},
|
||||
{"msaa8x", D3DDDIMULTISAMPLE_8_SAMPLES}
|
||||
})
|
||||
, m_param(0)
|
||||
{
|
||||
}
|
||||
|
||||
std::string Antialiasing::getParamStr() const
|
||||
Setting::ParamInfo Antialiasing::getParamInfo() const
|
||||
{
|
||||
return D3DDDIMULTISAMPLE_NONE != m_value ? std::to_string(m_param) : std::string();
|
||||
}
|
||||
|
||||
void Antialiasing::setDefaultParam(const UINT& value)
|
||||
{
|
||||
m_param = D3DDDIMULTISAMPLE_NONE != value ? 7 : 0;
|
||||
}
|
||||
|
||||
void Antialiasing::setValue(const UINT& value, const std::string& param)
|
||||
{
|
||||
if (D3DDDIMULTISAMPLE_NONE != value)
|
||||
if (D3DDDIMULTISAMPLE_NONE != m_value)
|
||||
{
|
||||
const UINT p = Config::Parser::parseUnsigned(param);
|
||||
if (p <= 7)
|
||||
{
|
||||
m_value = value;
|
||||
m_param = p;
|
||||
return;
|
||||
}
|
||||
return { "Quality", 0, 7, 7, m_param };
|
||||
}
|
||||
throw ParsingError("invalid parameter: '" + param + "'");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,15 +10,8 @@ namespace Config
|
||||
{
|
||||
public:
|
||||
Antialiasing();
|
||||
|
||||
UINT getParam() const { return m_param; }
|
||||
|
||||
protected:
|
||||
virtual std::string getParamStr() const override;
|
||||
virtual void setDefaultParam(const UINT& value) override;
|
||||
virtual void setValue(const UINT& value, const std::string& param) override;
|
||||
|
||||
UINT m_param;
|
||||
|
||||
virtual ParamInfo getParamInfo() const override;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -59,11 +59,7 @@ namespace Config
|
||||
unsigned result = 0;
|
||||
for (const auto& value : values)
|
||||
{
|
||||
auto num = Parser::parseUnsigned(value);
|
||||
if (num < 1 || num > 32)
|
||||
{
|
||||
throw ParsingError("'" + value + "' is not an integer between 1 and 32");
|
||||
}
|
||||
auto num = Parser::parseInt(value, 1, 32);
|
||||
result |= 1U << (num - 1);
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,11 @@ namespace Config
|
||||
public:
|
||||
CpuAffinity();
|
||||
|
||||
virtual std::string getValueStr() const override;
|
||||
|
||||
unsigned get() const { return m_value; }
|
||||
|
||||
private:
|
||||
std::string getValueStr() const override;
|
||||
void setValues(const std::vector<std::string>& values) override;
|
||||
|
||||
unsigned m_value;
|
||||
|
@ -2,37 +2,20 @@
|
||||
|
||||
namespace Config
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
DisplayFilter::DisplayFilter()
|
||||
: MappedSetting("DisplayFilter", "bilinear(0)", { {"point", POINT}, {"bilinear", BILINEAR} })
|
||||
, m_param(0)
|
||||
{
|
||||
}
|
||||
namespace Settings
|
||||
{
|
||||
DisplayFilter::DisplayFilter()
|
||||
: MappedSetting("DisplayFilter", "bilinear", { {"point", POINT}, {"bilinear", BILINEAR} })
|
||||
{
|
||||
}
|
||||
|
||||
std::string DisplayFilter::getParamStr() const
|
||||
{
|
||||
return BILINEAR == m_value ? std::to_string(m_param) : std::string();
|
||||
}
|
||||
|
||||
void DisplayFilter::setDefaultParam(const UINT& value)
|
||||
{
|
||||
m_param = BILINEAR == value ? 100 : 0;
|
||||
}
|
||||
|
||||
void DisplayFilter::setValue(const UINT& value, const std::string& param)
|
||||
{
|
||||
if (BILINEAR == value)
|
||||
{
|
||||
const UINT p = Config::Parser::parseUnsigned(param);
|
||||
if (p <= 100)
|
||||
{
|
||||
m_value = BILINEAR;
|
||||
m_param = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw ParsingError("invalid parameter: '" + param + "'");
|
||||
}
|
||||
}
|
||||
Setting::ParamInfo DisplayFilter::getParamInfo() const
|
||||
{
|
||||
if (BILINEAR == m_value)
|
||||
{
|
||||
return { "Blur", 0, 100, 0, m_param };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,24 +4,17 @@
|
||||
|
||||
namespace Config
|
||||
{
|
||||
namespace Settings
|
||||
{
|
||||
class DisplayFilter : public MappedSetting<UINT>
|
||||
{
|
||||
public:
|
||||
static const UINT POINT = 0;
|
||||
static const UINT BILINEAR = 1;
|
||||
namespace Settings
|
||||
{
|
||||
class DisplayFilter : public MappedSetting<UINT>
|
||||
{
|
||||
public:
|
||||
static const UINT POINT = 0;
|
||||
static const UINT BILINEAR = 1;
|
||||
|
||||
DisplayFilter();
|
||||
DisplayFilter();
|
||||
|
||||
UINT getParam() const { return m_param; }
|
||||
|
||||
protected:
|
||||
virtual std::string getParamStr() const override;
|
||||
virtual void setDefaultParam(const UINT& value) override;
|
||||
virtual void setValue(const UINT& value, const std::string& param) override;
|
||||
|
||||
UINT m_param;
|
||||
};
|
||||
}
|
||||
virtual ParamInfo getParamInfo() const override;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,11 @@ namespace Config
|
||||
|
||||
SupportedResolutions();
|
||||
|
||||
virtual std::string getValueStr() const override;
|
||||
|
||||
std::set<SIZE> get() const { return m_resolutions; }
|
||||
|
||||
private:
|
||||
std::string getValueStr() const override;
|
||||
void setValues(const std::vector<std::string>& values) override;
|
||||
|
||||
std::set<SIZE> m_resolutions;
|
||||
|
@ -110,7 +110,7 @@ namespace D3dDdi
|
||||
levels.Format = D3DDDIFMT_X8R8G8B8;
|
||||
levels.MsType = static_cast<D3DDDIMULTISAMPLE_TYPE>(samples);
|
||||
getCaps(D3DDDICAPS_GETMULTISAMPLEQUALITYLEVELS, levels);
|
||||
return { levels.MsType, min(Config::antialiasing.getParam(), levels.QualityLevels - 1) };
|
||||
return { levels.MsType, min(static_cast<UINT>(Config::antialiasing.getParam()), levels.QualityLevels - 1) };
|
||||
}
|
||||
|
||||
std::string Adapter::getSupportedMsaaModes(const std::map<D3DDDIFORMAT, FORMATOP>& formatOps) const
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <D3dDdi/DeviceFuncs.h>
|
||||
#include <D3dDdi/Resource.h>
|
||||
#include <D3dDdi/ScopedCriticalSection.h>
|
||||
#include <DDraw/ScopedThreadLock.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -335,6 +336,25 @@ namespace D3dDdi
|
||||
return m_origVtable.pfnUnlock(m_device, data);
|
||||
}
|
||||
|
||||
void Device::updateAllConfig()
|
||||
{
|
||||
DDraw::ScopedThreadLock ddLock;
|
||||
D3dDdi::ScopedCriticalSection lock;
|
||||
for (auto& device : s_devices)
|
||||
{
|
||||
device.second.updateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
void Device::updateConfig()
|
||||
{
|
||||
for (auto& resource : m_resources)
|
||||
{
|
||||
resource.second->updateConfig();
|
||||
}
|
||||
m_state.updateConfig();
|
||||
}
|
||||
|
||||
std::map<HANDLE, Device> Device::s_devices;
|
||||
bool Device::s_isFlushEnabled = true;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ namespace D3dDdi
|
||||
void prepareForRendering(HANDLE resource, UINT subResourceIndex);
|
||||
void prepareForRendering();
|
||||
void setRenderTarget(const D3DDDIARG_SETRENDERTARGET& data);
|
||||
void updateConfig();
|
||||
|
||||
static void add(Adapter& adapter, HANDLE device);
|
||||
static Device& get(HANDLE device) { return s_devices.find(device)->second; }
|
||||
@ -67,6 +68,7 @@ namespace D3dDdi
|
||||
static Resource* findResource(HANDLE resource);
|
||||
static Resource* getGdiResource();
|
||||
static void setGdiResourceHandle(HANDLE resource);
|
||||
static void updateAllConfig();
|
||||
|
||||
private:
|
||||
D3DDDI_DEVICEFUNCS m_origVtable;
|
||||
|
@ -6,6 +6,27 @@
|
||||
#include <D3dDdi/Log/DeviceFuncsLog.h>
|
||||
#include <D3dDdi/Resource.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
UINT mapTssValue(D3DDDITEXTURESTAGESTATETYPE type, UINT value)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case D3DDDITSS_MAGFILTER:
|
||||
case D3DDDITSS_MINFILTER:
|
||||
return D3DTEXF_NONE == Config::textureFilter.getFilter() ? value : Config::textureFilter.getFilter();
|
||||
|
||||
case D3DDDITSS_MIPFILTER:
|
||||
return D3DTEXF_NONE == Config::textureFilter.getMipFilter() ? value : Config::textureFilter.getMipFilter();
|
||||
|
||||
case D3DDDITSS_MAXANISOTROPY:
|
||||
return D3DTEXF_NONE == Config::textureFilter.getFilter() ? value : Config::textureFilter.getMaxAnisotropy();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
namespace D3dDdi
|
||||
{
|
||||
DeviceState::DeviceState(Device& device)
|
||||
@ -118,21 +139,12 @@ namespace D3dDdi
|
||||
m_textureStageState[i][D3DDDITSS_ADDRESSU] = D3DTADDRESS_WRAP;
|
||||
m_textureStageState[i][D3DDDITSS_ADDRESSV] = D3DTADDRESS_WRAP;
|
||||
m_textureStageState[i][D3DDDITSS_BORDERCOLOR] = 0;
|
||||
if (D3DTEXF_NONE == Config::textureFilter.getFilter())
|
||||
{
|
||||
m_textureStageState[i][D3DDDITSS_MAGFILTER] = D3DTEXF_POINT;
|
||||
m_textureStageState[i][D3DDDITSS_MINFILTER] = D3DTEXF_POINT;
|
||||
m_textureStageState[i][D3DDDITSS_MIPFILTER] = D3DTEXF_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_textureStageState[i][D3DDDITSS_MAGFILTER] = Config::textureFilter.getFilter();
|
||||
m_textureStageState[i][D3DDDITSS_MINFILTER] = Config::textureFilter.getFilter();
|
||||
m_textureStageState[i][D3DDDITSS_MIPFILTER] = Config::textureFilter.getMipFilter();
|
||||
}
|
||||
m_textureStageState[i][D3DDDITSS_MAGFILTER] = mapTssValue(D3DDDITSS_MAGFILTER, D3DTEXF_POINT);
|
||||
m_textureStageState[i][D3DDDITSS_MINFILTER] = mapTssValue(D3DDDITSS_MINFILTER, D3DTEXF_POINT);
|
||||
m_textureStageState[i][D3DDDITSS_MIPFILTER] = mapTssValue(D3DDDITSS_MIPFILTER, D3DTEXF_NONE);
|
||||
m_textureStageState[i][D3DDDITSS_MIPMAPLODBIAS] = 0;
|
||||
m_textureStageState[i][D3DDDITSS_MAXMIPLEVEL] = 0;
|
||||
m_textureStageState[i][D3DDDITSS_MAXANISOTROPY] = Config::textureFilter.getMaxAnisotropy();
|
||||
m_textureStageState[i][D3DDDITSS_MAXANISOTROPY] = mapTssValue(D3DDDITSS_MAXANISOTROPY, 1);
|
||||
m_textureStageState[i][D3DDDITSS_TEXTURETRANSFORMFLAGS] = D3DTTFF_DISABLE;
|
||||
m_textureStageState[i][D3DDDITSS_SRGBTEXTURE] = FALSE;
|
||||
m_textureStageState[i][D3DDDITSS_ADDRESSW] = D3DTADDRESS_WRAP;
|
||||
@ -434,6 +446,10 @@ namespace D3dDdi
|
||||
{
|
||||
m_renderTarget = {};
|
||||
}
|
||||
else if (m_depthStencil.hZBuffer == resource)
|
||||
{
|
||||
m_depthStencil = {};
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT DeviceState::setShader(HANDLE shader, HANDLE& currentShader,
|
||||
@ -519,6 +535,40 @@ namespace D3dDdi
|
||||
return result;
|
||||
}
|
||||
|
||||
void DeviceState::updateConfig()
|
||||
{
|
||||
if (m_renderTarget.hRenderTarget)
|
||||
{
|
||||
auto renderTarget = m_renderTarget;
|
||||
m_renderTarget = {};
|
||||
pfnSetRenderTarget(&renderTarget);
|
||||
}
|
||||
|
||||
if (m_depthStencil.hZBuffer)
|
||||
{
|
||||
auto depthStencil = m_depthStencil;
|
||||
m_depthStencil = {};
|
||||
pfnSetDepthStencil(&depthStencil);
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < m_textureStageState.size(); ++i)
|
||||
{
|
||||
updateTextureStageState(i, D3DDDITSS_MAGFILTER);
|
||||
updateTextureStageState(i, D3DDDITSS_MINFILTER);
|
||||
updateTextureStageState(i, D3DDDITSS_MIPFILTER);
|
||||
updateTextureStageState(i, D3DDDITSS_MAXANISOTROPY);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceState::updateTextureStageState(UINT stage, D3DDDITEXTURESTAGESTATETYPE state)
|
||||
{
|
||||
D3DDDIARG_TEXTURESTAGESTATE data = {};
|
||||
data.Stage = stage;
|
||||
data.State = state;
|
||||
data.Value = mapTssValue(state, m_textureStageState[stage][state]);
|
||||
m_device.getOrigVtable().pfnSetTextureStageState(m_device, &data);
|
||||
}
|
||||
|
||||
DeviceState::ScopedRenderState::ScopedRenderState(DeviceState& deviceState, const D3DDDIARG_RENDERSTATE& data)
|
||||
: m_deviceState(deviceState)
|
||||
, m_prevData{ data.State, deviceState.m_renderState[data.State] }
|
||||
@ -576,7 +626,7 @@ namespace D3dDdi
|
||||
DeviceState::ScopedTextureStageState::ScopedTextureStageState(
|
||||
DeviceState& deviceState, const D3DDDIARG_TEXTURESTAGESTATE& data)
|
||||
: m_deviceState(deviceState)
|
||||
, m_prevData{ data.Stage, data.State, deviceState.m_textureStageState[data.Stage][data.State] }
|
||||
, m_prevData{ data.Stage, data.State, mapTssValue(data.State, deviceState.m_textureStageState[data.Stage][data.State]) }
|
||||
{
|
||||
m_deviceState.m_device.getOrigVtable().pfnSetTextureStageState(m_deviceState.m_device, &data);
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ namespace D3dDdi
|
||||
HRESULT pfnUpdateWInfo(const D3DDDIARG_WINFO* data);
|
||||
|
||||
void onDestroyResource(HANDLE resource);
|
||||
void updateConfig();
|
||||
|
||||
private:
|
||||
HRESULT deleteShader(HANDLE shader, HANDLE& currentShader,
|
||||
@ -69,6 +70,8 @@ namespace D3dDdi
|
||||
HRESULT setStateArray(const StateData* data, std::array<UINT, size>& currentState,
|
||||
HRESULT(APIENTRY* origSetState)(HANDLE, const StateData*));
|
||||
|
||||
void updateTextureStageState(UINT stage, D3DDDITEXTURESTAGESTATETYPE state);
|
||||
|
||||
Device& m_device;
|
||||
D3DDDIARG_SETDEPTHSTENCIL m_depthStencil;
|
||||
HANDLE m_pixelShader;
|
||||
|
@ -24,8 +24,7 @@ namespace
|
||||
|
||||
const UINT g_resourceTypeFlags = getResourceTypeFlags().Value;
|
||||
RECT g_presentationRect = {};
|
||||
UINT g_presentationFilter = Config::Settings::DisplayFilter::POINT;
|
||||
UINT g_presentationFilterParam = 0;
|
||||
RECT g_primaryRect = {};
|
||||
D3DDDIFORMAT g_formatOverride = D3DDDIFMT_UNKNOWN;
|
||||
|
||||
RECT calculatePresentationRect()
|
||||
@ -108,6 +107,8 @@ namespace D3dDdi
|
||||
, m_lockBuffer(nullptr, &heapFree)
|
||||
, m_lockResource(nullptr, ResourceDeleter(device))
|
||||
, m_customSurface{}
|
||||
, m_multiSampleConfig{ D3DDDIMULTISAMPLE_NONE, 0 }
|
||||
, m_isSurfaceRepoResource(SurfaceRepository::inCreateSurface())
|
||||
{
|
||||
if (m_origData.Flags.VertexBuffer &&
|
||||
m_origData.Flags.MightDrawFromLocked &&
|
||||
@ -120,33 +121,14 @@ namespace D3dDdi
|
||||
{
|
||||
g_presentationRect = calculatePresentationRect();
|
||||
auto& si = m_origData.pSurfList[0];
|
||||
RECT rect = { 0, 0, static_cast<LONG>(si.Width), static_cast<LONG>(si.Height) };
|
||||
g_primaryRect = { 0, 0, static_cast<LONG>(si.Width), static_cast<LONG>(si.Height) };
|
||||
|
||||
Gdi::Cursor::setMonitorClipRect(DDraw::PrimarySurface::getMonitorRect());
|
||||
if (!EqualRect(&g_presentationRect, &rect))
|
||||
if (!EqualRect(&g_presentationRect, &g_primaryRect))
|
||||
{
|
||||
Gdi::Cursor::setEmulated(true);
|
||||
}
|
||||
Gdi::VirtualScreen::setFullscreenMode(true);
|
||||
|
||||
if (g_presentationRect.right - g_presentationRect.left != rect.right ||
|
||||
g_presentationRect.bottom - g_presentationRect.top != rect.bottom)
|
||||
{
|
||||
g_presentationFilter = Config::displayFilter.get();
|
||||
g_presentationFilterParam = Config::displayFilter.getParam();
|
||||
|
||||
if (Config::Settings::DisplayFilter::BILINEAR == g_presentationFilter &&
|
||||
0 == g_presentationFilterParam &&
|
||||
0 == (g_presentationRect.right - g_presentationRect.left) % rect.right &&
|
||||
0 == (g_presentationRect.bottom - g_presentationRect.top) % rect.bottom)
|
||||
{
|
||||
g_presentationFilter = Config::Settings::DisplayFilter::POINT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_presentationFilter = Config::Settings::DisplayFilter::POINT;
|
||||
}
|
||||
}
|
||||
|
||||
fixResourceData();
|
||||
@ -159,34 +141,7 @@ namespace D3dDdi
|
||||
}
|
||||
m_handle = m_fixedData.hResource;
|
||||
|
||||
if (!SurfaceRepository::inCreateSurface())
|
||||
{
|
||||
const auto msaa = getMultisampleConfig();
|
||||
if (D3DDDIMULTISAMPLE_NONE != msaa.first)
|
||||
{
|
||||
g_formatOverride = m_fixedData.Format;
|
||||
if (m_fixedData.Flags.ZBuffer)
|
||||
{
|
||||
DDPIXELFORMAT pf = {};
|
||||
pf.dwSize = sizeof(pf);
|
||||
pf.dwFlags = DDPF_ZBUFFER;
|
||||
pf.dwZBufferBitDepth = 16;
|
||||
pf.dwZBitMask = 0xFFFF;
|
||||
|
||||
SurfaceRepository::get(m_device.getAdapter()).getSurface(m_customSurface,
|
||||
m_fixedData.surfaceData[0].Width, m_fixedData.surfaceData[0].Height, pf,
|
||||
DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
SurfaceRepository::get(m_device.getAdapter()).getSurface(m_customSurface,
|
||||
m_fixedData.surfaceData[0].Width, m_fixedData.surfaceData[0].Height,
|
||||
DDraw::DirectDraw::getRgbPixelFormat(32),
|
||||
DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY);
|
||||
}
|
||||
g_formatOverride = D3DDDIFMT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
updateConfig();
|
||||
|
||||
if (D3DDDIPOOL_SYSTEMMEM == m_fixedData.Pool &&
|
||||
0 != m_formatInfo.bytesPerPixel)
|
||||
@ -675,8 +630,20 @@ namespace D3dDdi
|
||||
const RECT monitorRect = DDraw::PrimarySurface::getMonitorRect();
|
||||
const bool isLayeredPresentNeeded = Gdi::Window::presentLayered(nullptr, monitorRect);
|
||||
|
||||
UINT presentationFilter = Config::displayFilter.get();
|
||||
UINT presentationFilterParam = Config::displayFilter.getParam();
|
||||
if (Config::Settings::DisplayFilter::BILINEAR == presentationFilter &&
|
||||
(g_presentationRect.right - g_presentationRect.left == g_primaryRect.right &&
|
||||
g_presentationRect.bottom - g_presentationRect.top == g_primaryRect.bottom) ||
|
||||
(0 == presentationFilterParam &&
|
||||
0 == (g_presentationRect.right - g_presentationRect.left) % g_primaryRect.right &&
|
||||
0 == (g_presentationRect.bottom - g_presentationRect.top) % g_primaryRect.bottom))
|
||||
{
|
||||
presentationFilter = Config::Settings::DisplayFilter::POINT;
|
||||
}
|
||||
|
||||
if (isPalettized || isCursorEmulated || isLayeredPresentNeeded ||
|
||||
Config::Settings::DisplayFilter::POINT != g_presentationFilter)
|
||||
Config::Settings::DisplayFilter::POINT != presentationFilter)
|
||||
{
|
||||
const auto& si = srcResource->m_fixedData.pSurfList[0];
|
||||
const auto& dst(SurfaceRepository::get(m_device.getAdapter()).getRenderTarget(si.Width, si.Height));
|
||||
@ -719,10 +686,10 @@ namespace D3dDdi
|
||||
m_device.getShaderBlitter().cursorBlt(*dst.resource, 0, cursorInfo.hCursor, pos);
|
||||
}
|
||||
|
||||
if (Config::Settings::DisplayFilter::BILINEAR == g_presentationFilter)
|
||||
if (Config::Settings::DisplayFilter::BILINEAR == presentationFilter)
|
||||
{
|
||||
m_device.getShaderBlitter().genBilinearBlt(*this, data.DstSubResourceIndex, g_presentationRect,
|
||||
*dst.resource, data.SrcRect, g_presentationFilterParam);
|
||||
*dst.resource, data.SrcRect, presentationFilterParam);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -948,4 +915,59 @@ namespace D3dDdi
|
||||
|
||||
return m_device.getOrigVtable().pfnUnlock(m_device, &data);
|
||||
}
|
||||
|
||||
void Resource::updateConfig()
|
||||
{
|
||||
if (m_isSurfaceRepoResource)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto msaa = getMultisampleConfig();
|
||||
if (m_multiSampleConfig == msaa)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_multiSampleConfig = msaa;
|
||||
|
||||
if (m_customSurface.resource && m_fixedData.Flags.RenderTarget)
|
||||
{
|
||||
for (UINT i = 0; i < m_lockData.size(); ++i)
|
||||
{
|
||||
if (m_lockData[i].isCustomUpToDate && !m_lockData[i].isVidMemUpToDate)
|
||||
{
|
||||
copyToVidMem(i);
|
||||
}
|
||||
m_lockData[i].isCustomUpToDate = false;
|
||||
}
|
||||
}
|
||||
|
||||
auto& surfaceRepo(SurfaceRepository::get(m_device.getAdapter()));
|
||||
surfaceRepo.release(m_customSurface);
|
||||
|
||||
if (D3DDDIMULTISAMPLE_NONE != msaa.first)
|
||||
{
|
||||
g_formatOverride = m_fixedData.Format;
|
||||
if (m_fixedData.Flags.ZBuffer)
|
||||
{
|
||||
DDPIXELFORMAT pf = {};
|
||||
pf.dwSize = sizeof(pf);
|
||||
pf.dwFlags = DDPF_ZBUFFER;
|
||||
pf.dwZBufferBitDepth = 16;
|
||||
pf.dwZBitMask = 0xFFFF;
|
||||
|
||||
SurfaceRepository::get(m_device.getAdapter()).getSurface(m_customSurface,
|
||||
m_fixedData.surfaceData[0].Width, m_fixedData.surfaceData[0].Height, pf,
|
||||
DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY, m_fixedData.SurfCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
SurfaceRepository::get(m_device.getAdapter()).getSurface(m_customSurface,
|
||||
m_fixedData.surfaceData[0].Width, m_fixedData.surfaceData[0].Height,
|
||||
DDraw::DirectDraw::getRgbPixelFormat(32),
|
||||
DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY);
|
||||
}
|
||||
g_formatOverride = D3DDDIFMT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ namespace D3dDdi
|
||||
void prepareForRendering(UINT subResourceIndex);
|
||||
void setAsGdiResource(bool isGdiResource);
|
||||
HRESULT unlock(const D3DDDIARG_UNLOCK& data);
|
||||
void updateConfig();
|
||||
|
||||
private:
|
||||
class Data : public D3DDDIARG_CREATERESOURCE2
|
||||
@ -106,5 +107,7 @@ namespace D3dDdi
|
||||
std::vector<LockData> m_lockData;
|
||||
std::unique_ptr<void, ResourceDeleter> m_lockResource;
|
||||
SurfaceRepository::Surface m_customSurface;
|
||||
std::pair<D3DDDIMULTISAMPLE_TYPE, UINT> m_multiSampleConfig;
|
||||
bool m_isSurfaceRepoResource;
|
||||
};
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ namespace D3dDdi
|
||||
const Surface& getRenderTarget(DWORD width, DWORD height);
|
||||
Surface& getSurface(Surface& surface, DWORD width, DWORD height,
|
||||
const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount = 1);
|
||||
void release(Surface& surface);
|
||||
|
||||
static SurfaceRepository& get(const Adapter& adapter);
|
||||
static bool inCreateSurface() { return s_inCreateSurface; }
|
||||
@ -52,7 +53,6 @@ namespace D3dDdi
|
||||
Resource* getInitializedResource(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps,
|
||||
std::function<void(const DDSURFACEDESC2&)> initFunc);
|
||||
bool isLost(Surface& surface);
|
||||
void release(Surface& surface);
|
||||
|
||||
const Adapter& m_adapter;
|
||||
HCURSOR m_cursor;
|
||||
|
@ -36,3 +36,5 @@ FILESUBTYPE VFT2_UNKNOWN
|
||||
VALUE "Translation", 0x409, 0
|
||||
}
|
||||
}
|
||||
|
||||
BMP_ARROW BITMAP "arrow.bmp"
|
||||
|
@ -306,10 +306,18 @@
|
||||
<ClInclude Include="Gdi\VirtualScreen.h" />
|
||||
<ClInclude Include="Gdi\Window.h" />
|
||||
<ClInclude Include="Gdi\WinProc.h" />
|
||||
<ClInclude Include="Input\Input.h" />
|
||||
<ClInclude Include="Overlay\ComboBoxControl.h" />
|
||||
<ClInclude Include="Overlay\ComboBoxDropDown.h" />
|
||||
<ClInclude Include="Overlay\ConfigWindow.h" />
|
||||
<ClInclude Include="Overlay\Control.h" />
|
||||
<ClInclude Include="Overlay\LabelControl.h" />
|
||||
<ClInclude Include="Overlay\ScrollBarControl.h" />
|
||||
<ClInclude Include="Overlay\SettingControl.h" />
|
||||
<ClInclude Include="Overlay\Window.h" />
|
||||
<ClInclude Include="Win32\DisplayMode.h" />
|
||||
<ClInclude Include="Win32\Log.h" />
|
||||
<ClInclude Include="Win32\MemoryManagement.h" />
|
||||
<ClInclude Include="Win32\MsgHooks.h" />
|
||||
<ClInclude Include="Win32\Registry.h" />
|
||||
<ClInclude Include="Win32\Thread.h" />
|
||||
</ItemGroup>
|
||||
@ -395,10 +403,18 @@
|
||||
<ClCompile Include="Gdi\VirtualScreen.cpp" />
|
||||
<ClCompile Include="Gdi\Window.cpp" />
|
||||
<ClCompile Include="Gdi\WinProc.cpp" />
|
||||
<ClCompile Include="Input\Input.cpp" />
|
||||
<ClCompile Include="Overlay\ComboBoxControl.cpp" />
|
||||
<ClCompile Include="Overlay\ComboBoxDropDown.cpp" />
|
||||
<ClCompile Include="Overlay\ConfigWindow.cpp" />
|
||||
<ClCompile Include="Overlay\Control.cpp" />
|
||||
<ClCompile Include="Overlay\LabelControl.cpp" />
|
||||
<ClCompile Include="Overlay\ScrollBarControl.cpp" />
|
||||
<ClCompile Include="Overlay\SettingControl.cpp" />
|
||||
<ClCompile Include="Overlay\Window.cpp" />
|
||||
<ClCompile Include="Win32\DisplayMode.cpp" />
|
||||
<ClCompile Include="Win32\Log.cpp" />
|
||||
<ClCompile Include="Win32\MemoryManagement.cpp" />
|
||||
<ClCompile Include="Win32\MsgHooks.cpp" />
|
||||
<ClCompile Include="Win32\Registry.cpp" />
|
||||
<ClCompile Include="Win32\Thread.cpp" />
|
||||
</ItemGroup>
|
||||
@ -414,6 +430,9 @@
|
||||
<FxCompile Include="Shaders\PaletteLookup.hlsl" />
|
||||
<FxCompile Include="Shaders\TextureSampler.hlsl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="arrow.bmp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
@ -91,6 +91,18 @@
|
||||
<Filter Include="Shaders">
|
||||
<UniqueIdentifier>{00e06bd4-3f10-46dc-af0f-99834dfac835}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Input">
|
||||
<UniqueIdentifier>{32765547-b1b7-48d3-bf58-d09cf388de91}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Input">
|
||||
<UniqueIdentifier>{38167700-fb70-4ee8-b149-824a9fde51eb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Overlay">
|
||||
<UniqueIdentifier>{29dba6e7-0bca-44e2-9776-2ba478e088bc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Overlay">
|
||||
<UniqueIdentifier>{e0a8a3ac-59fd-4cb0-ae81-5ae2c56fbfac}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Gdi\Gdi.h">
|
||||
@ -222,9 +234,6 @@
|
||||
<ClInclude Include="Direct3d\Visitors\Direct3dVtblVisitor.h">
|
||||
<Filter>Header Files\Direct3d\Visitors</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Win32\MsgHooks.h">
|
||||
<Filter>Header Files\Win32</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Win32\Registry.h">
|
||||
<Filter>Header Files\Win32</Filter>
|
||||
</ClInclude>
|
||||
@ -456,6 +465,33 @@
|
||||
<ClInclude Include="Config\Settings\Antialiasing.h">
|
||||
<Filter>Header Files\Config\Settings</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\Input.h">
|
||||
<Filter>Header Files\Input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Overlay\Window.h">
|
||||
<Filter>Header Files\Overlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Overlay\Control.h">
|
||||
<Filter>Header Files\Overlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Overlay\ConfigWindow.h">
|
||||
<Filter>Header Files\Overlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Overlay\SettingControl.h">
|
||||
<Filter>Header Files\Overlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Overlay\LabelControl.h">
|
||||
<Filter>Header Files\Overlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Overlay\ComboBoxControl.h">
|
||||
<Filter>Header Files\Overlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Overlay\ScrollBarControl.h">
|
||||
<Filter>Header Files\Overlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Overlay\ComboBoxDropDown.h">
|
||||
<Filter>Header Files\Overlay</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Gdi\Gdi.cpp">
|
||||
@ -533,9 +569,6 @@
|
||||
<ClCompile Include="Common\Log.cpp">
|
||||
<Filter>Source Files\Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\MsgHooks.cpp">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\Registry.cpp">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
@ -719,6 +752,33 @@
|
||||
<ClCompile Include="Config\Settings\Antialiasing.cpp">
|
||||
<Filter>Source Files\Config\Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\Input.cpp">
|
||||
<Filter>Source Files\Input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Overlay\Window.cpp">
|
||||
<Filter>Source Files\Overlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Overlay\Control.cpp">
|
||||
<Filter>Source Files\Overlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Overlay\ConfigWindow.cpp">
|
||||
<Filter>Source Files\Overlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Overlay\SettingControl.cpp">
|
||||
<Filter>Source Files\Overlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Overlay\LabelControl.cpp">
|
||||
<Filter>Source Files\Overlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Overlay\ComboBoxControl.cpp">
|
||||
<Filter>Source Files\Overlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Overlay\ScrollBarControl.cpp">
|
||||
<Filter>Source Files\Overlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Overlay\ComboBoxDropDown.cpp">
|
||||
<Filter>Source Files\Overlay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="DDrawCompat.rc">
|
||||
@ -744,4 +804,9 @@
|
||||
<Filter>Shaders</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="arrow.bmp">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -19,9 +19,9 @@
|
||||
#include <Gdi/Gdi.h>
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
#include <Input/Input.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
#include <Win32/MemoryManagement.h>
|
||||
#include <Win32/MsgHooks.h>
|
||||
#include <Win32/Registry.h>
|
||||
#include <Win32/Thread.h>
|
||||
|
||||
@ -227,8 +227,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
|
||||
VISIT_PUBLIC_DDRAW_PROCS(HOOK_DDRAW_PROC);
|
||||
|
||||
Input::installHooks();
|
||||
Win32::MemoryManagement::installHooks();
|
||||
Win32::MsgHooks::installHooks();
|
||||
Win32::Thread::installHooks();
|
||||
Compat::closeDbgEng();
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <Dll/Dll.h>
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Gdi/WinProc.h>
|
||||
#include <Overlay/ConfigWindow.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
namespace
|
||||
@ -14,6 +15,7 @@ namespace
|
||||
|
||||
HANDLE g_presentationWindowThread = nullptr;
|
||||
unsigned g_presentationWindowThreadId = 0;
|
||||
Overlay::ConfigWindow* g_configWindow = nullptr;
|
||||
HWND g_messageWindow = nullptr;
|
||||
bool g_isThreadReady = false;
|
||||
|
||||
@ -65,6 +67,10 @@ namespace
|
||||
|
||||
if (presentationWindow)
|
||||
{
|
||||
if (lParam)
|
||||
{
|
||||
CALL_ORIG_FUNC(SetWindowLongA)(presentationWindow, GWL_WNDPROC, lParam);
|
||||
}
|
||||
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(presentationWindow, 0, 255, LWA_ALPHA);
|
||||
}
|
||||
|
||||
@ -131,6 +137,9 @@ namespace
|
||||
|
||||
Compat::closeDbgEng();
|
||||
|
||||
Overlay::ConfigWindow configWindow;
|
||||
g_configWindow = &configWindow;
|
||||
|
||||
MSG msg = {};
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
{
|
||||
@ -153,10 +162,10 @@ namespace Gdi
|
||||
{
|
||||
namespace PresentationWindow
|
||||
{
|
||||
HWND create(HWND owner)
|
||||
HWND create(HWND owner, WNDPROC wndProc)
|
||||
{
|
||||
return reinterpret_cast<HWND>(sendMessageBlocking(
|
||||
g_messageWindow, WM_CREATEPRESENTATIONWINDOW, reinterpret_cast<WPARAM>(owner), 0));
|
||||
return reinterpret_cast<HWND>(sendMessageBlocking(g_messageWindow, WM_CREATEPRESENTATIONWINDOW,
|
||||
reinterpret_cast<WPARAM>(owner), reinterpret_cast<LPARAM>(wndProc)));
|
||||
}
|
||||
|
||||
void destroy(HWND hwnd)
|
||||
@ -164,6 +173,11 @@ namespace Gdi
|
||||
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
|
||||
Overlay::ConfigWindow* getConfigWindow()
|
||||
{
|
||||
return g_configWindow;
|
||||
}
|
||||
|
||||
void installHooks()
|
||||
{
|
||||
WNDCLASS wc = {};
|
||||
|
@ -2,12 +2,18 @@
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class ConfigWindow;
|
||||
}
|
||||
|
||||
namespace Gdi
|
||||
{
|
||||
namespace PresentationWindow
|
||||
{
|
||||
HWND create(HWND owner);
|
||||
HWND create(HWND owner, WNDPROC wndProc = nullptr);
|
||||
void destroy(HWND hwnd);
|
||||
Overlay::ConfigWindow* getConfigWindow();
|
||||
bool isPresentationWindow(HWND hwnd);
|
||||
bool isThreadReady();
|
||||
void setWindowPos(HWND hwnd, const WINDOWPOS& wp);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <Gdi/TitleBar.h>
|
||||
#include <Gdi/Window.h>
|
||||
#include <Gdi/WinProc.h>
|
||||
#include <Overlay/ConfigWindow.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
namespace
|
||||
@ -53,6 +54,17 @@ namespace
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_ACTIVATEAPP:
|
||||
if (!wParam)
|
||||
{
|
||||
auto configWindow = Gdi::PresentationWindow::getConfigWindow();
|
||||
if (configWindow)
|
||||
{
|
||||
configWindow->setVisible(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DISPLAYCHANGE:
|
||||
{
|
||||
if (0 != wParam)
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
#include <Gdi/Window.h>
|
||||
#include <Input/Input.h>
|
||||
#include <Overlay/ConfigWindow.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -96,6 +98,64 @@ namespace
|
||||
return rgn;
|
||||
}
|
||||
|
||||
void presentLayeredWindow(CompatWeakPtr<IDirectDrawSurface7> dst,
|
||||
HWND hwnd, RECT wr, const RECT& monitorRect, HDC& dstDc, Gdi::Region* rgn = nullptr, bool isMenu = false)
|
||||
{
|
||||
if (!dst)
|
||||
{
|
||||
throw true;
|
||||
}
|
||||
|
||||
if (!dstDc)
|
||||
{
|
||||
dst->GetDC(dst, &dstDc);
|
||||
if (!dstDc)
|
||||
{
|
||||
throw false;
|
||||
}
|
||||
}
|
||||
|
||||
OffsetRect(&wr, -monitorRect.left, -monitorRect.top);
|
||||
if (rgn)
|
||||
{
|
||||
rgn->offset(-monitorRect.left, -monitorRect.top);
|
||||
}
|
||||
|
||||
HDC windowDc = GetWindowDC(hwnd);
|
||||
if (rgn)
|
||||
{
|
||||
SelectClipRgn(dstDc, *rgn);
|
||||
}
|
||||
|
||||
COLORREF colorKey = 0;
|
||||
BYTE alpha = 255;
|
||||
DWORD flags = ULW_ALPHA;
|
||||
if (isMenu || CALL_ORIG_FUNC(GetLayeredWindowAttributes)(hwnd, &colorKey, &alpha, &flags))
|
||||
{
|
||||
if (flags & LWA_COLORKEY)
|
||||
{
|
||||
CALL_ORIG_FUNC(TransparentBlt)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top,
|
||||
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, colorKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
BLENDFUNCTION blend = {};
|
||||
blend.SourceConstantAlpha = alpha;
|
||||
CALL_ORIG_FUNC(AlphaBlend)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top,
|
||||
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, blend);
|
||||
}
|
||||
}
|
||||
|
||||
CALL_ORIG_FUNC(ReleaseDC)(hwnd, windowDc);
|
||||
}
|
||||
|
||||
void presentOverlayWindow(CompatWeakPtr<IDirectDrawSurface7> dst, HWND hwnd, const RECT& monitorRect, HDC& dstDc)
|
||||
{
|
||||
RECT wr = {};
|
||||
GetWindowRect(hwnd, &wr);
|
||||
presentLayeredWindow(dst, hwnd, wr, monitorRect, dstDc);
|
||||
}
|
||||
|
||||
void updatePosition(Window& window, const RECT& oldWindowRect, const RECT& oldClientRect,
|
||||
const Gdi::Region& oldVisibleRegion, Gdi::Region& invalidatedRegion)
|
||||
{
|
||||
@ -451,64 +511,47 @@ namespace Gdi
|
||||
bool presentLayered(CompatWeakPtr<IDirectDrawSurface7> dst, const RECT& monitorRect)
|
||||
{
|
||||
HDC dstDc = nullptr;
|
||||
bool result = false;
|
||||
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
|
||||
|
||||
try
|
||||
{
|
||||
auto& window = **it;
|
||||
if (!window.isLayered || window.visibleRegion.isEmpty())
|
||||
for (auto it = g_windowZOrder.rbegin(); it != g_windowZOrder.rend(); ++it)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Gdi::Region rgn(window.visibleRegion);
|
||||
rgn &= monitorRect;
|
||||
if (rgn.isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RECT wr = window.windowRect;
|
||||
OffsetRect(&wr, -monitorRect.left, -monitorRect.top);
|
||||
rgn.offset(-monitorRect.left, -monitorRect.top);
|
||||
|
||||
if (!dst)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!dstDc)
|
||||
{
|
||||
dst->GetDC(dst, &dstDc);
|
||||
if (!dstDc)
|
||||
auto& window = **it;
|
||||
if (!window.isLayered || window.visibleRegion.isEmpty())
|
||||
{
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
Gdi::Region rgn(window.visibleRegion);
|
||||
rgn &= monitorRect;
|
||||
if (rgn.isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
presentLayeredWindow(dst, window.hwnd, window.windowRect, monitorRect, dstDc, &rgn, window.isMenu);
|
||||
}
|
||||
|
||||
auto configWindow = PresentationWindow::getConfigWindow();
|
||||
if (configWindow && configWindow->isVisible())
|
||||
{
|
||||
presentOverlayWindow(dst, configWindow->getWindow(), monitorRect, dstDc);
|
||||
auto capture = Input::getCapture();
|
||||
if (capture && capture != configWindow)
|
||||
{
|
||||
presentOverlayWindow(dst, capture->getWindow(), monitorRect, dstDc);
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
HDC windowDc = GetWindowDC(window.hwnd);
|
||||
SelectClipRgn(dstDc, rgn);
|
||||
|
||||
COLORREF colorKey = 0;
|
||||
BYTE alpha = 255;
|
||||
DWORD flags = ULW_ALPHA;
|
||||
if (window.isMenu || CALL_ORIG_FUNC(GetLayeredWindowAttributes)(window.hwnd, &colorKey, &alpha, &flags))
|
||||
HWND cursorWindow = Input::getCursorWindow();
|
||||
if (cursorWindow)
|
||||
{
|
||||
if (flags & LWA_COLORKEY)
|
||||
{
|
||||
CALL_ORIG_FUNC(TransparentBlt)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top,
|
||||
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, colorKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
BLENDFUNCTION blend = {};
|
||||
blend.SourceConstantAlpha = alpha;
|
||||
CALL_ORIG_FUNC(AlphaBlend)(dstDc, wr.left, wr.top, wr.right - wr.left, wr.bottom - wr.top,
|
||||
windowDc, 0, 0, wr.right - wr.left, wr.bottom - wr.top, blend);
|
||||
}
|
||||
presentOverlayWindow(dst, cursorWindow, monitorRect, dstDc);
|
||||
}
|
||||
|
||||
CALL_ORIG_FUNC(ReleaseDC)(window.hwnd, windowDc);
|
||||
}
|
||||
catch (bool result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (dstDc)
|
||||
@ -516,7 +559,8 @@ namespace Gdi
|
||||
SelectClipRgn(dstDc, nullptr);
|
||||
dst->ReleaseDC(dst, dstDc);
|
||||
}
|
||||
return result;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void updateAll()
|
||||
|
283
DDrawCompat/Input/Input.cpp
Normal file
283
DDrawCompat/Input/Input.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <hidusage.h>
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Log.h>
|
||||
#include <Dll/Dll.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Input/Input.h>
|
||||
#include <Overlay/Window.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct HotKeyData
|
||||
{
|
||||
std::function<void(void*)> action;
|
||||
void* context;
|
||||
};
|
||||
|
||||
const UINT WM_USER_HOTKEY = WM_USER;
|
||||
const UINT WM_USER_RESET_HOOK = WM_USER + 1;
|
||||
|
||||
HANDLE g_bmpArrow = nullptr;
|
||||
SIZE g_bmpArrowSize = {};
|
||||
Overlay::Window* g_capture = nullptr;
|
||||
POINT g_cursorPos = {};
|
||||
HWND g_cursorWindow = nullptr;
|
||||
std::map<Input::HotKey, HotKeyData> g_hotKeys;
|
||||
RECT g_monitorRect = {};
|
||||
DWORD g_inputThreadId = 0;
|
||||
HHOOK g_keyboardHook = nullptr;
|
||||
HHOOK g_mouseHook = nullptr;
|
||||
|
||||
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
void setCursorPos(POINT cp);
|
||||
|
||||
LRESULT CALLBACK cursorWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LOG_FUNC("cursorWindowProc", Compat::WindowMessageStruct(hwnd, uMsg, wParam, lParam));
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps = {};
|
||||
BeginPaint(hwnd, &ps);
|
||||
HDC dc = CreateCompatibleDC(nullptr);
|
||||
HGDIOBJ origBmp = SelectObject(dc, g_bmpArrow);
|
||||
CALL_ORIG_FUNC(BitBlt)(ps.hdc, 0, 0, g_bmpArrowSize.cx, g_bmpArrowSize.cy, dc, 0, 0, SRCCOPY);
|
||||
SelectObject(dc, origBmp);
|
||||
DeleteDC(dc);
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||
break;
|
||||
}
|
||||
|
||||
return CALL_ORIG_FUNC(DefWindowProcA)(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
unsigned WINAPI inputThreadProc(LPVOID /*lpParameter*/)
|
||||
{
|
||||
g_inputThreadId = GetCurrentThreadId();
|
||||
g_bmpArrow = CALL_ORIG_FUNC(LoadImageA)(Dll::g_currentModule, "BMP_ARROW", IMAGE_BITMAP, 0, 0, 0);
|
||||
|
||||
BITMAP bm = {};
|
||||
GetObject(g_bmpArrow, sizeof(bm), &bm);
|
||||
g_bmpArrowSize = { bm.bmWidth, bm.bmHeight };
|
||||
|
||||
g_keyboardHook = CALL_ORIG_FUNC(SetWindowsHookExA)(WH_KEYBOARD_LL, &lowLevelKeyboardProc, Dll::g_currentModule, 0);
|
||||
|
||||
MSG msg = {};
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
{
|
||||
if (msg.message == WM_TIMER && !msg.hwnd && msg.lParam)
|
||||
{
|
||||
reinterpret_cast<TIMERPROC>(msg.lParam)(nullptr, WM_TIMER, msg.wParam, 0);
|
||||
}
|
||||
if (!msg.hwnd)
|
||||
{
|
||||
if (WM_USER_HOTKEY == msg.message)
|
||||
{
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(GetForegroundWindow(), &pid);
|
||||
if (GetCurrentProcessId() == pid)
|
||||
{
|
||||
auto it = std::find_if(g_hotKeys.begin(), g_hotKeys.end(),
|
||||
[&](const auto& v) { return v.first.vk == msg.wParam; });
|
||||
if (it != g_hotKeys.end())
|
||||
{
|
||||
it->second.action(it->second.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (WM_USER_RESET_HOOK == msg.message)
|
||||
{
|
||||
if (msg.wParam == WH_KEYBOARD_LL)
|
||||
{
|
||||
UnhookWindowsHookEx(g_keyboardHook);
|
||||
g_keyboardHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
|
||||
WH_KEYBOARD_LL, &lowLevelKeyboardProc, Dll::g_currentModule, 0);
|
||||
}
|
||||
else if (msg.wParam == WH_MOUSE_LL && g_mouseHook)
|
||||
{
|
||||
UnhookWindowsHookEx(g_mouseHook);
|
||||
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(
|
||||
WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (HC_ACTION == nCode && (WM_KEYDOWN == wParam || WM_SYSKEYDOWN == wParam))
|
||||
{
|
||||
auto llHook = reinterpret_cast<const KBDLLHOOKSTRUCT*>(lParam);
|
||||
PostThreadMessage(GetCurrentThreadId(), WM_USER_HOTKEY, llHook->vkCode, llHook->scanCode);
|
||||
}
|
||||
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (HC_ACTION == nCode)
|
||||
{
|
||||
POINT cp = g_cursorPos;
|
||||
POINT origCp = {};
|
||||
GetCursorPos(&origCp);
|
||||
|
||||
auto& llHook = *reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
|
||||
cp.x += (llHook.pt.x - origCp.x);
|
||||
cp.y += (llHook.pt.y - origCp.y);
|
||||
cp.x = min(max(g_monitorRect.left, cp.x), g_monitorRect.right);
|
||||
cp.y = min(max(g_monitorRect.top, cp.y), g_monitorRect.bottom);
|
||||
setCursorPos(cp);
|
||||
|
||||
RECT r = g_capture->getRect();
|
||||
cp.x -= r.left;
|
||||
cp.y -= r.top;
|
||||
|
||||
switch (wParam)
|
||||
{
|
||||
case WM_LBUTTONDOWN:
|
||||
g_capture->onLButtonDown(cp);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
g_capture->onLButtonUp(cp);
|
||||
break;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
g_capture->onMouseMove(cp);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
return CallNextHookEx(nullptr, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
void setCursorPos(POINT cp)
|
||||
{
|
||||
g_cursorPos = cp;
|
||||
CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, cp.x, cp.y, g_bmpArrowSize.cx, g_bmpArrowSize.cy,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
|
||||
}
|
||||
|
||||
HHOOK setWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId,
|
||||
decltype(&SetWindowsHookExA) origSetWindowsHookEx)
|
||||
{
|
||||
if (WH_KEYBOARD_LL == idHook && hmod && GetModuleHandle("AcGenral") == hmod)
|
||||
{
|
||||
// Disable the IgnoreAltTab shim
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HHOOK result = origSetWindowsHookEx(idHook, lpfn, hmod, dwThreadId);
|
||||
if (result && g_inputThreadId && (WH_KEYBOARD_LL == idHook || WH_MOUSE_LL == idHook))
|
||||
{
|
||||
PostThreadMessage(g_inputThreadId, WM_USER_RESET_HOOK, idHook, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HHOOK WINAPI setWindowsHookExA(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId)
|
||||
{
|
||||
LOG_FUNC("SetWindowsHookExA", idHook, lpfn, hmod, Compat::hex(dwThreadId));
|
||||
return LOG_RESULT(setWindowsHookEx(idHook, lpfn, hmod, dwThreadId, CALL_ORIG_FUNC(SetWindowsHookExA)));
|
||||
}
|
||||
|
||||
HHOOK WINAPI setWindowsHookExW(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId)
|
||||
{
|
||||
LOG_FUNC("SetWindowsHookExW", idHook, lpfn, hmod, Compat::hex(dwThreadId));
|
||||
return LOG_RESULT(setWindowsHookEx(idHook, lpfn, hmod, dwThreadId, CALL_ORIG_FUNC(SetWindowsHookExW)));
|
||||
}
|
||||
|
||||
auto toTuple(const Input::HotKey& hotKey)
|
||||
{
|
||||
return std::make_tuple(hotKey.vk, hotKey.modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Input
|
||||
{
|
||||
bool operator<(const HotKey& lhs, const HotKey& rhs)
|
||||
{
|
||||
return toTuple(lhs) < toTuple(rhs);
|
||||
}
|
||||
|
||||
Overlay::Window* getCapture()
|
||||
{
|
||||
return g_capture;
|
||||
}
|
||||
|
||||
HWND getCursorWindow()
|
||||
{
|
||||
return g_cursorWindow;
|
||||
}
|
||||
|
||||
void installHooks()
|
||||
{
|
||||
HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA);
|
||||
HOOK_FUNCTION(user32, SetWindowsHookExW, setWindowsHookExW);
|
||||
}
|
||||
|
||||
void registerHotKey(const HotKey& hotKey, std::function<void(void*)> action, void* context)
|
||||
{
|
||||
static HANDLE thread = Dll::createThread(&inputThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
if (thread)
|
||||
{
|
||||
g_hotKeys[hotKey] = { action, context };
|
||||
}
|
||||
}
|
||||
|
||||
void setCapture(Overlay::Window* window)
|
||||
{
|
||||
g_capture = window;
|
||||
if (window)
|
||||
{
|
||||
if (!g_mouseHook)
|
||||
{
|
||||
g_cursorWindow = Gdi::PresentationWindow::create(window->getWindow(), &cursorWindowProc);
|
||||
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(g_cursorWindow, RGB(0xFF, 0xFF, 0xFF), 0, LWA_COLORKEY);
|
||||
|
||||
MONITORINFO mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(MonitorFromWindow(window->getWindow(), MONITOR_DEFAULTTOPRIMARY), &mi);
|
||||
g_monitorRect = mi.rcMonitor;
|
||||
|
||||
RECT r = window->getRect();
|
||||
g_cursorPos = { (r.left + r.right) / 2, (r.top + r.bottom) / 2 };
|
||||
CALL_ORIG_FUNC(SetWindowPos)(g_cursorWindow, HWND_TOPMOST, g_cursorPos.x, g_cursorPos.y,
|
||||
g_bmpArrowSize.cx, g_bmpArrowSize.cy, SWP_NOACTIVATE | SWP_NOSENDCHANGING);
|
||||
ShowWindow(g_cursorWindow, SW_SHOW);
|
||||
|
||||
g_mouseHook = CALL_ORIG_FUNC(SetWindowsHookExA)(WH_MOUSE_LL, &lowLevelMouseProc, Dll::g_currentModule, 0);
|
||||
}
|
||||
}
|
||||
else if (g_mouseHook)
|
||||
{
|
||||
UnhookWindowsHookEx(g_mouseHook);
|
||||
g_mouseHook = nullptr;
|
||||
PostMessage(g_cursorWindow, WM_CLOSE, 0, 0);
|
||||
g_cursorWindow = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
28
DDrawCompat/Input/Input.h
Normal file
28
DDrawCompat/Input/Input.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <set>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class Window;
|
||||
}
|
||||
|
||||
namespace Input
|
||||
{
|
||||
struct HotKey
|
||||
{
|
||||
UINT vk;
|
||||
std::set<UINT> modifiers;
|
||||
};
|
||||
|
||||
bool operator<(const HotKey& lhs, const HotKey& rhs);
|
||||
|
||||
Overlay::Window* getCapture();
|
||||
HWND getCursorWindow();
|
||||
void installHooks();
|
||||
void registerHotKey(const HotKey& hotKey, std::function<void(void*)> action, void* context);
|
||||
void setCapture(Overlay::Window* window);
|
||||
}
|
32
DDrawCompat/Overlay/ComboBoxControl.cpp
Normal file
32
DDrawCompat/Overlay/ComboBoxControl.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <Overlay/ComboBoxControl.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
ComboBoxControl::ComboBoxControl(Control& parent, const RECT& rect)
|
||||
: Control(&parent, rect, WS_BORDER | WS_VISIBLE)
|
||||
, m_dropDown(*this)
|
||||
{
|
||||
}
|
||||
|
||||
void ComboBoxControl::setValue(const std::string& value)
|
||||
{
|
||||
m_value = value;
|
||||
invalidate(m_rect);
|
||||
}
|
||||
|
||||
void ComboBoxControl::draw(HDC dc)
|
||||
{
|
||||
RECT rect = m_rect;
|
||||
rect.left = m_rect.right - 17;
|
||||
drawArrow(dc, rect, DFCS_SCROLLDOWN);
|
||||
|
||||
rect.left = m_rect.left + BORDER;
|
||||
CALL_ORIG_FUNC(DrawTextA)(dc, m_value.c_str(), m_value.size(), &rect, DT_NOCLIP | DT_SINGLELINE | DT_VCENTER);
|
||||
}
|
||||
|
||||
void ComboBoxControl::onLButtonDown(POINT /*pos*/)
|
||||
{
|
||||
m_dropDown.setVisible(true);
|
||||
}
|
||||
}
|
28
DDrawCompat/Overlay/ComboBoxControl.h
Normal file
28
DDrawCompat/Overlay/ComboBoxControl.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <Overlay/ComboBoxDropDown.h>
|
||||
#include <Overlay/Control.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class ComboBoxControl : public Control
|
||||
{
|
||||
public:
|
||||
ComboBoxControl(Control& parent, const RECT& rect);
|
||||
|
||||
std::string getValue() const { return m_value; }
|
||||
std::vector<std::string> getValues() const { return m_dropDown.getValues(); }
|
||||
void setValue(const std::string& value);
|
||||
void setValues(const std::vector<std::string>& values) { m_dropDown.setValues(values); }
|
||||
|
||||
private:
|
||||
virtual void draw(HDC dc) override;
|
||||
virtual void onLButtonDown(POINT pos) override;
|
||||
|
||||
std::string m_value;
|
||||
ComboBoxDropDown m_dropDown;
|
||||
};
|
||||
}
|
56
DDrawCompat/Overlay/ComboBoxDropDown.cpp
Normal file
56
DDrawCompat/Overlay/ComboBoxDropDown.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <Overlay/ComboBoxControl.h>
|
||||
#include <Overlay/ComboBoxDropDown.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
ComboBoxDropDown::ComboBoxDropDown(ComboBoxControl& parent)
|
||||
: Window(&static_cast<Window&>(parent.getRoot()), { 0, 0, 100, 100 })
|
||||
, m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
RECT ComboBoxDropDown::calculateRect(const RECT& monitorRect) const
|
||||
{
|
||||
const RECT parentRect = m_parent.getRect();
|
||||
RECT r = { parentRect.left, parentRect.bottom,
|
||||
parentRect.right, parentRect.bottom + static_cast<int>(m_parent.getValues().size()) * ARROW_SIZE };
|
||||
|
||||
const Window& rootWindow = static_cast<const Window&>(m_parent.getRoot());
|
||||
const RECT rootRect = rootWindow.calculateRect(monitorRect);
|
||||
OffsetRect(&r, rootRect.left, rootRect.top);
|
||||
return r;
|
||||
}
|
||||
|
||||
void ComboBoxDropDown::onLButtonDown(POINT pos)
|
||||
{
|
||||
if (PtInRect(&m_rect, { m_rect.left + pos.x, m_rect.top + pos.y }))
|
||||
{
|
||||
propagateMouseEvent(&Control::onLButtonDown, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBoxDropDown::onNotify(Control& control)
|
||||
{
|
||||
m_parent.setValue(static_cast<LabelControl&>(control).getLabel());
|
||||
m_parent.getParent()->onNotify(*m_parent.getParent());
|
||||
}
|
||||
|
||||
void ComboBoxDropDown::setValues(const std::vector<std::string>& values)
|
||||
{
|
||||
m_values = values;
|
||||
m_labels.clear();
|
||||
int i = 0;
|
||||
for (const auto& v : values)
|
||||
{
|
||||
m_labels.emplace_back(*this,
|
||||
RECT{ BORDER, i * ARROW_SIZE, m_rect.right - m_rect.left - BORDER, (i + 1) * ARROW_SIZE },
|
||||
v, DT_SINGLELINE | DT_VCENTER);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
32
DDrawCompat/Overlay/ComboBoxDropDown.h
Normal file
32
DDrawCompat/Overlay/ComboBoxDropDown.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <Overlay/LabelControl.h>
|
||||
#include <Overlay/Window.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class ComboBoxControl;
|
||||
class LabelControl;
|
||||
|
||||
class ComboBoxDropDown : public Window
|
||||
{
|
||||
public:
|
||||
ComboBoxDropDown(ComboBoxControl& parent);
|
||||
|
||||
virtual void onNotify(Control& control) override;
|
||||
|
||||
std::vector<std::string> getValues() const { return m_values; }
|
||||
void setValues(const std::vector<std::string>& values);
|
||||
|
||||
private:
|
||||
virtual RECT calculateRect(const RECT& monitorRect) const override;
|
||||
virtual void onLButtonDown(POINT pos) override;
|
||||
|
||||
ComboBoxControl& m_parent;
|
||||
std::vector<std::string> m_values;
|
||||
std::list<LabelControl> m_labels;
|
||||
};
|
||||
}
|
36
DDrawCompat/Overlay/ConfigWindow.cpp
Normal file
36
DDrawCompat/Overlay/ConfigWindow.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <Config/Config.h>
|
||||
#include <Overlay/ConfigWindow.h>
|
||||
#include <Overlay/SettingControl.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
ConfigWindow::ConfigWindow()
|
||||
: Window(nullptr, { 0, 0, SettingControl::TOTAL_WIDTH, 200 }, { VK_F11, {} })
|
||||
{
|
||||
addControl(Config::alternatePixelCenter);
|
||||
addControl(Config::antialiasing);
|
||||
addControl(Config::displayFilter);
|
||||
addControl(Config::textureFilter);
|
||||
}
|
||||
|
||||
void ConfigWindow::addControl(Config::Setting& setting)
|
||||
{
|
||||
const int index = m_controls.size();
|
||||
const int rowHeight = 25;
|
||||
|
||||
RECT rect = { 0, index * rowHeight + BORDER / 2, m_rect.right, (index + 1) * rowHeight + BORDER / 2 };
|
||||
m_controls.emplace_back(*this, rect, setting);
|
||||
}
|
||||
|
||||
RECT ConfigWindow::calculateRect(const RECT& monitorRect) const
|
||||
{
|
||||
const LONG width = m_rect.right - m_rect.left;
|
||||
const LONG height = m_rect.bottom - m_rect.top;
|
||||
|
||||
RECT r = { 0, 0, width, height };
|
||||
OffsetRect(&r, monitorRect.left, monitorRect.top);
|
||||
OffsetRect(&r, (monitorRect.right - monitorRect.left - width) / 2, (monitorRect.bottom - monitorRect.top - height) / 2);
|
||||
return r;
|
||||
}
|
||||
}
|
22
DDrawCompat/Overlay/ConfigWindow.h
Normal file
22
DDrawCompat/Overlay/ConfigWindow.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <Overlay/SettingControl.h>
|
||||
#include <Overlay/Window.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class ConfigWindow : public Window
|
||||
{
|
||||
public:
|
||||
ConfigWindow();
|
||||
|
||||
private:
|
||||
virtual RECT calculateRect(const RECT& monitorRect) const override;
|
||||
|
||||
void addControl(Config::Setting& setting);
|
||||
|
||||
std::list<SettingControl> m_controls;
|
||||
};
|
||||
}
|
159
DDrawCompat/Overlay/Control.cpp
Normal file
159
DDrawCompat/Overlay/Control.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <Overlay/Control.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
Control* g_capture = nullptr;
|
||||
|
||||
Control::Control(Control* parent, const RECT& rect, DWORD style)
|
||||
: m_parent(parent)
|
||||
, m_rect(rect)
|
||||
, m_style(style)
|
||||
{
|
||||
if (parent)
|
||||
{
|
||||
parent->m_children.insert(this);
|
||||
}
|
||||
}
|
||||
|
||||
Control::~Control()
|
||||
{
|
||||
if (m_parent)
|
||||
{
|
||||
m_parent->m_children.erase(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::drawAll(HDC dc)
|
||||
{
|
||||
draw(dc);
|
||||
|
||||
for (auto control : m_children)
|
||||
{
|
||||
control->drawAll(dc);
|
||||
}
|
||||
|
||||
if (m_style & WS_BORDER)
|
||||
{
|
||||
RECT r = m_rect;
|
||||
if (!m_parent)
|
||||
{
|
||||
OffsetRect(&r, -m_rect.left, -m_rect.top);
|
||||
}
|
||||
CALL_ORIG_FUNC(Rectangle)(dc, r.left, r.top, r.right, r.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::drawArrow(HDC dc, RECT rect, UINT state)
|
||||
{
|
||||
CALL_ORIG_FUNC(Rectangle)(dc, rect.left, rect.top, rect.right, rect.bottom);
|
||||
|
||||
POINT center = { (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 };
|
||||
rect = { center.x, center.y, center.x, center.y };
|
||||
InflateRect(&rect, 3, 3);
|
||||
POINT poly[3] = {};
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case DFCS_SCROLLDOWN:
|
||||
poly[0] = { rect.left, rect.top };
|
||||
poly[1] = { rect.right, rect.top };
|
||||
poly[2] = { center.x, rect.bottom };
|
||||
break;
|
||||
|
||||
case DFCS_SCROLLLEFT:
|
||||
poly[0] = { rect.left, center.y };
|
||||
poly[1] = { rect.right, rect.top };
|
||||
poly[2] = { rect.right, rect.bottom };
|
||||
break;
|
||||
|
||||
case DFCS_SCROLLRIGHT:
|
||||
poly[0] = { rect.left, rect.top };
|
||||
poly[1] = { rect.left, rect.bottom };
|
||||
poly[2] = { rect.right, center.y };
|
||||
break;
|
||||
|
||||
case DFCS_SCROLLUP:
|
||||
poly[0] = { center.x, rect.top };
|
||||
poly[1] = { rect.left, rect.bottom };
|
||||
poly[2] = { rect.right, rect.bottom };
|
||||
break;
|
||||
}
|
||||
|
||||
CALL_ORIG_FUNC(Polygon)(dc, poly, 3);
|
||||
}
|
||||
|
||||
Control* Control::getCapture()
|
||||
{
|
||||
return g_capture;
|
||||
}
|
||||
|
||||
const Control& Control::getRoot() const
|
||||
{
|
||||
if (m_parent)
|
||||
{
|
||||
return m_parent->getRoot();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Control& Control::getRoot()
|
||||
{
|
||||
return const_cast<Control&>(std::as_const(*this).getRoot());
|
||||
}
|
||||
|
||||
void Control::invalidate(const RECT& rect)
|
||||
{
|
||||
if (m_parent)
|
||||
{
|
||||
m_parent->invalidate(rect);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::onLButtonDown(POINT pos)
|
||||
{
|
||||
propagateMouseEvent(&Control::onLButtonDown, pos);
|
||||
}
|
||||
|
||||
void Control::onLButtonUp(POINT pos)
|
||||
{
|
||||
propagateMouseEvent(&Control::onLButtonUp, pos);
|
||||
}
|
||||
|
||||
void Control::onMouseMove(POINT pos)
|
||||
{
|
||||
propagateMouseEvent(&Control::onMouseMove, pos);
|
||||
}
|
||||
|
||||
void Control::propagateMouseEvent(void(Control::* onEvent)(POINT), POINT pos)
|
||||
{
|
||||
if (g_capture)
|
||||
{
|
||||
(g_capture->*onEvent)(pos);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto child : m_children)
|
||||
{
|
||||
if (PtInRect(&child->m_rect, pos))
|
||||
{
|
||||
(child->*onEvent)(pos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Control::setCapture(Control* control)
|
||||
{
|
||||
g_capture = control;
|
||||
}
|
||||
|
||||
void Control::setVisible(bool isVisible)
|
||||
{
|
||||
if (isVisible != Control::isVisible())
|
||||
{
|
||||
m_style ^= WS_VISIBLE;
|
||||
invalidate(m_rect);
|
||||
}
|
||||
}
|
||||
}
|
50
DDrawCompat/Overlay/Control.h
Normal file
50
DDrawCompat/Overlay/Control.h
Normal file
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class Control
|
||||
{
|
||||
public:
|
||||
static const int ARROW_SIZE = 17;
|
||||
static const int BORDER = 8;
|
||||
|
||||
Control(Control* parent, const RECT& rect, DWORD style);
|
||||
virtual ~Control();
|
||||
|
||||
Control(const Control&) = delete;
|
||||
Control(Control&&) = delete;
|
||||
Control& operator=(const Control&) = delete;
|
||||
Control& operator=(Control&&) = delete;
|
||||
|
||||
virtual void draw(HDC /*dc*/) {}
|
||||
virtual void invalidate(const RECT& rect);
|
||||
virtual void onLButtonDown(POINT pos);
|
||||
virtual void onLButtonUp(POINT pos);
|
||||
virtual void onMouseMove(POINT pos);
|
||||
virtual void onNotify(Control& /*control*/) {}
|
||||
virtual void setVisible(bool isVisible);
|
||||
|
||||
void drawAll(HDC dc);
|
||||
Control* getParent() const { return m_parent; }
|
||||
RECT getRect() const { return m_rect; }
|
||||
const Control& getRoot() const;
|
||||
Control& getRoot();
|
||||
bool isVisible() const { return m_style & WS_VISIBLE; }
|
||||
|
||||
protected:
|
||||
void drawArrow(HDC dc, RECT rect, UINT state);
|
||||
void propagateMouseEvent(void(Control::* onEvent)(POINT), POINT pos);
|
||||
|
||||
static Control* getCapture();
|
||||
static void setCapture(Control* control);
|
||||
|
||||
Control* m_parent;
|
||||
RECT m_rect;
|
||||
DWORD m_style;
|
||||
std::set<Control*> m_children;
|
||||
};
|
||||
}
|
24
DDrawCompat/Overlay/LabelControl.cpp
Normal file
24
DDrawCompat/Overlay/LabelControl.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include <Common/Hook.h>
|
||||
#include <Overlay/LabelControl.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
LabelControl::LabelControl(Control& parent, const RECT& rect, const std::string& label, UINT format)
|
||||
: Control(&parent, rect, WS_VISIBLE)
|
||||
, m_label(label)
|
||||
, m_format(format)
|
||||
{
|
||||
}
|
||||
|
||||
void LabelControl::draw(HDC dc)
|
||||
{
|
||||
RECT r = { m_rect.left + BORDER, m_rect.top, m_rect.right - BORDER, m_rect.bottom };
|
||||
CALL_ORIG_FUNC(DrawTextA)(dc, m_label.c_str(), m_label.size(), &r,
|
||||
m_format | DT_NOCLIP | DT_SINGLELINE | DT_VCENTER);
|
||||
}
|
||||
|
||||
void LabelControl::onLButtonDown(POINT /*pos*/)
|
||||
{
|
||||
m_parent->onNotify(*this);
|
||||
}
|
||||
}
|
26
DDrawCompat/Overlay/LabelControl.h
Normal file
26
DDrawCompat/Overlay/LabelControl.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Overlay/Control.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class LabelControl : public Control
|
||||
{
|
||||
public:
|
||||
LabelControl(Control& parent, const RECT& rect, const std::string& label, UINT format);
|
||||
|
||||
virtual void onLButtonDown(POINT pos) override;
|
||||
|
||||
std::string getLabel() const { return m_label; }
|
||||
|
||||
private:
|
||||
virtual void draw(HDC dc) override;
|
||||
|
||||
std::string m_label;
|
||||
UINT m_format;
|
||||
};
|
||||
}
|
149
DDrawCompat/Overlay/ScrollBarControl.cpp
Normal file
149
DDrawCompat/Overlay/ScrollBarControl.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Overlay/ScrollBarControl.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
const DWORD REPEAT_DELAY = 500;
|
||||
const DWORD REPEAT_INTERVAL = 100;
|
||||
|
||||
UINT_PTR g_repeatTimerId = 0;
|
||||
|
||||
long roundDiv(long n, long d)
|
||||
{
|
||||
return (n + d / 2) / d;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
ScrollBarControl::ScrollBarControl(Control& parent, const RECT& rect, int min, int max)
|
||||
: Control(&parent, rect, WS_VISIBLE)
|
||||
, m_min(min)
|
||||
, m_max(max)
|
||||
, m_pos(min)
|
||||
, m_leftArrow{ rect.left, rect.top, rect.left + ARROW_SIZE, rect.bottom }
|
||||
, m_rightArrow{ rect.right - ARROW_SIZE, rect.top, rect.right, rect.bottom }
|
||||
, m_state(State::IDLE)
|
||||
{
|
||||
}
|
||||
|
||||
void ScrollBarControl::draw(HDC dc)
|
||||
{
|
||||
drawArrow(dc, m_leftArrow, DFCS_SCROLLLEFT);
|
||||
drawArrow(dc, m_rightArrow, DFCS_SCROLLRIGHT);
|
||||
|
||||
RECT r = { m_leftArrow.right, m_rect.top, m_rightArrow.left, m_rect.bottom };
|
||||
CALL_ORIG_FUNC(Rectangle)(dc, r.left - 1, r.top, r.right + 1, r.bottom);
|
||||
|
||||
const int thumbPos = (m_pos - m_min) * (r.right - r.left - ARROW_SIZE) / (m_max - m_min);
|
||||
r = { m_leftArrow.right + thumbPos, r.top, m_leftArrow.right + thumbPos + ARROW_SIZE, r.bottom };
|
||||
SelectObject(dc, GetStockObject(DC_BRUSH));
|
||||
CALL_ORIG_FUNC(Ellipse)(dc, r.left, r.top, r.right, r.bottom);
|
||||
SelectObject(dc, GetStockObject(NULL_BRUSH));
|
||||
}
|
||||
|
||||
void ScrollBarControl::onLButtonDown(POINT pos)
|
||||
{
|
||||
setCapture(this);
|
||||
if (PtInRect(&m_leftArrow, pos))
|
||||
{
|
||||
setPos(m_pos - 1);
|
||||
if (State::IDLE == m_state)
|
||||
{
|
||||
m_state = State::LEFT_ARROW_PRESSED;
|
||||
startRepeatTimer(REPEAT_DELAY);
|
||||
}
|
||||
}
|
||||
else if (PtInRect(&m_rightArrow, pos))
|
||||
{
|
||||
setPos(m_pos + 1);
|
||||
if (State::IDLE == m_state)
|
||||
{
|
||||
m_state = State::RIGHT_ARROW_PRESSED;
|
||||
startRepeatTimer(REPEAT_DELAY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
onThumbTrack(pos);
|
||||
if (State::IDLE == m_state)
|
||||
{
|
||||
m_state = State::THUMB_TRACKING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollBarControl::onLButtonUp(POINT /*pos*/)
|
||||
{
|
||||
setCapture(nullptr);
|
||||
stopRepeatTimer();
|
||||
m_state = State::IDLE;
|
||||
}
|
||||
|
||||
void ScrollBarControl::onMouseMove(POINT pos)
|
||||
{
|
||||
if (State::THUMB_TRACKING == m_state)
|
||||
{
|
||||
onThumbTrack(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollBarControl::onRepeat()
|
||||
{
|
||||
stopRepeatTimer();
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case State::LEFT_ARROW_PRESSED:
|
||||
setPos(m_pos - 1);
|
||||
startRepeatTimer(REPEAT_INTERVAL);
|
||||
break;
|
||||
|
||||
case State::RIGHT_ARROW_PRESSED:
|
||||
setPos(m_pos + 1);
|
||||
startRepeatTimer(REPEAT_INTERVAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollBarControl::onThumbTrack(POINT pos)
|
||||
{
|
||||
const auto minPos = m_leftArrow.right + ARROW_SIZE / 2;
|
||||
const auto maxPos = m_rightArrow.left - ARROW_SIZE / 2;
|
||||
pos.x = max(pos.x, minPos);
|
||||
pos.x = min(pos.x, maxPos);
|
||||
setPos(m_min + roundDiv((pos.x - minPos) * (m_max - m_min), maxPos - minPos));
|
||||
}
|
||||
|
||||
void CALLBACK ScrollBarControl::repeatTimerProc(HWND /*hwnd*/, UINT /*message*/, UINT_PTR /*iTimerID*/, DWORD /*dwTime*/)
|
||||
{
|
||||
static_cast<ScrollBarControl*>(Overlay::Control::getCapture())->onRepeat();
|
||||
}
|
||||
|
||||
void ScrollBarControl::setPos(int pos)
|
||||
{
|
||||
pos = max(pos, m_min);
|
||||
pos = min(pos, m_max);
|
||||
if (pos != m_pos)
|
||||
{
|
||||
m_pos = pos;
|
||||
m_parent->onNotify(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollBarControl::startRepeatTimer(DWORD time)
|
||||
{
|
||||
g_repeatTimerId = SetTimer(nullptr, g_repeatTimerId, time, &repeatTimerProc);
|
||||
}
|
||||
|
||||
void ScrollBarControl::stopRepeatTimer()
|
||||
{
|
||||
if (0 != g_repeatTimerId)
|
||||
{
|
||||
KillTimer(nullptr, g_repeatTimerId);
|
||||
g_repeatTimerId = 0;
|
||||
}
|
||||
}
|
||||
}
|
43
DDrawCompat/Overlay/ScrollBarControl.h
Normal file
43
DDrawCompat/Overlay/ScrollBarControl.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <Overlay/Control.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class ScrollBarControl : public Control
|
||||
{
|
||||
public:
|
||||
ScrollBarControl(Control& parent, const RECT& rect, int min, int max);
|
||||
|
||||
int getPos() const { return m_pos; }
|
||||
void setPos(int pos);
|
||||
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
IDLE,
|
||||
LEFT_ARROW_PRESSED,
|
||||
RIGHT_ARROW_PRESSED,
|
||||
THUMB_TRACKING,
|
||||
};
|
||||
|
||||
int m_min;
|
||||
int m_max;
|
||||
int m_pos;
|
||||
RECT m_leftArrow;
|
||||
RECT m_rightArrow;
|
||||
State m_state;
|
||||
|
||||
virtual void draw(HDC dc) override;
|
||||
virtual void onLButtonDown(POINT pos) override;
|
||||
virtual void onLButtonUp(POINT pos) override;
|
||||
virtual void onMouseMove(POINT pos) override;
|
||||
|
||||
void onRepeat();
|
||||
void onThumbTrack(POINT pos);
|
||||
|
||||
static void CALLBACK repeatTimerProc(HWND hwnd, UINT message, UINT_PTR iTimerID, DWORD dwTime);
|
||||
static void startRepeatTimer(DWORD time);
|
||||
static void stopRepeatTimer();
|
||||
};
|
||||
}
|
99
DDrawCompat/Overlay/SettingControl.cpp
Normal file
99
DDrawCompat/Overlay/SettingControl.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include <Config/Config.h>
|
||||
#include <Config/Parser.h>
|
||||
#include <Config/Setting.h>
|
||||
#include <D3dDdi/Device.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <Overlay/ComboBoxControl.h>
|
||||
#include <Overlay/SettingControl.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
SettingControl::SettingControl(Control& parent, const RECT& rect, Config::Setting& setting)
|
||||
: Control(&parent, rect, WS_VISIBLE)
|
||||
, m_setting(setting)
|
||||
, m_settingLabel(*this, { rect.left, rect.top, rect.left + SETTING_LABEL_WIDTH, rect.bottom }, setting.getName() + ':', 0)
|
||||
{
|
||||
const RECT r = { rect.left + SETTING_LABEL_WIDTH, rect.top + BORDER / 2,
|
||||
rect.left + SETTING_LABEL_WIDTH + SETTING_CONTROL_WIDTH, rect.bottom - BORDER / 2 };
|
||||
m_valueControl.reset(new ComboBoxControl(*this, r));
|
||||
getValueComboBox().setValue(setting.getValueStr());
|
||||
getValueComboBox().setValues(setting.getDefaultValueStrings());
|
||||
onValueChanged();
|
||||
updateValuesParam();
|
||||
}
|
||||
|
||||
ComboBoxControl& SettingControl::getValueComboBox() const
|
||||
{
|
||||
return static_cast<ComboBoxControl&>(*m_valueControl);
|
||||
}
|
||||
|
||||
void SettingControl::onNotify(Control& control)
|
||||
{
|
||||
if (&control == m_paramControl.get())
|
||||
{
|
||||
onParamChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
onValueChanged();
|
||||
}
|
||||
|
||||
if (&Config::antialiasing == &m_setting ||
|
||||
&Config::textureFilter == &m_setting)
|
||||
{
|
||||
D3dDdi::Device::updateAllConfig();
|
||||
}
|
||||
|
||||
invalidate(m_rect);
|
||||
}
|
||||
|
||||
void SettingControl::onParamChanged()
|
||||
{
|
||||
const std::string value(Config::Parser::removeParam(m_setting.getValueStr()) +
|
||||
'(' + std::to_string(m_paramControl->getPos()) + ')');
|
||||
m_setting.set(value);
|
||||
getValueComboBox().setValue(value);
|
||||
updateValuesParam();
|
||||
}
|
||||
|
||||
void SettingControl::onValueChanged()
|
||||
{
|
||||
const std::string value(getValueComboBox().getValue());
|
||||
m_setting.set(value);
|
||||
|
||||
if (m_paramControl)
|
||||
{
|
||||
m_paramLabel.reset();
|
||||
m_paramControl.reset();
|
||||
}
|
||||
|
||||
const auto paramInfo = m_setting.getParamInfo();
|
||||
if (!paramInfo.name.empty())
|
||||
{
|
||||
RECT r = m_valueControl->getRect();
|
||||
r.left = r.right;
|
||||
r.right = r.left + PARAM_LABEL_WIDTH;
|
||||
m_paramLabel.reset(new LabelControl(*this, r, paramInfo.name + ':', 0));
|
||||
|
||||
r.left = r.right;
|
||||
r.right = r.left + PARAM_CONTROL_WIDTH;
|
||||
m_paramControl.reset(new ScrollBarControl(*this, r, paramInfo.min, paramInfo.max));
|
||||
m_paramControl->setPos(m_setting.getParam());
|
||||
}
|
||||
}
|
||||
|
||||
void SettingControl::updateValuesParam()
|
||||
{
|
||||
const auto currentValue(Config::Parser::removeParam(m_setting.getValueStr()));
|
||||
auto values(getValueComboBox().getValues());
|
||||
for (auto& v : values)
|
||||
{
|
||||
if (Config::Parser::removeParam(v) == currentValue)
|
||||
{
|
||||
v = m_setting.getValueStr();
|
||||
getValueComboBox().setValues(values);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
DDrawCompat/Overlay/SettingControl.h
Normal file
44
DDrawCompat/Overlay/SettingControl.h
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <Overlay/LabelControl.h>
|
||||
#include <Overlay/ScrollBarControl.h>
|
||||
|
||||
namespace Config
|
||||
{
|
||||
class Setting;
|
||||
}
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class ComboBoxControl;
|
||||
|
||||
class SettingControl : public Control
|
||||
{
|
||||
public:
|
||||
static const int PARAM_LABEL_WIDTH = 50;
|
||||
static const int PARAM_CONTROL_WIDTH = 151;
|
||||
static const int SETTING_LABEL_WIDTH = 120;
|
||||
static const int SETTING_CONTROL_WIDTH = 151;
|
||||
static const int TOTAL_WIDTH =
|
||||
SETTING_LABEL_WIDTH + SETTING_CONTROL_WIDTH + PARAM_LABEL_WIDTH + PARAM_CONTROL_WIDTH + BORDER;
|
||||
|
||||
SettingControl(Control& parent, const RECT& rect, Config::Setting& setting);
|
||||
|
||||
virtual void onNotify(Control& control) override;
|
||||
|
||||
private:
|
||||
ComboBoxControl& getValueComboBox() const;
|
||||
void onParamChanged();
|
||||
void onValueChanged();
|
||||
void updateValuesParam();
|
||||
|
||||
Config::Setting& m_setting;
|
||||
LabelControl m_settingLabel;
|
||||
std::unique_ptr<Control> m_valueControl;
|
||||
std::unique_ptr<LabelControl> m_paramLabel;
|
||||
std::unique_ptr<ScrollBarControl> m_paramControl;
|
||||
};
|
||||
}
|
194
DDrawCompat/Overlay/Window.cpp
Normal file
194
DDrawCompat/Overlay/Window.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
#include <map>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <CommCtrl.h>
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Common/Log.h>
|
||||
#include <Config/Config.h>
|
||||
#include <Dll/Dll.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Input/Input.h>
|
||||
#include <Overlay/Control.h>
|
||||
#include <Overlay/Window.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
enum class ControlType
|
||||
{
|
||||
COMBOBOX,
|
||||
SLIDER
|
||||
};
|
||||
|
||||
std::map<HWND, Overlay::Window&> g_windows;
|
||||
|
||||
HFONT createDefaultFont()
|
||||
{
|
||||
LOGFONT lf = {};
|
||||
lf.lfHeight = 13;
|
||||
lf.lfWeight = FW_NORMAL;
|
||||
lf.lfQuality = NONANTIALIASED_QUALITY;
|
||||
strcpy_s(lf.lfFaceName, "Segoe UI");
|
||||
return CreateFontIndirect(&lf);
|
||||
}
|
||||
|
||||
void toggleWindow(void* window)
|
||||
{
|
||||
auto wnd = static_cast<Overlay::Window*>(window);
|
||||
wnd->setVisible(!wnd->isVisible());
|
||||
}
|
||||
}
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
Window::Window(Window* parentWindow, const RECT& rect, const Input::HotKey& hotKey)
|
||||
: Control(nullptr, rect, WS_BORDER)
|
||||
, m_hwnd(Gdi::PresentationWindow::create(parentWindow ? parentWindow->m_hwnd : nullptr, &staticWindowProc))
|
||||
, m_parentWindow(parentWindow)
|
||||
, m_transparency(25)
|
||||
{
|
||||
g_windows.emplace(m_hwnd, *this);
|
||||
setTransparency(m_transparency);
|
||||
if (0 != hotKey.vk)
|
||||
{
|
||||
Input::registerHotKey(hotKey, &toggleWindow, this);
|
||||
}
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
Gdi::PresentationWindow::destroy(m_hwnd);
|
||||
g_windows.erase(m_hwnd);
|
||||
}
|
||||
|
||||
void Window::draw(HDC /*dc*/)
|
||||
{
|
||||
}
|
||||
|
||||
void Window::invalidate(const RECT& rect)
|
||||
{
|
||||
InvalidateRect(m_hwnd, &rect, TRUE);
|
||||
}
|
||||
|
||||
void Window::onEraseBackground(HDC dc)
|
||||
{
|
||||
RECT r = { 0, 0, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top };
|
||||
CALL_ORIG_FUNC(FillRect)(dc, &r, static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
|
||||
}
|
||||
|
||||
void Window::onPaint()
|
||||
{
|
||||
static HFONT font = createDefaultFont();
|
||||
|
||||
PAINTSTRUCT ps = {};
|
||||
HDC dc = BeginPaint(m_hwnd, &ps);
|
||||
SelectObject(dc, font);
|
||||
SelectObject(dc, GetStockObject(DC_PEN));
|
||||
SelectObject(dc, GetStockObject(NULL_BRUSH));
|
||||
SetBkColor(dc, RGB(0, 0, 0));
|
||||
SetDCBrushColor(dc, RGB(0, 0, 0));
|
||||
SetDCPenColor(dc, RGB(0, 255, 0));
|
||||
SetTextColor(dc, RGB(0, 255, 0));
|
||||
|
||||
drawAll(dc);
|
||||
|
||||
EndPaint(m_hwnd, &ps);
|
||||
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||
}
|
||||
|
||||
void Window::setTransparency(int transparency)
|
||||
{
|
||||
m_transparency = transparency;
|
||||
CALL_ORIG_FUNC(SetLayeredWindowAttributes)(m_hwnd, 0, static_cast<BYTE>(100 - transparency) * 255 / 100, ULW_ALPHA);
|
||||
}
|
||||
|
||||
void Window::setVisible(bool isVisible)
|
||||
{
|
||||
if (isVisible == Window::isVisible())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_style ^= WS_VISIBLE;
|
||||
if (m_style & WS_VISIBLE)
|
||||
{
|
||||
updatePos();
|
||||
ShowWindow(m_hwnd, SW_SHOWNA);
|
||||
Input::setCapture(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto capture = Input::getCapture();
|
||||
if (capture != this && capture->m_parentWindow == this)
|
||||
{
|
||||
capture->setVisible(false);
|
||||
}
|
||||
ShowWindow(m_hwnd, SW_HIDE);
|
||||
Input::setCapture(m_parentWindow);
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK Window::staticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return g_windows.find(hwnd)->second.windowProc(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
void Window::updatePos()
|
||||
{
|
||||
auto monitorRect = Win32::DisplayMode::getEmulatedDisplayMode().rect;
|
||||
if (IsRectEmpty(&monitorRect))
|
||||
{
|
||||
monitorRect = DDraw::PrimarySurface::getMonitorRect();
|
||||
if (IsRectEmpty(&monitorRect))
|
||||
{
|
||||
HMONITOR monitor = nullptr;
|
||||
HWND foregroundWindow = GetForegroundWindow();
|
||||
if (foregroundWindow)
|
||||
{
|
||||
monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTONEAREST);
|
||||
}
|
||||
else
|
||||
{
|
||||
monitor = MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
|
||||
MONITORINFO mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
CALL_ORIG_FUNC(GetMonitorInfoA)(monitor, &mi);
|
||||
monitorRect = mi.rcMonitor;
|
||||
|
||||
if (IsRectEmpty(&monitorRect))
|
||||
{
|
||||
monitorRect = { 0, 0, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_rect = calculateRect(monitorRect);
|
||||
CALL_ORIG_FUNC(SetWindowPos)(m_hwnd, HWND_TOPMOST, m_rect.left, m_rect.top,
|
||||
m_rect.right - m_rect.left, m_rect.bottom - m_rect.top, SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
LRESULT Window::windowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_DISPLAYCHANGE:
|
||||
updatePos();
|
||||
break;
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
onEraseBackground(reinterpret_cast<HDC>(wParam));
|
||||
return 1;
|
||||
|
||||
case WM_PAINT:
|
||||
onPaint();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CALL_ORIG_FUNC(DefWindowProcA)(m_hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
41
DDrawCompat/Overlay/Window.h
Normal file
41
DDrawCompat/Overlay/Window.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Input/Input.h>
|
||||
#include <Overlay/Control.h>
|
||||
|
||||
namespace Overlay
|
||||
{
|
||||
class Window : public Control
|
||||
{
|
||||
public:
|
||||
Window(Window* parentWindow, const RECT& rect, const Input::HotKey& hotKey = {});
|
||||
virtual ~Window() override;
|
||||
|
||||
virtual RECT calculateRect(const RECT& monitorRect) const = 0;
|
||||
virtual void invalidate(const RECT& rect) override;
|
||||
virtual void setVisible(bool isVisible) override;
|
||||
|
||||
HWND getWindow() const { return m_hwnd; }
|
||||
void setTransparency(int transparency);
|
||||
|
||||
protected:
|
||||
HWND m_hwnd;
|
||||
Window* m_parentWindow;
|
||||
int m_transparency;
|
||||
|
||||
void updatePos();
|
||||
|
||||
private:
|
||||
virtual void draw(HDC dc) override;
|
||||
|
||||
void onEraseBackground(HDC dc);
|
||||
void onPaint();
|
||||
LRESULT windowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
static LRESULT CALLBACK staticWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
};
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Common/Hook.h>
|
||||
#include <Win32/MsgHooks.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
HHOOK WINAPI setWindowsHookExA(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId)
|
||||
{
|
||||
if (WH_KEYBOARD_LL == idHook && hMod && GetModuleHandle("AcGenral") == hMod)
|
||||
{
|
||||
// This effectively disables the IgnoreAltTab shim
|
||||
return nullptr;
|
||||
}
|
||||
return CALL_ORIG_FUNC(SetWindowsHookExA)(idHook, lpfn, hMod, dwThreadId);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Win32
|
||||
{
|
||||
namespace MsgHooks
|
||||
{
|
||||
void installHooks()
|
||||
{
|
||||
HOOK_FUNCTION(user32, SetWindowsHookExA, setWindowsHookExA);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace Win32
|
||||
{
|
||||
namespace MsgHooks
|
||||
{
|
||||
void installHooks();
|
||||
}
|
||||
}
|
BIN
DDrawCompat/arrow.bmp
Normal file
BIN
DDrawCompat/arrow.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 310 B |
Loading…
x
Reference in New Issue
Block a user