only screenshot launcher window; organized

This commit is contained in:
mrbesen 2022-03-06 01:00:19 +01:00
parent afb7c2adde
commit 84795aa725
Signed by untrusted user: MrBesen
GPG Key ID: 596B2350DCD67504
10 changed files with 392 additions and 97 deletions

41
include/lolautoaccept.h Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include "scaleableinputs.h"
#include "screen.h"
#include "matcher.h"
#include <xinputsimulator.h>
class LolAutoAccept {
private:
ScreenShot* screen;
Matcher acceptmatcher;
Matcher arrowmatcher;
Matcher::Match lastacceptmatch;
XInputSimulator& sim;
ScaleableInputs inputs;
std::string prepick;
std::string ban;
std::string pick;
enum class State {
LOBBY,
PREPICK,
BAN,
PICK,
GAME
};
State state = State::LOBBY;
void checkForGame();
void performClick(uint32_t nr);
void enterSearch(const std::string& text);
void pickFirst(const std::string& search);
public:
LolAutoAccept();
void run();
};

View File

@ -19,6 +19,16 @@ public:
bool operator==(const Match&) const;
bool operator!=(const Match&) const;
// get the center of the button
constexpr int getButtonX() const {
return x + (width/2);
}
constexpr int getButtonY() const {
return y + (height/2);
}
};
Match match(const cv::Mat& img);

29
include/scaleableinputs.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <cstdint>
#include <vector>
class ScaleableInputs {
public:
struct Point {
uint32_t x;
uint32_t y;
};
private:
double xScale = 1;
double yScale = 1;
double xOffset = 0;
double yOffset = 0;
std::vector<Point> points;
public:
void addPoint(Point p);
void setScale(double x, double y);
void setOffset(double x, double y);
Point get(uint32_t nr) const;
};

View File

@ -12,20 +12,49 @@
class ScreenShot {
private:
Display* display = nullptr;
Window root;
XWindowAttributes window_attributes;
Window window;
XWindowAttributes wattrib;
XImage* ximg = nullptr;
XShmSegmentInfo shminfo;
int x, y, width, height;
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);
~ScreenShot();
void take(cv::Mat& cvimg);
void operator() (cv::Mat& cvimg);
};
constexpr operator bool () const {
return valid;
}
constexpr int getXOffset() const {
return wattrib.x;
}
constexpr int getYOffset() const {
return wattrib.y;
}
constexpr double getXScale() const {
return wattrib.width / DEFAULTWIDTH;
}
constexpr double getYScale() const {
return wattrib.height / DEFAULTHEIGHT;
}
};

5
include/util.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <opencv2/opencv.hpp>
void debugImage(cv::Mat img, const std::string& name = "");

131
src/lolautoaccept.cpp Normal file
View File

@ -0,0 +1,131 @@
#include "lolautoaccept.h"
#include <thread>
#include <Log.h>
#include "util.h"
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);
}
void LolAutoAccept::checkForGame() {
cv::Mat img;
screen->take(img);
cv::resize(img, img, cv::Size(ScreenShot::DEFAULTWIDTH, ScreenShot::DEFAULTHEIGHT));
Matcher::Match mat = acceptmatcher.match(img);
if(mat.doesMatch) {
Log::info << "matched";
cv::rectangle(img, cv::Point(mat.x, mat.y), cv::Point( mat.x + mat.width , mat.y + mat.height ), cv::Scalar(0, 0, 255, 0), 2);
debugImage(img);
if(lastacceptmatch.doesMatch) {
Log::info << "second match";
if(lastacceptmatch != mat) {
Log::warn << "not same match!";
lastacceptmatch.doesMatch = false;
return;
}
performClick(0); // accept Game
// security sleep
std::this_thread::sleep_for(std::chrono::seconds(3));
} else {
Log::info << "first match";
}
} else {
// check if next stage is here
Matcher::Match mat = arrowmatcher.match(img);
if(mat.doesMatch) {
Log::info << "Pre pick state";
if(!prepick.empty())
pickFirst(prepick);
state = State::PREPICK;
}
}
lastacceptmatch = mat;
}
void LolAutoAccept::performClick(uint32_t nr) {
inputs.setOffset(screen->getXOffset(), screen->getYOffset());
inputs.setScale(1 / screen->getXScale(), 1 / 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(120));
sim.mouseClick(XIS::LEFT_MOUSE_BUTTON);
// move mouse away
std::this_thread::sleep_for(std::chrono::milliseconds(120));
sim.mouseMoveTo(0, 0);
}
void LolAutoAccept::enterSearch(const std::string& text) {
performClick(1); // click searchbox
Log::debug << "enter text: " << text;
sim.keySequence(text);
std::this_thread::sleep_for(std::chrono::milliseconds(180));
}
void LolAutoAccept::pickFirst(const std::string& search) {
enterSearch(search);
performClick(2); // first champion
}
LolAutoAccept::LolAutoAccept() : acceptmatcher("imgs/Accept.png"), arrowmatcher("imgs/arrowdown.png"), sim(XInputSimulator::getInstance()) {
inputs.addPoint({645, 560}); // accept game
inputs.addPoint({775, 105}); // search box
inputs.addPoint({180, 160}); // first champ
}
void LolAutoAccept::run() {
// get window
auto wins = ScreenShot::getWindows("League of Legends");
if(wins.size() != 1) {
Log::fatal << "invalid count of windows found: " << wins.size();
return;
}
screen = (wins.at(0)); // just take the first
//delete other screens
for(uint32_t i = 1; i < wins.size(); ++i) {
ScreenShot* ss = wins.at(i);
delete ss;
}
lastacceptmatch = {false};
while(true) {
switch(state) {
case State::LOBBY:
checkForGame();
break;
default: break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(800));
}
delete wins.at(0);
}

View File

@ -1,24 +1,6 @@
#include "lolautoaccept.h"
#include "Log.h"
#include "screen.h"
#include "matcher.h"
#include <xinputsimulator.h>
#include <thread>
static void debugImage(cv::Mat img) {
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/" + std::to_string(t) + ".png", img);
}
#include <Log.h>
int main(int argc, const char** argv) {
Log::init();
@ -30,53 +12,21 @@ int main(int argc, const char** argv) {
Log::info << "Hello, World!";
// load template
Matcher matcher("imgs/Accept.png");
Matcher test1("imgs/arrowdown.png");
Matcher test2("imgs/blitzcranktest.png");
auto testimg = cv::imread("imgs/Bildschirmfoto vom 2022-02-28 19-27-59.png");
auto testimg2 = cv::imread("imgs/Bildschirmfoto vom 2022-02-28 19-27-44.png");
test1.match(testimg);
test2.match(testimg);
ScreenShot screen;
test1.match(testimg2);
test2.match(testimg2);
XInputSimulator& sim = XInputSimulator::getInstance();
return 0;
Matcher::Match lastmatch = {false};
while(true) {
cv::Mat img;
screen(img);
Matcher::Match mat = matcher.match(img);
if(mat.doesMatch) {
Log::info << "matched";
cv::rectangle(img, cv::Point(mat.x, mat.y), cv::Point( mat.x + mat.width , mat.y + mat.height ), cv::Scalar(0, 0, 255, 0), 2);
debugImage(img);
if(lastmatch.doesMatch) {
Log::info << "second match";
if(lastmatch != mat) {
Log::warn << "not same match!";
lastmatch.doesMatch = false;
continue;
}
int x = mat.x + (mat.width/2);
int y = mat.y + (mat.height/2);
Log::info << "click";
sim.mouseMoveTo(x, y);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
sim.mouseClick(XIS::LEFT_MOUSE_BUTTON);
// security sleep
std::this_thread::sleep_for(std::chrono::seconds(10));
} else {
Log::info << "first match";
}
}
lastmatch = mat;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
LolAutoAccept lolaa;
lolaa.run();
Log::stop();
return 0;

View File

@ -40,7 +40,7 @@ Matcher::Match Matcher::match(const cv::Mat& img) {
cv::Point minLoc; cv::Point maxLoc;
cv::minMaxLoc( out, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat() );
Log::debug << "minValbn: " << minValbn << " maxValbn: " << maxValbn << " minVal: " << minVal << " maxVal: " << maxVal << " minLoc: " << minLoc.x << " " << minLoc.y << " maxLoc: " << maxLoc.x << " " << maxLoc.y;
Log::debug << "pixelcount: " << (templ.cols * templ.rows) << " minValbn: " << minValbn << " maxValbn: " << maxValbn << " minVal: " << minVal << " maxVal: " << maxVal << " minLoc: " << minLoc.x << " " << minLoc.y << " maxLoc: " << maxLoc.x << " " << maxLoc.y;
bool matched = minValbn < 2e7;

20
src/scaleableinputs.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "scaleableinputs.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);
return {(uint32_t) ((p.x * xScale) + xOffset), (uint32_t) ((p.y * yScale) + yOffset)};
}

View File

@ -4,15 +4,103 @@
#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);
root = DefaultRootWindow(display);
window = DefaultRootWindow(display);
int count_screens = ScreenCount(display);
if(count_screens == 0) {
if (count_screens == 0) {
puts("no screen info!");
}
for (int i = 0; i < count_screens; ++i) {
@ -20,40 +108,32 @@ ScreenShot::ScreenShot() {
printf("\tScreen %d: %dX%d\n", i + 1, screen->width, screen->height);
}
XGetWindowAttributes(display, root, &window_attributes);
Screen* screen = window_attributes.screen;
width = screen->width;
height = screen->height;
x = 0;
y = 0;
ximg = XShmCreateImage(display, DefaultVisualOfScreen(screen), DefaultDepthOfScreen(screen), ZPixmap, NULL, &shminfo, width, 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)
puts("Fatal shminfo error!");
Status s1 = XShmAttach(display, &shminfo);
printf("XShmAttach() %s\n", s1 ? "success!" : "failure!");
init = true;
valid = initImg();
}
void ScreenShot::operator() (cv::Mat& cv_img){
if(init)
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;
XShmGetImage(display, root, ximg, 0, 0, 0x00ffffff);
cv_img = cv::Mat(height, width, CV_8UC4, ximg->data);
XShmGetImage(display, window, ximg, 0, 0, 0x00ffffff);
cv_img = cv::Mat(wattrib.height, wattrib.width, CV_8UC4, ximg->data);
}
ScreenShot::~ScreenShot(){
if(!init)
void ScreenShot::operator() (cv::Mat& cv_img) {
take(cv_img);
}
ScreenShot::~ScreenShot() {
if (!init)
XDestroyImage(ximg);
XShmDetach(display, &shminfo);
shmdt(shminfo.shmaddr);
XCloseDisplay(display);
}
if (closeDisp)
XCloseDisplay(display);
}