Merge branch 'ci-test-jsapi'

This commit is contained in:
MrZ_26
2024-11-03 01:43:54 +08:00
36 changed files with 594 additions and 478 deletions

BIN
.github/build/web/dev/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

112
.github/build/web/dev/index.html vendored Normal file
View File

@@ -0,0 +1,112 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, minimum-scale=1, maximum-scale=1">
<title>Techmino Development</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" type="text/css" href="theme/love.css">
<script src="consolewrapper.js"></script>
<script src="webdb.js"></script>
</head>
<body>
<center>
<div>
<h1>Techmino</h1>
<canvas id="loadingCanvas" oncontextmenu="event.preventDefault()" width="800" height="600"></canvas>
<canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
</div>
</center>
<script type='text/javascript'>
function goFullScreen(){
var canvas = document.getElementById("canvas");
if(canvas.requestFullScreen)
canvas.requestFullScreen();
else if(canvas.webkitRequestFullScreen)
canvas.webkitRequestFullScreen();
else if(canvas.mozRequestFullScreen)
canvas.mozRequestFullScreen();
}
function FullScreenHook(){
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
}
var loadingContext = document.getElementById('loadingCanvas').getContext('2d');
function drawLoadingText(text) {
var canvas = loadingContext.canvas;
loadingContext.fillStyle = "rgb(142, 195, 227)";
loadingContext.fillRect(0, 0, canvas.scrollWidth, canvas.scrollHeight);
loadingContext.font = '2em arial';
loadingContext.textAlign = 'center'
loadingContext.fillStyle = "rgb( 11, 86, 117 )";
loadingContext.fillText(text, canvas.scrollWidth / 2, canvas.scrollHeight / 2);
loadingContext.fillText("Powered By Emscripten.", canvas.scrollWidth / 2, canvas.scrollHeight / 4);
loadingContext.fillText("Powered By LÖVE.", canvas.scrollWidth / 2, canvas.scrollHeight / 4 * 3);
}
window.onload = function () { window.focus(); };
window.onclick = function () { window.focus(); };
window.addEventListener("keydown", function(e) {
// space and arrow keys
if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
e.preventDefault();
}
}, false);
var Module = {
arguments: ["./game.love"],
INITIAL_MEMORY: 128000000,
printErr: console.error.bind(console),
canvas: (function() {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {
if (text) {
drawLoadingText(text);
} else if (Module.remainingDependencies === 0) {
document.getElementById('loadingCanvas').style.display = 'none';
document.getElementById('canvas').style.visibility = 'visible';
}
},
totalDependencies: 0,
remainingDependencies: 0,
monitorRunDependencies: function(left) {
this.remainingDependencies = left;
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
};
Module.setStatus('Downloading...');
window.onerror = function(event) {
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
Module.setStatus('Exception thrown, see JavaScript console');
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
var applicationLoad = function(e) {
Love(Module);
}
</script>
<script type="text/javascript" src="game.js"></script>
<script async type="text/javascript" src="love.js" onload="applicationLoad(this)"></script>
<footer>
<p>Built with <a href="https://github.com/Davidobot/love.js">love.js</a> <button onclick="goFullScreen();">Go Fullscreen</button><br>Hint: Reload the page if screen is blank</p>
</footer>
</body>
</html>

View File

@@ -1,288 +0,0 @@
var Module;
if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
if (!Module.expectedDataFileDownloads) {
Module.expectedDataFileDownloads = 0;
Module.finishedDataFileDownloads = 0;
}
Module.expectedDataFileDownloads++;
(function() {
var loadPackage = function(metadata) {
var PACKAGE_PATH;
if (typeof window === 'object') {
PACKAGE_PATH = window['encodeURIComponent'](window.location.pathname.toString().substring(0, window.location.pathname.toString().lastIndexOf('/')) + '/');
} else if (typeof location !== 'undefined') {
// worker
PACKAGE_PATH = encodeURIComponent(location.pathname.toString().substring(0, location.pathname.toString().lastIndexOf('/')) + '/');
} else {
throw 'using preloaded data can only be done on a web page or in a web worker';
}
var PACKAGE_NAME = 'game.data';
var REMOTE_PACKAGE_BASE = 'game.data';
if (typeof Module['locateFilePackage'] === 'function' && !Module['locateFile']) {
Module['locateFile'] = Module['locateFilePackage'];
Module.printErr('warning: you defined Module.locateFilePackage, that has been renamed to Module.locateFile (using your locateFilePackage for now)');
}
var REMOTE_PACKAGE_NAME = typeof Module['locateFile'] === 'function' ?
Module['locateFile'](REMOTE_PACKAGE_BASE) :
((Module['filePackagePrefixURL'] || '') + REMOTE_PACKAGE_BASE);
var REMOTE_PACKAGE_SIZE = metadata.remote_package_size;
var PACKAGE_UUID = metadata.package_uuid;
function fetchRemotePackage(packageName, packageSize, callback, errback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', packageName, true);
xhr.responseType = 'arraybuffer';
xhr.onprogress = function(event) {
var url = packageName;
var size = packageSize;
if (event.total) size = event.total;
if (event.loaded) {
if (!xhr.addedTotal) {
xhr.addedTotal = true;
if (!Module.dataFileDownloads) Module.dataFileDownloads = {};
Module.dataFileDownloads[url] = {
loaded: event.loaded,
total: size
};
} else {
Module.dataFileDownloads[url].loaded = event.loaded;
}
var total = 0;
var loaded = 0;
var num = 0;
for (var download in Module.dataFileDownloads) {
var data = Module.dataFileDownloads[download];
total += data.total;
loaded += data.loaded;
num++;
}
total = Math.ceil(total * Module.expectedDataFileDownloads/num);
if (Module['setStatus']) Module['setStatus']('Downloading data... (' + loaded + '/' + total + ')');
} else if (!Module.dataFileDownloads) {
if (Module['setStatus']) Module['setStatus']('Downloading data...');
}
};
xhr.onerror = function(event) {
throw new Error("NetworkError for: " + packageName);
}
xhr.onload = function(event) {
if (xhr.status == 200 || xhr.status == 304 || xhr.status == 206 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
var packageData = xhr.response;
callback(packageData);
} else {
throw new Error(xhr.statusText + " : " + xhr.responseURL);
}
};
xhr.send(null);
};
function handleError(error) {
console.error('package error:', error);
};
function runWithFS() {
function assert(check, msg) {
if (!check) throw msg + new Error().stack;
}
function DataRequest(start, end, crunched, audio) {
this.start = start;
this.end = end;
this.crunched = crunched;
this.audio = audio;
}
DataRequest.prototype = {
requests: {},
open: function(mode, name) {
this.name = name;
this.requests[name] = this;
Module['addRunDependency']('fp ' + this.name);
},
send: function() {},
onload: function() {
var byteArray = this.byteArray.subarray(this.start, this.end);
this.finish(byteArray);
},
finish: function(byteArray) {
var that = this;
Module['FS_createDataFile'](this.name, null, byteArray, true, true, true); // canOwn this data in the filesystem, it is a slide into the heap that will never change
Module['removeRunDependency']('fp ' + that.name);
this.requests[this.name] = null;
}
};
var files = metadata.files;
for (i = 0; i < files.length; ++i) {
new DataRequest(files[i].start, files[i].end, files[i].crunched, files[i].audio).open('GET', files[i].filename);
}
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
var IDB_RO = "readonly";
var IDB_RW = "readwrite";
var DB_NAME = "EM_PRELOAD_CACHE";
var DB_VERSION = 1;
var METADATA_STORE_NAME = 'METADATA';
var PACKAGE_STORE_NAME = 'PACKAGES';
function openDatabase(callback, errback) {
try {
var openRequest = indexedDB.open(DB_NAME, DB_VERSION);
} catch (e) {
return errback(e);
}
openRequest.onupgradeneeded = function(event) {
var db = event.target.result;
if(db.objectStoreNames.contains(PACKAGE_STORE_NAME)) {
db.deleteObjectStore(PACKAGE_STORE_NAME);
}
var packages = db.createObjectStore(PACKAGE_STORE_NAME);
if(db.objectStoreNames.contains(METADATA_STORE_NAME)) {
db.deleteObjectStore(METADATA_STORE_NAME);
}
var metadata = db.createObjectStore(METADATA_STORE_NAME);
};
openRequest.onsuccess = function(event) {
var db = event.target.result;
callback(db);
};
openRequest.onerror = function(error) {
errback(error);
};
};
/* Check if there's a cached package, and if so whether it's the latest available */
function checkCachedPackage(db, packageName, callback, errback) {
var transaction = db.transaction([METADATA_STORE_NAME], IDB_RO);
var metadata = transaction.objectStore(METADATA_STORE_NAME);
var getRequest = metadata.get("metadata/" + packageName);
getRequest.onsuccess = function(event) {
var result = event.target.result;
if (!result) {
return callback(false);
} else {
return callback(PACKAGE_UUID === result.uuid);
}
};
getRequest.onerror = function(error) {
errback(error);
};
};
function fetchCachedPackage(db, packageName, callback, errback) {
var transaction = db.transaction([PACKAGE_STORE_NAME], IDB_RO);
var packages = transaction.objectStore(PACKAGE_STORE_NAME);
var getRequest = packages.get("package/" + packageName);
getRequest.onsuccess = function(event) {
var result = event.target.result;
callback(result);
};
getRequest.onerror = function(error) {
errback(error);
};
};
function cacheRemotePackage(db, packageName, packageData, packageMeta, callback, errback) {
var transaction_packages = db.transaction([PACKAGE_STORE_NAME], IDB_RW);
var packages = transaction_packages.objectStore(PACKAGE_STORE_NAME);
var putPackageRequest = packages.put(packageData, "package/" + packageName);
putPackageRequest.onsuccess = function(event) {
var transaction_metadata = db.transaction([METADATA_STORE_NAME], IDB_RW);
var metadata = transaction_metadata.objectStore(METADATA_STORE_NAME);
var putMetadataRequest = metadata.put(packageMeta, "metadata/" + packageName);
putMetadataRequest.onsuccess = function(event) {
callback(packageData);
};
putMetadataRequest.onerror = function(error) {
errback(error);
};
};
putPackageRequest.onerror = function(error) {
errback(error);
};
};
function processPackageData(arrayBuffer) {
Module.finishedDataFileDownloads++;
assert(arrayBuffer, 'Loading data file failed.');
assert(arrayBuffer instanceof ArrayBuffer, 'bad input to processPackageData');
var byteArray = new Uint8Array(arrayBuffer);
var curr;
// copy the entire loaded file into a spot in the heap. Files will refer to slices in that. They cannot be freed though
// (we may be allocating before malloc is ready, during startup).
if (Module['SPLIT_MEMORY']) Module.printErr('warning: you should run the file packager with --no-heap-copy when SPLIT_MEMORY is used, otherwise copying into the heap may fail due to the splitting');
var ptr = Module['getMemory'](byteArray.length);
Module['HEAPU8'].set(byteArray, ptr);
DataRequest.prototype.byteArray = Module['HEAPU8'].subarray(ptr, ptr+byteArray.length);
var files = metadata.files;
for (i = 0; i < files.length; ++i) {
DataRequest.prototype.requests[files[i].filename].onload();
}
Module['removeRunDependency']('datafile_game.data');
};
Module['addRunDependency']('datafile_game.data');
if (!Module.preloadResults) Module.preloadResults = {};
function preloadFallback(error) {
console.error(error);
console.error('falling back to default preload behavior');
fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE, processPackageData, handleError);
};
openDatabase(
function(db) {
checkCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME,
function(useCached) {
Module.preloadResults[PACKAGE_NAME] = {fromCache: useCached};
if (useCached) {
console.info('loading ' + PACKAGE_NAME + ' from cache');
fetchCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME, processPackageData, preloadFallback);
} else {
console.info('loading ' + PACKAGE_NAME + ' from remote');
fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE,
function(packageData) {
cacheRemotePackage(db, PACKAGE_PATH + PACKAGE_NAME, packageData, {uuid:PACKAGE_UUID}, processPackageData,
function(error) {
console.error(error);
processPackageData(packageData);
});
}
, preloadFallback);
}
}
, preloadFallback);
}
, preloadFallback);
if (Module['setStatus']) Module['setStatus']('Downloading...');
}
if (Module['calledRun']) {
runWithFS();
} else {
if (!Module['preRun']) Module['preRun'] = [];
Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it
}
}
loadPackage({"package_uuid":"80826f15-f924-4428-a8c4-e984743417c6","remote_package_size":62246034,"files":[{"filename":"/game.love","crunched":0,"start":0,"end":62246034,"audio":false}]});
})();

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 305 KiB

After

Width:  |  Height:  |  Size: 305 KiB

View File

@@ -5,9 +5,10 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, minimum-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, minimum-scale=1, maximum-scale=1">
<title>Techmino</title> <title>Techmino</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!-- Load custom style sheet -->
<link rel="stylesheet" type="text/css" href="theme/love.css"> <link rel="stylesheet" type="text/css" href="theme/love.css">
<script src="consolewrapper.js"></script>
<script src="webdb.js"></script>
</head> </head>
<body> <body>
<center> <center>
@@ -61,7 +62,7 @@
var Module = { var Module = {
arguments: ["./game.love"], arguments: ["./game.love"],
INITIAL_MEMORY: 536870912, INITIAL_MEMORY: 128000000,
printErr: console.error.bind(console), printErr: console.error.bind(console),
canvas: (function() { canvas: (function() {
var canvas = document.getElementById('canvas'); var canvas = document.getElementById('canvas');

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -1,49 +0,0 @@
* {
box-sizing: border-box;
}
h1 {
font-family: arial;
color: rgb( 11, 86, 117 );
}
body {
background-image: url(bg.png);
background-repeat: no-repeat;
font-family: arial;
margin: 0;
padding: none;
background-color: rgb( 154, 205, 237 );
color: rgb( 28, 78, 104 );
}
footer {
font-family: arial;
font-size: 12px;
padding-left: 10px;
position:absolute;
bottom: 0;
width: 100%;
}
/* Links */
a {
text-decoration: none;
}
a:link {
color: rgb( 233, 73, 154 );
}
a:visited {
color: rgb( 110, 30, 71 );
}
a:hover {
color: rgb( 252, 207, 230 );
}
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
#canvas {
padding-right: 0;
display: block;
border: 0px none;
visibility: hidden;
}

View File

@@ -136,35 +136,36 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: Love actions for testing # - name: Love actions for testing
uses: love-actions/love-actions-test@v1 # uses: love-actions/love-actions-test@v1
with: # with:
font-path: ./parts/fonts/proportional.otf # font-path: ./parts/fonts/proportional.otf
language-folder: ./parts/language # language-folder: ./parts/language
- name: Download core love package # - name: Download core love package
uses: actions/download-artifact@v3 # uses: actions/download-artifact@v3
with: # with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }} # name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Download love # - name: Download love
shell: bash # shell: bash
run: | # run: |
curl -OL --retry 5 https://github.com/love2d/love/releases/download/11.4/love-11.4-x86_64.AppImage # curl -OL --retry 5 https://github.com/love2d/love/releases/download/11.4/love-11.4-x86_64.AppImage
chmod +x love-11.4-x86_64.AppImage # chmod +x love-11.4-x86_64.AppImage
- name: Prepare PulseAudio and AppImage # - name: Prepare PulseAudio and AppImage
shell: bash # shell: bash
run: | # run: |
sudo apt-get update # sudo apt-get update
sudo apt-get install pulseaudio pulseaudio-utils pavucontrol alsa-oss alsa-utils libfuse2 -y # sudo apt-get install pulseaudio pulseaudio-utils pavucontrol alsa-oss alsa-utils libfuse2 -y
- name: Run automated test # - name: Run automated test
uses: coactions/setup-xvfb@v1 # uses: coactions/setup-xvfb@v1
with: # with:
run: | # run: |
./love-11.4-x86_64.AppImage ${{ env.CORE_LOVE_PACKAGE_PATH }} --test # ./love-11.4-x86_64.AppImage ${{ env.CORE_LOVE_PACKAGE_PATH }} --test
build-android: build-android:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
if: github.event_name != 'pull_request' # if: github.event_name != 'pull_request'
if: ${{ !always()}}
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release
@@ -237,6 +238,7 @@ jobs:
build-linux: build-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
if: ${{ !always()}}
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release
@@ -320,7 +322,8 @@ jobs:
build-macos-portable: build-macos-portable:
runs-on: macos-latest runs-on: macos-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
if: github.event_name != 'pull_request' # if: github.event_name != 'pull_request'
if: ${{ !always()}}
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build
RELEASE_FOLDER: ./release RELEASE_FOLDER: ./release
@@ -423,6 +426,9 @@ jobs:
build-web: build-web:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
env:
MEMORY_LIMIT: 128000000
OUTPUT_FOLDER: ./build
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@@ -431,25 +437,38 @@ jobs:
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
with: with:
name: ${{ env.CORE_LOVE_ARTIFACT_NAME }} name: ${{ env.CORE_LOVE_ARTIFACT_NAME }}
- name: Move core love package - name: Build web packages
run: | run: |
mv ${{ env.CORE_LOVE_PACKAGE_PATH }} ./.github/build/web/game.data npx love.js ${{ env.CORE_LOVE_PACKAGE_PATH }} ${{ env.OUTPUT_FOLDER }} -t "${{ needs.get-info.outputs.app-name }}" -m ${{ env.MEMORY_LIMIT }} -c
- name: Deploy to GitHub Pages - name: Move assets
uses: crazy-max/ghaction-github-pages@v3 run: |
env: mv ./.github/build/web/${{ env.BUILD_TYPE }}/* ${{ env.OUTPUT_FOLDER }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Initialize Love.js Api Player
with: run: |
build_dir: ./.github/build/web/ pushd ${{ env.OUTPUT_FOLDER }}
keep_history: false wget https://raw.githubusercontent.com/MrcSnm/Love.js-Api-Player/refs/heads/master/consolewrapper.js
target_branch: web-dev wget https://raw.githubusercontent.com/MrcSnm/Love.js-Api-Player/refs/heads/master/globalizeFS.js
wget https://raw.githubusercontent.com/MrcSnm/Love.js-Api-Player/refs/heads/master/webdb.js
node globalizeFS.js
rm globalizeFS.js
popd
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: ${{ needs.get-info.outputs.base-name }}_Web_PWA name: ${{ needs.get-info.outputs.base-name }}_Web
path: ./.github/build/web/ path: ${{ env.OUTPUT_FOLDER }}
- name: Deploy to GitHub Pages
uses: crazy-max/ghaction-github-pages@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
build_dir: ${{ env.OUTPUT_FOLDER }}
keep_history: false
target_branch: gh-pages
build-windows: build-windows:
runs-on: windows-latest runs-on: windows-latest
if: ${{ !always()}}
needs: [get-info, build-core, auto-test] needs: [get-info, build-core, auto-test]
env: env:
OUTPUT_FOLDER: ./build OUTPUT_FOLDER: ./build

103
Zframework/clipboard.lua Normal file
View File

@@ -0,0 +1,103 @@
local function _sanitize(content)
if type(content)=='boolean' then
content=content and 'true' or 'false'
end
if type(content)=='nil' then
content=''
end
if type(content)=='number' then
content=tostring(content)
end
if type(content)~='string' then
MES.new('error',"Invalid content type!")
MES.traceback()
return ''
end
return content
end
if SYSTEM~='Web' then
local get=love.system.getClipboardText
local set=love.system.setClipboardText
return {
get=function() return get() or '' end,
set=function(content) set(_sanitize(content)) end,
setFreshInterval=NULL,
_update=NULL,
}
end
if WEB_COMPAT_MODE then
local _clipboardBuffer=''
return {
get=function()
JS.newPromiseRequest(
JS.stringFunc(
[[
window.navigator.clipboard
.readText()
.then((text) => _$_(text))
.catch((e) => {
console.warn(e);
_$_('');
});
]]
),
function(data) _clipboardBuffer=data end,
function() _clipboardBuffer='' end,
3,
'getClipboardText'
)
if TASK.lock('clipboard_compat_interval',2.6) then
_clipboardBuffer=''
MES.new('warn',"Web-Compat mode, paste again to confirm",2.6)
end
return _clipboardBuffer
end,
set=function(str)
JS.callJS(JS.stringFunc(
[[
window.navigator.clipboard
.writeText('%s')
.then(() => console.log('Copied to clipboard'))
.catch((e) => console.warn(e));
]],
_sanitize(str)
))
end,
setFreshInterval=NULL,
_update=NULL,
}
end
local getCHN=love.thread.getChannel('CLIP_get')
local setCHN=love.thread.getChannel('CLIP_set')
local trigCHN=love.thread.getChannel('CLIP_trig')
local clipboard_thread=love.thread.newThread('Zframework/clipboard_thread.lua')
local isStarted,errorMessage=clipboard_thread:start()
if not isStarted then
MES.new("error",errorMessage,26)
end
local freshInterval=1
local timer=-.626
return {
get=function() return getCHN:peek() or '' end,
set=function(content) setCHN:push(_sanitize(content)) end,
setFreshInterval=function(val)
freshInterval=val
end,
_update=function(dt)
timer=timer+dt
if timer>freshInterval then
if isStarted and not clipboard_thread:isRunning() then
MES.new("warn",clipboard_thread:getError(),26)
isStarted=false
end
trigCHN:push(timer)
timer=0
end
end,
}

View File

@@ -0,0 +1,48 @@
local getCHN=love.thread.getChannel('CLIP_get')
local setCHN=love.thread.getChannel('CLIP_set')
local trigCHN=love.thread.getChannel('CLIP_trig')
JS=require'Zframework.js'
local sleep=require'love.timer'.sleep
local retrieving=false
while true do
if trigCHN:getCount()>0 then
local dt = trigCHN:pop()
if setCHN:getCount()>0 then
while setCHN:getCount()>1 do setCHN:pop() end
-- Set Clipboard
JS.callJS(JS.stringFunc(
[[
window.navigator.clipboard
.writeText('%s')
.then(() => console.log('Copied to clipboard'))
.catch((e) => console.warn(e));
]],
setCHN:pop()
))
end
-- Get Clipboard
if not retrieving then
JS.newPromiseRequest(
JS.stringFunc[[
window.navigator.clipboard
.readText()
.then((text) => _$_(text))
.catch((e)=>{});
]],
function(data)
while getCHN:getCount()>0 do getCHN:pop() end
getCHN:push(data)
retrieving=false
end,
function() retrieving=false end,
1,
'getClipboardText'
)
retrieving=true
end
JS.retrieveData(dt)
end
sleep(.001)
end

View File

@@ -1,5 +1,5 @@
local sendCHN=love.thread.getChannel('inputChannel') local sendCHN=love.thread.getChannel('HTTP_inputChannel')
local recvCHN=love.thread.getChannel('outputChannel') local recvCHN=love.thread.getChannel('HTTP_outputChannel')
local threads={} local threads={}
local threadCount=0 local threadCount=0
@@ -9,11 +9,15 @@ local threadCode=[[
local http=require'socket.http' local http=require'socket.http'
local ltn12=require'ltn12' local ltn12=require'ltn12'
local sendCHN=love.thread.getChannel('inputChannel') local sendCHN=love.thread.getChannel('HTTP_inputChannel')
local recvCHN=love.thread.getChannel('outputChannel') local recvCHN=love.thread.getChannel('HTTP_outputChannel')
local sleep=require'love.timer'.sleep
while true do while true do
local arg=sendCHN:demand() -- local arg=sendCHN:demand()
-- Warning: workaround for love.js
while sendCHN:getCount()==0 do sleep(.0626) end
local arg=sendCHN:pop()
if arg._destroy then if arg._destroy then
recvCHN:push{ recvCHN:push{

View File

@@ -3,8 +3,24 @@
NONE={}function NULL() end PAPER=love.graphics.newCanvas(1,1) NONE={}function NULL() end PAPER=love.graphics.newCanvas(1,1)
EDITING="" EDITING=""
LOADED=false LOADED=false
--[[
Available SYSTEM values:
Android
iOS
Linux
macOS
Web
Windows
]]--
SYSTEM=love.system.getOS() SYSTEM=love.system.getOS()
if SYSTEM=='OS X' then SYSTEM='macOS' end WEB_COMPAT_MODE=false
if SYSTEM=='OS X' then
SYSTEM='macOS'
elseif SYSTEM=='Web' then
WEB_COMPAT_MODE=not love.thread.newThread('\n'):start()
print('Web compatible mode: ', WEB_COMPAT_MODE)
end
-- Bit module -- Bit module
local success local success
@@ -72,6 +88,7 @@ do
end end
-- Love-based modules (basic) -- Love-based modules (basic)
CLIPBOARD= require'Zframework.clipboard'
HTTP= require'Zframework.http' HTTP= require'Zframework.http'
WS= require'Zframework.websocket' WS= require'Zframework.websocket'
FILE= require'Zframework.file' FILE= require'Zframework.file'
@@ -94,6 +111,10 @@ IMG= require'Zframework.image'
BGM= require'Zframework.bgm' BGM= require'Zframework.bgm'
VOC= require'Zframework.voice' VOC= require'Zframework.voice'
if SYSTEM=='Web' then
JS=require'Zframework.js'
end
local ms,kb=love.mouse,love.keyboard local ms,kb=love.mouse,love.keyboard
local KBisDown=kb.isDown local KBisDown=kb.isDown
@@ -174,6 +195,7 @@ local function updatePowerInfo()
gc_pop() gc_pop()
gc.setCanvas() gc.setCanvas()
end end
------------------------------------------------------------- -------------------------------------------------------------
local lastX,lastY=0,0-- Last click pos local lastX,lastY=0,0-- Last click pos
local function _updateMousePos(x,y,dx,dy) local function _updateMousePos(x,y,dx,dy)
@@ -423,38 +445,38 @@ local dPadToKey={
start='return', start='return',
back='escape', back='escape',
} }
function love.joystickadded(JS) function love.joystickadded(joystick)
table.insert(jsState,{ table.insert(jsState,{
_id=JS:getID(), _id=joystick:getID(),
_jsObj=JS, _jsObj=joystick,
leftx=0,lefty=0, leftx=0,lefty=0,
rightx=0,righty=0, rightx=0,righty=0,
triggerleft=0,triggerright=0 triggerleft=0,triggerright=0
}) })
MES.new('info',"Joystick added") MES.new('info',"Joystick added")
end end
function love.joystickremoved(JS) function love.joystickremoved(joystick)
for i=1,#jsState do for i=1,#jsState do
if jsState[i]._jsObj==JS then if jsState[i]._jsObj==joystick then
for j=1,#gamePadKeys do for j=1,#gamePadKeys do
if JS:isGamepadDown(gamePadKeys[j]) then if joystick:isGamepadDown(gamePadKeys[j]) then
love.gamepadreleased(JS,gamePadKeys[j]) love.gamepadreleased(joystick,gamePadKeys[j])
end end
end end
love.gamepadaxis(JS,'leftx',0) love.gamepadaxis(joystick,'leftx',0)
love.gamepadaxis(JS,'lefty',0) love.gamepadaxis(joystick,'lefty',0)
love.gamepadaxis(JS,'rightx',0) love.gamepadaxis(joystick,'rightx',0)
love.gamepadaxis(JS,'righty',0) love.gamepadaxis(joystick,'righty',0)
love.gamepadaxis(JS,'triggerleft',-1) love.gamepadaxis(joystick,'triggerleft',-1)
love.gamepadaxis(JS,'triggerright',-1) love.gamepadaxis(joystick,'triggerright',-1)
MES.new('info',"Joystick removed") MES.new('info',"Joystick removed")
table.remove(jsState,i) table.remove(jsState,i)
break break
end end
end end
end end
function love.gamepadaxis(JS,axis,val) function love.gamepadaxis(joystick,axis,val)
if jsState[1] and JS==jsState[1]._jsObj then if jsState[1] and joystick==jsState[1]._jsObj then
local js=jsState[1] local js=jsState[1]
if axis=='leftx' or axis=='lefty' or axis=='rightx' or axis=='righty' then if axis=='leftx' or axis=='lefty' or axis=='rightx' or axis=='righty' then
local newVal=-- range: [0,1] local newVal=-- range: [0,1]
@@ -463,14 +485,14 @@ function love.gamepadaxis(JS,axis,val)
0 0
if newVal~=js[axis] then if newVal~=js[axis] then
if js[axis]==-1 then if js[axis]==-1 then
love.gamepadreleased(JS,jsAxisEventName[axis][1]) love.gamepadreleased(joystick,jsAxisEventName[axis][1])
elseif js[axis]~=0 then elseif js[axis]~=0 then
love.gamepadreleased(JS,jsAxisEventName[axis][2]) love.gamepadreleased(joystick,jsAxisEventName[axis][2])
end end
if newVal==-1 then if newVal==-1 then
love.gamepadpressed(JS,jsAxisEventName[axis][1]) love.gamepadpressed(joystick,jsAxisEventName[axis][1])
elseif newVal==1 then elseif newVal==1 then
love.gamepadpressed(JS,jsAxisEventName[axis][2]) love.gamepadpressed(joystick,jsAxisEventName[axis][2])
end end
js[axis]=newVal js[axis]=newVal
end end
@@ -478,9 +500,9 @@ function love.gamepadaxis(JS,axis,val)
local newVal=val>.3 and 1 or 0-- range: [0,1] local newVal=val>.3 and 1 or 0-- range: [0,1]
if newVal~=js[axis] then if newVal~=js[axis] then
if newVal==1 then if newVal==1 then
love.gamepadpressed(JS,jsAxisEventName[axis]) love.gamepadpressed(joystick,jsAxisEventName[axis])
else else
love.gamepadreleased(JS,jsAxisEventName[axis]) love.gamepadreleased(joystick,jsAxisEventName[axis])
end end
js[axis]=newVal js[axis]=newVal
end end
@@ -720,6 +742,10 @@ function love.run()
-- UPDATE -- UPDATE
STEP() STEP()
if SYSTEM == 'Web' then
JS.retrieveData(dt)
CLIPBOARD._update(dt)
end
if mouseShow then mouse_update(dt) end if mouseShow then mouse_update(dt) end
if next(jsState) then gp_update(jsState[1],dt) end if next(jsState) then gp_update(jsState[1],dt) end
VOC.update() VOC.update()

148
Zframework/js.lua Normal file
View File

@@ -0,0 +1,148 @@
local __requestQueue={}
local _requestCount=0
local _Request=
{
command="",
currentTime=0,
timeOut=2,
id='0',
}
local __defaultErrorFunction=nil
local isDebugActive=false
local JS={}
function JS.callJS(funcToCall)
print("callJavascriptFunction "..funcToCall)
end
--You can pass a set of commands here and, it is a syntactic sugar for executing many commands inside callJS, as it only calls a function
--If you pass arguments to the func beyond the string, it will perform automatically string.format
--Return statement is possible inside this structure
--This will return a string containing a function to be called by JS.callJS
function JS.stringFunc(str,...)
str="(function(){"..str.."})()"
if (#arg>0) then
str=str:format(unpack(arg))
end
str=str:gsub("[\n\t]", "")
return str
end
--The call will store in the webDB the return value from the function passed
--it timeouts
local function retrieveJS(funcToCall,filename)
--Used for retrieveData function
JS.callJS(("FS.writeFile('%s/%s',%s);"):format(love.filesystem.getSaveDirectory(),filename,funcToCall))
end
--Call JS.newRequest instead
function _Request:new(isPromise,command,onDataLoaded,onError,timeout,id)
local obj={}
setmetatable(obj, self)
obj.command=command
obj.onError=onError or __defaultErrorFunction
if not isPromise then
retrieveJS(command, self.filename)
else
JS.callJS(command)
end
obj.onDataLoaded=onDataLoaded
obj.timeOut=(timeout==nil) and obj.timeOut or timeout
obj.id=id
obj.filename="__temp"..id
function obj:getData()
--Try to read from webdb
if love.filesystem.getInfo(self.filename) then
return love.filesystem.read(self.filename)
end
end
function obj:purgeData()
--Data must be purged for not allowing old data to be retrieved
love.filesystem.remove(self.filename)
end
function obj:update(dt)
self.timeOut=self.timeOut-dt
local retData=self:getData()
if ((retData~=nil and retData~="nil") or self.timeOut<=0) then
if (retData~=nil and retData:match("ERROR")==nil) then
if isDebugActive then
print("Data has been retrieved "..retData)
end
self.onDataLoaded(retData)
else
self.onError(self.id, retData)
end
self:purgeData()
return false
else
return true
end
end
return obj
end
--Place this function on love.update and set it to return if it returns false (This API is synchronous)
function JS.retrieveData(dt)
local isRetrieving=#__requestQueue~=0
local deadRequests={}
for i=1,#__requestQueue do
local isUpdating=__requestQueue[i]:update(dt)
if not isUpdating then
table.insert(deadRequests, i)
end
end
for i=1,#deadRequests do
if (isDebugActive) then
print("Request died: "..deadRequests[i])
end
table.remove(__requestQueue, deadRequests[i])
end
return isRetrieving
end
--May only be used for functions that don't return a promise
function JS.newRequest(funcToCall,onDataLoaded,onError,timeout,optionalId)
table.insert(__requestQueue, _Request:new(false, funcToCall, onDataLoaded, onError, timeout or 5, optionalId or _requestCount))
end
--This function can be handled manually (in JS code)
--How to: add the function call when your events resolve: FS.writeFile("Put love.filesystem.getSaveDirectory here", "Pass a string here (NUMBER DONT WORK"))
--Or it can be handled by Lua, it auto sets your data if you write the following command:
-- _$_(yourStringOrFunctionHere)
function JS.newPromiseRequest(funcToCall,onDataLoaded,onError,timeout,optionalId)
optionalId=optionalId or _requestCount
funcToCall=funcToCall:gsub("_$_%(", "FS.writeFile('"..love.filesystem.getSaveDirectory().."/__temp"..optionalId.."', ")
table.insert(__requestQueue, _Request:new(true, funcToCall, onDataLoaded, onError, timeout or 5, optionalId))
end
--It receives the ID from ther request
--Don't try printing the request.command, as it will execute the javascript command
function JS.setDefaultErrorFunction(func)
__defaultErrorFunction=func
end
JS.setDefaultErrorFunction(function(id,error)
if (isDebugActive) then
local msg="Data could not be loaded for id:'"..id.."'"
if (error) then
msg=msg.."\nError: "..error
end
print(msg)
end
end)
JS.callJS(JS.stringFunc(
[[
__getWebDB("%s");
]]
, "__LuaJSDB"))
return JS

View File

@@ -140,7 +140,7 @@ function profile.switch()
switch=not switch switch=not switch
if not switch then if not switch then
profile.stop() profile.stop()
love.system.setClipboardText(profile.report()) CLIPBOARD.set(profile.report())
profile.reset() profile.reset()
return false return false
else else

View File

@@ -189,7 +189,7 @@ do-- functions to shorted big numbers
function STRING.bigInt(t) function STRING.bigInt(t)
if t<1000 then if t<1000 then
return tostring(t) return tostring(t)
elseif t~=1e999 then elseif t~=1/0 then
local e=floorint(lg(t)/3) local e=floorint(lg(t)/3)
return(t/10^(e*3))..units[e+1] return(t/10^(e*3))..units[e+1]
else else

View File

@@ -1,3 +1,4 @@
---@type love.Channel,love.Channel,love.Channel
local triggerCHN,sendCHN,readCHN=... local triggerCHN,sendCHN,readCHN=...
local CHN_demand,CHN_getCount=triggerCHN.demand,triggerCHN.getCount local CHN_demand,CHN_getCount=triggerCHN.demand,triggerCHN.getCount
@@ -5,13 +6,16 @@ local CHN_push,CHN_pop=triggerCHN.push,triggerCHN.pop
local SOCK=require'socket'.tcp() local SOCK=require'socket'.tcp()
local JSON=require'Zframework.json' local JSON=require'Zframework.json'
local sleep=require'love.timer'.sleep
do-- Connect do-- Connect
local host=CHN_demand(sendCHN) -- Warning: workaround for love.js, used to use CHN_demand instead
local port=CHN_demand(sendCHN) while CHN_getCount(sendCHN)<5 do sleep(.0626) end
local path=CHN_demand(sendCHN) local host=CHN_pop(sendCHN)
local head=CHN_demand(sendCHN) local port=CHN_pop(sendCHN)
local timeout=CHN_demand(sendCHN) local path=CHN_pop(sendCHN)
local head=CHN_pop(sendCHN)
local timeout=CHN_pop(sendCHN)
SOCK:settimeout(timeout) SOCK:settimeout(timeout)
local res,err=SOCK:connect(host,port) local res,err=SOCK:connect(host,port)
@@ -186,7 +190,8 @@ end)
local success,err local success,err
while true do-- Running while true do-- Running
CHN_demand(triggerCHN) while CHN_getCount(triggerCHN)==0 do sleep(.0626) end
CHN_pop(triggerCHN)
success,err=pcall(sendThread) success,err=pcall(sendThread)
if not success or err then break end if not success or err then break end
success,err=pcall(readThread) success,err=pcall(readThread)

View File

@@ -1,9 +1,9 @@
local OS=love._os local system=love._os
if OS=='OS X' then OS='macOS' end if system=='OS X' then system='macOS' end
MOBILE=OS=='Android' or OS=='iOS' MOBILE=system=='Android' or system=='iOS'
FNNS=OS:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol FNNS=system:find'\79\83' -- What does FNSF stand for? IDK so don't ask me lol
if OS=='Web' then if system=='Web' then
local oldRead=love.filesystem.read local oldRead=love.filesystem.read
function love.filesystem.read(name,size) function love.filesystem.read(name,size)
if love.filesystem.getInfo(name) then if love.filesystem.getInfo(name) then

View File

@@ -49,6 +49,10 @@ SCR.setSize(1280,720) -- Initialize Screen size
BGM.setMaxSources(5) BGM.setMaxSources(5)
VOC.setDiversion(.62) VOC.setDiversion(.62)
if SYSTEM == 'Web' and not WEB_COMPAT_MODE then
CLIPBOARD.setFreshInterval(.5)
end
WIDGET.setOnChange(function() WIDGET.setOnChange(function()
if SCN.cur=='net_game' or SCN.cur=='custom_field' then return end if SCN.cur=='net_game' or SCN.cur=='custom_field' then return end
local colorList=THEME.getThemeColor() local colorList=THEME.getThemeColor()

View File

@@ -330,20 +330,20 @@ local L={
}, },
cards={-- F0300 - F070F cards={-- F0300 - F070F
cardBack= 0xF0300, cardBack= 0xF0300,
clubA= 0xF0301, spadeA= 0xF0301,
club2= 0xF0302, spade2= 0xF0302,
club3= 0xF0303, spade3= 0xF0303,
club4= 0xF0304, spade4= 0xF0304,
club5= 0xF0305, spade5= 0xF0305,
club6= 0xF0306, spade6= 0xF0306,
club7= 0xF0307, spade7= 0xF0307,
club8= 0xF0308, spade8= 0xF0308,
club9= 0xF0309, spade9= 0xF0309,
club10= 0xF030A, spade10= 0xF030A,
clubJ= 0xF030B, spadeJ= 0xF030B,
clubC= 0xF030C, spadeC= 0xF030C,
clubQ= 0xF030D, spadeQ= 0xF030D,
clubK= 0xF030E, spadeK= 0xF030E,
heartA= 0xF0401, heartA= 0xF0401,
heart2= 0xF0402, heart2= 0xF0402,
heart3= 0xF0403, heart3= 0xF0403,

View File

@@ -1,3 +1,9 @@
if SYSTEM=='Web' then
return {
update=NULL
}
end
local appId='1288557386700951554' local appId='1288557386700951554'
local ffi=require"ffi" local ffi=require"ffi"
@@ -133,7 +139,7 @@ if RPC_C then
local function checkIntArg(arg,maxBits,argName,func,maybeNil) local function checkIntArg(arg,maxBits,argName,func,maybeNil)
maxBits=math.min(maxBits or 32,52) -- lua number (double) can only store integers < 2^53 maxBits=math.min(maxBits or 32,52) -- lua number (double) can only store integers < 2^53
local maxVal=2^(maxBits-1) -- assuming signed integers, which, for now, are the only ones in use local maxVal=2^(maxBits-1) -- assuming signed integers, which, for now, are the only ones in use
assert(type(arg)=="number" and math.floor(arg)==arg assert(type(arg)=="number" and math.floor(arg)==arg
and arg<maxVal and arg>=-maxVal and arg<maxVal and arg>=-maxVal
or (maybeNil and arg==nil), or (maybeNil and arg==nil),

View File

@@ -949,16 +949,16 @@ end
local combKey={ local combKey={
x=function() x=function()
love.system.setClipboardText(inputBox:getText()) CLIPBOARD.set(inputBox:getText())
inputBox:clear() inputBox:clear()
SFX.play('reach') SFX.play('reach')
end, end,
c=function() c=function()
love.system.setClipboardText(inputBox:getText()) CLIPBOARD.set(inputBox:getText())
SFX.play('reach') SFX.play('reach')
end, end,
v=function() v=function()
inputBox:addText(love.system.getClipboardText()) inputBox:addText(CLIPBOARD.get())
SFX.play('reach') SFX.play('reach')
end, end,
} }

View File

@@ -204,7 +204,7 @@ function scene.update(dt)
end end
ct=ct-1 ct=ct-1
if ct==0 then if ct==0 then
local t=love.system.getClipboardText() local t=CLIPBOARD.get()
if type(t)=='string' then if type(t)=='string' then
t=t:lower():match("^s=(%d+)$") t=t:lower():match("^s=(%d+)$")
t=t and tonumber(t) and tonumber(t)>0 and tonumber(t)<=8000 and floor(tonumber(t)) t=t and tonumber(t) and tonumber(t)>0 and tonumber(t)<=8000 and floor(tonumber(t))

View File

@@ -181,7 +181,7 @@ function reset()
time=0 time=0
score=0 score=0
local t=love.system.getClipboardText() local t=CLIPBOARD.get()
if type(t)=='string' then if type(t)=='string' then
t=t:lower():match("^s=(.+)") t=t:lower():match("^s=(.+)")
t=t and tonumber(t) and tonumber(t)*2 t=t and tonumber(t) and tonumber(t)*2

View File

@@ -188,10 +188,10 @@ function scene.keyDown(key,isRep)
if #CUSTOMGAME_LOCAL.bag>0 then str=str..DATA.copySequence(CUSTOMGAME_LOCAL.bag) end if #CUSTOMGAME_LOCAL.bag>0 then str=str..DATA.copySequence(CUSTOMGAME_LOCAL.bag) end
str=str.."!" str=str.."!"
if #CUSTOMGAME_LOCAL.mission>0 then str=str..DATA.copyMission(CUSTOMGAME_LOCAL.mission) end if #CUSTOMGAME_LOCAL.mission>0 then str=str..DATA.copyMission(CUSTOMGAME_LOCAL.mission) end
sys.setClipboardText(str.."!"..DATA.copyBoards(CUSTOMGAME_LOCAL.field).."!") CLIPBOARD.set(str.."!"..DATA.copyBoards(CUSTOMGAME_LOCAL.field).."!")
MES.new('check',text.exportSuccess) MES.new('check',text.exportSuccess)
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
local str=sys.getClipboardText() local str=CLIPBOARD.get()
local args=str:sub((str:find(":") or 0)+1):split("!") local args=str:sub((str:find(":") or 0)+1):split("!")
local hasTooHighField=false local hasTooHighField=false
repeat repeat

View File

@@ -226,10 +226,10 @@ function scene.keyDown(key)
SFX.play('clear_4',.8) SFX.play('clear_4',.8)
SFX.play('fall',.8) SFX.play('fall',.8)
elseif key=='c' and kb.isDown('lctrl','rctrl') or key=='cC' then elseif key=='c' and kb.isDown('lctrl','rctrl') or key=='cC' then
sys.setClipboardText("Techmino Field:"..DATA.copyBoard(FIELD[page])) CLIPBOARD.set("Techmino Field:"..DATA.copyBoard(FIELD[page]))
MES.new('check',text.exportSuccess) MES.new('check',text.exportSuccess)
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
local str=sys.getClipboardText() local str=CLIPBOARD.get()
local p=str:find(":")-- ptr* local p=str:find(":")-- ptr*
if p then if p then
if not str:sub(1,p-1):find("Field") then if not str:sub(1,p-1):find("Field") then

View File

@@ -68,11 +68,11 @@ function scene.keyDown(key)
end end
elseif key=='c' and kb.isDown('lctrl','rctrl') or key=='cC' then elseif key=='c' and kb.isDown('lctrl','rctrl') or key=='cC' then
if #MISSION>0 then if #MISSION>0 then
sys.setClipboardText("Techmino Target:"..DATA.copyMission(MISSION)) CLIPBOARD.set("Techmino Target:"..DATA.copyMission(MISSION))
MES.new('check',text.exportSuccess) MES.new('check',text.exportSuccess)
end end
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
local str=sys.getClipboardText() local str=CLIPBOARD.get()
local p=str:find(":")-- ptr* local p=str:find(":")-- ptr*
if p then if p then
if not str:sub(1,p-1):find("Target") then if not str:sub(1,p-1):find("Target") then

View File

@@ -1,4 +1,3 @@
local sys=love.system
local kb=love.keyboard local kb=love.keyboard
local sin=math.sin local sin=math.sin
@@ -76,11 +75,11 @@ function scene.keyDown(key)
scene.widgetList.sequence:scroll(kb.isDown('lshift','rshift') and -1 or 1) scene.widgetList.sequence:scroll(kb.isDown('lshift','rshift') and -1 or 1)
elseif key=='c' and kb.isDown('lctrl','rctrl') or key=='cC' then elseif key=='c' and kb.isDown('lctrl','rctrl') or key=='cC' then
if #BAG>0 then if #BAG>0 then
sys.setClipboardText("Techmino SEQ:"..DATA.copySequence(BAG)) CLIPBOARD.set("Techmino SEQ:"..DATA.copySequence(BAG))
MES.new('check',text.exportSuccess) MES.new('check',text.exportSuccess)
end end
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
local str=sys.getClipboardText() local str=CLIPBOARD.get()
local p=str:find(":")-- ptr* local p=str:find(":")-- ptr*
if p then if p then
if not str:sub(1,p-1):find("SEQ") then if not str:sub(1,p-1):find("SEQ") then

View File

@@ -124,7 +124,7 @@ end
local function _copy() local function _copy()
local t=_getList()[listBox.selected] local t=_getList()[listBox.selected]
t=t.title_Org..":\n"..t.content_Org..(t.url and "\n[ "..t.url.." ]\n" or "\n")..text.dictNote t=t.title_Org..":\n"..t.content_Org..(t.url and "\n[ "..t.url.." ]\n" or "\n")..text.dictNote
love.system.setClipboardText(t) CLIPBOARD.set(t)
scene.widgetList.copy.hide=true scene.widgetList.copy.hide=true
MES.new('info',text.copyDone) MES.new('info',text.copyDone)
end end

View File

@@ -14,7 +14,7 @@ local function _submit()
end end
end end
local function _paste() local function _paste()
local t=love.system.getClipboardText() local t=CLIPBOARD.get()
if t then if t then
t=STRING.trim(t) t=STRING.trim(t)
if #t==128 and t:match("[0-9A-Z]+") then if #t==128 and t:match("[0-9A-Z]+") then

View File

@@ -97,7 +97,7 @@ function scene.keyDown(key)
if rep.available and rep.fileName then if rep.available and rep.fileName then
local repStr=loadFile(rep.fileName,'-string') local repStr=loadFile(rep.fileName,'-string')
if repStr then if repStr then
love.system.setClipboardText(love.data.encode('string','base64',repStr)) CLIPBOARD.set(love.data.encode('string','base64',repStr))
MES.new('info',text.exportSuccess) MES.new('info',text.exportSuccess)
else else
MES.new('error',text.replayBroken) MES.new('error',text.replayBroken)
@@ -107,7 +107,7 @@ function scene.keyDown(key)
end end
end end
elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then elseif key=='v' and kb.isDown('lctrl','rctrl') or key=='cV' then
local repStr=love.system.getClipboardText() local repStr=CLIPBOARD.get()
local res,fileData=pcall(love.data.decode,'string','base64',repStr) local res,fileData=pcall(love.data.decode,'string','base64',repStr)
if res then if res then
local fileName=os.date("replay/%Y_%m_%d_%H%M%S_import.rep") local fileName=os.date("replay/%Y_%m_%d_%H%M%S_import.rep")

View File

@@ -15,7 +15,7 @@ local function _setPW()
end end
end end
local function _paste() local function _paste()
local t=love.system.getClipboardText() local t=CLIPBOARD.get()
if t then if t then
t=STRING.trim(t) t=STRING.trim(t)
if #t==8 and t:match("[0-9]+") then if #t==8 and t:match("[0-9]+") then

View File

@@ -7,12 +7,12 @@ function scene.enter()
end end
local function _dumpCB(T) local function _dumpCB(T)
love.system.setClipboardText(STRING.packText(TABLE.dump(T))) CLIPBOARD.set(STRING.packText(TABLE.dump(T)))
MES.new('check',text.exportSuccess) MES.new('check',text.exportSuccess)
end end
local function _parseCB() local function _parseCB()
local _ local _
local s=love.system.getClipboardText() local s=CLIPBOARD.get()
-- Decode -- Decode
s=STRING.unpackText(s) s=STRING.unpackText(s)

View File

@@ -136,7 +136,7 @@ scene.widgetList={
}, },
WIDGET.newKey{name='bg_custom_base64',x=1010,y=1502.5,w=420,h=135,align='M', WIDGET.newKey{name='bg_custom_base64',x=1010,y=1502.5,w=420,h=135,align='M',
code=function() code=function()
local okay,data=pcall(love.data.decode,"data","base64",love.system.getClipboardText()) local okay,data=pcall(love.data.decode,"data","base64",CLIPBOARD.get())
if okay and pcall(gc.newImage,data) then if okay and pcall(gc.newImage,data) then
love.filesystem.write('conf/customBG',data) love.filesystem.write('conf/customBG',data)
SETTING.bg='custom' SETTING.bg='custom'

View File

@@ -164,7 +164,7 @@ scene.widgetList={
textBox, textBox,
WIDGET.newButton {name='home',x=1140,y= 90,w=170,h=80,sound='click',font=60,fText=CHAR.key.macHome,code=pressKey('home')}, WIDGET.newButton {name='home',x=1140,y= 90,w=170,h=80,sound='click',font=60,fText=CHAR.key.macHome,code=pressKey('home')},
WIDGET.newButton {name='endd',x=1140,y=190,w=170,h=80,sound='click',font=60,fText=CHAR.key.macEnd ,code=pressKey('end')}, WIDGET.newButton {name='endd',x=1140,y=190,w=170,h=80,sound='click',font=60,fText=CHAR.key.macEnd ,code=pressKey('end')},
WIDGET.newButton {name='copy',x=1140,y=290,w=170,h=80,sound='click',font=60,fText=CHAR.icon.copy ,code=function()love.system.setClipboardText(table.concat(textBox.texts,'\n'))end,color='lC'}, WIDGET.newButton {name='copy',x=1140,y=290,w=170,h=80,sound='click',font=60,fText=CHAR.icon.copy ,code=function()CLIPBOARD.set(table.concat(textBox.texts,'\n'))end,color='lC'},
logList, logList,