static include

This commit is contained in:
4yn
2022-02-07 11:47:11 +08:00
parent 98509250d6
commit 3acf511da8
18 changed files with 67 additions and 43 deletions

View File

@@ -13,20 +13,25 @@ where
// https://stackoverflow.com/a/68950006
let to = to.as_ref().to_path_buf();
for path in fs::read_dir(from).unwrap() {
let path = path.unwrap().path();
let to = to.clone().join(path.file_name().unwrap());
match fs::read_dir(from) {
Ok(paths) => {
for path in paths {
let path = path.unwrap().path();
let to = to.clone().join(path.file_name().unwrap());
if path.is_file() {
fs::copy(&path, to).unwrap();
} else if path.is_dir() {
if !to.exists() {
fs::create_dir(&to).unwrap();
if path.is_file() {
fs::copy(&path, to).unwrap();
} else if path.is_dir() {
if !to.exists() {
fs::create_dir(&to).unwrap();
}
copy_dir(&path, to);
} else { /* Skip other content */
}
}
copy_dir(&path, to);
} else { /* Skip other content */
}
Err(_) => {}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,21 @@
var config = {
// Inverted layout mode.
// Set to "true" to have the "lift" key at the bottom of the screen rather than the top.
invert: false,
// Use a solid background color
bgImage: false,
bgColor: "#000000",
// Use a custom background image
// bgColor is overlayed on the image, so make it semi-transparent
// bgImage:
// "https://raw.githubusercontent.com/gist/4yn/df052666266ce25554110ca1b4f33ce3/raw/1e5e6ab966639bb6786a4690dc49097763b16ba0/subtle-prism.svg",
// bgColor: "rgba(0, 0, 0, 0.5)",
// Key Press Color
keyColor: "#FF00FF",
// Lift key color
lkeyColor: "#00FFFF",
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,120 @@
<!DOCTYPE html>
<html>
<head>
<title>slidershim-brokenithm</title>
<meta charset="utf8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="apple-touch-icon" href="favicon.ico" />
<style>
#fullscreen {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: #000000;
color: hotpink;
}
.container {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
flex-flow: column nowrap;
touch-action: none;
align-items: stretch;
}
.air-container {
/* display: flex; */
display: none;
flex-flow: column nowrap;
align-items: stretch;
flex: 1;
}
.touch-container {
display: flex;
flex-flow: row nowrap;
align-items: stretch;
flex: 1;
}
.grow > * {
flex: 1;
}
.key {
flex: 1;
border: 1px solid green;
}
.key[data-active] {
background-color: hotpink;
}
.key.air[data-active] {
background-color: skyblue;
}
canvas {
-ms-interpolation-mode: nearest-neighbor;
image-rendering: crisp-edges;
image-rendering: pixelated;
touch-action: none;
margin: 0px -1.5625vw;
}
</style>
</head>
<body>
<div id="fullscreen">
<!-- Offset for LED display -->
<div class="container">
<div class="air-container grow"></div>
<div class="touch-container grow">
<canvas id="canvas" width="33" height="1"></canvas>
</div>
</div>
<!-- Hitbox Divs -->
<div class="container" id="main">
<div class="air-container grow">
<div class="air key" data-air="1" data-kflag="5"></div>
<div class="air key" data-air="1" data-kflag="4"></div>
<div class="air key" data-air="1" data-kflag="3"></div>
<div class="air key" data-air="1" data-kflag="2"></div>
<div class="air key" data-air="1" data-kflag="1"></div>
<div class="air key" data-air="1" data-kflag="0"></div>
</div>
<div class="touch-container grow">
<div class="key" data-kflag="0"></div>
<div class="key" data-kflag="2"></div>
<div class="key" data-kflag="4"></div>
<div class="key" data-kflag="6"></div>
<div class="key" data-kflag="8"></div>
<div class="key" data-kflag="10"></div>
<div class="key" data-kflag="12"></div>
<div class="key" data-kflag="14"></div>
<div class="key" data-kflag="16"></div>
<div class="key" data-kflag="18"></div>
<div class="key" data-kflag="20"></div>
<div class="key" data-kflag="22"></div>
<div class="key" data-kflag="24"></div>
<div class="key" data-kflag="26"></div>
<div class="key" data-kflag="28"></div>
<div class="key" data-kflag="30"></div>
</div>
</div>
</div>
<script src="/config.js"></script>
<script src="/src.js"></script>
</body>
</html>

View File

@@ -0,0 +1,119 @@
<!DOCTYPE html>
<html>
<head>
<title>slidershim-brokenithm</title>
<meta charset="utf8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="apple-touch-icon" href="favicon.ico" />
<style>
#fullscreen {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: #000000;
color: hotpink;
}
.container {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
flex-flow: column nowrap;
touch-action: none;
align-items: stretch;
}
.air-container {
display: flex;
flex-flow: column nowrap;
align-items: stretch;
flex: 1;
}
.touch-container {
display: flex;
flex-flow: row nowrap;
align-items: stretch;
flex: 1;
}
.grow > * {
flex: 1;
}
.key {
flex: 1;
border: 1px solid green;
}
.key[data-active] {
background-color: hotpink;
}
.key.air[data-active] {
background-color: skyblue;
}
canvas {
-ms-interpolation-mode: nearest-neighbor;
image-rendering: crisp-edges;
image-rendering: pixelated;
touch-action: none;
margin: 0px -1.5625vw;
}
</style>
</head>
<body>
<div id="fullscreen">
<!-- Offset for LED display -->
<div class="container">
<div class="air-container grow"></div>
<div class="touch-container grow">
<canvas id="canvas" width="33" height="1"></canvas>
</div>
</div>
<!-- Hitbox Divs -->
<div class="container" id="main">
<div class="air-container grow">
<div class="air key" data-air="1" data-kflag="5"></div>
<div class="air key" data-air="1" data-kflag="4"></div>
<div class="air key" data-air="1" data-kflag="3"></div>
<div class="air key" data-air="1" data-kflag="2"></div>
<div class="air key" data-air="1" data-kflag="1"></div>
<div class="air key" data-air="1" data-kflag="0"></div>
</div>
<div class="touch-container grow">
<div class="key" data-kflag="0"></div>
<div class="key" data-kflag="2"></div>
<div class="key" data-kflag="4"></div>
<div class="key" data-kflag="6"></div>
<div class="key" data-kflag="8"></div>
<div class="key" data-kflag="10"></div>
<div class="key" data-kflag="12"></div>
<div class="key" data-kflag="14"></div>
<div class="key" data-kflag="16"></div>
<div class="key" data-kflag="18"></div>
<div class="key" data-kflag="20"></div>
<div class="key" data-kflag="22"></div>
<div class="key" data-kflag="24"></div>
<div class="key" data-kflag="26"></div>
<div class="key" data-kflag="28"></div>
<div class="key" data-kflag="30"></div>
</div>
</div>
</div>
<script src="/config.js"></script>
<script src="/src.js"></script>
</body>
</html>

View File

@@ -0,0 +1,347 @@
/*
Post-process with https://babeljs.io/repl and https://javascript-minifier.com/
*/
const throttle = (func, wait) => {
var ready = true;
var args = null;
return function throttled() {
var context = this;
if (ready) {
ready = false;
setTimeout(function () {
ready = true;
if (args) {
throttled.apply(context);
}
}, wait);
if (args) {
func.apply(this, args);
args = null;
} else {
func.apply(this, arguments);
}
} else {
args = arguments;
}
};
};
// Element refs
var keys = document.getElementsByClassName("key");
var airKeys = [];
var midline = 0;
var touchKeys = [];
var allKeys = [];
var topKeys = airKeys;
var bottomKeys = touchKeys;
const compileKey = (key) => {
const prev = key.previousElementSibling;
const next = key.nextElementSibling;
return {
top: key.offsetTop,
bottom: key.offsetTop + key.offsetHeight,
left: key.offsetLeft,
right: key.offsetLeft + key.offsetWidth,
almostLeft: !!prev ? key.offsetLeft + key.offsetWidth / 4 : -99999,
almostRight: !!next ? key.offsetLeft + (key.offsetWidth * 3) / 4 : 99999,
kflag: parseInt(key.dataset.kflag) + (parseInt(key.dataset.air) ? 32 : 0),
isAir: parseInt(key.dataset.air) ? true : false,
prevKeyRef: prev,
prevKeyKflag: prev
? parseInt(prev.dataset.kflag) + (parseInt(prev.dataset.air) ? 32 : 0)
: null,
nextKeyRef: next,
nextKeyKflag: next
? parseInt(next.dataset.kflag) + (parseInt(next.dataset.air) ? 32 : 0)
: null,
ref: key,
};
};
const isInside = (x, y, compiledKey) => {
return (
compiledKey.left <= x &&
x < compiledKey.right &&
compiledKey.top <= y &&
y < compiledKey.bottom
);
};
const compileKeys = () => {
keys = document.getElementsByClassName("key");
airKeys = [];
touchKeys = [];
for (var i = 0, key; i < keys.length; i++) {
const compiledKey = compileKey(keys[i]);
if (!compiledKey.isAir) {
touchKeys.push(compiledKey);
} else {
airKeys.push(compiledKey);
}
allKeys.push(compiledKey);
}
if (!config.invert) {
// Not inverted
topKeys = airKeys;
bottomKeys = touchKeys;
midline = touchKeys[0].top;
} else {
// Inverted
topKeys = touchKeys;
bottomKeys = airKeys;
midline = touchKeys[0].bottom;
}
};
const getKey = (x, y) => {
if (y < midline) {
for (var i = 0; i < topKeys.length; i++) {
if (isInside(x, y, topKeys[i])) return topKeys[i];
}
} else {
for (var i = 0; i < bottomKeys.length; i++) {
if (isInside(x, y, bottomKeys[i])) {
return bottomKeys[i];
}
}
}
return null;
};
// Button State
// prettier-ignore
var lastState = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
function updateTouches(e) {
try {
e.preventDefault();
// prettier-ignore
var keyFlags = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
throttledRequestFullscreen();
for (var i = 0; i < e.touches.length; i++) {
const touch = e.touches[i];
const x = touch.clientX;
const y = touch.clientY;
const key = getKey(x, y);
if (!key) continue;
setKey(keyFlags, key.kflag, key.isAir);
if (key.isAir) continue;
if (x < key.almostLeft) {
setKey(keyFlags, key.prevKeyKflag, false);
}
if (key.almostRight < x) {
setKey(keyFlags, key.nextKeyKflag, false);
}
}
// Render keys
for (var i = 0; i < allKeys.length; i++) {
const key = allKeys[i];
const kflag = key.kflag;
if (keyFlags[kflag] !== lastState[kflag]) {
if (keyFlags[kflag]) {
key.ref.setAttribute("data-active", "");
} else {
key.ref.removeAttribute("data-active");
}
}
}
if (keyFlags !== lastState) {
throttledSendKeys(keyFlags);
}
lastState = keyFlags;
} catch (err) {
alert(err);
}
}
const throttledUpdateTouches = throttle(updateTouches, 10);
const setKey = (keyFlags, kflag, isAir) => {
var idx = kflag;
if (keyFlags[idx] && !isAir) {
idx++;
}
keyFlags[idx] = 1;
};
const sendKeys = (keyFlags) => {
if (wsConnected) {
ws.send("b" + keyFlags.join(""));
}
};
const throttledSendKeys = throttle(sendKeys, 10);
// Websockets
var ws = null;
var wsTimeout = 0;
var wsConnected = false;
const wsConnect = () => {
ws = new WebSocket("ws://" + location.host + "/ws");
ws.binaryType = "arraybuffer";
ws.onopen = () => {
ws.send("alive?");
};
ws.onmessage = (e) => {
if (e.data.byteLength) {
updateLed(e.data);
} else if (e.data == "alive") {
wsTimeout = 0;
wsConnected = true;
}
};
};
const wsWatch = () => {
if (wsTimeout++ > 2) {
wsTimeout = 0;
ws.close();
wsConnected = false;
wsConnect();
return;
}
if (wsConnected) {
ws.send("alive?");
}
};
// Canvas vars
var canvas = document.getElementById("canvas");
var canvasCtx = canvas.getContext("2d");
var canvasData = canvasCtx.getImageData(0, 0, 33, 1);
const setupLed = () => {
for (var i = 0; i < 33; i++) {
canvasData.data[i * 4 + 3] = 255;
}
};
setupLed();
const updateLed = (data) => {
const buf = new Uint8Array(data);
for (var i = 0; i < 31; i++) {
canvasData.data[i * 4 + 4] = buf[i * 3]; // r
canvasData.data[i * 4 + 5] = buf[i * 3 + 1]; // g
canvasData.data[i * 4 + 6] = buf[i * 3 + 2]; // b
}
canvasData.data[0] = buf[0]
canvasData.data[1] = buf[1]
canvasData.data[2] = buf[2]
canvasData.data[128] = buf[90];
canvasData.data[129] = buf[91];
canvasData.data[130] = buf[92];
canvasCtx.putImageData(canvasData, 0, 0);
};
// Fullscreener
const fs = document.getElementById("fullscreen");
const requestFullscreen = () => {
if (!document.fullscreenElement && screen.height <= 1024) {
if (fs.requestFullscreen) {
fs.requestFullscreen();
} else if (fs.mozRequestFullScreen) {
fs.mozRequestFullScreen();
} else if (fs.webkitRequestFullScreen) {
fs.webkitRequestFullScreen();
}
}
};
const throttledRequestFullscreen = throttle(requestFullscreen, 3000);
// Do update hooks
const cnt = document.getElementById("main");
cnt.addEventListener("touchstart", updateTouches);
cnt.addEventListener("touchmove", updateTouches);
cnt.addEventListener("touchend", updateTouches);
// cnt.addEventListener("touchstart", throttledUpdateTouches);
// cnt.addEventListener("touchmove", throttledUpdateTouches);
// cnt.addEventListener("touchend", throttledUpdateTouches);
// Load config
const readConfig = (config) => {
var style = "";
if (!!config.invert) {
style += `.container, .air-container {flex-flow: column-reverse nowrap;} `;
}
var bgColor = config.bgColor || "rbga(0, 0, 0, 0.9)";
if (!config.bgImage) {
style += `#fullscreen {background: ${bgColor};} `;
} else {
style += `#fullscreen {background: ${bgColor} url("${config.bgImage}") fixed center / cover!important; background-repeat: no-repeat;} `;
}
if (typeof config.ledOpacity === "number") {
if (config.ledOpacity === 0) {
style += `#canvas {display: none} `;
} else {
style += `#canvas {opacity: ${config.ledOpacity}} `;
}
}
if (typeof config.keyColor === "string") {
style += `.key[data-active] {background-color: ${config.keyColor};} `;
}
if (typeof config.keyColor === "string") {
style += `.key.air[data-active] {background-color: ${config.lkeyColor};} `;
}
if (typeof config.keyBorderColor === "string") {
style += `.key {border: 1px solid ${config.keyBorderColor};} `;
}
if (!!config.keyColorFade && typeof config.keyColorFade === "number") {
style += `.key:not([data-active]) {transition: background ${config.keyColorFade}ms ease-out;} `;
}
if (typeof config.keyHeight === "number") {
if (config.keyHeight === 0) {
style += `.touch-container {display: none;} `;
} else {
style += `.touch-container {flex: ${config.keyHeight};} `;
}
}
if (typeof config.lkeyHeight === "number") {
if (config.lkeyHeight === 0) {
style += `.air-container {display: none;} `;
} else {
style += `.air-container {flex: ${config.keyHeight};} `;
}
}
var styleRef = document.createElement("style");
styleRef.innerHTML = style;
document.head.appendChild(styleRef);
};
// Initialize
const initialize = () => {
readConfig(config);
compileKeys();
wsConnect();
setInterval(wsWatch, 1000);
};
initialize();
// Update keys on resize
window.onresize = compileKeys;

View File

@@ -8,16 +8,14 @@ use hyper::{
Body, Method, Request, Response, Server, StatusCode,
};
use log::{error, info};
use path_clean::PathClean;
use std::{convert::Infallible, env::current_exe, future::Future, net::SocketAddr};
use phf::phf_map;
use std::{convert::Infallible, future::Future, net::SocketAddr};
use tokio::{
fs::File,
select,
sync::mpsc,
time::{sleep, Duration},
};
use tokio_tungstenite::WebSocketStream;
use tokio_util::codec::{BytesCodec, FramedRead};
use tungstenite::{handshake, Message};
use crate::slider_io::{controller_state::FullState, worker::AsyncJob};
@@ -33,23 +31,37 @@ async fn error_response() -> Result<Response<Body>, Infallible> {
)
}
// static x: &'static [u8] = include_bytes!("./brokenithm-www/favicon.ico");
static BROKENITHM_FILES: phf::Map<&'static str, &'static [u8]> = phf_map! {
"app.js" => include_bytes!("./brokenithm-www/app.js"),
"config.js" => include_bytes!("./brokenithm-www/config.js"),
"favicon.ico" => include_bytes!("./brokenithm-www/favicon.ico"),
"index-go.html" => include_bytes!("./brokenithm-www/index-go.html"),
"index.html" => include_bytes!("./brokenithm-www/index.html"),
};
async fn serve_file(path: &str) -> Result<Response<Body>, Infallible> {
let mut pb = current_exe().unwrap();
pb.pop();
pb.push("res/www");
pb.push(path);
pb.clean();
// let mut pb = current_exe().unwrap();
// pb.pop();
// pb.push("res/www");
// pb.push(path);
// pb.clean();
// println!("CWD {:?}", std::env::current_dir());
// // println!("CWD {:?}", std::env::current_dir());
match File::open(&pb).await {
Ok(f) => {
info!("Serving file {:?}", pb);
let stream = FramedRead::new(f, BytesCodec::new());
let body = Body::wrap_stream(stream);
Ok(Response::new(body))
}
Err(_) => error_response().await,
// match File::open(&pb).await {
// Ok(f) => {
// info!("Serving file {:?}", pb);
// let stream = FramedRead::new(f, BytesCodec::new());
// let body = Body::wrap_stream(stream);
// Ok(Response::new(body))
// }
// Err(_) => error_response().await,
// }
match BROKENITHM_FILES.get(path) {
Some(x) => Ok(Response::new(Body::from(*x))),
None => error_response().await,
}
}

View File

@@ -23,7 +23,7 @@ pub enum DeviceMode {
pub enum OutputPolling {
Sixty,
Hundred,
ThreeHundred,
TwoHundredFifty,
FiveHundred,
Thousand,
}
@@ -33,7 +33,7 @@ impl OutputPolling {
match s {
"60" => Some(OutputPolling::Sixty),
"100" => Some(OutputPolling::Hundred),
"330" => Some(OutputPolling::ThreeHundred),
"250" => Some(OutputPolling::TwoHundredFifty),
"500" => Some(OutputPolling::FiveHundred),
"1000" => Some(OutputPolling::Thousand),
_ => None,
@@ -42,11 +42,11 @@ impl OutputPolling {
pub fn to_t_u64(&self) -> u64 {
match self {
OutputPolling::Sixty => 16,
OutputPolling::Hundred => 10,
OutputPolling::ThreeHundred => 3,
OutputPolling::FiveHundred => 2,
OutputPolling::Thousand => 1,
OutputPolling::Sixty => 16666,
OutputPolling::Hundred => 10000,
OutputPolling::TwoHundredFifty => 4000,
OutputPolling::FiveHundred => 2000,
OutputPolling::Thousand => 1000,
}
}
}

View File

@@ -3,7 +3,6 @@ use palette::{FromColor, Hsv, Srgb};
use serialport::{ClearBuffer, SerialPort};
use std::{
ops::DerefMut,
thread,
time::{Duration, Instant},
};
@@ -218,7 +217,7 @@ impl ThreadJob for LedJob {
);
}
// thread::sleep(Duration::from_millis(30));
spin_sleep::sleep(Duration::from_millis(30));
spin_sleep::sleep(Duration::from_micros(33333));
true
}

View File

@@ -1,4 +1,4 @@
use std::{thread, time::Duration};
use std::time::Duration;
use crate::slider_io::{
config::OutputMode, controller_state::FullState, gamepad::GamepadOutput,
@@ -59,7 +59,7 @@ impl ThreadJob for OutputJob {
self.handler.tick(&flat_controller_state);
// thread::sleep(Duration::from_millis(self.t));
spin_sleep::sleep(Duration::from_millis(self.t));
spin_sleep::sleep(Duration::from_micros(self.t));
true
}