mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5cabd026ae | |||
| 7ccd938f9b | |||
| 88a210e82e |
@@ -1,13 +1,14 @@
|
|||||||
#include "keypads.h"
|
#include "keypads.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "external/rapidjson/document.h"
|
#include "external/rapidjson/document.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
#include "util/precise_timer.h"
|
|
||||||
|
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
@@ -59,7 +60,6 @@ namespace api::modules {
|
|||||||
// get params
|
// get params
|
||||||
auto keypad = req.params[0].GetUint();
|
auto keypad = req.params[0].GetUint();
|
||||||
auto input = std::string(req.params[1].GetString());
|
auto input = std::string(req.params[1].GetString());
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
|
|
||||||
// process all chars
|
// process all chars
|
||||||
for (auto c : input) {
|
for (auto c : input) {
|
||||||
@@ -93,11 +93,11 @@ namespace api::modules {
|
|||||||
|
|
||||||
// set
|
// set
|
||||||
eamuse_set_keypad_overrides(keypad, state);
|
eamuse_set_keypad_overrides(keypad, state);
|
||||||
timer.sleep(sleep_time);
|
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
|
||||||
|
|
||||||
// unset
|
// unset
|
||||||
eamuse_set_keypad_overrides(keypad, 0);
|
eamuse_set_keypad_overrides(keypad, 0);
|
||||||
timer.sleep(sleep_time);
|
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/precise_timer.h"
|
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -17,7 +18,6 @@ namespace api {
|
|||||||
controller->init_state(this->state);
|
controller->init_state(this->state);
|
||||||
this->thread = new std::thread([this] () {
|
this->thread = new std::thread([this] () {
|
||||||
log_warning("api::serial", "listening on {} (baud: {})", this->port, this->baud);
|
log_warning("api::serial", "listening on {} (baud: {})", this->port, this->baud);
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
|
|
||||||
// read buffer
|
// read buffer
|
||||||
uint8_t read_buffer[16*1024];
|
uint8_t read_buffer[16*1024];
|
||||||
@@ -162,7 +162,7 @@ namespace api {
|
|||||||
|
|
||||||
// slow down on reconnect
|
// slow down on reconnect
|
||||||
if (this->running) {
|
if (this->running) {
|
||||||
timer.sleep(retry_time);
|
std::this_thread::sleep_for(std::chrono::milliseconds(retry_time));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -534,7 +534,7 @@ namespace games::iidx {
|
|||||||
if (mediaTypePointer && mediaTypePointer->IsString()) {
|
if (mediaTypePointer && mediaTypePointer->IsString()) {
|
||||||
std::string mediaType = mediaTypePointer->GetString();
|
std::string mediaType = mediaTypePointer->GetString();
|
||||||
if (mediaType.length() > 0) {
|
if (mediaType.length() > 0) {
|
||||||
camera->m_selectedMediaTypeDescription = mediaType;
|
camera->SetSelectedMediaTypeDescription(mediaType);
|
||||||
camera->m_useAutoMediaType = false;
|
camera->m_useAutoMediaType = false;
|
||||||
} else {
|
} else {
|
||||||
camera->m_useAutoMediaType = true;
|
camera->m_useAutoMediaType = true;
|
||||||
@@ -547,7 +547,7 @@ namespace games::iidx {
|
|||||||
std::string drawModeString = drawModePointer->GetString();
|
std::string drawModeString = drawModePointer->GetString();
|
||||||
for (int j = 0; j < DRAW_MODE_SIZE; j++) {
|
for (int j = 0; j < DRAW_MODE_SIZE; j++) {
|
||||||
if (DRAW_MODE_LABELS[j].compare(drawModeString) == 0) {
|
if (DRAW_MODE_LABELS[j].compare(drawModeString) == 0) {
|
||||||
camera->m_drawMode = (LocalCameraDrawMode) j;
|
camera->m_drawMode.store((LocalCameraDrawMode) j);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -556,12 +556,12 @@ namespace games::iidx {
|
|||||||
// Flip
|
// Flip
|
||||||
auto flipHorizontalPointer = rapidjson::Pointer(root + "/" + symLink + "/FlipHorizontal").Get(doc);
|
auto flipHorizontalPointer = rapidjson::Pointer(root + "/" + symLink + "/FlipHorizontal").Get(doc);
|
||||||
if (flipHorizontalPointer && flipHorizontalPointer->IsBool()) {
|
if (flipHorizontalPointer && flipHorizontalPointer->IsBool()) {
|
||||||
camera->m_flipHorizontal = flipHorizontalPointer->GetBool();
|
camera->m_flipHorizontal.store(flipHorizontalPointer->GetBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto flipVerticalPointer = rapidjson::Pointer(root + "/" + symLink + "/FlipVertical").Get(doc);
|
auto flipVerticalPointer = rapidjson::Pointer(root + "/" + symLink + "/FlipVertical").Get(doc);
|
||||||
if (flipVerticalPointer && flipVerticalPointer->IsBool()) {
|
if (flipVerticalPointer && flipVerticalPointer->IsBool()) {
|
||||||
camera->m_flipVertical = flipVerticalPointer->GetBool();
|
camera->m_flipVertical.store(flipVerticalPointer->GetBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow manual control
|
// Allow manual control
|
||||||
@@ -625,15 +625,17 @@ namespace games::iidx {
|
|||||||
if (camera->m_useAutoMediaType) {
|
if (camera->m_useAutoMediaType) {
|
||||||
rapidjson::Pointer(root + "MediaType").Set(doc, "");
|
rapidjson::Pointer(root + "MediaType").Set(doc, "");
|
||||||
} else {
|
} else {
|
||||||
rapidjson::Pointer(root + "MediaType").Set(doc, camera->m_selectedMediaTypeDescription);
|
const auto mediaTypeDescription = camera->GetSelectedMediaTypeDescription();
|
||||||
|
rapidjson::Pointer(root + "MediaType").Set(doc, mediaTypeDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw Mode
|
// Draw Mode
|
||||||
rapidjson::Pointer(root + "DrawMode").Set(doc, DRAW_MODE_LABELS[camera->m_drawMode]);
|
const auto drawMode = camera->m_drawMode.load();
|
||||||
|
rapidjson::Pointer(root + "DrawMode").Set(doc, DRAW_MODE_LABELS[drawMode]);
|
||||||
|
|
||||||
// Flip
|
// Flip
|
||||||
rapidjson::Pointer(root + "FlipHorizontal").Set(doc, camera->m_flipHorizontal);
|
rapidjson::Pointer(root + "FlipHorizontal").Set(doc, camera->m_flipHorizontal.load());
|
||||||
rapidjson::Pointer(root + "FlipVertical").Set(doc, camera->m_flipVertical);
|
rapidjson::Pointer(root + "FlipVertical").Set(doc, camera->m_flipVertical.load());
|
||||||
|
|
||||||
// Manual control
|
// Manual control
|
||||||
rapidjson::Pointer(root + "AllowManualControl").Set(doc, camera->m_allowManualControl);
|
rapidjson::Pointer(root + "AllowManualControl").Set(doc, camera->m_allowManualControl);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#if SPICE64 && !SPICE_XP
|
#if SPICE64 && !SPICE_XP
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
#include <dxva2api.h>
|
#include <dxva2api.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -66,6 +67,8 @@ extern std::string CAMERA_CONTROL_LABELS[];
|
|||||||
extern std::string DRAW_MODE_LABELS[];
|
extern std::string DRAW_MODE_LABELS[];
|
||||||
|
|
||||||
namespace games::iidx {
|
namespace games::iidx {
|
||||||
|
class IIDXCameraSourceReaderCallback;
|
||||||
|
|
||||||
namespace Camera {
|
namespace Camera {
|
||||||
struct PlayVideoCamera {
|
struct PlayVideoCamera {
|
||||||
IDirect3DTexture9** d3d9_texture(const uintptr_t offset) {
|
IDirect3DTexture9** d3d9_texture(const uintptr_t offset) {
|
||||||
@@ -87,7 +90,7 @@ namespace games::iidx {
|
|||||||
|
|
||||||
class IIDXLocalCamera {
|
class IIDXLocalCamera {
|
||||||
protected:
|
protected:
|
||||||
virtual ~IIDXLocalCamera() {};
|
virtual ~IIDXLocalCamera();
|
||||||
|
|
||||||
LONG m_nRefCount;
|
LONG m_nRefCount;
|
||||||
CRITICAL_SECTION m_critsec;
|
CRITICAL_SECTION m_critsec;
|
||||||
@@ -101,9 +104,14 @@ namespace games::iidx {
|
|||||||
// For reading frames from Camera
|
// For reading frames from Camera
|
||||||
IMFMediaSource *m_pSource = nullptr;
|
IMFMediaSource *m_pSource = nullptr;
|
||||||
IMFSourceReader *m_pSourceReader = nullptr;
|
IMFSourceReader *m_pSourceReader = nullptr;
|
||||||
|
IMFSourceReaderEx *m_pSourceReaderEx = nullptr;
|
||||||
|
IIDXCameraSourceReaderCallback *m_pSourceReaderCallback = nullptr;
|
||||||
|
std::mutex m_mediaTypeMutex;
|
||||||
|
IMFMediaType *m_pendingMediaType = nullptr;
|
||||||
|
int m_selectedMediaTypeIndex = 0;
|
||||||
|
std::string m_selectedMediaTypeDescription = "";
|
||||||
|
|
||||||
// Camera Format information
|
// Camera Format information
|
||||||
double m_frameRate = 0;
|
|
||||||
LONG m_cameraWidth;
|
LONG m_cameraWidth;
|
||||||
LONG m_cameraHeight;
|
LONG m_cameraHeight;
|
||||||
|
|
||||||
@@ -129,6 +137,12 @@ namespace games::iidx {
|
|||||||
LPDIRECT3DTEXTURE9 m_conversionTexture = nullptr;
|
LPDIRECT3DTEXTURE9 m_conversionTexture = nullptr;
|
||||||
IDirect3DSurface9 *m_pConversionSurf = nullptr;
|
IDirect3DSurface9 *m_pConversionSurf = nullptr;
|
||||||
|
|
||||||
|
// upload surface for decoded camera frames returned in system memory
|
||||||
|
IDirect3DSurface9 *m_pDecodedSurf = nullptr;
|
||||||
|
GUID m_decodedSubtype = GUID_NULL;
|
||||||
|
GUID m_outputSubtype = GUID_NULL;
|
||||||
|
bool m_drawErrorLogged = false;
|
||||||
|
|
||||||
// Texture for custom transform (e.g. horizontal flip)
|
// Texture for custom transform (e.g. horizontal flip)
|
||||||
LPDIRECT3DTEXTURE9 m_transformTexture = nullptr;
|
LPDIRECT3DTEXTURE9 m_transformTexture = nullptr;
|
||||||
IDirect3DSurface9 *m_pTransformSurf = nullptr;
|
IDirect3DSurface9 *m_pTransformSurf = nullptr;
|
||||||
@@ -153,21 +167,19 @@ namespace games::iidx {
|
|||||||
BOOL m_initialized = false;
|
BOOL m_initialized = false;
|
||||||
|
|
||||||
// True if all the setup steps succeeded
|
// True if all the setup steps succeeded
|
||||||
BOOL m_active = false;
|
std::atomic_bool m_active = false;
|
||||||
|
|
||||||
// Media type select
|
// Media type select
|
||||||
std::vector<MediaTypeInfo> m_mediaTypeInfos = {};
|
std::vector<MediaTypeInfo> m_mediaTypeInfos = {};
|
||||||
int m_selectedMediaTypeIndex = 0;
|
|
||||||
bool m_useAutoMediaType = true;
|
bool m_useAutoMediaType = true;
|
||||||
IMFMediaType *m_pAutoMediaType = nullptr;
|
IMFMediaType *m_pAutoMediaType = nullptr;
|
||||||
std::string m_selectedMediaTypeDescription = "";
|
|
||||||
bool m_allowManualControl = false;
|
bool m_allowManualControl = false;
|
||||||
|
|
||||||
LocalCameraDrawMode m_drawMode = DrawModeCrop4_3;
|
std::atomic<LocalCameraDrawMode> m_drawMode = DrawModeCrop4_3;
|
||||||
|
|
||||||
// Render processing
|
// Render processing
|
||||||
bool m_flipHorizontal = false;
|
std::atomic_bool m_flipHorizontal = false;
|
||||||
bool m_flipVertical = false;
|
std::atomic_bool m_flipVertical = false;
|
||||||
|
|
||||||
IIDXLocalCamera(
|
IIDXLocalCamera(
|
||||||
std::string name,
|
std::string name,
|
||||||
@@ -184,11 +196,14 @@ namespace games::iidx {
|
|||||||
HRESULT GetCameraControlProp(int index, CameraControlProp *pProp);
|
HRESULT GetCameraControlProp(int index, CameraControlProp *pProp);
|
||||||
HRESULT SetCameraControlProp(int index, long value, long flags);
|
HRESULT SetCameraControlProp(int index, long value, long flags);
|
||||||
HRESULT ResetCameraControlProps();
|
HRESULT ResetCameraControlProps();
|
||||||
HRESULT FlushDrawCommands();
|
|
||||||
std::string GetName();
|
std::string GetName();
|
||||||
std::string GetFriendlyName();
|
std::string GetFriendlyName();
|
||||||
std::string GetSymLink();
|
std::string GetSymLink();
|
||||||
|
int GetSelectedMediaTypeIndex();
|
||||||
|
std::string GetSelectedMediaTypeDescription();
|
||||||
|
void SetSelectedMediaTypeDescription(const std::string &description);
|
||||||
HRESULT ChangeMediaType(IMFMediaType *pType);
|
HRESULT ChangeMediaType(IMFMediaType *pType);
|
||||||
|
void RequestMediaType(IMFMediaType *pType);
|
||||||
HRESULT StartCapture();
|
HRESULT StartCapture();
|
||||||
void UpdateDrawRect();
|
void UpdateDrawRect();
|
||||||
|
|
||||||
@@ -197,12 +212,22 @@ namespace games::iidx {
|
|||||||
void CreateThread();
|
void CreateThread();
|
||||||
MediaTypeInfo GetMediaTypeInfo(IMFMediaType *pType);
|
MediaTypeInfo GetMediaTypeInfo(IMFMediaType *pType);
|
||||||
std::string GetVideoFormatName(GUID subtype);
|
std::string GetVideoFormatName(GUID subtype);
|
||||||
HRESULT TryMediaType(IMFMediaType *pType, UINT32 *pBestWidth, double *pBestFrameRate);
|
static bool CompareMediaTypes(const MediaTypeInfo &a, const MediaTypeInfo &b);
|
||||||
|
bool MatchesPreferredAspect(const MediaTypeInfo &info) const;
|
||||||
|
static bool IsBetterAutoType(const MediaTypeInfo &candidate, const MediaTypeInfo ¤t);
|
||||||
|
IMFMediaType *FindBestNativeAutoType(bool requirePreferredAspect) const;
|
||||||
|
IMFMediaType *FindBestAutoType(const GUID &subtype, bool requirePreferredAspect) const;
|
||||||
|
HRESULT ValidateMediaType(IMFMediaType *pType);
|
||||||
HRESULT InitTargetTexture();
|
HRESULT InitTargetTexture();
|
||||||
|
HRESULT EnsureTransformTextures();
|
||||||
HRESULT InitCameraControl();
|
HRESULT InitCameraControl();
|
||||||
|
void SetSelectedMediaType(int index, const std::string &description);
|
||||||
|
bool HasPendingMediaType();
|
||||||
|
HRESULT ApplyPendingMediaType();
|
||||||
|
HRESULT UploadDecodedSample(IMFMediaBuffer *pSrcBuffer);
|
||||||
HRESULT DrawSample(IMFMediaBuffer *pSrcBuffer);
|
HRESULT DrawSample(IMFMediaBuffer *pSrcBuffer);
|
||||||
HRESULT ReadSample();
|
HRESULT ReadSample();
|
||||||
LPDIRECT3DTEXTURE9 Render();
|
HRESULT Render();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ namespace games::iidx {
|
|||||||
_In_ UINT32 cInitialSize
|
_In_ UINT32 cInitialSize
|
||||||
);
|
);
|
||||||
|
|
||||||
|
typedef HRESULT (__stdcall * MFCreateMediaType_t)(
|
||||||
|
_Out_ IMFMediaType** ppMFType
|
||||||
|
);
|
||||||
|
|
||||||
typedef HRESULT (__stdcall * MFEnumDeviceSources_t)(
|
typedef HRESULT (__stdcall * MFEnumDeviceSources_t)(
|
||||||
_In_ IMFAttributes* pAttributes,
|
_In_ IMFAttributes* pAttributes,
|
||||||
_Outptr_result_buffer_(*pcSourceActivate) IMFActivate*** pppSourceActivate,
|
_Outptr_result_buffer_(*pcSourceActivate) IMFActivate*** pppSourceActivate,
|
||||||
@@ -35,6 +39,7 @@ namespace games::iidx {
|
|||||||
);
|
);
|
||||||
|
|
||||||
static MFCreateAttributes_t MFCreateAttributes = nullptr;
|
static MFCreateAttributes_t MFCreateAttributes = nullptr;
|
||||||
|
static MFCreateMediaType_t MFCreateMediaType = nullptr;
|
||||||
static MFEnumDeviceSources_t MFEnumDeviceSources = nullptr;
|
static MFEnumDeviceSources_t MFEnumDeviceSources = nullptr;
|
||||||
static MFCreateSourceReaderFromMediaSource_t MFCreateSourceReaderFromMediaSource = nullptr;
|
static MFCreateSourceReaderFromMediaSource_t MFCreateSourceReaderFromMediaSource = nullptr;
|
||||||
static MFGetService_t MFGetService = nullptr;
|
static MFGetService_t MFGetService = nullptr;
|
||||||
@@ -66,6 +71,12 @@ namespace games::iidx {
|
|||||||
log_fatal("mf_wrappers", "MFCreateAttributes failed to hook");
|
log_fatal("mf_wrappers", "MFCreateAttributes failed to hook");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MFCreateMediaType = (MFCreateMediaType_t)
|
||||||
|
libutils::get_proc(mfplat_dll, "MFCreateMediaType");
|
||||||
|
if (!MFCreateMediaType) {
|
||||||
|
log_fatal("mf_wrappers", "MFCreateMediaType failed to hook");
|
||||||
|
}
|
||||||
|
|
||||||
MFEnumDeviceSources = (MFEnumDeviceSources_t)
|
MFEnumDeviceSources = (MFEnumDeviceSources_t)
|
||||||
libutils::get_proc(mf_dll, "MFEnumDeviceSources");
|
libutils::get_proc(mf_dll, "MFEnumDeviceSources");
|
||||||
if (!MFEnumDeviceSources) {
|
if (!MFEnumDeviceSources) {
|
||||||
@@ -92,6 +103,11 @@ namespace games::iidx {
|
|||||||
return MFCreateAttributes(ppMFAttributes, cInitialSize);
|
return MFCreateAttributes(ppMFAttributes, cInitialSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HRESULT WrappedMFCreateMediaType (
|
||||||
|
_Out_ IMFMediaType** ppMFType) {
|
||||||
|
return MFCreateMediaType(ppMFType);
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT WrappedMFEnumDeviceSources (
|
HRESULT WrappedMFEnumDeviceSources (
|
||||||
_In_ IMFAttributes* pAttributes,
|
_In_ IMFAttributes* pAttributes,
|
||||||
_Outptr_result_buffer_(*pcSourceActivate) IMFActivate*** pppSourceActivate,
|
_Outptr_result_buffer_(*pcSourceActivate) IMFActivate*** pppSourceActivate,
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ namespace games::iidx {
|
|||||||
_Out_ IMFAttributes** ppMFAttributes,
|
_Out_ IMFAttributes** ppMFAttributes,
|
||||||
_In_ UINT32 cInitialSize);
|
_In_ UINT32 cInitialSize);
|
||||||
|
|
||||||
|
HRESULT WrappedMFCreateMediaType (
|
||||||
|
_Out_ IMFMediaType** ppMFType);
|
||||||
|
|
||||||
HRESULT WrappedMFEnumDeviceSources (
|
HRESULT WrappedMFEnumDeviceSources (
|
||||||
_In_ IMFAttributes* pAttributes,
|
_In_ IMFAttributes* pAttributes,
|
||||||
_Outptr_result_buffer_(*pcSourceActivate) IMFActivate*** pppSourceActivate,
|
_Outptr_result_buffer_(*pcSourceActivate) IMFActivate*** pppSourceActivate,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "poke.h"
|
#include "poke.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@@ -11,7 +12,6 @@
|
|||||||
#include "touch/native/inject.h"
|
#include "touch/native/inject.h"
|
||||||
#include "touch/touch.h"
|
#include "touch/touch.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/precise_timer.h"
|
|
||||||
|
|
||||||
namespace games::iidx::poke {
|
namespace games::iidx::poke {
|
||||||
|
|
||||||
@@ -125,8 +125,6 @@ namespace games::iidx::poke {
|
|||||||
// create new thread
|
// create new thread
|
||||||
THREAD_RUNNING = true;
|
THREAD_RUNNING = true;
|
||||||
THREAD = new std::thread([] {
|
THREAD = new std::thread([] {
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
|
|
||||||
// log
|
// log
|
||||||
log_info("poke", "enabled");
|
log_info("poke", "enabled");
|
||||||
|
|
||||||
@@ -198,7 +196,7 @@ namespace games::iidx::poke {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// slow down
|
// slow down
|
||||||
timer.sleep(50);
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!touch_points.empty()) {
|
if (!touch_points.empty()) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "poke.h"
|
#include "poke.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@@ -11,7 +12,6 @@
|
|||||||
#include "touch/native/inject.h"
|
#include "touch/native/inject.h"
|
||||||
#include "touch/native/nativetouchhook.h"
|
#include "touch/native/nativetouchhook.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/precise_timer.h"
|
|
||||||
|
|
||||||
namespace games::nost::poke {
|
namespace games::nost::poke {
|
||||||
|
|
||||||
@@ -68,8 +68,6 @@ namespace games::nost::poke {
|
|||||||
// create new thread
|
// create new thread
|
||||||
THREAD_RUNNING = true;
|
THREAD_RUNNING = true;
|
||||||
THREAD = new std::thread([] {
|
THREAD = new std::thread([] {
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
|
|
||||||
const int swipe_anim_total_frames = 6;
|
const int swipe_anim_total_frames = 6;
|
||||||
const int swipe_anim_y = 300;
|
const int swipe_anim_y = 300;
|
||||||
|
|
||||||
@@ -194,7 +192,7 @@ namespace games::nost::poke {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// slow down
|
// slow down
|
||||||
timer.sleep(30);
|
std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contact_active) {
|
if (contact_active) {
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "hooks/audio/util.h"
|
#include "hooks/audio/util.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/precise_timer.h"
|
|
||||||
|
|
||||||
NullDiscardBackend::~NullDiscardBackend() {
|
NullDiscardBackend::~NullDiscardBackend() {
|
||||||
this->running = false;
|
this->running = false;
|
||||||
@@ -125,8 +125,6 @@ HRESULT NullDiscardBackend::on_release_buffer(uint32_t, DWORD) {
|
|||||||
void NullDiscardBackend::pace_loop() {
|
void NullDiscardBackend::pace_loop() {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
|
|
||||||
// audio is discarded, so timing precision and drift do not matter; just wake the
|
// audio is discarded, so timing precision and drift do not matter; just wake the
|
||||||
// game once per buffer period to keep its render thread from blocking on the event.
|
// game once per buffer period to keep its render thread from blocking on the event.
|
||||||
const auto period = duration_cast<steady_clock::duration>(
|
const auto period = duration_cast<steady_clock::duration>(
|
||||||
@@ -136,6 +134,6 @@ void NullDiscardBackend::pace_loop() {
|
|||||||
if (this->relay_handle) {
|
if (this->relay_handle) {
|
||||||
SetEvent(this->relay_handle);
|
SetEvent(this->relay_handle);
|
||||||
}
|
}
|
||||||
timer.sleep(period);
|
std::this_thread::sleep_for(period);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "eamuse.h"
|
#include "eamuse.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@@ -10,7 +11,6 @@
|
|||||||
#include "rawinput/rawinput.h"
|
#include "rawinput/rawinput.h"
|
||||||
#include "games/sdvx/sdvx.h"
|
#include "games/sdvx/sdvx.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/precise_timer.h"
|
|
||||||
#include "util/time.h"
|
#include "util/time.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
#include "overlay/overlay.h"
|
#include "overlay/overlay.h"
|
||||||
@@ -335,7 +335,6 @@ void eamuse_coin_start_thread() {
|
|||||||
COIN_INPUT_THREAD = new std::thread([]() {
|
COIN_INPUT_THREAD = new std::thread([]() {
|
||||||
auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game());
|
auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game());
|
||||||
static bool COIN_INPUT_KEY_STATE = false;
|
static bool COIN_INPUT_KEY_STATE = false;
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
while (COIN_INPUT_THREAD_ACTIVE) {
|
while (COIN_INPUT_THREAD_ACTIVE) {
|
||||||
|
|
||||||
// check input key
|
// check input key
|
||||||
@@ -355,7 +354,7 @@ void eamuse_coin_start_thread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// once every two frames
|
// once every two frames
|
||||||
timer.sleep(1000 / 30);
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 30));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -409,7 +408,6 @@ void eamuse_pin_macro_start_thread() {
|
|||||||
size_t pin_index[2] = {PIN_MACRO_VALUES[0].length(), PIN_MACRO_VALUES[1].length()};
|
size_t pin_index[2] = {PIN_MACRO_VALUES[0].length(), PIN_MACRO_VALUES[1].length()};
|
||||||
|
|
||||||
std::optional<uint8_t> active_unit = std::nullopt;
|
std::optional<uint8_t> active_unit = std::nullopt;
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
|
|
||||||
while (PIN_MACRO_THREAD_ACTIVE) {
|
while (PIN_MACRO_THREAD_ACTIVE) {
|
||||||
// wait for key press or auto-trigger
|
// wait for key press or auto-trigger
|
||||||
@@ -438,7 +436,7 @@ void eamuse_pin_macro_start_thread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!active_unit.has_value()) {
|
if (!active_unit.has_value()) {
|
||||||
timer.sleep(20);
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,22 +452,22 @@ void eamuse_pin_macro_start_thread() {
|
|||||||
eamuse_set_keypad_overrides(unit, keypad_overrides[char_index]);
|
eamuse_set_keypad_overrides(unit, keypad_overrides[char_index]);
|
||||||
}
|
}
|
||||||
pin_index[unit]++;
|
pin_index[unit]++;
|
||||||
timer.sleep(100);
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
|
||||||
// clear
|
// clear
|
||||||
eamuse_set_keypad_overrides(unit, 0);
|
eamuse_set_keypad_overrides(unit, 0);
|
||||||
timer.sleep(50);
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
|
||||||
// end of PIN
|
// end of PIN
|
||||||
if (pin_index[unit] == PIN_MACRO_VALUES[unit].length()) {
|
if (pin_index[unit] == PIN_MACRO_VALUES[unit].length()) {
|
||||||
active_unit = std::nullopt;
|
active_unit = std::nullopt;
|
||||||
timer.sleep(120);
|
std::this_thread::sleep_for(std::chrono::milliseconds(120));
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.sleep(200);
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -495,6 +495,14 @@ namespace wintouchemu {
|
|||||||
if (hWnd != nullptr && USE_MOUSE) {
|
if (hWnd != nullptr && USE_MOUSE) {
|
||||||
bool button_pressed = get_async_primary_mouse();
|
bool button_pressed = get_async_primary_mouse();
|
||||||
|
|
||||||
|
// while the subscreen overlay cannot accept the mouse, treat the button as
|
||||||
|
// released; this ends any active touch and prevents new mouse touch contacts
|
||||||
|
if (overlay::OVERLAY &&
|
||||||
|
overlay::OVERLAY->has_subscreen_touch_transform() &&
|
||||||
|
!overlay::OVERLAY->accepts_subscreen_mouse_input()) {
|
||||||
|
button_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
// if there was a touch event in the last 500 ms, don't insert new button presses
|
// if there was a touch event in the last 500 ms, don't insert new button presses
|
||||||
if (button_pressed && (now - last_touch_event) < 500) {
|
if (button_pressed && (now - last_touch_event) < 500) {
|
||||||
button_pressed = false;
|
button_pressed = false;
|
||||||
|
|||||||
@@ -908,6 +908,17 @@ bool overlay::SpiceOverlay::get_active() {
|
|||||||
return this->active;
|
return this->active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool overlay::SpiceOverlay::is_subscreen_overlay_visible() {
|
||||||
|
return this->get_active() &&
|
||||||
|
this->window_sub != nullptr &&
|
||||||
|
this->window_sub->get_active();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool overlay::SpiceOverlay::accepts_subscreen_mouse_input() {
|
||||||
|
return this->is_subscreen_overlay_visible() &&
|
||||||
|
this->window_sub->is_mouse_hovered();
|
||||||
|
}
|
||||||
|
|
||||||
bool overlay::SpiceOverlay::has_focus() {
|
bool overlay::SpiceOverlay::has_focus() {
|
||||||
return this->get_active() && ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow);
|
return this->get_active() && ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ namespace overlay {
|
|||||||
void show_main_menu();
|
void show_main_menu();
|
||||||
void set_active(bool active);
|
void set_active(bool active);
|
||||||
bool get_active();
|
bool get_active();
|
||||||
|
bool accepts_subscreen_mouse_input();
|
||||||
bool has_focus();
|
bool has_focus();
|
||||||
bool hotkeys_triggered();
|
bool hotkeys_triggered();
|
||||||
|
|
||||||
@@ -143,20 +144,20 @@ namespace overlay {
|
|||||||
return this->hWnd;
|
return this->hWnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_transform_touch_input() {
|
bool has_subscreen_touch_transform() {
|
||||||
return (this->subscreen_mouse_handler != nullptr);
|
return (this->subscreen_touch_transform != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool transform_touch_point(LONG *x, LONG *y) {
|
bool transform_touch_point(LONG *x, LONG *y) {
|
||||||
if (this->get_active() && this->subscreen_mouse_handler) {
|
if (this->get_active() && this->subscreen_touch_transform) {
|
||||||
return this->subscreen_mouse_handler(x, y);
|
return this->subscreen_touch_transform(x, y);
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_subscreen_mouse_handler(const std::function<bool(LONG *, LONG *)> &f) {
|
void set_subscreen_touch_transform(const std::function<bool(LONG *, LONG *)> &f) {
|
||||||
this->subscreen_mouse_handler = f;
|
this->subscreen_touch_transform = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderer
|
// renderer
|
||||||
@@ -203,7 +204,7 @@ namespace overlay {
|
|||||||
|
|
||||||
std::vector<std::unique_ptr<Window>> windows;
|
std::vector<std::unique_ptr<Window>> windows;
|
||||||
|
|
||||||
std::function<bool(LONG *, LONG *)> subscreen_mouse_handler = nullptr;
|
std::function<bool(LONG *, LONG *)> subscreen_touch_transform = nullptr;
|
||||||
|
|
||||||
bool active = false;
|
bool active = false;
|
||||||
bool toggle_down = false;
|
bool toggle_down = false;
|
||||||
@@ -216,6 +217,7 @@ namespace overlay {
|
|||||||
// so render() never runs without a matching NewFrame.
|
// so render() never runs without a matching NewFrame.
|
||||||
bool has_pending_frame = false;
|
bool has_pending_frame = false;
|
||||||
|
|
||||||
|
bool is_subscreen_overlay_visible();
|
||||||
void init();
|
void init();
|
||||||
void add_font(const char* font, ImFontConfig* config, const ImWchar* glyphs);
|
void add_font(const char* font, ImFontConfig* config, const ImWchar* glyphs);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ void overlay::Window::build() {
|
|||||||
|
|
||||||
// check if active
|
// check if active
|
||||||
if (!this->active) {
|
if (!this->active) {
|
||||||
|
this->mouse_hovered = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,10 +107,18 @@ void overlay::Window::build() {
|
|||||||
// top spot. suppress that so only an explicit focus request (see below)
|
// top spot. suppress that so only an explicit focus request (see below)
|
||||||
// decides what comes to the front.
|
// decides what comes to the front.
|
||||||
const std::string window_id = this->title + "###" + to_string(this);
|
const std::string window_id = this->title + "###" + to_string(this);
|
||||||
if (ImGui::Begin(
|
const bool build_contents = ImGui::Begin(
|
||||||
window_id.c_str(),
|
window_id.c_str(),
|
||||||
&this->active,
|
&this->active,
|
||||||
this->flags | ImGuiWindowFlags_NoFocusOnAppearing)) {
|
this->flags | ImGuiWindowFlags_NoFocusOnAppearing);
|
||||||
|
|
||||||
|
// keep the window hovered while its invisible input button is held during a drag
|
||||||
|
this->mouse_hovered =
|
||||||
|
ImGui::IsWindowHovered(
|
||||||
|
ImGuiHoveredFlags_RootAndChildWindows |
|
||||||
|
ImGuiHoveredFlags_AllowWhenBlockedByActiveItem);
|
||||||
|
|
||||||
|
if (build_contents) {
|
||||||
|
|
||||||
// window attributes - init_pos / init_size are only honored once
|
// window attributes - init_pos / init_size are only honored once
|
||||||
// (ImGuiCond_Once), so compute them a single time instead of every frame
|
// (ImGuiCond_Once), so compute them a single time instead of every frame
|
||||||
@@ -154,6 +163,9 @@ void overlay::Window::build() {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
// raw content does not have an ImGui window to hover
|
||||||
|
this->mouse_hovered = false;
|
||||||
|
|
||||||
// add raw content
|
// add raw content
|
||||||
this->build_content();
|
this->build_content();
|
||||||
}
|
}
|
||||||
@@ -201,3 +213,7 @@ bool overlay::Window::get_active() {
|
|||||||
// now it depends on us
|
// now it depends on us
|
||||||
return this->active;
|
return this->active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool overlay::Window::is_mouse_hovered() {
|
||||||
|
return this->mouse_hovered;
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace overlay {
|
|||||||
void toggle_active();
|
void toggle_active();
|
||||||
void set_active(bool active);
|
void set_active(bool active);
|
||||||
bool get_active();
|
bool get_active();
|
||||||
|
bool is_mouse_hovered();
|
||||||
|
|
||||||
// raise this window to the top of the z-order on its next build. only
|
// raise this window to the top of the z-order on its next build. only
|
||||||
// call in response to an explicit user action (keyboard toggle, UI
|
// call in response to an explicit user action (keyboard toggle, UI
|
||||||
@@ -37,6 +38,7 @@ namespace overlay {
|
|||||||
// set when the window transitions to visible so build() raises it to the
|
// set when the window transitions to visible so build() raises it to the
|
||||||
// top of the z-order on the next frame
|
// top of the z-order on the next frame
|
||||||
bool request_focus = false;
|
bool request_focus = false;
|
||||||
|
bool mouse_hovered = false;
|
||||||
std::vector<Window*> children;
|
std::vector<Window*> children;
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
|
|||||||
@@ -82,9 +82,14 @@ namespace overlay::windows {
|
|||||||
ImGui::Text("Rendering");
|
ImGui::Text("Rendering");
|
||||||
|
|
||||||
// Media Type Selector
|
// Media Type Selector
|
||||||
int selectedMediaTypeIndex = selectedCamera->m_selectedMediaTypeIndex;
|
int selectedMediaTypeIndex = selectedCamera->GetSelectedMediaTypeIndex();
|
||||||
auto numMediaTypes = selectedCamera->m_mediaTypeInfos.size();
|
auto numMediaTypes = selectedCamera->m_mediaTypeInfos.size();
|
||||||
|
|
||||||
|
if (numMediaTypes == 0) {
|
||||||
|
ImGui::TextColored(ImVec4(1.f, 1.f, 0.f, 1.f), "%s", "No supported media types");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto selectedMediaTypeIndexChanged = ImGui::BeginCombo(
|
auto selectedMediaTypeIndexChanged = ImGui::BeginCombo(
|
||||||
"Media Type", selectedCamera->m_mediaTypeInfos.at(selectedMediaTypeIndex).description.c_str()
|
"Media Type", selectedCamera->m_mediaTypeInfos.at(selectedMediaTypeIndex).description.c_str()
|
||||||
);
|
);
|
||||||
@@ -103,9 +108,9 @@ namespace overlay::windows {
|
|||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedMediaTypeIndexChanged && selectedMediaTypeIndex != selectedCamera->m_selectedMediaTypeIndex) {
|
if (selectedMediaTypeIndexChanged && selectedMediaTypeIndex != selectedCamera->GetSelectedMediaTypeIndex()) {
|
||||||
selectedCamera->m_useAutoMediaType = false;
|
selectedCamera->m_useAutoMediaType = false;
|
||||||
selectedCamera->ChangeMediaType(selectedCamera->m_mediaTypeInfos.at(selectedMediaTypeIndex).p_mediaType);
|
selectedCamera->RequestMediaType(selectedCamera->m_mediaTypeInfos.at(selectedMediaTypeIndex).p_mediaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto media type
|
// Auto media type
|
||||||
@@ -114,13 +119,14 @@ namespace overlay::windows {
|
|||||||
if (ImGui::Checkbox("Auto##MediaType", &isAutoMediaType)) {
|
if (ImGui::Checkbox("Auto##MediaType", &isAutoMediaType)) {
|
||||||
selectedCamera->m_useAutoMediaType = isAutoMediaType;
|
selectedCamera->m_useAutoMediaType = isAutoMediaType;
|
||||||
if (isAutoMediaType) {
|
if (isAutoMediaType) {
|
||||||
selectedCamera->ChangeMediaType(selectedCamera->m_pAutoMediaType);
|
selectedCamera->RequestMediaType(selectedCamera->m_pAutoMediaType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw mode
|
// Draw mode
|
||||||
int selectedDrawModeIndex = selectedCamera->m_drawMode;
|
const auto drawMode = selectedCamera->m_drawMode.load();
|
||||||
if (ImGui::BeginCombo("Draw Mode", DRAW_MODE_LABELS[selectedCamera->m_drawMode].c_str())) {
|
int selectedDrawModeIndex = drawMode;
|
||||||
|
if (ImGui::BeginCombo("Draw Mode", DRAW_MODE_LABELS[drawMode].c_str())) {
|
||||||
for (size_t i = 0; i < DRAW_MODE_SIZE; i++) {
|
for (size_t i = 0; i < DRAW_MODE_SIZE; i++) {
|
||||||
const bool is_selected = (selectedDrawModeIndex == (int) i);
|
const bool is_selected = (selectedDrawModeIndex == (int) i);
|
||||||
if (ImGui::Selectable(DRAW_MODE_LABELS[i].c_str(), is_selected)) {
|
if (ImGui::Selectable(DRAW_MODE_LABELS[i].c_str(), is_selected)) {
|
||||||
@@ -142,15 +148,25 @@ namespace overlay::windows {
|
|||||||
"Letterbox to 4:3: Like Letterbox, but target 4:3"
|
"Letterbox to 4:3: Like Letterbox, but target 4:3"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (selectedDrawModeIndex != selectedCamera->m_drawMode) {
|
if (selectedDrawModeIndex != selectedCamera->m_drawMode.load()) {
|
||||||
selectedCamera->m_drawMode = (LocalCameraDrawMode)selectedDrawModeIndex;
|
selectedCamera->m_drawMode.store((LocalCameraDrawMode)selectedDrawModeIndex);
|
||||||
selectedCamera->UpdateDrawRect();
|
selectedCamera->UpdateDrawRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
ImGui::Checkbox("Horizontal Flip", &selectedCamera->m_flipHorizontal);
|
bool flipHorizontal = selectedCamera->m_flipHorizontal.load();
|
||||||
|
if (ImGui::Checkbox("Horizontal Flip", &flipHorizontal)) {
|
||||||
|
selectedCamera->m_flipHorizontal.store(flipHorizontal);
|
||||||
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Checkbox("Vertical Flip", &selectedCamera->m_flipVertical);
|
bool flipVertical = selectedCamera->m_flipVertical.load();
|
||||||
|
if (ImGui::Checkbox("Vertical Flip", &flipVertical)) {
|
||||||
|
selectedCamera->m_flipVertical.store(flipVertical);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::HelpMarker(
|
||||||
|
"Flips are done by the CPU and can be very expensive, potentially causing frame drops! "
|
||||||
|
"Prefer to use camera's built-in flip if available.");
|
||||||
|
|
||||||
// Camera control parameters
|
// Camera control parameters
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace overlay::windows {
|
|||||||
this->texture_width = 0;
|
this->texture_width = 0;
|
||||||
this->texture_height = 0;
|
this->texture_height = 0;
|
||||||
|
|
||||||
overlay->set_subscreen_mouse_handler([this](LONG *x, LONG *y) -> bool {
|
overlay->set_subscreen_touch_transform([this](LONG *x, LONG *y) -> bool {
|
||||||
// convert to normalized form (relative window coordinates 0.f-1.f)
|
// convert to normalized form (relative window coordinates 0.f-1.f)
|
||||||
ImVec2 xy;
|
ImVec2 xy;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
@@ -103,6 +102,13 @@ namespace rawinput {
|
|||||||
std::vector<HIDTouchPoint> touch_points;
|
std::vector<HIDTouchPoint> touch_points;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HIDButtonInputGroup {
|
||||||
|
USAGE usage_page;
|
||||||
|
USHORT link_collection;
|
||||||
|
std::vector<size_t> cap_indices;
|
||||||
|
std::vector<USAGE> usages;
|
||||||
|
};
|
||||||
|
|
||||||
struct DeviceHIDInfo {
|
struct DeviceHIDInfo {
|
||||||
HANDLE handle;
|
HANDLE handle;
|
||||||
_HIDP_CAPS caps;
|
_HIDP_CAPS caps;
|
||||||
@@ -125,11 +131,12 @@ namespace rawinput {
|
|||||||
|
|
||||||
std::vector<std::vector<bool>> button_states;
|
std::vector<std::vector<bool>> button_states;
|
||||||
std::vector<std::vector<double>> button_up, button_down;
|
std::vector<std::vector<double>> button_up, button_down;
|
||||||
|
std::vector<std::vector<uint8_t>> button_report_states;
|
||||||
std::vector<std::vector<bool>> button_output_states;
|
std::vector<std::vector<bool>> button_output_states;
|
||||||
|
std::vector<HIDButtonInputGroup> button_input_groups;
|
||||||
// key: usage page, link collection
|
std::vector<CHAR> output_report;
|
||||||
// value: number of buttons for that key (combine ranges and nonranges)
|
std::vector<USAGE> button_output_usages;
|
||||||
std::map<std::pair<USAGE, ULONG>, ULONG> button_usage_pages;
|
std::vector<USAGE> button_output_usages_off;
|
||||||
|
|
||||||
std::vector<float> value_states;
|
std::vector<float> value_states;
|
||||||
std::vector<LONG> value_states_raw;
|
std::vector<LONG> value_states_raw;
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#include "rawinput.h"
|
#include "rawinput.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
#include <map>
|
||||||
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -9,7 +13,6 @@
|
|||||||
|
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "external/robin_hood.h"
|
#include "external/robin_hood.h"
|
||||||
#include "util/precise_timer.h"
|
|
||||||
#include "util/time.h"
|
#include "util/time.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
|
||||||
@@ -169,9 +172,8 @@ void rawinput::RawInputManager::input_hwnd_create() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// wait for window creation being done
|
// wait for window creation being done
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
while (!this->input_hwnd) {
|
while (!this->input_hwnd) {
|
||||||
timer.sleep(1);
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,7 +441,9 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
|
|||||||
std::vector<std::string> button_caps_names;
|
std::vector<std::string> button_caps_names;
|
||||||
std::vector<std::vector<bool>> button_states;
|
std::vector<std::vector<bool>> button_states;
|
||||||
std::vector<std::vector<double>> button_up, button_down;
|
std::vector<std::vector<double>> button_up, button_down;
|
||||||
std::map<std::pair<USAGE, ULONG>, ULONG> button_usage_pages;
|
std::vector<std::vector<uint8_t>> button_report_states;
|
||||||
|
std::vector<HIDButtonInputGroup> button_input_groups;
|
||||||
|
std::map<std::pair<USAGE, ULONG>, size_t> button_input_group_indices;
|
||||||
for (int button_cap_num = 0; button_cap_num < button_cap_length; button_cap_num++) {
|
for (int button_cap_num = 0; button_cap_num < button_cap_length; button_cap_num++) {
|
||||||
auto &button_caps = button_cap_data[button_cap_num];
|
auto &button_caps = button_cap_data[button_cap_num];
|
||||||
|
|
||||||
@@ -458,7 +462,7 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
|
|||||||
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
|
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
|
||||||
|
|
||||||
// ignore bad ranges reported by bad devices
|
// ignore bad ranges reported by bad devices
|
||||||
if (button_count >= 0xffff) {
|
if (button_count <= 0 || button_count >= 0xffff) {
|
||||||
log_warning("rawinput", "skipping bad button cap range for device {}, range [{}, {}]",
|
log_warning("rawinput", "skipping bad button cap range for device {}, range [{}, {}]",
|
||||||
device_name,
|
device_name,
|
||||||
button_caps.Range.UsageMin,
|
button_caps.Range.UsageMin,
|
||||||
@@ -467,11 +471,30 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fill vectors
|
// fill vectors
|
||||||
|
const size_t cap_index = button_caps_list.size();
|
||||||
button_caps_list.emplace_back(button_caps);
|
button_caps_list.emplace_back(button_caps);
|
||||||
button_states.emplace_back(std::vector<bool>(static_cast<unsigned int>(button_count), false));
|
button_states.emplace_back(std::vector<bool>(static_cast<unsigned int>(button_count), false));
|
||||||
button_up.emplace_back(std::vector<double>(static_cast<unsigned int>(button_count), 0.0));
|
button_up.emplace_back(std::vector<double>(static_cast<unsigned int>(button_count), 0.0));
|
||||||
button_down.emplace_back(std::vector<double>(static_cast<unsigned int>(button_count), 0.0));
|
button_down.emplace_back(std::vector<double>(static_cast<unsigned int>(button_count), 0.0));
|
||||||
button_usage_pages[std::make_pair(button_caps.UsagePage, button_caps.LinkCollection)] += button_count;
|
button_report_states.emplace_back(static_cast<size_t>(button_count), 0);
|
||||||
|
|
||||||
|
const auto group_key = std::make_pair(
|
||||||
|
button_caps.UsagePage,
|
||||||
|
static_cast<ULONG>(button_caps.LinkCollection));
|
||||||
|
auto [group_it, inserted] = button_input_group_indices.try_emplace(
|
||||||
|
group_key,
|
||||||
|
button_input_groups.size());
|
||||||
|
if (inserted) {
|
||||||
|
button_input_groups.emplace_back(HIDButtonInputGroup {
|
||||||
|
.usage_page = button_caps.UsagePage,
|
||||||
|
.link_collection = button_caps.LinkCollection,
|
||||||
|
.cap_indices = {},
|
||||||
|
.usages = {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
auto &input_group = button_input_groups[group_it->second];
|
||||||
|
input_group.cap_indices.push_back(cap_index);
|
||||||
|
input_group.usages.resize(input_group.usages.size() + button_count);
|
||||||
|
|
||||||
// names
|
// names
|
||||||
for (USAGE usg = button_caps.Range.UsageMin; usg <= button_caps.Range.UsageMax; usg++) {
|
for (USAGE usg = button_caps.Range.UsageMin; usg <= button_caps.Range.UsageMax; usg++) {
|
||||||
@@ -512,7 +535,7 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
|
|||||||
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
|
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
|
||||||
|
|
||||||
// ignore bad ranges reported by bad devices
|
// ignore bad ranges reported by bad devices
|
||||||
if (button_count >= 0xffff) {
|
if (button_count <= 0 || button_count >= 0xffff) {
|
||||||
log_warning("rawinput", "skipping bad button output cap range for device {}, range [{}, {}]",
|
log_warning("rawinput", "skipping bad button output cap range for device {}, range [{}, {}]",
|
||||||
device_name,
|
device_name,
|
||||||
button_caps.Range.UsageMin,
|
button_caps.Range.UsageMin,
|
||||||
@@ -800,8 +823,18 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
|
|||||||
new_device.hidInfo->button_states = std::move(button_states);
|
new_device.hidInfo->button_states = std::move(button_states);
|
||||||
new_device.hidInfo->button_up = std::move(button_up);
|
new_device.hidInfo->button_up = std::move(button_up);
|
||||||
new_device.hidInfo->button_down = std::move(button_down);
|
new_device.hidInfo->button_down = std::move(button_down);
|
||||||
|
new_device.hidInfo->button_report_states = std::move(button_report_states);
|
||||||
new_device.hidInfo->button_output_states = std::move(button_output_states);
|
new_device.hidInfo->button_output_states = std::move(button_output_states);
|
||||||
new_device.hidInfo->button_usage_pages = std::move(button_usage_pages);
|
new_device.hidInfo->button_input_groups = std::move(button_input_groups);
|
||||||
|
new_device.hidInfo->output_report.resize(caps.OutputReportByteLength);
|
||||||
|
size_t max_button_output_count = 0;
|
||||||
|
for (const auto &button_output_state : new_device.hidInfo->button_output_states) {
|
||||||
|
if (button_output_state.size() > max_button_output_count) {
|
||||||
|
max_button_output_count = button_output_state.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_device.hidInfo->button_output_usages.reserve(max_button_output_count);
|
||||||
|
new_device.hidInfo->button_output_usages_off.reserve(max_button_output_count);
|
||||||
new_device.hidInfo->value_states = std::move(value_states);
|
new_device.hidInfo->value_states = std::move(value_states);
|
||||||
new_device.hidInfo->value_states_raw = std::move(value_states_raw);
|
new_device.hidInfo->value_states_raw = std::move(value_states_raw);
|
||||||
new_device.hidInfo->value_output_states = std::move(value_output_states);
|
new_device.hidInfo->value_output_states = std::move(value_output_states);
|
||||||
@@ -1573,11 +1606,17 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
|
|||||||
if (!data_size) {
|
if (!data_size) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::shared_ptr<RAWINPUT> data((RAWINPUT *) new char[data_size]{});
|
thread_local std::vector<RAWINPUT> data_buffer;
|
||||||
|
const size_t data_count =
|
||||||
|
(data_size + sizeof(RAWINPUT) - 1) / sizeof(RAWINPUT);
|
||||||
|
if (data_buffer.size() < data_count) {
|
||||||
|
data_buffer.resize(data_count);
|
||||||
|
}
|
||||||
|
auto data = data_buffer.data();
|
||||||
if (GetRawInputData(
|
if (GetRawInputData(
|
||||||
(HRAWINPUT) lParam,
|
(HRAWINPUT) lParam,
|
||||||
RID_INPUT,
|
RID_INPUT,
|
||||||
data.get(),
|
data,
|
||||||
&data_size,
|
&data_size,
|
||||||
sizeof(RAWINPUTHEADER)) != data_size) {
|
sizeof(RAWINPUTHEADER)) != data_size) {
|
||||||
break;
|
break;
|
||||||
@@ -1791,17 +1830,13 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
|
|||||||
+ (size_t) hid_report_index * data_hid.dwSizeHid;
|
+ (size_t) hid_report_index * data_hid.dwSizeHid;
|
||||||
|
|
||||||
// parse reports
|
// parse reports
|
||||||
for (const auto &pair : device.hidInfo->button_usage_pages) {
|
for (auto &input_group : device.hidInfo->button_input_groups) {
|
||||||
const auto usage_page = pair.first.first;
|
auto &usages = input_group.usages;
|
||||||
const auto link_collection = pair.first.second;
|
ULONG usages_length = static_cast<ULONG>(usages.size());
|
||||||
const auto button_count = pair.second;
|
|
||||||
|
|
||||||
ULONG usages_length = button_count;
|
|
||||||
std::vector<USAGE> usages(static_cast<size_t>(usages_length));
|
|
||||||
if (HidP_GetUsages(
|
if (HidP_GetUsages(
|
||||||
HidP_Input,
|
HidP_Input,
|
||||||
usage_page,
|
input_group.usage_page,
|
||||||
link_collection,
|
input_group.link_collection,
|
||||||
usages.data(),
|
usages.data(),
|
||||||
&usages_length,
|
&usages_length,
|
||||||
reinterpret_cast<PHIDP_PREPARSED_DATA>(device.hidInfo->preparsed_data.get()),
|
reinterpret_cast<PHIDP_PREPARSED_DATA>(device.hidInfo->preparsed_data.get()),
|
||||||
@@ -1819,29 +1854,22 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
|
|||||||
// log_info(
|
// log_info(
|
||||||
// "rawinput",
|
// "rawinput",
|
||||||
// "processing HID input for device {}, usage page {:x} and link collection {:x} with {} buttons, got {} reports",
|
// "processing HID input for device {}, usage page {:x} and link collection {:x} with {} buttons, got {} reports",
|
||||||
// device.desc,
|
// device.desc, input_group.usage_page,
|
||||||
// usage_page, link_collection, button_count, usages_length);
|
// input_group.link_collection, usages.size(), usages_length);
|
||||||
|
|
||||||
// buttons
|
// buttons
|
||||||
for (size_t cap_num = 0; cap_num < device.hidInfo->button_caps_list.size(); cap_num++) {
|
for (const size_t cap_num : input_group.cap_indices) {
|
||||||
auto &button_caps = device.hidInfo->button_caps_list[cap_num];
|
auto &button_caps = device.hidInfo->button_caps_list[cap_num];
|
||||||
auto &button_states = device.hidInfo->button_states[cap_num];
|
auto &button_states = device.hidInfo->button_states[cap_num];
|
||||||
auto &button_down = device.hidInfo->button_down[cap_num];
|
auto &button_down = device.hidInfo->button_down[cap_num];
|
||||||
auto &button_up = device.hidInfo->button_up[cap_num];
|
auto &button_up = device.hidInfo->button_up[cap_num];
|
||||||
|
auto &new_states = device.hidInfo->button_report_states[cap_num];
|
||||||
// is this the right usage page and link collection?
|
|
||||||
if (button_caps.UsagePage != usage_page || button_caps.LinkCollection != link_collection) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get button count
|
// get button count
|
||||||
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
|
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
|
||||||
if (button_count <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update buttons
|
// update buttons
|
||||||
std::vector<bool> new_states(button_count);
|
std::fill(new_states.begin(), new_states.end(), 0);
|
||||||
for (ULONG usage_num = 0; usage_num < usages_length; usage_num++) {
|
for (ULONG usage_num = 0; usage_num < usages_length; usage_num++) {
|
||||||
if (usages[usage_num] < button_caps.Range.UsageMin ||
|
if (usages[usage_num] < button_caps.Range.UsageMin ||
|
||||||
usages[usage_num] > button_caps.Range.UsageMax) {
|
usages[usage_num] > button_caps.Range.UsageMax) {
|
||||||
@@ -1852,17 +1880,18 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
|
|||||||
|
|
||||||
// guard against some buggy device sending an event for a usage below UsageMin
|
// guard against some buggy device sending an event for a usage below UsageMin
|
||||||
if (usage < button_count) {
|
if (usage < button_count) {
|
||||||
new_states[usage] = true;
|
new_states[usage] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int button_num = 0; button_num < button_count; button_num++) {
|
for (int button_num = 0; button_num < button_count; button_num++) {
|
||||||
if (!new_states[button_num] && button_states[button_num]) {
|
const bool new_state = new_states[button_num] != 0;
|
||||||
|
if (!new_state && button_states[button_num]) {
|
||||||
device.updated = true;
|
device.updated = true;
|
||||||
button_states[button_num] = new_states[button_num];
|
button_states[button_num] = new_state;
|
||||||
button_down[button_num] = input_time;
|
button_down[button_num] = input_time;
|
||||||
} else if (new_states[button_num] && !button_states[button_num]) {
|
} else if (new_state && !button_states[button_num]) {
|
||||||
device.updated = true;
|
device.updated = true;
|
||||||
button_states[button_num] = new_states[button_num];
|
button_states[button_num] = new_state;
|
||||||
button_up[button_num] = input_time;
|
button_up[button_num] = input_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2017,8 +2046,10 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
|
|||||||
switch (hid->driver) {
|
switch (hid->driver) {
|
||||||
case HIDDriver::Default: {
|
case HIDDriver::Default: {
|
||||||
|
|
||||||
// allocate report
|
auto &report_data = hid->output_report;
|
||||||
CHAR *report_data = new CHAR[hid->caps.OutputReportByteLength] {};
|
auto &usage_list = hid->button_output_usages;
|
||||||
|
auto &usage_off_list = hid->button_output_usages_off;
|
||||||
|
std::fill(report_data.begin(), report_data.end(), 0);
|
||||||
|
|
||||||
// set buttons
|
// set buttons
|
||||||
for (size_t cap_no = 0; cap_no < hid->button_output_caps_list.size(); cap_no++) {
|
for (size_t cap_no = 0; cap_no < hid->button_output_caps_list.size(); cap_no++) {
|
||||||
@@ -2026,10 +2057,8 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
|
|||||||
auto &button_state_list = hid->button_output_states[cap_no];
|
auto &button_state_list = hid->button_output_states[cap_no];
|
||||||
|
|
||||||
// determine which buttons to turn on
|
// determine which buttons to turn on
|
||||||
std::vector<USAGE> usage_list;
|
usage_list.clear();
|
||||||
std::vector<USAGE> usage_off_list;
|
usage_off_list.clear();
|
||||||
usage_list.reserve(button_state_list.size());
|
|
||||||
usage_off_list.reserve(button_state_list.size());
|
|
||||||
for (size_t state_no = 0; state_no < button_state_list.size(); state_no++) {
|
for (size_t state_no = 0; state_no < button_state_list.size(); state_no++) {
|
||||||
if (button_state_list[state_no]) {
|
if (button_state_list[state_no]) {
|
||||||
usage_list.push_back(button_cap.Range.UsageMin + (USAGE) state_no);
|
usage_list.push_back(button_cap.Range.UsageMin + (USAGE) state_no);
|
||||||
@@ -2044,15 +2073,18 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
|
|||||||
HidP_Output,
|
HidP_Output,
|
||||||
button_cap.UsagePage,
|
button_cap.UsagePage,
|
||||||
button_cap.LinkCollection,
|
button_cap.LinkCollection,
|
||||||
&usage_list[0],
|
usage_list.data(),
|
||||||
&usage_list_length,
|
&usage_list_length,
|
||||||
reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()),
|
reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()),
|
||||||
report_data,
|
report_data.data(),
|
||||||
hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
|
hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
|
||||||
|
|
||||||
// flush report
|
// flush report
|
||||||
HidD_SetOutputReport(hid->handle, report_data, hid->caps.OutputReportByteLength);
|
HidD_SetOutputReport(
|
||||||
memset(report_data, 0, hid->caps.OutputReportByteLength);
|
hid->handle,
|
||||||
|
report_data.data(),
|
||||||
|
hid->caps.OutputReportByteLength);
|
||||||
|
std::fill(report_data.begin(), report_data.end(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the buttons
|
// clear the buttons
|
||||||
@@ -2061,22 +2093,22 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
|
|||||||
HidP_Output,
|
HidP_Output,
|
||||||
button_cap.UsagePage,
|
button_cap.UsagePage,
|
||||||
button_cap.LinkCollection,
|
button_cap.LinkCollection,
|
||||||
&usage_off_list[0],
|
usage_off_list.data(),
|
||||||
&usage_off_list_length,
|
&usage_off_list_length,
|
||||||
reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()),
|
reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()),
|
||||||
report_data,
|
report_data.data(),
|
||||||
hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
|
hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
|
||||||
|
|
||||||
// flush report
|
// flush report
|
||||||
DWORD written_bytes = 0;
|
DWORD written_bytes = 0;
|
||||||
WriteFile(
|
WriteFile(
|
||||||
hid->handle,
|
hid->handle,
|
||||||
reinterpret_cast<void *>(report_data),
|
report_data.data(),
|
||||||
hid->caps.OutputReportByteLength,
|
hid->caps.OutputReportByteLength,
|
||||||
&written_bytes,
|
&written_bytes,
|
||||||
nullptr
|
nullptr
|
||||||
);
|
);
|
||||||
memset(report_data, 0, hid->caps.OutputReportByteLength);
|
std::fill(report_data.begin(), report_data.end(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2105,19 +2137,19 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
|
|||||||
value_cap.NotRange.Usage,
|
value_cap.NotRange.Usage,
|
||||||
static_cast<ULONG>(usage_value),
|
static_cast<ULONG>(usage_value),
|
||||||
reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()),
|
reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()),
|
||||||
report_data,
|
report_data.data(),
|
||||||
hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
|
hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
|
||||||
|
|
||||||
// flush report
|
// flush report
|
||||||
DWORD written_bytes = 0;
|
DWORD written_bytes = 0;
|
||||||
WriteFile(
|
WriteFile(
|
||||||
hid->handle,
|
hid->handle,
|
||||||
reinterpret_cast<void *>(report_data),
|
report_data.data(),
|
||||||
hid->caps.OutputReportByteLength,
|
hid->caps.OutputReportByteLength,
|
||||||
&written_bytes,
|
&written_bytes,
|
||||||
nullptr
|
nullptr
|
||||||
);
|
);
|
||||||
memset(report_data, 0, hid->caps.OutputReportByteLength);
|
std::fill(report_data.begin(), report_data.end(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2151,15 +2183,12 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
|
|||||||
DWORD written_bytes = 0;
|
DWORD written_bytes = 0;
|
||||||
WriteFile(
|
WriteFile(
|
||||||
hid->handle,
|
hid->handle,
|
||||||
reinterpret_cast<void *>(report_data),
|
report_data.data(),
|
||||||
hid->caps.OutputReportByteLength,
|
hid->caps.OutputReportByteLength,
|
||||||
&written_bytes,
|
&written_bytes,
|
||||||
nullptr
|
nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
// delete report
|
|
||||||
delete[] report_data;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HIDDriver::PacDrive: {
|
case HIDDriver::PacDrive: {
|
||||||
|
|||||||
@@ -319,7 +319,8 @@ namespace rawinput::touch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// iterate all input data and get touch points
|
// iterate all input data and get touch points
|
||||||
std::vector<HIDTouchPoint> touch_points;
|
thread_local std::vector<HIDTouchPoint> touch_points;
|
||||||
|
touch_points.clear();
|
||||||
touch_points.reserve(touch.elements_x.size());
|
touch_points.reserve(touch.elements_x.size());
|
||||||
for (size_t i = 0; i < touch.elements_x.size(); i++) {
|
for (size_t i = 0; i < touch.elements_x.size(); i++) {
|
||||||
|
|
||||||
@@ -424,9 +425,15 @@ namespace rawinput::touch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// process touch points
|
// process touch points
|
||||||
std::vector<DWORD> touch_removes;
|
thread_local std::vector<DWORD> touch_removes;
|
||||||
std::vector<TouchPoint> touch_writes;
|
thread_local std::vector<TouchPoint> touch_writes;
|
||||||
std::vector<DWORD> touch_modifications;
|
thread_local std::vector<DWORD> touch_modifications;
|
||||||
|
touch_removes.clear();
|
||||||
|
touch_writes.clear();
|
||||||
|
touch_modifications.clear();
|
||||||
|
touch_removes.reserve(touch.touch_points.size() + touch_points.size());
|
||||||
|
touch_writes.reserve(touch_points.size());
|
||||||
|
touch_modifications.reserve(touch_points.size());
|
||||||
|
|
||||||
// drop every touch point with the given id (marking it as released)
|
// drop every touch point with the given id (marking it as released)
|
||||||
auto remove_touch_point = [&] (DWORD id) {
|
auto remove_touch_point = [&] (DWORD id) {
|
||||||
@@ -581,7 +588,9 @@ namespace rawinput::touch {
|
|||||||
auto deadline = get_system_milliseconds() - 50;
|
auto deadline = get_system_milliseconds() - 50;
|
||||||
|
|
||||||
// check touch points
|
// check touch points
|
||||||
std::vector<DWORD> touch_removes;
|
thread_local std::vector<DWORD> touch_removes;
|
||||||
|
touch_removes.clear();
|
||||||
|
touch_removes.reserve(touch.touch_points.size());
|
||||||
auto touch_it = touch.touch_points.begin();
|
auto touch_it = touch.touch_points.begin();
|
||||||
while (touch_it != touch.touch_points.end()) {
|
while (touch_it != touch.touch_points.end()) {
|
||||||
auto &hid_tp = *touch_it;
|
auto &hid_tp = *touch_it;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#include "reader.h"
|
#include "reader.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <cstring>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
#include "util/precise_timer.h"
|
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
#include "structuredmessage.h"
|
#include "structuredmessage.h"
|
||||||
|
|
||||||
@@ -218,8 +218,6 @@ bool Reader::set_comm_state(DWORD BaudRate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Reader::wait_for_handshake() {
|
bool Reader::wait_for_handshake() {
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
|
|
||||||
// baud rates
|
// baud rates
|
||||||
DWORD baud_rates[] = { CBR_57600, CBR_38400, CBR_19200, CBR_9600 };
|
DWORD baud_rates[] = { CBR_57600, CBR_38400, CBR_19200, CBR_9600 };
|
||||||
|
|
||||||
@@ -270,7 +268,7 @@ bool Reader::wait_for_handshake() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sleep
|
// sleep
|
||||||
timer.sleep(50);
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
}
|
}
|
||||||
|
|
||||||
log_warning("reader", "{}: no handshake received for {} baud", this->port, baud_rates[i]);
|
log_warning("reader", "{}: no handshake received for {} baud", this->port, baud_rates[i]);
|
||||||
@@ -407,7 +405,6 @@ void start_reader_thread(const std::string &port, int id) {
|
|||||||
READER_THREAD_RUNNING = true;
|
READER_THREAD_RUNNING = true;
|
||||||
READER_THREADS.push_back(new std::thread([port, id]() {
|
READER_THREADS.push_back(new std::thread([port, id]() {
|
||||||
log_info("reader", "{}: starting reader thread", port);
|
log_info("reader", "{}: starting reader thread", port);
|
||||||
timeutils::PreciseSleepTimer timer;
|
|
||||||
|
|
||||||
while (READER_THREAD_RUNNING) {
|
while (READER_THREAD_RUNNING) {
|
||||||
|
|
||||||
@@ -445,22 +442,21 @@ void start_reader_thread(const std::string &port, int id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (did_read_card) {
|
if (did_read_card) {
|
||||||
timer.sleep(2500);
|
std::this_thread::sleep_for(std::chrono::milliseconds(2500));
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.sleep(20);
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sleep between reader connection retries
|
// sleep between reader connection retries
|
||||||
if (READER_THREAD_RUNNING)
|
if (READER_THREAD_RUNNING)
|
||||||
timer.sleep(5000);
|
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// wait for thread to start
|
// wait for thread to start
|
||||||
timeutils::PreciseSleepTimer timer;
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
timer.sleep(10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop_reader_thread() {
|
void stop_reader_thread() {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace nativetouch::inject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
POINT transformed = *position;
|
POINT transformed = *position;
|
||||||
return transform::screen_to_game(window, &transformed);
|
return transform::mouse_to_game(window, &transformed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// release the active injected contact and its window capture
|
// release the active injected contact and its window capture
|
||||||
@@ -108,7 +108,7 @@ namespace nativetouch::inject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
POINT transformed = position;
|
POINT transformed = position;
|
||||||
if (!transform::screen_to_game(window, &transformed)) {
|
if (!transform::mouse_to_game(window, &transformed)) {
|
||||||
end_mouse_contact(window);
|
end_mouse_contact(window);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace nativetouch::transform {
|
|||||||
static bool has_active_overlay_transform() {
|
static bool has_active_overlay_transform() {
|
||||||
return overlay::OVERLAY != nullptr &&
|
return overlay::OVERLAY != nullptr &&
|
||||||
overlay::OVERLAY->get_active() &&
|
overlay::OVERLAY->get_active() &&
|
||||||
overlay::OVERLAY->can_transform_touch_input();
|
overlay::OVERLAY->has_subscreen_touch_transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool transform_overlay_touch_position(POINT *position) {
|
static bool transform_overlay_touch_position(POINT *position) {
|
||||||
@@ -120,6 +120,25 @@ namespace nativetouch::transform {
|
|||||||
return transform_overlay_touch_position(position);
|
return transform_overlay_touch_position(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mouse_to_game(HWND window, POINT *position) {
|
||||||
|
|
||||||
|
// exception: iidx tdj dedicated subscreen window is allowed
|
||||||
|
if (is_tdj_dedicated_subscreen(window)) {
|
||||||
|
return screen_to_game(window, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this game has a subscreen overlay that can transform touch input
|
||||||
|
// but the window is hidden or not under the cursor, reject mouse-as-touch
|
||||||
|
// (e.g., iidx/sdvx are rejected here, but nostalgia is allowed)
|
||||||
|
if (overlay::OVERLAY != nullptr &&
|
||||||
|
overlay::OVERLAY->has_subscreen_touch_transform() &&
|
||||||
|
!overlay::OVERLAY->accepts_subscreen_mouse_input()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return screen_to_game(window, position);
|
||||||
|
}
|
||||||
|
|
||||||
// route hardware screen coordinates through dedicated or overlay mapping and report the result
|
// route hardware screen coordinates through dedicated or overlay mapping and report the result
|
||||||
Result hardware_to_game(POINT *position) {
|
Result hardware_to_game(POINT *position) {
|
||||||
const auto dedicated_subscreen = is_tdj_dedicated_subscreen(TDJ_SUBSCREEN_WINDOW);
|
const auto dedicated_subscreen = is_tdj_dedicated_subscreen(TDJ_SUBSCREEN_WINDOW);
|
||||||
|
|||||||
@@ -12,5 +12,6 @@ namespace nativetouch::transform {
|
|||||||
bool is_tdj_dedicated_subscreen(HWND window);
|
bool is_tdj_dedicated_subscreen(HWND window);
|
||||||
bool game_to_screen(HWND window, POINT *position);
|
bool game_to_screen(HWND window, POINT *position);
|
||||||
bool screen_to_game(HWND window, POINT *position);
|
bool screen_to_game(HWND window, POINT *position);
|
||||||
|
bool mouse_to_game(HWND window, POINT *position);
|
||||||
Result hardware_to_game(POINT *position);
|
Result hardware_to_game(POINT *position);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -944,7 +944,7 @@ void touch_get_points(std::vector<TouchPoint> &touch_points, bool overlay) {
|
|||||||
if (!overlay &&
|
if (!overlay &&
|
||||||
overlay::OVERLAY &&
|
overlay::OVERLAY &&
|
||||||
overlay::OVERLAY->get_active() &&
|
overlay::OVERLAY->get_active() &&
|
||||||
!overlay::OVERLAY->can_transform_touch_input() &&
|
!overlay::OVERLAY->has_subscreen_touch_transform() &&
|
||||||
ImGui::GetIO().WantCaptureMouse) {
|
ImGui::GetIO().WantCaptureMouse) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -971,7 +971,7 @@ void touch_get_events(std::vector<TouchEvent> &touch_events, bool overlay) {
|
|||||||
if (!overlay &&
|
if (!overlay &&
|
||||||
overlay::OVERLAY &&
|
overlay::OVERLAY &&
|
||||||
overlay::OVERLAY->get_active() &&
|
overlay::OVERLAY->get_active() &&
|
||||||
!overlay::OVERLAY->can_transform_touch_input() &&
|
!overlay::OVERLAY->has_subscreen_touch_transform() &&
|
||||||
ImGui::GetIO().WantCaptureMouse) {
|
ImGui::GetIO().WantCaptureMouse) {
|
||||||
|
|
||||||
TOUCH_EVENTS.reset();
|
TOUCH_EVENTS.reset();
|
||||||
|
|||||||
Reference in New Issue
Block a user