step to REST api
This commit is contained in:
parent
07ee1df44e
commit
500b12f756
|
@ -5,26 +5,54 @@
|
||||||
|
|
||||||
class ClientAPI : public RestClient {
|
class ClientAPI : public RestClient {
|
||||||
public:
|
public:
|
||||||
enum class SearchState : uint32_t {
|
enum class ReadyCheckState : uint32_t {
|
||||||
INVALID = 0,
|
INVALID = 0,
|
||||||
SEARCHING,
|
NONE,
|
||||||
FOUND,
|
INPROGRESS,
|
||||||
|
Accepted,
|
||||||
ABANDONEDLOWPRIORITYQUEUE,
|
DECLINED
|
||||||
CANCELED,
|
|
||||||
ERROR,
|
|
||||||
SERVICEERROR,
|
|
||||||
SERVICESHUTDOWN,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GameflowPhase : uint32_t {
|
||||||
|
NONE = 0,
|
||||||
|
LOBBY,
|
||||||
|
MATCHMAKING,
|
||||||
|
CHECKEDINTOTOURNAMENT,
|
||||||
|
READYCHECK,
|
||||||
|
CHAMPSELECT,
|
||||||
|
GAMESTART,
|
||||||
|
FAILEDTOLAUNCH,
|
||||||
|
INPROGRESS,
|
||||||
|
RECONNECT,
|
||||||
|
WAITINGFORSTATS,
|
||||||
|
PREENDOFGAME,
|
||||||
|
ENDOFGAME,
|
||||||
|
TERMINATEDINERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TimerInfo {
|
||||||
|
int64_t adjustedTimeLeftInPhase;
|
||||||
|
int64_t internalNowInEpochMs;
|
||||||
|
bool isefinite;
|
||||||
|
std::string phase;
|
||||||
|
int64_t totalTimeInPhase;
|
||||||
|
|
||||||
|
bool valid = false;
|
||||||
|
};
|
||||||
|
|
||||||
ClientAPI(const ClientAccess& access);
|
ClientAPI(const ClientAccess& access);
|
||||||
~ClientAPI();
|
~ClientAPI();
|
||||||
|
|
||||||
SearchState getSearchState();
|
ReadyCheckState getReadyCheckState();
|
||||||
|
GameflowPhase getGameflowPhase();
|
||||||
void acceptMatch();
|
void acceptMatch();
|
||||||
void declineMatch();
|
void declineMatch();
|
||||||
|
|
||||||
|
std::vector<int32_t> getBannableChampIDs();
|
||||||
|
std::vector<int32_t> getPickableChampIDs();
|
||||||
|
|
||||||
|
TimerInfo getTimerInfo();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,3 +60,6 @@ protected:
|
||||||
private:
|
private:
|
||||||
ClientAccess access;
|
ClientAccess access;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream&, const ClientAPI::ReadyCheckState&);
|
||||||
|
std::ostream& operator<<(std::ostream&, const ClientAPI::GameflowPhase&);
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
#include "screen.h"
|
|
||||||
|
|
||||||
class FakeScreen : public ScreenShot {
|
|
||||||
private:
|
|
||||||
int xoffset = 0;
|
|
||||||
int yoffset = 0;
|
|
||||||
int xsize = 0;
|
|
||||||
int ysize = 0;
|
|
||||||
public:
|
|
||||||
|
|
||||||
FakeScreen(int xoffset = 0, int yoffset = 0, int xsize = 0, int ysize = 0);
|
|
||||||
~FakeScreen();
|
|
||||||
|
|
||||||
virtual void take(cv::Mat& cvimg) override;
|
|
||||||
virtual void operator() (cv::Mat& cvimg) override;
|
|
||||||
|
|
||||||
virtual int getXOffset() const override;
|
|
||||||
virtual int getYOffset() const override;
|
|
||||||
virtual double getXScale() const override;
|
|
||||||
virtual double getYScale() const override;
|
|
||||||
};
|
|
|
@ -1,67 +1,28 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "scaleableinputs.h"
|
|
||||||
#include "screen.h"
|
|
||||||
#include "matcher.h"
|
|
||||||
|
|
||||||
#include <xinputsimulator.h>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "clientapi.h"
|
||||||
|
|
||||||
class LolAutoAccept {
|
class LolAutoAccept {
|
||||||
protected:
|
protected:
|
||||||
struct Stage {
|
struct Stage {
|
||||||
Stage(const std::string& matchertmpl);
|
Stage();
|
||||||
virtual ~Stage();
|
virtual ~Stage();
|
||||||
|
|
||||||
Matcher matcher;
|
|
||||||
std::string champ; // not every stage has a champ
|
std::string champ; // not every stage has a champ
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
virtual void action(LolAutoAccept& lolaa) = 0;
|
virtual void action(LolAutoAccept& lolaa);
|
||||||
virtual bool process(LolAutoAccept& lolaa, cv::Mat& img);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CooldownStage : public Stage {
|
|
||||||
CooldownStage(const std::string& matchertmpl);
|
|
||||||
|
|
||||||
time_t lastused = 0;
|
|
||||||
uint32_t cooldown = 30; // how long until this stage can be used again (seconds)
|
|
||||||
|
|
||||||
virtual bool process(LolAutoAccept& lolaa, cv::Mat& img) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AcceptStage : public Stage {
|
|
||||||
AcceptStage();
|
|
||||||
virtual void action(LolAutoAccept& lolaa) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PrePickStage : public CooldownStage {
|
|
||||||
PrePickStage();
|
|
||||||
virtual void action(LolAutoAccept& lolaa) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BanStage : public CooldownStage {
|
|
||||||
BanStage();
|
|
||||||
virtual void action(LolAutoAccept& lolaa) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PickStage : public CooldownStage {
|
|
||||||
PickStage();
|
|
||||||
virtual void action(LolAutoAccept& lolaa) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
ScreenShot* screen = nullptr;
|
|
||||||
|
|
||||||
std::vector<Stage*> stages;
|
std::vector<Stage*> stages;
|
||||||
XInputSimulator& sim;
|
|
||||||
|
|
||||||
ScaleableInputs inputs;
|
|
||||||
|
|
||||||
bool shouldrun = false;
|
bool shouldrun = false;
|
||||||
std::thread lolaathread;
|
std::thread lolaathread;
|
||||||
|
|
||||||
void performClick(uint32_t nr, bool movemouseaway = true);
|
std::shared_ptr<ClientAPI> clientapi;
|
||||||
void enterSearch(const std::string& text);
|
|
||||||
void pickFirst(const std::string& search);
|
|
||||||
public:
|
public:
|
||||||
enum class State {
|
enum class State {
|
||||||
LOBBY = 0,
|
LOBBY = 0,
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <opencv2/opencv.hpp>
|
|
||||||
|
|
||||||
class Matcher {
|
|
||||||
private:
|
|
||||||
cv::Mat templ;
|
|
||||||
cv::Mat mask;
|
|
||||||
int32_t posx = -1;
|
|
||||||
int32_t posy = -1;
|
|
||||||
|
|
||||||
static std::string pathbase;
|
|
||||||
public:
|
|
||||||
static void setPathBase(const std::string& pa);
|
|
||||||
|
|
||||||
Matcher(const std::string& filename);
|
|
||||||
Matcher(const cv::Mat& templ);
|
|
||||||
~Matcher();
|
|
||||||
|
|
||||||
// instead of searching for a match, just look at this position
|
|
||||||
void setOffset(int32_t x, int32_t y);
|
|
||||||
|
|
||||||
struct Match {
|
|
||||||
bool doesMatch = false;
|
|
||||||
int x = 0, y = 0;
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
|
|
||||||
bool operator==(const Match&) const;
|
|
||||||
bool operator!=(const Match&) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
Match match(const cv::Mat& img);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Match matchAll(const cv::Mat& img);
|
|
||||||
Match matchPos(const cv::Mat& img);
|
|
||||||
|
|
||||||
// when the template has a alpha channel try to create a mask from that
|
|
||||||
void maskFromTemplate();
|
|
||||||
};
|
|
|
@ -1,89 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <opencv2/opencv.hpp>
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
|
|
||||||
#include <X11/extensions/XShm.h>
|
|
||||||
#include <sys/ipc.h>
|
|
||||||
#include <sys/shm.h>
|
|
||||||
|
|
||||||
#undef Bool
|
|
||||||
#undef CursorShape
|
|
||||||
#undef None
|
|
||||||
#undef KeyPress
|
|
||||||
#undef KeyRelease
|
|
||||||
#undef ButtonPress
|
|
||||||
#undef ButtonRelease
|
|
||||||
#undef MotionNotify
|
|
||||||
#undef EnterNotify
|
|
||||||
#undef LeaveNotify
|
|
||||||
#undef FocusIn
|
|
||||||
#undef FocusOut
|
|
||||||
#undef KeymapNotify
|
|
||||||
#undef Expose
|
|
||||||
#undef GraphicsExpose
|
|
||||||
#undef NoExpose
|
|
||||||
#undef VisibilityNotify
|
|
||||||
#undef CreateNotify
|
|
||||||
#undef DestroyNotify
|
|
||||||
#undef UnmapNotify
|
|
||||||
#undef MapNotify
|
|
||||||
#undef MapRequest
|
|
||||||
#undef ReparentNotify
|
|
||||||
#undef ConfigureNotify
|
|
||||||
#undef ConfigureRequest
|
|
||||||
#undef GravityNotify
|
|
||||||
#undef ResizeRequest
|
|
||||||
#undef CirculateNotify
|
|
||||||
#undef CirculateRequest
|
|
||||||
#undef PropertyNotify
|
|
||||||
#undef SelectionClear
|
|
||||||
#undef SelectionRequest
|
|
||||||
#undef SelectionNotify
|
|
||||||
#undef ColormapNotify
|
|
||||||
#undef ClientMessage
|
|
||||||
#undef MappingNotify
|
|
||||||
#undef GenericEvent
|
|
||||||
#undef LASTEvent
|
|
||||||
#undef FontChange
|
|
||||||
|
|
||||||
class ScreenShot {
|
|
||||||
private:
|
|
||||||
Display* display = nullptr;
|
|
||||||
Window window;
|
|
||||||
XWindowAttributes wattrib;
|
|
||||||
XImage* ximg = nullptr;
|
|
||||||
XShmSegmentInfo shminfo;
|
|
||||||
|
|
||||||
bool init;
|
|
||||||
bool closeDisp = true;
|
|
||||||
bool valid = false;
|
|
||||||
std::string windowname;
|
|
||||||
|
|
||||||
bool updateAttrib();
|
|
||||||
bool initImg();
|
|
||||||
public:
|
|
||||||
|
|
||||||
static std::vector<ScreenShot*> getWindows(const std::string& name);
|
|
||||||
|
|
||||||
static const uint32_t DEFAULTWIDTH;
|
|
||||||
static const uint32_t DEFAULTHEIGHT;
|
|
||||||
|
|
||||||
ScreenShot();
|
|
||||||
ScreenShot(Display* d, Window w);
|
|
||||||
virtual ~ScreenShot();
|
|
||||||
|
|
||||||
virtual void take(cv::Mat& cvimg);
|
|
||||||
virtual void operator() (cv::Mat& cvimg);
|
|
||||||
|
|
||||||
constexpr operator bool () const {
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int getXOffset() const;
|
|
||||||
virtual int getYOffset() const;
|
|
||||||
virtual double getXScale() const;
|
|
||||||
virtual double getYScale() const;
|
|
||||||
};
|
|
|
@ -1,5 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <opencv2/opencv.hpp>
|
|
||||||
|
|
||||||
void debugImage(cv::Mat img, const std::string& name = "");
|
|
|
@ -29,21 +29,13 @@ SOURCES += \
|
||||||
src/config.cpp \
|
src/config.cpp \
|
||||||
src/datadragon.cpp \
|
src/datadragon.cpp \
|
||||||
src/datadragonimagecache.cpp \
|
src/datadragonimagecache.cpp \
|
||||||
src/fakescreen.cpp \
|
|
||||||
src/files.cpp \
|
src/files.cpp \
|
||||||
src/json.cpp \
|
src/json.cpp \
|
||||||
src/lolautoaccept_accept.cpp \
|
|
||||||
src/lolautoaccept_ban.cpp \
|
|
||||||
src/lolautoaccept_pick.cpp \
|
|
||||||
src/lolautoaccept_prepick.cpp \
|
|
||||||
src/lolautoaccept.cpp \
|
src/lolautoaccept.cpp \
|
||||||
src/main.cpp \
|
src/main.cpp \
|
||||||
src/mainwindow.cpp \
|
src/mainwindow.cpp \
|
||||||
src/matcher.cpp \
|
|
||||||
src/memoryimagecache.cpp \
|
src/memoryimagecache.cpp \
|
||||||
src/restclient.cpp \
|
src/restclient.cpp \
|
||||||
src/scaleableinputs.cpp \
|
|
||||||
src/screen.cpp \
|
|
||||||
src/stagesettings.cpp \
|
src/stagesettings.cpp \
|
||||||
thirdparty/Log/Log.cpp
|
thirdparty/Log/Log.cpp
|
||||||
|
|
||||||
|
@ -56,16 +48,12 @@ HEADERS += \
|
||||||
include/config.h \
|
include/config.h \
|
||||||
include/datadragon.h \
|
include/datadragon.h \
|
||||||
include/datadragonimagecache.h \
|
include/datadragonimagecache.h \
|
||||||
include/fakescreen.h \
|
|
||||||
include/files.h \
|
include/files.h \
|
||||||
include/json.h \
|
include/json.h \
|
||||||
include/lolautoaccept.h \
|
include/lolautoaccept.h \
|
||||||
include/mainwindow.h \
|
include/mainwindow.h \
|
||||||
include/matcher.h \
|
|
||||||
include/memoryimagecache.h \
|
include/memoryimagecache.h \
|
||||||
include/restclient.h \
|
include/restclient.h \
|
||||||
include/scaleableinputs.h \
|
|
||||||
include/screen.h \
|
|
||||||
include/stagesettings.h \
|
include/stagesettings.h \
|
||||||
thirdparty/Log/Log.h
|
thirdparty/Log/Log.h
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,26 @@
|
||||||
#include "clientapi.h"
|
#include "clientapi.h"
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <QJsonArray>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include <Log.h>
|
#include <Log.h>
|
||||||
|
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
|
|
||||||
static const std::string SearchStateNames[] = {"Invalid", "Searching", "Found", "AbandonedLowPriorityQueue", "Canceled", "Error", "ServiceError", "ServiceShutdown"};
|
// calculate the size of a constant sized array
|
||||||
static const uint32_t SearchStateNamesCount = sizeof(SearchStateNames) / sizeof(SearchStateNames[0]);
|
#define ARRSIZE(ARRNAME) (sizeof(ARRNAME) / sizeof(ARRNAME[0]))
|
||||||
|
|
||||||
|
static const std::string ReadyCheckStateNames[] = { "Invalid", "None", "InProgress", "Accepted", "Declined" };
|
||||||
|
static const uint32_t ReadyCheckStateNamesCount = ARRSIZE(ReadyCheckStateNames);
|
||||||
|
|
||||||
|
static const std::string GameflowPhaseNames[] = {"None", "Lobby", "Matchmaking", "CheckedIntoTournament", "ReadyCheck", "ChampSelect", "GameStart", "FailedToLaunch", "InProgress", "Reconnect", "WaitingForStats", "PreEndOfGame", "EndOfGame", "TerminatedInError"};
|
||||||
|
static const uint32_t GameflowPhaseNamesCount = ARRSIZE(GameflowPhaseNames);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static T mapEnum(const std::string& input, const std::string* names, uint32_t count, T defaul) {
|
static T mapEnum(const std::string& input, const std::string* names, uint32_t count, T defaul) {
|
||||||
for(uint32_t i = 0; i < count; ++i) {
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
if(names[i] == input) {
|
if (names[i] == input) {
|
||||||
return (T) i;
|
return (T) i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,24 +35,105 @@ ClientAPI::ClientAPI(const ClientAccess& ca) : RestClient(ca.getURL()), access(c
|
||||||
}
|
}
|
||||||
ClientAPI::~ClientAPI() {}
|
ClientAPI::~ClientAPI() {}
|
||||||
|
|
||||||
ClientAPI::SearchState ClientAPI::getSearchState() {
|
ClientAPI::ReadyCheckState ClientAPI::getReadyCheckState() {
|
||||||
QJsonDocument doc = request("lol-lobby/v2/lobby/matchmaking/search-state");
|
QJsonDocument doc = request("lol-matchmaking/v1/ready-check");
|
||||||
|
|
||||||
if(doc.isObject()) {
|
if (doc.isObject()) {
|
||||||
QJsonObject obj = doc.object();
|
QJsonObject obj = doc.object();
|
||||||
std::string searchState = getValue<std::string>(obj, "searchState", "Invalid");
|
Log::info << "ready check obj: " << doc.toJson().toStdString();
|
||||||
|
|
||||||
return mapEnum(searchState, SearchStateNames, SearchStateNamesCount, ClientAPI::SearchState::INVALID);
|
std::string searchState = getValue<std::string>(obj, "state", "Invalid");
|
||||||
|
std::string playerresponse = getValue<std::string>(obj, "playerResponse", "None");
|
||||||
|
|
||||||
|
ClientAPI::ReadyCheckState response = mapEnum(playerresponse, ReadyCheckStateNames, ReadyCheckStateNamesCount, ClientAPI::ReadyCheckState::NONE);
|
||||||
|
|
||||||
|
if(response == ClientAPI::ReadyCheckState::NONE) {
|
||||||
|
auto sstate = mapEnum(searchState, ReadyCheckStateNames, ReadyCheckStateNamesCount, ClientAPI::ReadyCheckState::INVALID);
|
||||||
|
if(sstate == ClientAPI::ReadyCheckState::INPROGRESS) {
|
||||||
|
return sstate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ClientAPI::SearchState::INVALID;
|
return ClientAPI::ReadyCheckState::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientAPI::GameflowPhase ClientAPI::getGameflowPhase() {
|
||||||
|
// it is just a json-string no object
|
||||||
|
QByteArray data = requestRaw("lol-gameflow/v1/gameflow-phase");
|
||||||
|
|
||||||
|
std::string datastr = data.toStdString();
|
||||||
|
if (data.size() > 2) {
|
||||||
|
datastr = datastr.substr(1, datastr.size() -2);
|
||||||
|
|
||||||
|
return mapEnum(datastr, GameflowPhaseNames, GameflowPhaseNamesCount, ClientAPI::GameflowPhase::NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClientAPI::GameflowPhase::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientAPI::acceptMatch() {
|
void ClientAPI::acceptMatch() {
|
||||||
|
request("lol-matchmaking/v1/ready-check/accept", Method::POST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientAPI::declineMatch() {
|
void ClientAPI::declineMatch() {
|
||||||
|
request("lol-matchmaking/v1/ready-check/decline", Method::POST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<int32_t> fromArrayToVector(const QJsonArray& arr) {
|
||||||
|
std::vector<int32_t> out;
|
||||||
|
out.reserve(arr.size());
|
||||||
|
for (auto it = arr.begin(); it != arr.end(); ++it) {
|
||||||
|
if (it->isDouble())
|
||||||
|
out.push_back(it->toInt());
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int32_t> ClientAPI::getBannableChampIDs() {
|
||||||
|
QJsonDocument doc = request("lol-champ-select/v1/bannable-champion-ids");
|
||||||
|
|
||||||
|
if (doc.isArray()) {
|
||||||
|
return fromArrayToVector(doc.array());
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}; // empty vector
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int32_t> ClientAPI::getPickableChampIDs() {
|
||||||
|
QJsonDocument doc = request("lol-champ-select/v1/pickable-champion-ids");
|
||||||
|
|
||||||
|
if (doc.isArray()) {
|
||||||
|
return fromArrayToVector(doc.array());
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}; // empty vector
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientAPI::TimerInfo ClientAPI::getTimerInfo() {
|
||||||
|
QJsonDocument doc = request("lol-champ-select/v1/session/timer");
|
||||||
|
|
||||||
|
if (!doc.isObject()) return {};
|
||||||
|
|
||||||
|
TimerInfo ti;
|
||||||
|
|
||||||
|
QJsonObject obj = doc.object();
|
||||||
|
ti.adjustedTimeLeftInPhase = getValue<int64_t>(obj, "adjustedTimeLeftInPhase", 0);
|
||||||
|
ti.internalNowInEpochMs = getValue<int64_t>(obj, "internalNowInEpochMs", 0);
|
||||||
|
ti.isefinite = getValue<bool>(obj, "isefinite", 0);
|
||||||
|
ti.phase = getValue<std::string>(obj, "phase", "");
|
||||||
|
ti.totalTimeInPhase = getValue<int64_t>(obj, "totalTimeInPhase", 0);
|
||||||
|
|
||||||
|
return ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PRINTENUM(ENUMNAME) \
|
||||||
|
std::ostream& operator<<(std::ostream& str, const ClientAPI:: ENUMNAME & state) { \
|
||||||
|
return str << ENUMNAME ## Names[(int) state] << " (" << (int) state << ')'; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PRINTENUM(ReadyCheckState)
|
||||||
|
PRINTENUM(GameflowPhase)
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
#include "fakescreen.h"
|
|
||||||
|
|
||||||
FakeScreen::FakeScreen(int xoffset, int yoffset, int xsize, int ysize) : ScreenShot(),
|
|
||||||
xoffset(xoffset), yoffset(yoffset), xsize(xsize), ysize(ysize) {
|
|
||||||
}
|
|
||||||
|
|
||||||
FakeScreen::~FakeScreen() {}
|
|
||||||
|
|
||||||
|
|
||||||
void FakeScreen::take(cv::Mat& cvimg) {
|
|
||||||
// take screenshot from entire screen using base class
|
|
||||||
cv::Mat entireScreen;
|
|
||||||
ScreenShot::take(entireScreen);
|
|
||||||
|
|
||||||
// only return part of the screenshot
|
|
||||||
entireScreen({yoffset, yoffset + ysize}, {xoffset, xoffset + xsize}).copyTo(cvimg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FakeScreen::operator() (cv::Mat& cvimg) {
|
|
||||||
take(cvimg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int FakeScreen::getXOffset() const {
|
|
||||||
return xoffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FakeScreen::getYOffset() const {
|
|
||||||
return yoffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
double FakeScreen::getXScale() const {
|
|
||||||
return xsize / (double) DEFAULTWIDTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
double FakeScreen::getYScale() const {
|
|
||||||
return ysize / (double) DEFAULTHEIGHT;
|
|
||||||
}
|
|
|
@ -3,99 +3,18 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <Log.h>
|
#include <Log.h>
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
#include "fakescreen.h"
|
|
||||||
|
|
||||||
// set to 1 to use the test screenshot feature
|
LolAutoAccept::Stage::Stage() {}
|
||||||
#define TESTSCREEN 0
|
|
||||||
|
|
||||||
void debugImage(cv::Mat img, const std::string& name) {
|
|
||||||
if(img.channels() > 3) {
|
|
||||||
std::vector<cv::Mat> channels(4);
|
|
||||||
cv::split(img, channels);
|
|
||||||
channels.resize(3); // drop alpha channel
|
|
||||||
cv::merge(channels, img);
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t t = time(0);
|
|
||||||
cv::imwrite("debugimages/" + name + std::to_string(t) + ".png", img);
|
|
||||||
}
|
|
||||||
|
|
||||||
LolAutoAccept::Stage::Stage(const std::string& matchertmpl) : matcher(matchertmpl) {}
|
|
||||||
LolAutoAccept::Stage::~Stage() {}
|
LolAutoAccept::Stage::~Stage() {}
|
||||||
|
|
||||||
bool LolAutoAccept::Stage::process(LolAutoAccept& lolaa, cv::Mat& img) {
|
void LolAutoAccept::Stage::action(LolAutoAccept& lolaa) {}
|
||||||
if(enabled) {
|
|
||||||
auto match = matcher.match(img);
|
|
||||||
if(match.doesMatch) {
|
|
||||||
action(lolaa);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LolAutoAccept::CooldownStage::CooldownStage(const std::string& matchertmpl) : Stage(matchertmpl) {}
|
|
||||||
|
|
||||||
bool LolAutoAccept::CooldownStage::process(LolAutoAccept& lolaa, cv::Mat& img) {
|
|
||||||
if((time(0) - lastused) > cooldown) {
|
|
||||||
if(Stage::process(lolaa, img)) {
|
|
||||||
lastused = time(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LolAutoAccept::performClick(uint32_t nr, bool movemouseaway) {
|
|
||||||
inputs.setOffset(screen->getXOffset(), screen->getYOffset());
|
|
||||||
inputs.setScale(screen->getXScale(), screen->getYScale());
|
|
||||||
|
|
||||||
auto p = inputs.get(nr);
|
|
||||||
Log::info << "click " << nr << " @ " << p.x << " " << p.y;
|
|
||||||
|
|
||||||
sim.mouseMoveTo(p.x, p.y);
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(170));
|
|
||||||
sim.mouseClick(XIS::LEFT_MOUSE_BUTTON);
|
|
||||||
|
|
||||||
// move mouse away
|
|
||||||
if(movemouseaway) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(170));
|
|
||||||
p = inputs.get(0);
|
|
||||||
sim.mouseMoveTo(p.x, p.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LolAutoAccept::enterSearch(const std::string& text) {
|
|
||||||
performClick(2, false); // click searchbox
|
|
||||||
|
|
||||||
Log::debug << "enter text: " << text;
|
|
||||||
|
|
||||||
sim.keySequence(text);
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(750));
|
|
||||||
}
|
|
||||||
|
|
||||||
void LolAutoAccept::pickFirst(const std::string& search) {
|
|
||||||
enterSearch(search);
|
|
||||||
|
|
||||||
performClick(3, false); // first champion
|
|
||||||
}
|
|
||||||
|
|
||||||
LolAutoAccept::LolAutoAccept() : sim(XInputSimulator::getInstance()) {
|
|
||||||
// click positions in 1280x720 scale
|
|
||||||
inputs.addPoint({0, 0}); // zero zero
|
|
||||||
inputs.addPoint({645, 560}); // accept game
|
|
||||||
inputs.addPoint({775, 105}); // search box
|
|
||||||
inputs.addPoint({380, 160}); // first champ
|
|
||||||
inputs.addPoint({638, 608}); // pick/ban champ
|
|
||||||
|
|
||||||
|
LolAutoAccept::LolAutoAccept() {
|
||||||
stages.reserve(4);
|
stages.reserve(4);
|
||||||
stages.push_back(new AcceptStage());
|
stages.push_back(new Stage()); // accept
|
||||||
stages.push_back(new PrePickStage());
|
stages.push_back(new Stage()); // prepick
|
||||||
stages.push_back(new BanStage());
|
stages.push_back(new Stage()); // ban
|
||||||
stages.push_back(new PickStage());
|
stages.push_back(new Stage()); // pick
|
||||||
}
|
}
|
||||||
|
|
||||||
LolAutoAccept::~LolAutoAccept() {
|
LolAutoAccept::~LolAutoAccept() {
|
||||||
|
@ -104,9 +23,6 @@ LolAutoAccept::~LolAutoAccept() {
|
||||||
for(auto s : stages) {
|
for(auto s : stages) {
|
||||||
delete s;
|
delete s;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete screen;
|
|
||||||
screen = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LolAutoAccept::setChamp(const std::string& champ, State s) {
|
void LolAutoAccept::setChamp(const std::string& champ, State s) {
|
||||||
|
@ -128,37 +44,21 @@ void LolAutoAccept::setEnabled(bool b, State s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LolAutoAccept::init() {
|
bool LolAutoAccept::init() {
|
||||||
if(screen)
|
if(clientapi) return true;
|
||||||
return true;
|
|
||||||
|
|
||||||
// get window
|
auto ca = ClientAccess::find();
|
||||||
#if TESTSCREEN == 0
|
if(ca) {
|
||||||
auto wins = ScreenShot::getWindows("League of Legends");
|
clientapi = std::make_shared<ClientAPI>(*ca.get());
|
||||||
if(wins.size() != 1) {
|
|
||||||
Log::fatal << "invalid count of windows found: " << wins.size();
|
|
||||||
for(auto w : wins) {
|
|
||||||
delete w;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
screen = (wins.at(0)); // just take the first
|
return (bool) clientapi;
|
||||||
#else
|
|
||||||
|
|
||||||
// testing whole screen, but take a part of it, so it behaves like a focused screenshot
|
|
||||||
screen = new FakeScreen(1, 683, 1280, 720);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// testing: whole screen:
|
|
||||||
// screen = new ScreenShot();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LolAutoAccept::run() {
|
void LolAutoAccept::run() {
|
||||||
// make sure its not running
|
// make sure its not running
|
||||||
stopJoinThread();
|
stopJoinThread();
|
||||||
|
|
||||||
if(!screen) return;
|
if(!clientapi) return; // no client api
|
||||||
|
|
||||||
lolaathread = std::thread(&LolAutoAccept::innerRun, this);
|
lolaathread = std::thread(&LolAutoAccept::innerRun, this);
|
||||||
}
|
}
|
||||||
|
@ -181,24 +81,29 @@ void LolAutoAccept::innerRun() {
|
||||||
while(shouldrun) {
|
while(shouldrun) {
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
cv::Mat img;
|
auto phase = clientapi->getGameflowPhase();
|
||||||
screen->take(img);
|
Log::debug << "current Gameflowphase: " << phase;
|
||||||
cv::resize(img, img, cv::Size(ScreenShot::DEFAULTWIDTH, ScreenShot::DEFAULTHEIGHT));
|
|
||||||
|
// TODO: do processing
|
||||||
|
if(phase == ClientAPI::GameflowPhase::READYCHECK) {
|
||||||
|
if(stages.at(0)->enabled) { // auto accept enabled
|
||||||
|
auto state = clientapi->getReadyCheckState();
|
||||||
|
|
||||||
|
Log::info << "readychack state: " << state;
|
||||||
|
if(state == ClientAPI::ReadyCheckState::INPROGRESS) {
|
||||||
|
Log::info << "auto accepting";
|
||||||
|
clientapi->acceptMatch();
|
||||||
|
}
|
||||||
|
} else if(phase == ClientAPI::GameflowPhase::CHAMPSELECT) {
|
||||||
|
|
||||||
for(size_t i = 0; i < stages.size(); ++i) {
|
|
||||||
Log::trace << "processing stage " << i;
|
|
||||||
Stage* stage = stages.at(i);
|
|
||||||
if(stage->process(*this, img)) {
|
|
||||||
Log::debug << "stage successful: " << i;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto end = std::chrono::high_resolution_clock::now();
|
auto end = std::chrono::high_resolution_clock::now();
|
||||||
std::chrono::duration<double> dur = (end-start);
|
std::chrono::duration<double> dur = (end-start);
|
||||||
if(dur.count() > 1e-5)
|
//if(dur.count() > 1e-5)
|
||||||
Log::info << "iteration took: " << (dur.count() * 1000) << " ms";
|
Log::info << "iteration took: " << (dur.count() * 1000) << " ms";
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(800));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1200));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
#include "lolautoaccept.h"
|
|
||||||
|
|
||||||
LolAutoAccept::AcceptStage::AcceptStage() : Stage("imgs/accept.png") {
|
|
||||||
matcher.setOffset(539, 529);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LolAutoAccept::AcceptStage::action(LolAutoAccept& lolaa) {
|
|
||||||
lolaa.performClick(1); // accept Game
|
|
||||||
|
|
||||||
// security sleep
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
#include "lolautoaccept.h"
|
|
||||||
|
|
||||||
LolAutoAccept::BanStage::BanStage() : CooldownStage("imgs/ban.png") {
|
|
||||||
matcher.setOffset(1232, 90);
|
|
||||||
cooldown = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LolAutoAccept::BanStage::action(LolAutoAccept& lolaa) {
|
|
||||||
if(!champ.empty()) {
|
|
||||||
lolaa.pickFirst(champ);
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1800));
|
|
||||||
|
|
||||||
// click "ban"
|
|
||||||
lolaa.performClick(4);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
#include "lolautoaccept.h"
|
|
||||||
|
|
||||||
LolAutoAccept::PickStage::PickStage() : CooldownStage("imgs/pick.png") {
|
|
||||||
matcher.setOffset(538, 587);
|
|
||||||
cooldown = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LolAutoAccept::PickStage::action(LolAutoAccept& lolaa) {
|
|
||||||
if(!champ.empty()) {
|
|
||||||
lolaa.pickFirst(champ);
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1800));
|
|
||||||
|
|
||||||
// click "accept"
|
|
||||||
lolaa.performClick(4);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
#include "lolautoaccept.h"
|
|
||||||
|
|
||||||
LolAutoAccept::PrePickStage::PrePickStage() : CooldownStage("imgs/arrowdown.png") {
|
|
||||||
matcher.setOffset(615, 617);
|
|
||||||
cooldown = 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LolAutoAccept::PrePickStage::action(LolAutoAccept& lolaa) {
|
|
||||||
if(!champ.empty())
|
|
||||||
lolaa.pickFirst(champ);
|
|
||||||
}
|
|
18
src/main.cpp
18
src/main.cpp
|
@ -12,6 +12,8 @@
|
||||||
#include "arg.h"
|
#include "arg.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "lolautoaccept.h"
|
#include "lolautoaccept.h"
|
||||||
|
#include "clientaccess.h"
|
||||||
|
#include "clientapi.h"
|
||||||
|
|
||||||
static std::string getBaseString(char** argv) {
|
static std::string getBaseString(char** argv) {
|
||||||
std::string base;
|
std::string base;
|
||||||
|
@ -51,7 +53,6 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
std::string base = getBaseString(argv);
|
std::string base = getBaseString(argv);
|
||||||
Log::info << "appbase: " << base;
|
Log::info << "appbase: " << base;
|
||||||
Matcher::setPathBase(base);
|
|
||||||
|
|
||||||
LolAutoAccept lolaa;
|
LolAutoAccept lolaa;
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
@ -65,21 +66,6 @@ int main(int argc, char** argv) {
|
||||||
QIcon icon(QString::fromStdString(base + "lolautoaccept.png"));
|
QIcon icon(QString::fromStdString(base + "lolautoaccept.png"));
|
||||||
win.setWindowIcon(icon);
|
win.setWindowIcon(icon);
|
||||||
|
|
||||||
while(!lolaa.init()) {
|
|
||||||
QMessageBox warn;
|
|
||||||
warn.setWindowIcon(icon);
|
|
||||||
warn.setWindowTitle(MainWindow::tr("LoL-Auto-Accept"));
|
|
||||||
warn.setText(QMessageBox::tr("League of Legends Client not found!"));
|
|
||||||
warn.setInformativeText(QMessageBox::tr("Open the client and retry or close."));
|
|
||||||
warn.setStandardButtons(QMessageBox::Retry | QMessageBox::Close);
|
|
||||||
warn.setDefaultButton(QMessageBox::Retry);
|
|
||||||
warn.setIcon(QMessageBox::Warning);
|
|
||||||
if(warn.exec() == QMessageBox::Close) {
|
|
||||||
Log::stop();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
win.show();
|
win.show();
|
||||||
int ret = app.exec();
|
int ret = app.exec();
|
||||||
|
|
||||||
|
|
102
src/matcher.cpp
102
src/matcher.cpp
|
@ -1,102 +0,0 @@
|
||||||
#include "matcher.h"
|
|
||||||
|
|
||||||
#include <Log.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
std::string Matcher::pathbase;
|
|
||||||
|
|
||||||
void Matcher::setPathBase(const std::string& pa) {
|
|
||||||
pathbase = pa;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matcher::Matcher(const std::string& filename) {
|
|
||||||
templ = cv::imread(pathbase + filename, cv::IMREAD_UNCHANGED); // unchanged so alpha channel does not get dropped
|
|
||||||
maskFromTemplate();
|
|
||||||
}
|
|
||||||
Matcher::Matcher(const cv::Mat& templ) {
|
|
||||||
templ.copyTo(this->templ);
|
|
||||||
maskFromTemplate();
|
|
||||||
}
|
|
||||||
Matcher::~Matcher() {}
|
|
||||||
|
|
||||||
void Matcher::setOffset(int32_t x, int32_t y) {
|
|
||||||
posx = x;
|
|
||||||
posy = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Matcher::Match::operator==(const Match& other) const {
|
|
||||||
return doesMatch == other.doesMatch && x == other.x && y == other.y && width == other.width && height == other.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Matcher::Match::operator!=(const Match& other) const {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Matcher::Match Matcher::match(const cv::Mat& img) {
|
|
||||||
// remove Alpha channel from input
|
|
||||||
cv::Mat converted;
|
|
||||||
cv::cvtColor(img, converted, cv::COLOR_RGBA2RGB);
|
|
||||||
|
|
||||||
if(posx < 0 || posy < 0) {
|
|
||||||
return matchAll(converted);
|
|
||||||
}
|
|
||||||
return matchPos(converted);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://stackoverflow.com/a/43133263/4399859
|
|
||||||
Matcher::Match Matcher::matchAll(const cv::Mat& img) {
|
|
||||||
// create out mat
|
|
||||||
int result_cols = img.cols - templ.cols + 1;
|
|
||||||
int result_rows = img.rows - templ.rows + 1;
|
|
||||||
cv::Mat out(result_rows, result_cols, CV_32FC1);
|
|
||||||
Log::info << "match size: " << result_cols << " " << result_cols;
|
|
||||||
|
|
||||||
// match
|
|
||||||
cv::matchTemplate(img, templ, out, cv::TM_CCORR_NORMED, mask);
|
|
||||||
|
|
||||||
double minVal; double maxVal;
|
|
||||||
cv::Point minLoc; cv::Point maxLoc;
|
|
||||||
cv::minMaxLoc( out, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());
|
|
||||||
|
|
||||||
Log::debug << "pixelcount: " << (templ.cols * templ.rows) << " minVal: " << minVal << " maxVal: " << maxVal << " minLoc: " << minLoc.x << " " << minLoc.y << " maxLoc: " << maxLoc.x << " " << maxLoc.y;
|
|
||||||
|
|
||||||
bool matched = maxVal > 0.95;
|
|
||||||
|
|
||||||
return {matched, maxLoc.x, maxLoc.y, templ.cols, templ.rows};
|
|
||||||
}
|
|
||||||
|
|
||||||
Matcher::Match Matcher::matchPos(const cv::Mat& img) {
|
|
||||||
cv::Mat matchpart = img(cv::Range(posy, posy + templ.rows), cv::Range(posx, posx + templ.cols));
|
|
||||||
|
|
||||||
// create out mat (only one pxl)
|
|
||||||
cv::Mat out(1, 1, CV_32FC1);
|
|
||||||
|
|
||||||
// match
|
|
||||||
cv::matchTemplate(matchpart, templ, out, cv::TM_CCORR_NORMED, mask);
|
|
||||||
|
|
||||||
float val = out.at<float>({0, 0});
|
|
||||||
bool matched = val > 0.95;
|
|
||||||
|
|
||||||
Log::debug << "val: " << val;
|
|
||||||
|
|
||||||
return {matched, posx, posy, templ.cols, templ.rows};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matcher::maskFromTemplate() {
|
|
||||||
if(templ.channels() == 4) {
|
|
||||||
// split channels
|
|
||||||
std::vector<cv::Mat> split;
|
|
||||||
cv::split(templ, split);
|
|
||||||
|
|
||||||
// template without alpha channel
|
|
||||||
cv::merge(std::vector(split.begin(), split.end()-1), templ);
|
|
||||||
|
|
||||||
// 3*alpha channel
|
|
||||||
cv::Mat alphaChannel = split.at(3);
|
|
||||||
alphaChannel.convertTo(alphaChannel, CV_8U);
|
|
||||||
cv::merge(std::vector(3, alphaChannel), mask);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -45,7 +45,9 @@ QByteArray RestClient::requestRaw(const std::string& url, Method m) {
|
||||||
case Method::GET:
|
case Method::GET:
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); break;
|
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); break;
|
||||||
case Method::POST:
|
case Method::POST:
|
||||||
curl_easy_setopt(curl, CURLOPT_POST, 1L); break;
|
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
|
||||||
|
break;
|
||||||
case Method::PUT:
|
case Method::PUT:
|
||||||
curl_easy_setopt(curl, CURLOPT_PUT, 1L); break;
|
curl_easy_setopt(curl, CURLOPT_PUT, 1L); break;
|
||||||
case Method::DELETE:
|
case Method::DELETE:
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
#include "scaleableinputs.h"
|
|
||||||
|
|
||||||
#include <Log.h>
|
|
||||||
|
|
||||||
void ScaleableInputs::addPoint(Point p) {
|
|
||||||
points.push_back(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScaleableInputs::setScale(double x, double y) {
|
|
||||||
xScale = x;
|
|
||||||
yScale = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScaleableInputs::setOffset(double x, double y) {
|
|
||||||
xOffset = x;
|
|
||||||
yOffset = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScaleableInputs::Point ScaleableInputs::get(uint32_t nr) const {
|
|
||||||
Point p = points.at(nr);
|
|
||||||
|
|
||||||
Log::debug << "scaling: " << p.x << " " << p.y << " with: " << xOffset << " " << yOffset << " scale: " << xScale << " " << yScale;
|
|
||||||
|
|
||||||
return {(uint32_t) ((p.x * xScale) + xOffset), (uint32_t) ((p.y * yScale) + yOffset)};
|
|
||||||
}
|
|
161
src/screen.cpp
161
src/screen.cpp
|
@ -1,161 +0,0 @@
|
||||||
// g++ screena.cpp -o screena -lX11 -lXext -Ofast -mfpmath=both -march=native -m64 -funroll-loops -mavx2 `pkg-config opencv --cflags --libs` && ./screena
|
|
||||||
|
|
||||||
// This includes most headers!
|
|
||||||
|
|
||||||
#include "screen.h"
|
|
||||||
|
|
||||||
#include <X11/cursorfont.h>
|
|
||||||
#include <Log.h>
|
|
||||||
|
|
||||||
const uint32_t ScreenShot::DEFAULTWIDTH = 1280;
|
|
||||||
const uint32_t ScreenShot::DEFAULTHEIGHT = 720;
|
|
||||||
|
|
||||||
// https://stackoverflow.com/a/39781697/4399859
|
|
||||||
|
|
||||||
static void searchWindows(Display* disp, Window top, const std::string& search, std::vector<Window>& result) {
|
|
||||||
|
|
||||||
char* window_name;
|
|
||||||
if (XFetchName(disp, top, &window_name)) {
|
|
||||||
if (search == window_name) {
|
|
||||||
result.push_back(top);
|
|
||||||
return; // dont look for kids
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Window* children = nullptr, dummy;
|
|
||||||
unsigned int nchildren;
|
|
||||||
if (!XQueryTree(disp, top, &dummy, &dummy, &children, &nchildren))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < nchildren; i++) {
|
|
||||||
searchWindows(disp, children[i], search, result);
|
|
||||||
}
|
|
||||||
if (children)
|
|
||||||
XFree((char*) children);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ScreenShot*> ScreenShot::getWindows(const std::string& name) {
|
|
||||||
Display* display = XOpenDisplay(nullptr);
|
|
||||||
|
|
||||||
Log::info << "searching for: " << name;
|
|
||||||
|
|
||||||
std::vector<Window> list;
|
|
||||||
searchWindows(display, DefaultRootWindow(display), name, list);
|
|
||||||
std::vector<ScreenShot*> out;
|
|
||||||
|
|
||||||
out.reserve(list.size());
|
|
||||||
for (Window w : list) {
|
|
||||||
ScreenShot* ss = new ScreenShot(display, w);
|
|
||||||
if(ss->valid)
|
|
||||||
out.push_back(ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScreenShot::updateAttrib() {
|
|
||||||
Status attrb = XGetWindowAttributes(display, window, &wattrib);
|
|
||||||
|
|
||||||
if (attrb == BadWindow || attrb == BadDrawable) {
|
|
||||||
Log::error << "XGetWindowAttributes() falied";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((wattrib.c_class != InputOutput) || (wattrib.map_state != IsViewable)) {
|
|
||||||
Log::warn << "Window is not viewable - window class: " << wattrib.c_class << " map state: " << wattrib.map_state << " - ignoring window";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ScreenShot::initImg() {
|
|
||||||
bool upd = updateAttrib();
|
|
||||||
if(!upd) return false;
|
|
||||||
|
|
||||||
char* wname = nullptr;
|
|
||||||
XFetchName(display, window, &wname);
|
|
||||||
if (wname)
|
|
||||||
windowname = std::string(wname);
|
|
||||||
|
|
||||||
Log::info << "Window " << std::quoted(windowname) << " x: " << wattrib.x << " y: " << wattrib.y << " w: " << wattrib.width << " h: " << wattrib.height;
|
|
||||||
|
|
||||||
ximg = XShmCreateImage(display, wattrib.visual, wattrib.depth, ZPixmap, NULL, &shminfo, wattrib.width, wattrib.height);
|
|
||||||
|
|
||||||
shminfo.shmid = shmget(IPC_PRIVATE, ximg->bytes_per_line * ximg->height, IPC_CREAT | 0777);
|
|
||||||
shminfo.shmaddr = ximg->data = (char*) shmat(shminfo.shmid, 0, 0);
|
|
||||||
shminfo.readOnly = false;
|
|
||||||
if (shminfo.shmid < 0)
|
|
||||||
Log::fatal << "Fatal shminfo error!";
|
|
||||||
Status s1 = XShmAttach(display, &shminfo);
|
|
||||||
Log::info << "XShmAttach() " << (s1 ? "success!" : "failure!");
|
|
||||||
|
|
||||||
init = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreenShot::ScreenShot() {
|
|
||||||
|
|
||||||
display = XOpenDisplay(nullptr);
|
|
||||||
window = DefaultRootWindow(display);
|
|
||||||
|
|
||||||
int count_screens = ScreenCount(display);
|
|
||||||
if (count_screens == 0) {
|
|
||||||
puts("no screen info!");
|
|
||||||
}
|
|
||||||
for (int i = 0; i < count_screens; ++i) {
|
|
||||||
Screen* screen = ScreenOfDisplay(display, i);
|
|
||||||
printf("\tScreen %d: %dX%d\n", i + 1, screen->width, screen->height);
|
|
||||||
}
|
|
||||||
|
|
||||||
valid = initImg();
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreenShot::ScreenShot(Display* d, Window w) : display(d), window(w), closeDisp(false) {
|
|
||||||
valid = initImg();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenShot::take(cv::Mat& cv_img) {
|
|
||||||
if (init)
|
|
||||||
init = false;
|
|
||||||
|
|
||||||
// window not viewable
|
|
||||||
if(!updateAttrib()) {
|
|
||||||
cv_img.create(0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
XShmGetImage(display, window, ximg, 0, 0, 0x00ffffff);
|
|
||||||
cv_img = cv::Mat(wattrib.height, wattrib.width, CV_8UC4, ximg->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScreenShot::operator() (cv::Mat& cv_img) {
|
|
||||||
take(cv_img);
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreenShot::~ScreenShot() {
|
|
||||||
if (!init)
|
|
||||||
XDestroyImage(ximg);
|
|
||||||
|
|
||||||
XShmDetach(display, &shminfo);
|
|
||||||
shmdt(shminfo.shmaddr);
|
|
||||||
|
|
||||||
if (closeDisp)
|
|
||||||
XCloseDisplay(display);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int ScreenShot::getXOffset() const {
|
|
||||||
return wattrib.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ScreenShot::getYOffset() const {
|
|
||||||
return wattrib.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
double ScreenShot::getXScale() const {
|
|
||||||
return wattrib.width / (double) DEFAULTWIDTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
double ScreenShot::getYScale() const {
|
|
||||||
return wattrib.height / (double) DEFAULTHEIGHT;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user