Skip to content

Commit

Permalink
initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
ACK72 committed Sep 14, 2023
0 parents commit f84dee9
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Created by https://www.toptal.com/developers/gitignore/api/rust
# Edit at https://www.toptal.com/developers/gitignore?templates=rust

### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# End of https://www.toptal.com/developers/gitignore/api/rust
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "PlayBridge"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
image = "*"
screenshots = "*"
spin_sleep = "*"
windows = {version = "*", features = ["Win32_Foundation", "Win32_UI_WindowsAndMessaging"]}
24 changes: 24 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
BSD 2-Clause License

Copyright (c) 2023, ACK72

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# PlayBridge

Simple ADB emulator for Google Play Games, especially for Arknights & MAA

## Download

- You can get latest builds at [release page](https://github.com/ACK72/PlayBridge/releases/latest)

## Set-Up
![setting](https://github.com/ACK72/PlayBridge/assets/25812442/69f980b6-7c9e-4a93-b1b5-f2a21c1b0680)

- You don't need to consider about connection address

## Limitations

- Currently, only supports in korean windows (You can customize and build your own)
124 changes: 124 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#![allow(non_snake_case)]
use std::{env, io::*, time::Duration};
use image::{codecs::png::PngEncoder, DynamicImage};
use screenshots::Screen;
use windows::{
core::*, Win32::Foundation::*, Win32::UI::WindowsAndMessaging::*
};

fn main() {
let args: Vec<String> = env::args().collect();
let command = args.join(" ");

if command.contains("connect") {
let mut stdout = stdout().lock();
stdout.write_all(b"connected to Google Play Games").unwrap();
}

if command.contains("shell input tap") {
let x = args[6].parse::<i32>().unwrap();
let y = args[7].parse::<i32>().unwrap();

input_tap(x, y);
}

if command.contains("shell input swipe") {
let x1 = args[6].parse::<i32>().unwrap();
let y1 = args[7].parse::<i32>().unwrap();
let x2 = args[8].parse::<i32>().unwrap();
let y2 = args[9].parse::<i32>().unwrap();
let dur = args[10].parse::<i32>().unwrap();

input_swipe(x1, y1, x2, y2, dur);
}

if command.contains("shell input keyevent 111") {
input_keyevent(0x01);
}

if command.contains("shell dumpsys window displays") {
let (x, y) = get_screen_size();

let mut stdout = stdout().lock();
stdout.write_all(format!("{x}\n{y}").as_bytes()).unwrap();
}

if command.contains("exec-out screencap -p") {
let image = get_screen_capture();

let mut stdout = stdout().lock();
image.write_with_encoder(PngEncoder::new(&mut stdout)).unwrap();
}
}

fn get_screen_size() -> (i32, i32) {
let hwnd = unsafe { FindWindowW(PCWSTR::null(), w!("명일방주")) };
let mut rect = RECT::default();
let _ = unsafe { GetWindowRect(hwnd, &mut rect) };

(rect.right - rect.left, rect.bottom - rect.top)
}

fn input_tap(x: i32, y: i32) {
let hwnd = unsafe { FindWindowW(PCWSTR::null(), w!("명일방주")) };

let pos = (y << 16 | x) as isize;

unsafe {
let _ = SendMessageA(hwnd, WM_LBUTTONDOWN, WPARAM(1), LPARAM(pos));
let _ = SendMessageA(hwnd, WM_LBUTTONUP, WPARAM(1), LPARAM(pos));
}
}

fn input_swipe(x1: i32, y1: i32, x2: i32, y2: i32, dur: i32) {
let hwnd = unsafe { FindWindowW(PCWSTR::null(), w!("명일방주")) };

let polling = 1000 / 250;
let times = dur as f32 / polling as f32;

let dx = ((x2 - x1) as f32) / times;
let dy = ((y2 - y1) as f32) / times;

unsafe {
let mut count = 0f32;
loop {
if count >= times {
break;
}

let pos = ((y1 + (dy * count as f32) as i32) << 16 | (x1 + (dx * count as f32) as i32)) as isize;
let _ = SendMessageA(hwnd, WM_LBUTTONDOWN, WPARAM(1), LPARAM(pos));

spin_sleep::sleep(Duration::new(0, polling * 1000000));
count += 1.0;
}

let pos = (y2 << 16 | x2) as isize;
let _ = SendMessageA(hwnd, WM_LBUTTONUP, WPARAM(1), LPARAM(pos));
}
}

fn input_keyevent(keycode: i32) {
let hwnd = unsafe { FindWindowW(PCWSTR::null(), w!("명일방주")) };

let wparam = WPARAM(keycode as usize);
let down = LPARAM((keycode << 16) as isize);
let up = LPARAM((keycode << 16 | 1 << 30 | 1 << 31) as isize);

unsafe {
let _ = SendMessageA(hwnd, WM_KEYDOWN, wparam, down);
let _ = SendMessageA(hwnd, WM_KEYUP, wparam, up);
}
}

fn get_screen_capture() -> DynamicImage {
let hwnd = unsafe { FindWindowW(PCWSTR::null(), w!("명일방주")) };

let mut rect = RECT::default();
let _ = unsafe { GetWindowRect(hwnd, &mut rect) };

let screen = Screen::from_point((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2).unwrap();
let capture = screen.capture().unwrap();

image::DynamicImage::ImageRgba8(capture)
}

0 comments on commit f84dee9

Please sign in to comment.