funziona
commit
0012585992
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "volume"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Pietro Brenna <pietro.brenna@briq.it>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
actix-web = { version = "3.3.2", default-features = false }
|
||||||
|
ipconfig = "0.2.2"
|
||||||
|
qr2term = "0.2.2"
|
||||||
|
#autopilot = {version = "0.4.0", default-featuers = false }
|
||||||
|
win_key_codes = "0.1.2"
|
||||||
|
winapi = { version = "*", features = ["winuser"] }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
opt-level = "z"
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Controlla volume</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 0;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row1, .row2 {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 50vh;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border: none;
|
||||||
|
font-size: calc(min(20vh, 20vw));
|
||||||
|
outline: 0;
|
||||||
|
margin: 0;
|
||||||
|
flex-grow:2;
|
||||||
|
padding: 0;
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.down {
|
||||||
|
background: #000;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.up {
|
||||||
|
background: #444;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.play_pause {
|
||||||
|
background: #222;
|
||||||
|
|
||||||
|
}
|
||||||
|
.prev {
|
||||||
|
background: #444;
|
||||||
|
}
|
||||||
|
.next {
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active {
|
||||||
|
background: #888;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="row1">
|
||||||
|
<button onmousedown="md('down')" onmouseup="mu('down')" class="down">-</button>
|
||||||
|
<button onmousedown="md('up')" onmouseup="mu('up')" class="up">+</button>
|
||||||
|
</div>
|
||||||
|
<div class="row1">
|
||||||
|
<button onmousedown="md('prev')" onmouseup="mu('prev')" class="prev">⏮</button>
|
||||||
|
<button onclick="vol('play_pause')" class="play_pause">⏯</button>
|
||||||
|
<button onmousedown="md('next')" onmouseup="mu('next')" class="next">⏭</button>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var premuto = null;
|
||||||
|
var interval = null;
|
||||||
|
function md(direz) {
|
||||||
|
premuto = direz;
|
||||||
|
vol(premuto);
|
||||||
|
interval = setInterval(function () {
|
||||||
|
vol(premuto);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
function mu(direz) {
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
async function vol(direz) {
|
||||||
|
let f = await fetch("/a/" + direz);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer};
|
||||||
|
use win_key_codes;
|
||||||
|
type WinKeyCode = i32;
|
||||||
|
|
||||||
|
fn win_send_key_event(keycode: WinKeyCode, down: bool, delay_ms: u64) {
|
||||||
|
use winapi::um::winuser::{keybd_event, KEYEVENTF_KEYUP};
|
||||||
|
let flags = if down { 0 } else { KEYEVENTF_KEYUP };
|
||||||
|
unsafe { keybd_event(keycode as u8, 0, flags, 0) };
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(delay_ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn index(_req: HttpRequest) -> HttpResponse {
|
||||||
|
HttpResponse::Ok()
|
||||||
|
.content_type("text/html")
|
||||||
|
.body(include_str!("index.html"))
|
||||||
|
}
|
||||||
|
async fn action(req: HttpRequest) -> HttpResponse {
|
||||||
|
match req.match_info().get("action") {
|
||||||
|
Some(action) => {
|
||||||
|
let key_code = match action {
|
||||||
|
"up" => win_key_codes::VK_VOLUME_UP,
|
||||||
|
"down" => win_key_codes::VK_VOLUME_DOWN,
|
||||||
|
"play_pause" => win_key_codes::VK_MEDIA_PLAY_PAUSE,
|
||||||
|
"prev" => win_key_codes::VK_LEFT,
|
||||||
|
"next" => win_key_codes::VK_RIGHT,
|
||||||
|
_ => return HttpResponse::BadRequest().body("Bad request"),
|
||||||
|
};
|
||||||
|
win_send_key_event(key_code, true, 10);
|
||||||
|
win_send_key_event(key_code, false, 10);
|
||||||
|
HttpResponse::NoContent().body("")
|
||||||
|
}
|
||||||
|
None => HttpResponse::BadRequest().body("Bad request"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web::main]
|
||||||
|
async fn main() -> std::io::Result<()> {
|
||||||
|
let port = 8030;
|
||||||
|
println!("Chiudi questa finestra per terminare il programma. Collegati alla porta {} per controllare il volume.", port);
|
||||||
|
let mut candidates = vec![];
|
||||||
|
if let Ok(adapters) = ipconfig::get_adapters() {
|
||||||
|
for adapter in adapters {
|
||||||
|
if adapter.oper_status() == ipconfig::OperStatus::IfOperStatusUp {
|
||||||
|
let desc = adapter.description().to_lowercase().to_string();
|
||||||
|
if !desc.contains("virtual") && !desc.contains("loopback") {
|
||||||
|
for addr in adapter.ip_addresses() {
|
||||||
|
match addr {
|
||||||
|
std::net::IpAddr::V4(v4addr) if v4addr.is_private() => {
|
||||||
|
candidates.push(v4addr.clone());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(addr) = candidates.first() {
|
||||||
|
qr2term::print_qr(format!("http://{}:{}/", addr, port)).unwrap();
|
||||||
|
}
|
||||||
|
HttpServer::new(|| {
|
||||||
|
App::new()
|
||||||
|
.route("/", web::get().to(index))
|
||||||
|
.route("/a/{action}", web::get().to(action))
|
||||||
|
})
|
||||||
|
.bind(("0.0.0.0", port))?
|
||||||
|
.run()
|
||||||
|
.await
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue