Grand validation:
Ajouté interface pour plusiers APIs de tablette. Essayé d'ajouter .NET interop Changé storage des champs Nouveau functions pour afficher du texte
This commit is contained in:
parent
422ec60f3b
commit
b2eeb12fc3
|
@ -1,4 +1,20 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
#include(CMakePrintHelpers)
|
||||
|
||||
|
||||
# Runtime checks are not compatiable
|
||||
#string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
#string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
#string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
#string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
||||
#cmake_print_variables(CMAKE_C_FLAGS)
|
||||
#cmake_print_variables(CMAKE_C_FLAGS_DEBUG)
|
||||
|
||||
# Exception handling should use C++ standard stack unwinding
|
||||
#string(REGEX REPLACE "/EHs" "/EHa" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
#string(REGEX REPLACE "/EHs" "/EHa" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
project(yaw-audio)
|
||||
add_subdirectory("lib")
|
||||
add_subdirectory("src")
|
|
@ -12,5 +12,11 @@ target_include_directories(yaw-tab PUBLIC
|
|||
"."
|
||||
"../../lib/wintab"
|
||||
)
|
||||
target_compile_definitions(yaw-tab PUBLIC YAW_USE_WINTAB)
|
||||
|
||||
set_target_properties(yaw-tab PROPERTIES VS_DOTNET_REFERENCES "System")
|
||||
set_target_properties(yaw-tab PROPERTIES COMPILE_FLAGS "/clr")
|
||||
set_target_properties(yaw-tab PROPERTIES COMPILE_FLAGS "/Zc:twoPhase-")
|
||||
|
||||
# default compiler flags from CMAKE conflict with managed code compliation, probably a better way of doing this.
|
||||
|
||||
target_compile_definitions(yaw-tab PUBLIC YAW_USE_WINTAB=1 YAW_USE_RTSTYLUS=1)
|
|
@ -19,11 +19,11 @@
|
|||
#endif
|
||||
|
||||
enum Parameters {
|
||||
kParameterTabletX = 0,
|
||||
kParameterTabletY,
|
||||
kParameterTabletZ,
|
||||
kParameterTabletPressure,
|
||||
kParameterTabletButtons,
|
||||
ktpax = 0,
|
||||
ktpay,
|
||||
ktpaz,
|
||||
ktpap,
|
||||
ktpab,
|
||||
kParameterTime,
|
||||
kParameterCount
|
||||
};
|
||||
|
|
|
@ -33,23 +33,23 @@ protected:
|
|||
|
||||
switch (index)
|
||||
{
|
||||
case kParameterTabletX:
|
||||
case ktpax:
|
||||
parameter.name = "x";
|
||||
parameter.symbol = "x";
|
||||
break;
|
||||
case kParameterTabletY:
|
||||
case ktpay:
|
||||
parameter.name = "y";
|
||||
parameter.symbol = "y";
|
||||
break;
|
||||
case kParameterTabletZ:
|
||||
case ktpaz:
|
||||
parameter.name = "z";
|
||||
parameter.symbol = "z";
|
||||
break;
|
||||
case kParameterTabletPressure:
|
||||
case ktpap:
|
||||
parameter.name = "p";
|
||||
parameter.symbol = "p";
|
||||
break;
|
||||
case kParameterTabletButtons:
|
||||
case ktpab:
|
||||
parameter.name = "Buttons";
|
||||
parameter.symbol = "b";
|
||||
parameter.hints = kParameterIsAutomable | kParameterIsInteger;
|
||||
|
@ -78,17 +78,17 @@ protected:
|
|||
{
|
||||
fParameters[idx] = val;
|
||||
switch (idx) {
|
||||
case kParameterTabletX:
|
||||
case ktpax:
|
||||
period = 0.02f * val * static_cast<float>(sampleRate);
|
||||
break;
|
||||
case kParameterTabletY:
|
||||
case ktpay:
|
||||
break;
|
||||
case kParameterTabletZ:
|
||||
case ktpaz:
|
||||
break;
|
||||
case kParameterTabletPressure:
|
||||
case ktpap:
|
||||
volume = val;
|
||||
break;
|
||||
case kParameterTabletButtons:
|
||||
case ktpab:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#ifdef YAW_USE_OTD
|
||||
// text_write.cpp
|
||||
// compile with: /clr
|
||||
using namespace System;
|
||||
using namespace System::IO;
|
||||
|
||||
int func()
|
||||
{
|
||||
String^ fileName = "textfile.txt";
|
||||
|
||||
StreamWriter^ sw = gcnew StreamWriter(fileName);
|
||||
sw->WriteLine("A text file is born!");
|
||||
sw->Write("You can use WriteLine");
|
||||
sw->WriteLine("...or just Write");
|
||||
sw->WriteLine("and do {0} output too.", "formatted");
|
||||
sw->WriteLine("You can also send non-text objects:");
|
||||
sw->WriteLine(DateTime::Now);
|
||||
sw->Close();
|
||||
Console::WriteLine("a new file ('{0}') has been written", fileName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
//Interface to supported tablet APIs.
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#ifdef YAW_USE_WINTAB
|
||||
#include <Windows.h>
|
||||
#include "MSGPACK.H"
|
||||
#include "wintab.h"
|
||||
#endif
|
||||
|
||||
|
||||
struct Packet {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float p;
|
||||
unsigned long buttons;
|
||||
bool operator==(const Packet& p)
|
||||
{ return
|
||||
this->x == p.x &&
|
||||
this->y == p.y &&
|
||||
this->z == p.z &&
|
||||
this->p == p.p &&
|
||||
this->buttons == p.buttons;
|
||||
};
|
||||
bool operator!=(const Packet& p) { return !(*this == p); }
|
||||
};
|
||||
|
||||
class Tablet {
|
||||
public:
|
||||
Tablet(uintptr_t handle);
|
||||
~Tablet();
|
||||
bool GetPacket( Packet &pkt );
|
||||
bool initialized;
|
||||
std::string errormsg = "";
|
||||
|
||||
private:
|
||||
|
||||
Packet ext = { 0 };
|
||||
|
||||
#ifdef YAW_USE_WINTAB
|
||||
void NewContext(HWND hwnd);
|
||||
HCTX hctx = NULL;
|
||||
#endif
|
||||
};
|
|
@ -1,10 +1,6 @@
|
|||
#include "DistrhoUI.hpp"
|
||||
#ifdef YAW_USE_WINTAB
|
||||
#include "wintab.cpp"
|
||||
#endif
|
||||
#ifdef YAW_USE_RTSTYLUS
|
||||
#include "rtstylus.cpp"
|
||||
#endif
|
||||
#include "tablet.h"
|
||||
#include <format>
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
|
@ -18,12 +14,8 @@ public:
|
|||
: UI(kInitialWidth, kInitialHeight),
|
||||
fSampleRate(getSampleRate()),
|
||||
fResizable(isResizable()),
|
||||
fScale(1.0f),
|
||||
fScaleFactor(getScaleFactor()),
|
||||
tab(reinterpret_cast<HWND>(getWindow().getNativeWindowHandle()))
|
||||
tab(getWindow().getNativeWindowHandle())
|
||||
{
|
||||
std::memset(fParameters, 0, sizeof(float) * kParameterCount);
|
||||
std::memset(fStrBuf, 0, sizeof(char) * (0xff + 1));
|
||||
|
||||
#ifdef DGL_NO_SHARED_RESOURCES
|
||||
createFontFromFile("sans", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
|
||||
|
@ -38,42 +30,32 @@ protected:
|
|||
|
||||
void getTabletData()
|
||||
{
|
||||
//Lire donnés de la tablet
|
||||
tab.NewPacket();
|
||||
|
||||
float x = static_cast<float>(tab.pkt.pkX) / tab.extX;
|
||||
float y = static_cast<float>(tab.pkt.pkY) / tab.extY;
|
||||
float z = static_cast<float>(tab.pkt.pkZ) / tab.extZ;
|
||||
float p = static_cast<float>(tab.pkt.pkNormalPressure) / tab.extP;
|
||||
|
||||
if (x != fParameters[kParameterTabletX]) {
|
||||
setParameterValue(kParameterTabletX, x);
|
||||
fParameters[kParameterTabletX] = x;
|
||||
}
|
||||
if (y != fParameters[kParameterTabletY]) {
|
||||
setParameterValue(kParameterTabletY, y);
|
||||
fParameters[kParameterTabletY] = y;
|
||||
}
|
||||
if (z != fParameters[kParameterTabletZ]) {
|
||||
setParameterValue(kParameterTabletZ, z);
|
||||
fParameters[kParameterTabletZ] = z;
|
||||
}
|
||||
if (p != fParameters[kParameterTabletPressure]) {
|
||||
setParameterValue(kParameterTabletPressure, p);
|
||||
fParameters[kParameterTabletPressure] = p;
|
||||
}
|
||||
if (!tab.initialized || !tab.GetPacket(pkt)) return;
|
||||
if (pkt == lastPkt) return;
|
||||
if (pkt.x != lastPkt.x) setParameterValue(ktpax, pkt.x);
|
||||
if (pkt.y != lastPkt.y) setParameterValue(ktpay, pkt.y);
|
||||
if (pkt.z != lastPkt.z) setParameterValue(ktpaz, pkt.z);
|
||||
if (pkt.p != lastPkt.p) setParameterValue(ktpap, pkt.p);
|
||||
if (pkt.buttons != lastPkt.buttons) setParameterValue(ktpab, pkt.buttons);
|
||||
lastPkt = pkt;
|
||||
}
|
||||
|
||||
void parameterChanged(uint32_t index, float value) override
|
||||
{
|
||||
|
||||
if (index != kParameterTime) {
|
||||
fParameters[index] = value;
|
||||
if (index != kParameterTime && index < kParameterCount) {
|
||||
switch (index)
|
||||
{
|
||||
case(ktpax): pkt.x = value;
|
||||
case(ktpay): pkt.y = value;
|
||||
case(ktpaz): pkt.z = value;
|
||||
case(ktpap): pkt.p = value;
|
||||
case(ktpab): pkt.buttons = static_cast<unsigned long>(value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
getTabletData();
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
@ -100,44 +82,30 @@ protected:
|
|||
|
||||
void onNanoDisplay() override
|
||||
{
|
||||
drawCircle(
|
||||
fParameters[kParameterTabletX],
|
||||
fParameters[kParameterTabletY],
|
||||
fParameters[kParameterTabletZ],
|
||||
fParameters[kParameterTabletPressure]
|
||||
);
|
||||
fontSize(15.0f);
|
||||
textLineHeight(1.f);
|
||||
|
||||
const float lineHeight = 20 * fScale;
|
||||
|
||||
fontSize(15.0f * fScale);
|
||||
textLineHeight(lineHeight);
|
||||
|
||||
|
||||
|
||||
float x = 0.0f * fScale;
|
||||
float y = 15.0f * fScale;
|
||||
|
||||
if (!tab.wintabAvailable) {
|
||||
drawLeft(x, y, "Failed to connect to tablet.");
|
||||
//Report tablet errors.
|
||||
if (!tab.initialized) {
|
||||
const std::string err = std::vformat("Tablet not supported:\n{}",
|
||||
std::make_format_args(tab.errormsg));
|
||||
beginPath();
|
||||
fillColor(200, 200, 200);
|
||||
// textBox(0.f, 15.f, 250.f, err.c_str(), nullptr);
|
||||
closePath();
|
||||
return;
|
||||
}
|
||||
|
||||
drawLeft(x, y, "x:");
|
||||
drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletX]));
|
||||
y += lineHeight;
|
||||
|
||||
drawLeft(x, y, "y:");
|
||||
drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletY]));
|
||||
y += lineHeight;
|
||||
|
||||
drawLeft(x, y, "z:");
|
||||
drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletZ]));
|
||||
y += lineHeight;
|
||||
|
||||
drawLeft(x, y, "p:");
|
||||
drawRight(x, y, getTextBufFloat(fParameters[kParameterTabletPressure]));
|
||||
y += lineHeight;
|
||||
//Numerical feedback.
|
||||
beginPath();
|
||||
fillColor(200, 200, 200);
|
||||
textBox(0.f, 15.f, 250.f,
|
||||
std::format("x: {:.3f}\ny: {:.3f}\nz: {:.3f}\np: {:.3f}\nb: {}",
|
||||
pkt.x, pkt.y, pkt.z, pkt.p, pkt.buttons).c_str(), nullptr);
|
||||
closePath();
|
||||
|
||||
//Pen position and pressure.
|
||||
drawCircle(pkt.x, pkt.y, pkt.z, pkt.p);
|
||||
}
|
||||
|
||||
void drawCircle(float x, float y, float z, float p) {
|
||||
|
@ -156,8 +124,8 @@ protected:
|
|||
|
||||
beginPath();
|
||||
strokeColor(1.f, 1.f, 1.f, 0.5f);
|
||||
moveTo(x , y - z * circleRadius);
|
||||
lineTo(x , y + z * circleRadius);
|
||||
moveTo(x, y - z * circleRadius);
|
||||
lineTo(x, y + z * circleRadius);
|
||||
stroke();
|
||||
closePath();
|
||||
|
||||
|
@ -192,7 +160,6 @@ protected:
|
|||
|
||||
private:
|
||||
// Parameters
|
||||
float fParameters[kParameterCount];
|
||||
double fSampleRate;
|
||||
|
||||
// UI stuff
|
||||
|
@ -202,61 +169,9 @@ private:
|
|||
|
||||
// Tablet context handler
|
||||
Tablet tab;
|
||||
Packet pkt = { 0 };
|
||||
Packet lastPkt = { 0 };
|
||||
|
||||
// temp buf for text
|
||||
char fStrBuf[0xff + 1];
|
||||
|
||||
// helpers for putting text into fStrBuf and returning it
|
||||
const char* getTextBufInt(const int value)
|
||||
{
|
||||
std::snprintf(fStrBuf, 0xff, "%i", value);
|
||||
return fStrBuf;
|
||||
}
|
||||
|
||||
const char* getTextBufFloat(const float value)
|
||||
{
|
||||
std::snprintf(fStrBuf, 0xff, "%.1f", value);
|
||||
return fStrBuf;
|
||||
}
|
||||
|
||||
const char* getTextBufFloatExtra(const float value)
|
||||
{
|
||||
std::snprintf(fStrBuf, 0xff, "%.2f", value + 0.001f);
|
||||
return fStrBuf;
|
||||
}
|
||||
|
||||
const char* getTextBufTime(const uint64_t frame)
|
||||
{
|
||||
const uint32_t time = frame / uint64_t(fSampleRate);
|
||||
const uint32_t secs = time % 60;
|
||||
const uint32_t mins = (time / 60) % 60;
|
||||
const uint32_t hrs = (time / 3600) % 60;
|
||||
std::snprintf(fStrBuf, 0xff, "%02i:%02i:%02i", hrs, mins, secs);
|
||||
return fStrBuf;
|
||||
}
|
||||
|
||||
// helpers for drawing text
|
||||
void drawLeft(float x, const float y, const char* const text, const int offset = 0)
|
||||
{
|
||||
const float width = (100.0f + offset) * fScale;
|
||||
x += offset * fScale;
|
||||
beginPath();
|
||||
fillColor(200, 200, 200);
|
||||
textAlign(ALIGN_RIGHT | ALIGN_TOP);
|
||||
textBox(x, y, width, text);
|
||||
closePath();
|
||||
}
|
||||
|
||||
void drawRight(float x, const float y, const char* const text, const int offset = 0)
|
||||
{
|
||||
const float width = (100.0f + offset) * fScale;
|
||||
x += offset * fScale;
|
||||
beginPath();
|
||||
fillColor(255, 255, 255);
|
||||
textAlign(ALIGN_LEFT | ALIGN_TOP);
|
||||
textBox(x + (105 * fScale), y, width, text);
|
||||
closePath();
|
||||
}
|
||||
|
||||
/**
|
||||
Set our UI class as non-copyable and add a leak detector just in case.
|
||||
|
|
|
@ -1,104 +1,81 @@
|
|||
#include <string>
|
||||
#include <Windows.h>
|
||||
#include "MSGPACK.H"
|
||||
#include "wintab.h"
|
||||
|
||||
#ifdef YAW_USE_WINTAB
|
||||
#include "tablet.h"
|
||||
#define PACKETDATA (PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE)
|
||||
#define PACKETMODE PK_BUTTONS
|
||||
//#define PACKETMODE
|
||||
#include "pktdef.h"
|
||||
#include "wtutil.h"
|
||||
|
||||
class Tablet {
|
||||
public:
|
||||
Tablet::Tablet(uintptr_t handle)
|
||||
{
|
||||
HWND hwnd = reinterpret_cast<HWND>(handle);
|
||||
if (!hwnd) { return; }
|
||||
|
||||
Tablet(HWND hwnd) {
|
||||
if (!hwnd) { return; }
|
||||
|
||||
if (!LoadWintab() || !gpWTInfoA(0, 0, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NewContext(hwnd);
|
||||
if (!LoadWintab() || !gpWTInfoA(0, 0, NULL)) {
|
||||
errormsg = "Wintab not installed.";
|
||||
return;
|
||||
}
|
||||
|
||||
~Tablet() {
|
||||
if (hctx) { gpWTClose(hctx); }
|
||||
UnloadWintab();
|
||||
NewContext(hwnd);
|
||||
}
|
||||
|
||||
Tablet::~Tablet() {
|
||||
if (hctx) { gpWTClose(hctx); }
|
||||
UnloadWintab();
|
||||
}
|
||||
|
||||
bool Tablet::GetPacket( Packet& packet ) {
|
||||
//Serial number of newest packet.
|
||||
UINT oldest, newest;
|
||||
//This function returns false when it fails
|
||||
//which may happen with a full or empty queue.
|
||||
if (!gpWTQueuePacketsEx(hctx, &oldest, &newest)) {
|
||||
//Queue may be full, flush it all just in case.
|
||||
gpWTPacketsGet(hctx, gpWTQueueSizeGet(hctx), nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NewPacket() {
|
||||
//Serial number of newest packet.
|
||||
UINT oldest, newest;
|
||||
//This function returns false when it fails
|
||||
//which may happen with a full or empty queue.
|
||||
if (!gpWTQueuePacketsEx(hctx, &oldest, &newest)) {
|
||||
//Queue may be full, flush it all just in case.
|
||||
gpWTPacketsGet(hctx, gpWTQueueSizeGet(hctx), nullptr);
|
||||
return false;
|
||||
}
|
||||
//Store newest packet in pkt, flush older packets.
|
||||
PACKET pkt;
|
||||
bool newData = gpWTPacket(hctx, newest, &pkt);
|
||||
if (!newData) return false;
|
||||
packet.x = static_cast<float>(pkt.pkX) / ext.x;
|
||||
packet.y = static_cast<float>(pkt.pkY) / ext.y;
|
||||
packet.z = static_cast<float>(pkt.pkZ) / ext.z;
|
||||
packet.p = static_cast<float>(pkt.pkNormalPressure) / ext.p;
|
||||
packet.buttons = pkt.pkButtons;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Store newest packet in pkt, flush older packets.
|
||||
return gpWTPacket(hctx, newest, &pkt);
|
||||
}
|
||||
|
||||
bool wintabAvailable = false;
|
||||
PACKET pkt = { 0 };
|
||||
UINT maxPressure = 1;
|
||||
float extX;
|
||||
float extY;
|
||||
float extZ;
|
||||
float extP;
|
||||
|
||||
private:
|
||||
|
||||
HCTX hctx = NULL;
|
||||
UINT wDevice = 0;
|
||||
void Tablet::NewContext(HWND hwnd) {
|
||||
if (hctx) { gpWTClose(hctx); }
|
||||
LOGCONTEXT ctx = {};
|
||||
AXIS TabletX = { 0 };
|
||||
AXIS TabletY = { 0 };
|
||||
AXIS TabletZ = { 0 };
|
||||
AXIS TabletPressure = { 0 };
|
||||
LOGCONTEXT ctx = {};
|
||||
gpWTInfoA(WTI_DEFCONTEXT, 0, &ctx);
|
||||
ctx.lcOptions |= CXO_MESSAGES; //TODO: checker çela
|
||||
ctx.lcPktData = PACKETDATA;
|
||||
ctx.lcPktMode = 0;
|
||||
|
||||
void NewContext(HWND hwnd) {
|
||||
if (hctx) { gpWTClose(hctx); }
|
||||
gpWTInfoA(WTI_DEFCONTEXT, 0, &ctx);
|
||||
ctx.lcOptions |= CXO_MESSAGES; //TODO: checker çela
|
||||
ctx.lcPktData = PACKETDATA;
|
||||
ctx.lcPktMode = PACKETMODE;
|
||||
//Tablet extents.
|
||||
gpWTInfoA(WTI_DEVICES, DVC_X, &TabletX);
|
||||
gpWTInfoA(WTI_DEVICES, DVC_Y, &TabletY);
|
||||
gpWTInfoA(WTI_DEVICES, DVC_Z, &TabletZ);
|
||||
gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &TabletPressure);
|
||||
|
||||
//Tablet extents.
|
||||
gpWTInfoA(WTI_DEVICES, DVC_X, &TabletX);
|
||||
gpWTInfoA(WTI_DEVICES, DVC_Y, &TabletY);
|
||||
gpWTInfoA(WTI_DEVICES, DVC_Z, &TabletZ);
|
||||
gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &TabletPressure);
|
||||
ext.x = static_cast<float>(TabletX.axMax);
|
||||
ext.y = static_cast<float>(TabletY.axMax);
|
||||
ext.z = static_cast<float>(TabletZ.axMax);
|
||||
ext.p = static_cast<float>(TabletPressure.axMax);
|
||||
|
||||
ctx.lcInOrgX = TabletX.axMin;
|
||||
ctx.lcInExtX = TabletX.axMax;
|
||||
ctx.lcOutOrgX = TabletX.axMin;
|
||||
ctx.lcOutExtX = TabletX.axMax;
|
||||
extX = static_cast<float>(TabletX.axMax);
|
||||
hctx = gpWTOpenA(hwnd, &ctx, TRUE);
|
||||
|
||||
ctx.lcInOrgY = TabletY.axMin;
|
||||
ctx.lcInExtY = TabletY.axMax;
|
||||
ctx.lcOutOrgY = TabletY.axMin;
|
||||
ctx.lcOutExtY = TabletY.axMax;
|
||||
extY = static_cast<float>(TabletY.axMax);
|
||||
|
||||
ctx.lcInOrgZ = TabletZ.axMin;
|
||||
ctx.lcInExtZ = TabletZ.axMax;
|
||||
ctx.lcOutOrgZ = TabletZ.axMin;
|
||||
ctx.lcOutExtZ = TabletZ.axMax;
|
||||
extZ = static_cast<float>(TabletZ.axMax);
|
||||
|
||||
extP = static_cast<float>(TabletPressure.axMax);
|
||||
|
||||
hctx = gpWTOpenA(hwnd, &ctx, FALSE);
|
||||
|
||||
if (!hctx) { return; }
|
||||
|
||||
gpWTEnable(hctx, TRUE);
|
||||
wintabAvailable = true;
|
||||
if (!hctx)
|
||||
{
|
||||
errormsg = "Could not open Wintab context.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
initialized = true;
|
||||
};
|
||||
#endif
|
Loading…
Reference in New Issue