Initial commit with .gitignore
This commit is contained in:
commit
b19e63f847
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with Litmus
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
# vendor/
|
||||||
|
|
||||||
|
# Go workspace file
|
||||||
|
go.work
|
||||||
|
|
||||||
|
# Wails
|
||||||
|
frontend/dist/
|
||||||
|
build/bin/
|
||||||
|
kvmote_debug.log
|
||||||
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Wails: Debug Backend (Go)",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "${workspaceRoot}",
|
||||||
|
"buildFlags": "-tags desktop,debug",
|
||||||
|
"args": [],
|
||||||
|
"env": {
|
||||||
|
"WAILS_DEBUG": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"go.buildTags": "desktop,debug",
|
||||||
|
"go.lintFlags": ["--tags", "desktop,debug"]
|
||||||
|
}
|
||||||
128
CLAUDE.md
Normal file
128
CLAUDE.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# CLAUDE.md — KVMote (Go/Wails)
|
||||||
|
|
||||||
|
Reescrita em Go do KVMote (original em C#/WinForms em `C:\vscode\KVMote`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## O que é
|
||||||
|
|
||||||
|
KVM over Bluetooth/BLE. Controla PC remoto (cliente) a partir do host usando microcontrolador como HID USB. **Sem software no PC cliente.**
|
||||||
|
|
||||||
|
```
|
||||||
|
Host PC ──BLE NUS──► ESP32-S3 ──USB HID──► Cliente PC (sem sw)
|
||||||
|
```
|
||||||
|
|
||||||
|
Hardware suportado: ESP32-S3 (BLE NUS) e Arduino Leonardo + HC-06 (Serial SPP). Ver CLAUDE.md do projeto C# para detalhes de hardware e firmware.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
- **Go 1.23** + **Wails v2** (webview desktop)
|
||||||
|
- **tinygo.org/x/bluetooth** — BLE via WinRT
|
||||||
|
- **golang.org/x/sys/windows** — hooks globais (WH_MOUSE_LL, WH_KEYBOARD_LL)
|
||||||
|
- **github.com/atotto/clipboard** — leitura de clipboard
|
||||||
|
- Frontend: HTML estático em `frontend/dist/` (sem framework JS)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Estrutura
|
||||||
|
|
||||||
|
```
|
||||||
|
main.go — entry point Wails, bind App
|
||||||
|
app.go — App struct, métodos expostos ao frontend
|
||||||
|
internal/
|
||||||
|
transport/
|
||||||
|
transport.go — interface Transport (Detect/Connect/Send/SendLossy...)
|
||||||
|
ble_windows.go — BLE NUS via tinygo/bluetooth
|
||||||
|
kvm/
|
||||||
|
engine.go — lógica KVM: mouse, teclado, clipboard, modo cliente
|
||||||
|
input/
|
||||||
|
input.go — interface InputHandler + tipos (Point, MouseEvent, KeyboardEvent)
|
||||||
|
input_windows.go — hooks Win32, SetCursorPos, ShowCursor, GetSystemMetrics
|
||||||
|
frontend/
|
||||||
|
dist/index.html — UI
|
||||||
|
wails.json — config Wails
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Protocolo binário (Host → Dispositivo)
|
||||||
|
|
||||||
|
Idêntico ao projeto C#:
|
||||||
|
|
||||||
|
| Cmd | Bytes | Ação |
|
||||||
|
|-----|-------|------|
|
||||||
|
| `M` dx dy | 3 | Mouse move (int8) |
|
||||||
|
| `W` delta | 2 | Scroll (int8) |
|
||||||
|
| `K` char | 2 | Keyboard.write |
|
||||||
|
| `P` key | 2 | Keyboard.press |
|
||||||
|
| `U` key | 2 | Keyboard.release |
|
||||||
|
| `A` | 1 | releaseAll |
|
||||||
|
| `C` L\|R | 2 | Click |
|
||||||
|
| `D` L\|R | 2 | Mouse press |
|
||||||
|
| `E` L\|R | 2 | Mouse release |
|
||||||
|
| `T` lenH lenL data | 3+N | Clipboard batch (Go-specific) |
|
||||||
|
| `O` | 1 | LED magenta (modo cliente) |
|
||||||
|
| `H` | 1 | LED azul (host conectado) |
|
||||||
|
| `G` | 1 | LED verde (desconectado) |
|
||||||
|
| `~` | 1 | Ping → `[PONG]` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lógica KVM (engine.go)
|
||||||
|
|
||||||
|
- **Entrada modo cliente:** cursor atinge borda configurada → esconde cursor, warp centro, acumula deltas (técnica FPS)
|
||||||
|
- **Retorno ao host:** coordenadas virtuais cruzam `-ReturnThreshold` (120px) na direção de entrada
|
||||||
|
- **Debounce:** 800ms anti-bounce após troca de modo
|
||||||
|
- **Mouse throttle:** 40ms (~25 pacotes/s)
|
||||||
|
- **Scroll:** `scrollActive` suprime warp por 200ms durante scroll (evita cancelar gesto touchpad)
|
||||||
|
- **Clipboard:** Ctrl+C no host seta `clipboardReady`, Ctrl+V em modo cliente envia via comando `T` (batch)
|
||||||
|
- **Ctrl+Alt+Del:** sequência P/U com delay 50ms
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hooks Win32 (input_windows.go)
|
||||||
|
|
||||||
|
- `runtime.LockOSThread()` obrigatório — hooks Win32 exigem message pump na mesma thread
|
||||||
|
- Loop `GetMessageW` mantém thread viva
|
||||||
|
- `Uninstall()` via `PostThreadMessageW(WM_QUIT)`
|
||||||
|
- `SetProcessDPIAware` chamado no init()
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Dev
|
||||||
|
wails dev
|
||||||
|
|
||||||
|
# Produção
|
||||||
|
wails build
|
||||||
|
```
|
||||||
|
|
||||||
|
Saída: `build/bin/kvmote.exe`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Diferenças do projeto C#
|
||||||
|
|
||||||
|
| Aspecto | C# (WinForms) | Go (Wails) |
|
||||||
|
|---------|---------------|------------|
|
||||||
|
| UI | WinForms nativo | Webview (HTML) |
|
||||||
|
| Transporte | Serial + BLE (dual) | Só BLE (por enquanto) |
|
||||||
|
| Clipboard | char-a-char com delay | Batch via comando `T` |
|
||||||
|
| ClipboardMax | 500/1000 chars | 65536 chars |
|
||||||
|
| Scroll | acumulador _wheelAccum + _scrollActive | scrollActive only |
|
||||||
|
| ReturnThreshold | 15px | 120px |
|
||||||
|
| Reconexão | auto-reconnect loop | manual |
|
||||||
|
| Heartbeat/Watchdog | sim | não implementado |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Cuidados
|
||||||
|
|
||||||
|
- **Scroll touchpad:** `scrollActive` e `scrollTimer` não devem ser resetados em enter/exitClientMode
|
||||||
|
- **runtime.LockOSThread:** nunca remover da goroutine de hooks
|
||||||
|
- **isWarping flag:** previne loop infinito SetCursorPos → WM_MOUSEMOVE → SetCursorPos
|
||||||
|
- **Mutex ordering:** engine.mu protege todo estado KVM; transport.mu protege conexão BLE
|
||||||
78
app.go
Normal file
78
app.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"kvmote/internal/input"
|
||||||
|
"kvmote/internal/kvm"
|
||||||
|
"kvmote/internal/transport"
|
||||||
|
)
|
||||||
|
|
||||||
|
// App struct
|
||||||
|
type App struct {
|
||||||
|
ctx context.Context
|
||||||
|
engine *kvm.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewApp creates a new App application struct
|
||||||
|
func NewApp() *App {
|
||||||
|
t := transport.NewBleTransport()
|
||||||
|
h := input.NewInputHandler()
|
||||||
|
e := kvm.NewEngine(t, h)
|
||||||
|
return &App{
|
||||||
|
engine: e,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// startup is called when the app starts. The context is saved
|
||||||
|
// so we can call the runtime methods
|
||||||
|
func (a *App) startup(ctx context.Context) {
|
||||||
|
a.ctx = ctx
|
||||||
|
err := a.engine.Start(ctx)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error starting engine: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Connect() string {
|
||||||
|
err := a.engine.Start(a.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Erro Hook: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lógica real de conexão Bluetooth
|
||||||
|
ctx, cancel := context.WithTimeout(a.ctx, 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
ok, err := a.engine.Transport().Detect(ctx)
|
||||||
|
if err != nil || !ok {
|
||||||
|
return "Erro: KVMote não encontrado"
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.engine.Transport().Connect(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Erro Conexão: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Conectado"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Disconnect() string {
|
||||||
|
a.engine.Transport().Disconnect()
|
||||||
|
return "Desconectado"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) SendCtrlAltDel() {
|
||||||
|
kvm.LogDebug("App: Chamando SendCtrlAltDel")
|
||||||
|
a.engine.SendCtrlAltDel()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) ChangeLayout(layout int) {
|
||||||
|
a.engine.SetLayout(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) SetPosition(pos int) {
|
||||||
|
a.engine.SetPosition(pos)
|
||||||
|
}
|
||||||
BIN
build/appicon.png
Normal file
BIN
build/appicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
BIN
build/windows/icon.ico
Normal file
BIN
build/windows/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
15
build/windows/info.json
Normal file
15
build/windows/info.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"fixed": {
|
||||||
|
"file_version": "{{.Info.ProductVersion}}"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"0000": {
|
||||||
|
"ProductVersion": "{{.Info.ProductVersion}}",
|
||||||
|
"CompanyName": "{{.Info.CompanyName}}",
|
||||||
|
"FileDescription": "{{.Info.ProductName}}",
|
||||||
|
"LegalCopyright": "{{.Info.Copyright}}",
|
||||||
|
"ProductName": "{{.Info.ProductName}}",
|
||||||
|
"Comments": "{{.Info.Comments}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
build/windows/wails.exe.manifest
Normal file
15
build/windows/wails.exe.manifest
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<assemblyIdentity type="win32" name="com.wails.{{.Name}}" version="{{.Info.ProductVersion}}.0" processorArchitecture="*"/>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<asmv3:application>
|
||||||
|
<asmv3:windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> <!-- fallback for Windows 7 and 8 -->
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness> <!-- falls back to per-monitor if per-monitor v2 is not supported -->
|
||||||
|
</asmv3:windowsSettings>
|
||||||
|
</asmv3:application>
|
||||||
|
</assembly>
|
||||||
226
frontend/dist/index.html
vendored
Normal file
226
frontend/dist/index.html
vendored
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pt-br">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>KVMote</title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
|
||||||
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg-color: #121212;
|
||||||
|
--card-bg: #1e1e1e;
|
||||||
|
--text-color: #e0e0e0;
|
||||||
|
--accent-color: #3273dc;
|
||||||
|
--border-color: #333;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.app-container {
|
||||||
|
padding: 20px;
|
||||||
|
max-width: 400px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.section-title {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #888;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
/* Monitor Cross Layout */
|
||||||
|
.monitor-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
grid-template-rows: repeat(3, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
width: 240px;
|
||||||
|
margin: 0 auto 30px auto;
|
||||||
|
}
|
||||||
|
.monitor-btn {
|
||||||
|
background-color: #333;
|
||||||
|
border: 1px solid #444;
|
||||||
|
color: #bbb;
|
||||||
|
padding: 10px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.monitor-btn:hover { background-color: #444; }
|
||||||
|
.monitor-btn.active {
|
||||||
|
background-color: #2c3e50;
|
||||||
|
border-color: #3498db;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.host-pc {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 2;
|
||||||
|
background-color: #1a2a3a;
|
||||||
|
border: 1px solid var(--accent-color);
|
||||||
|
color: #3498db;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-label { font-size: 0.85rem; color: #aaa; margin-bottom: 5px; }
|
||||||
|
.control-panel { background: var(--card-bg); padding: 15px; border-radius: 4px; border: 1px solid var(--border-color); }
|
||||||
|
|
||||||
|
.status-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: #1a1a1a;
|
||||||
|
padding: 5px 15px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #666;
|
||||||
|
border-top: 1px solid #222;
|
||||||
|
}
|
||||||
|
.status-dot { height: 8px; width: 8px; border-radius: 50%; display: inline-block; margin-right: 8px; }
|
||||||
|
|
||||||
|
/* Custom UI components */
|
||||||
|
.custom-select {
|
||||||
|
width: 100%;
|
||||||
|
background: #252525;
|
||||||
|
color: white;
|
||||||
|
border: 1px solid #444;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.btn-action {
|
||||||
|
background: #333;
|
||||||
|
border: 1px solid #444;
|
||||||
|
color: white;
|
||||||
|
padding: 8px;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.btn-action:hover { background: #444; }
|
||||||
|
.btn-connect {
|
||||||
|
background: var(--accent-color);
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.btn-cad { margin-top: 10px; background: #2a2a2a; color: #ccc; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body x-data="kvmApp()">
|
||||||
|
<div class="app-container">
|
||||||
|
<div class="section-title">Posição do PC Cliente:</div>
|
||||||
|
|
||||||
|
<div class="monitor-grid">
|
||||||
|
<!-- Top -->
|
||||||
|
<button class="monitor-btn" style="grid-column: 2; grid-row: 1;"
|
||||||
|
:class="pos === 'above' ? 'active' : ''" @click="setPos('above')">Acima</button>
|
||||||
|
|
||||||
|
<!-- Left -->
|
||||||
|
<button class="monitor-btn" style="grid-column: 1; grid-row: 2;"
|
||||||
|
:class="pos === 'left' ? 'active' : ''" @click="setPos('left')">Esquerda</button>
|
||||||
|
|
||||||
|
<!-- Center -->
|
||||||
|
<div class="host-pc">[HOST PC]</div>
|
||||||
|
|
||||||
|
<!-- Right -->
|
||||||
|
<button class="monitor-btn" style="grid-column: 3; grid-row: 2;"
|
||||||
|
:class="pos === 'right' ? 'active' : ''" @click="setPos('right')">Direita</button>
|
||||||
|
|
||||||
|
<!-- Bottom -->
|
||||||
|
<button class="monitor-btn" style="grid-column: 2; grid-row: 3;"
|
||||||
|
:class="pos === 'below' ? 'active' : ''" @click="setPos('below')">Abaixo</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="is-flex is-align-items-center mb-4" style="font-size: 0.85rem; color: #888;">
|
||||||
|
<span class="status-dot" :style="{ backgroundColor: detected ? '#3498db' : '#555' }"></span>
|
||||||
|
<span x-text="detected ? 'KVMote (BLE) detectado' : 'Buscando dispositivo...'"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="columns is-mobile is-gapless mb-2">
|
||||||
|
<div class="column pr-1">
|
||||||
|
<button class="btn-action" @click="detect()">Detectar</button>
|
||||||
|
</div>
|
||||||
|
<div class="column pl-1">
|
||||||
|
<button class="btn-action btn-connect" @click="toggleConnect()" x-text="connected ? 'Desconectar' : 'Conectar'"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field mb-4">
|
||||||
|
<div class="is-flex is-align-items-center is-justify-content-space-between">
|
||||||
|
<label class="field-label">Layout do cliente:</label>
|
||||||
|
<select class="custom-select" style="width: 60%;" x-model="layout" @change="setLayout()">
|
||||||
|
<option value="0">US / EN</option>
|
||||||
|
<option value="1">PT-BR ABNT2</option>
|
||||||
|
<option value="2">US International</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn-action btn-cad" @click="sendCAD()">Enviar Ctrl+Alt+Del</button>
|
||||||
|
|
||||||
|
<div class="field mt-4">
|
||||||
|
<div class="is-flex is-align-items-center is-justify-content-space-between">
|
||||||
|
<label class="field-label">Ao fechar:</label>
|
||||||
|
<select class="custom-select" style="width: 60%;">
|
||||||
|
<option value="tray">Minimizar para Tray</option>
|
||||||
|
<option value="exit">Fechar aplicação</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status-bar">
|
||||||
|
<span x-text="statusText"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function kvmApp() {
|
||||||
|
return {
|
||||||
|
connected: false,
|
||||||
|
detected: true,
|
||||||
|
statusText: 'Desconectado',
|
||||||
|
pos: 'right',
|
||||||
|
layout: 1,
|
||||||
|
toggleConnect() {
|
||||||
|
if (this.connected) {
|
||||||
|
window.go.main.App.Disconnect().then(res => {
|
||||||
|
this.connected = false;
|
||||||
|
this.statusText = res;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.go.main.App.Connect().then(res => {
|
||||||
|
this.connected = true;
|
||||||
|
this.statusText = 'Conectado';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setPos(p) {
|
||||||
|
this.pos = p;
|
||||||
|
const map = { 'left': 1, 'right': 2, 'above': 3, 'below': 4 };
|
||||||
|
window.go.main.App.SetPosition(map[p]);
|
||||||
|
},
|
||||||
|
setLayout() {
|
||||||
|
window.go.main.App.ChangeLayout(parseInt(this.layout));
|
||||||
|
},
|
||||||
|
sendCAD() {
|
||||||
|
window.go.main.App.SendCtrlAltDel();
|
||||||
|
},
|
||||||
|
detect() {
|
||||||
|
// Chamar detecção no backend
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
frontend/dist/placeholder.txt
vendored
Normal file
BIN
frontend/dist/placeholder.txt
vendored
Normal file
Binary file not shown.
12
frontend/src/wailsjs/wailsjs/go/main/App.d.ts
vendored
Normal file
12
frontend/src/wailsjs/wailsjs/go/main/App.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
export function ChangeLayout(arg1:number):Promise<void>;
|
||||||
|
|
||||||
|
export function Connect():Promise<string>;
|
||||||
|
|
||||||
|
export function Disconnect():Promise<string>;
|
||||||
|
|
||||||
|
export function SendCtrlAltDel():Promise<void>;
|
||||||
|
|
||||||
|
export function SetPosition(arg1:number):Promise<void>;
|
||||||
23
frontend/src/wailsjs/wailsjs/go/main/App.js
Normal file
23
frontend/src/wailsjs/wailsjs/go/main/App.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// @ts-check
|
||||||
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
|
export function ChangeLayout(arg1) {
|
||||||
|
return window['go']['main']['App']['ChangeLayout'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Connect() {
|
||||||
|
return window['go']['main']['App']['Connect']();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Disconnect() {
|
||||||
|
return window['go']['main']['App']['Disconnect']();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SendCtrlAltDel() {
|
||||||
|
return window['go']['main']['App']['SendCtrlAltDel']();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SetPosition(arg1) {
|
||||||
|
return window['go']['main']['App']['SetPosition'](arg1);
|
||||||
|
}
|
||||||
24
frontend/src/wailsjs/wailsjs/runtime/package.json
Normal file
24
frontend/src/wailsjs/wailsjs/runtime/package.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@wailsapp/runtime",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"description": "Wails Javascript runtime library",
|
||||||
|
"main": "runtime.js",
|
||||||
|
"types": "runtime.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/wailsapp/wails.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"Wails",
|
||||||
|
"Javascript",
|
||||||
|
"Go"
|
||||||
|
],
|
||||||
|
"author": "Lea Anthony <lea.anthony@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/wailsapp/wails/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/wailsapp/wails#readme"
|
||||||
|
}
|
||||||
330
frontend/src/wailsjs/wailsjs/runtime/runtime.d.ts
vendored
Normal file
330
frontend/src/wailsjs/wailsjs/runtime/runtime.d.ts
vendored
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The electron alternative for Go
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface Position {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Size {
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Screen {
|
||||||
|
isCurrent: boolean;
|
||||||
|
isPrimary: boolean;
|
||||||
|
width : number
|
||||||
|
height : number
|
||||||
|
}
|
||||||
|
|
||||||
|
// Environment information such as platform, buildtype, ...
|
||||||
|
export interface EnvironmentInfo {
|
||||||
|
buildType: string;
|
||||||
|
platform: string;
|
||||||
|
arch: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
|
||||||
|
// emits the given event. Optional data may be passed with the event.
|
||||||
|
// This will trigger any event listeners.
|
||||||
|
export function EventsEmit(eventName: string, ...data: any): void;
|
||||||
|
|
||||||
|
// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
|
||||||
|
export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
|
||||||
|
|
||||||
|
// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
|
||||||
|
// sets up a listener for the given event name, but will only trigger a given number times.
|
||||||
|
export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
|
||||||
|
|
||||||
|
// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
|
||||||
|
// sets up a listener for the given event name, but will only trigger once.
|
||||||
|
export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
|
||||||
|
|
||||||
|
// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
|
||||||
|
// unregisters the listener for the given event name.
|
||||||
|
export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
|
||||||
|
|
||||||
|
// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
|
||||||
|
// unregisters all listeners.
|
||||||
|
export function EventsOffAll(): void;
|
||||||
|
|
||||||
|
// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
|
||||||
|
// logs the given message as a raw message
|
||||||
|
export function LogPrint(message: string): void;
|
||||||
|
|
||||||
|
// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
|
||||||
|
// logs the given message at the `trace` log level.
|
||||||
|
export function LogTrace(message: string): void;
|
||||||
|
|
||||||
|
// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
|
||||||
|
// logs the given message at the `debug` log level.
|
||||||
|
export function LogDebug(message: string): void;
|
||||||
|
|
||||||
|
// [LogError](https://wails.io/docs/reference/runtime/log#logerror)
|
||||||
|
// logs the given message at the `error` log level.
|
||||||
|
export function LogError(message: string): void;
|
||||||
|
|
||||||
|
// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
|
||||||
|
// logs the given message at the `fatal` log level.
|
||||||
|
// The application will quit after calling this method.
|
||||||
|
export function LogFatal(message: string): void;
|
||||||
|
|
||||||
|
// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
|
||||||
|
// logs the given message at the `info` log level.
|
||||||
|
export function LogInfo(message: string): void;
|
||||||
|
|
||||||
|
// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
|
||||||
|
// logs the given message at the `warning` log level.
|
||||||
|
export function LogWarning(message: string): void;
|
||||||
|
|
||||||
|
// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
|
||||||
|
// Forces a reload by the main application as well as connected browsers.
|
||||||
|
export function WindowReload(): void;
|
||||||
|
|
||||||
|
// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
|
||||||
|
// Reloads the application frontend.
|
||||||
|
export function WindowReloadApp(): void;
|
||||||
|
|
||||||
|
// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop)
|
||||||
|
// Sets the window AlwaysOnTop or not on top.
|
||||||
|
export function WindowSetAlwaysOnTop(b: boolean): void;
|
||||||
|
|
||||||
|
// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
|
||||||
|
// *Windows only*
|
||||||
|
// Sets window theme to system default (dark/light).
|
||||||
|
export function WindowSetSystemDefaultTheme(): void;
|
||||||
|
|
||||||
|
// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
|
||||||
|
// *Windows only*
|
||||||
|
// Sets window to light theme.
|
||||||
|
export function WindowSetLightTheme(): void;
|
||||||
|
|
||||||
|
// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
|
||||||
|
// *Windows only*
|
||||||
|
// Sets window to dark theme.
|
||||||
|
export function WindowSetDarkTheme(): void;
|
||||||
|
|
||||||
|
// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
|
||||||
|
// Centers the window on the monitor the window is currently on.
|
||||||
|
export function WindowCenter(): void;
|
||||||
|
|
||||||
|
// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
|
||||||
|
// Sets the text in the window title bar.
|
||||||
|
export function WindowSetTitle(title: string): void;
|
||||||
|
|
||||||
|
// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
|
||||||
|
// Makes the window full screen.
|
||||||
|
export function WindowFullscreen(): void;
|
||||||
|
|
||||||
|
// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
|
||||||
|
// Restores the previous window dimensions and position prior to full screen.
|
||||||
|
export function WindowUnfullscreen(): void;
|
||||||
|
|
||||||
|
// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
|
||||||
|
// Returns the state of the window, i.e. whether the window is in full screen mode or not.
|
||||||
|
export function WindowIsFullscreen(): Promise<boolean>;
|
||||||
|
|
||||||
|
// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
|
||||||
|
// Sets the width and height of the window.
|
||||||
|
export function WindowSetSize(width: number, height: number): void;
|
||||||
|
|
||||||
|
// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
|
||||||
|
// Gets the width and height of the window.
|
||||||
|
export function WindowGetSize(): Promise<Size>;
|
||||||
|
|
||||||
|
// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
|
||||||
|
// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
|
||||||
|
// Setting a size of 0,0 will disable this constraint.
|
||||||
|
export function WindowSetMaxSize(width: number, height: number): void;
|
||||||
|
|
||||||
|
// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
|
||||||
|
// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
|
||||||
|
// Setting a size of 0,0 will disable this constraint.
|
||||||
|
export function WindowSetMinSize(width: number, height: number): void;
|
||||||
|
|
||||||
|
// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
|
||||||
|
// Sets the window position relative to the monitor the window is currently on.
|
||||||
|
export function WindowSetPosition(x: number, y: number): void;
|
||||||
|
|
||||||
|
// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
|
||||||
|
// Gets the window position relative to the monitor the window is currently on.
|
||||||
|
export function WindowGetPosition(): Promise<Position>;
|
||||||
|
|
||||||
|
// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
|
||||||
|
// Hides the window.
|
||||||
|
export function WindowHide(): void;
|
||||||
|
|
||||||
|
// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
|
||||||
|
// Shows the window, if it is currently hidden.
|
||||||
|
export function WindowShow(): void;
|
||||||
|
|
||||||
|
// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
|
||||||
|
// Maximises the window to fill the screen.
|
||||||
|
export function WindowMaximise(): void;
|
||||||
|
|
||||||
|
// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
|
||||||
|
// Toggles between Maximised and UnMaximised.
|
||||||
|
export function WindowToggleMaximise(): void;
|
||||||
|
|
||||||
|
// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
|
||||||
|
// Restores the window to the dimensions and position prior to maximising.
|
||||||
|
export function WindowUnmaximise(): void;
|
||||||
|
|
||||||
|
// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
|
||||||
|
// Returns the state of the window, i.e. whether the window is maximised or not.
|
||||||
|
export function WindowIsMaximised(): Promise<boolean>;
|
||||||
|
|
||||||
|
// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
|
||||||
|
// Minimises the window.
|
||||||
|
export function WindowMinimise(): void;
|
||||||
|
|
||||||
|
// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
|
||||||
|
// Restores the window to the dimensions and position prior to minimising.
|
||||||
|
export function WindowUnminimise(): void;
|
||||||
|
|
||||||
|
// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
|
||||||
|
// Returns the state of the window, i.e. whether the window is minimised or not.
|
||||||
|
export function WindowIsMinimised(): Promise<boolean>;
|
||||||
|
|
||||||
|
// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
|
||||||
|
// Returns the state of the window, i.e. whether the window is normal or not.
|
||||||
|
export function WindowIsNormal(): Promise<boolean>;
|
||||||
|
|
||||||
|
// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
|
||||||
|
// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
|
||||||
|
export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
|
||||||
|
|
||||||
|
// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
|
||||||
|
// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
|
||||||
|
export function ScreenGetAll(): Promise<Screen[]>;
|
||||||
|
|
||||||
|
// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
|
||||||
|
// Opens the given URL in the system browser.
|
||||||
|
export function BrowserOpenURL(url: string): void;
|
||||||
|
|
||||||
|
// [Environment](https://wails.io/docs/reference/runtime/intro#environment)
|
||||||
|
// Returns information about the environment
|
||||||
|
export function Environment(): Promise<EnvironmentInfo>;
|
||||||
|
|
||||||
|
// [Quit](https://wails.io/docs/reference/runtime/intro#quit)
|
||||||
|
// Quits the application.
|
||||||
|
export function Quit(): void;
|
||||||
|
|
||||||
|
// [Hide](https://wails.io/docs/reference/runtime/intro#hide)
|
||||||
|
// Hides the application.
|
||||||
|
export function Hide(): void;
|
||||||
|
|
||||||
|
// [Show](https://wails.io/docs/reference/runtime/intro#show)
|
||||||
|
// Shows the application.
|
||||||
|
export function Show(): void;
|
||||||
|
|
||||||
|
// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
|
||||||
|
// Returns the current text stored on clipboard
|
||||||
|
export function ClipboardGetText(): Promise<string>;
|
||||||
|
|
||||||
|
// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
|
||||||
|
// Sets a text on the clipboard
|
||||||
|
export function ClipboardSetText(text: string): Promise<boolean>;
|
||||||
|
|
||||||
|
// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop)
|
||||||
|
// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
||||||
|
export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void
|
||||||
|
|
||||||
|
// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff)
|
||||||
|
// OnFileDropOff removes the drag and drop listeners and handlers.
|
||||||
|
export function OnFileDropOff() :void
|
||||||
|
|
||||||
|
// Check if the file path resolver is available
|
||||||
|
export function CanResolveFilePaths(): boolean;
|
||||||
|
|
||||||
|
// Resolves file paths for an array of files
|
||||||
|
export function ResolveFilePaths(files: File[]): void
|
||||||
|
|
||||||
|
// Notification types
|
||||||
|
export interface NotificationOptions {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
subtitle?: string; // macOS and Linux only
|
||||||
|
body?: string;
|
||||||
|
categoryId?: string;
|
||||||
|
data?: { [key: string]: any };
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotificationAction {
|
||||||
|
id?: string;
|
||||||
|
title?: string;
|
||||||
|
destructive?: boolean; // macOS-specific
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotificationCategory {
|
||||||
|
id?: string;
|
||||||
|
actions?: NotificationAction[];
|
||||||
|
hasReplyField?: boolean;
|
||||||
|
replyPlaceholder?: string;
|
||||||
|
replyButtonTitle?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [InitializeNotifications](https://wails.io/docs/reference/runtime/notification#initializenotifications)
|
||||||
|
// Initializes the notification service for the application.
|
||||||
|
// This must be called before sending any notifications.
|
||||||
|
export function InitializeNotifications(): Promise<void>;
|
||||||
|
|
||||||
|
// [CleanupNotifications](https://wails.io/docs/reference/runtime/notification#cleanupnotifications)
|
||||||
|
// Cleans up notification resources and releases any held connections.
|
||||||
|
export function CleanupNotifications(): Promise<void>;
|
||||||
|
|
||||||
|
// [IsNotificationAvailable](https://wails.io/docs/reference/runtime/notification#isnotificationavailable)
|
||||||
|
// Checks if notifications are available on the current platform.
|
||||||
|
export function IsNotificationAvailable(): Promise<boolean>;
|
||||||
|
|
||||||
|
// [RequestNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#requestnotificationauthorization)
|
||||||
|
// Requests notification authorization from the user (macOS only).
|
||||||
|
export function RequestNotificationAuthorization(): Promise<boolean>;
|
||||||
|
|
||||||
|
// [CheckNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#checknotificationauthorization)
|
||||||
|
// Checks the current notification authorization status (macOS only).
|
||||||
|
export function CheckNotificationAuthorization(): Promise<boolean>;
|
||||||
|
|
||||||
|
// [SendNotification](https://wails.io/docs/reference/runtime/notification#sendnotification)
|
||||||
|
// Sends a basic notification with the given options.
|
||||||
|
export function SendNotification(options: NotificationOptions): Promise<void>;
|
||||||
|
|
||||||
|
// [SendNotificationWithActions](https://wails.io/docs/reference/runtime/notification#sendnotificationwithactions)
|
||||||
|
// Sends a notification with action buttons. Requires a registered category.
|
||||||
|
export function SendNotificationWithActions(options: NotificationOptions): Promise<void>;
|
||||||
|
|
||||||
|
// [RegisterNotificationCategory](https://wails.io/docs/reference/runtime/notification#registernotificationcategory)
|
||||||
|
// Registers a notification category that can be used with SendNotificationWithActions.
|
||||||
|
export function RegisterNotificationCategory(category: NotificationCategory): Promise<void>;
|
||||||
|
|
||||||
|
// [RemoveNotificationCategory](https://wails.io/docs/reference/runtime/notification#removenotificationcategory)
|
||||||
|
// Removes a previously registered notification category.
|
||||||
|
export function RemoveNotificationCategory(categoryId: string): Promise<void>;
|
||||||
|
|
||||||
|
// [RemoveAllPendingNotifications](https://wails.io/docs/reference/runtime/notification#removeallpendingnotifications)
|
||||||
|
// Removes all pending notifications from the notification center.
|
||||||
|
export function RemoveAllPendingNotifications(): Promise<void>;
|
||||||
|
|
||||||
|
// [RemovePendingNotification](https://wails.io/docs/reference/runtime/notification#removependingnotification)
|
||||||
|
// Removes a specific pending notification by its identifier.
|
||||||
|
export function RemovePendingNotification(identifier: string): Promise<void>;
|
||||||
|
|
||||||
|
// [RemoveAllDeliveredNotifications](https://wails.io/docs/reference/runtime/notification#removealldeliverednotifications)
|
||||||
|
// Removes all delivered notifications from the notification center.
|
||||||
|
export function RemoveAllDeliveredNotifications(): Promise<void>;
|
||||||
|
|
||||||
|
// [RemoveDeliveredNotification](https://wails.io/docs/reference/runtime/notification#removedeliverednotification)
|
||||||
|
// Removes a specific delivered notification by its identifier.
|
||||||
|
export function RemoveDeliveredNotification(identifier: string): Promise<void>;
|
||||||
|
|
||||||
|
// [RemoveNotification](https://wails.io/docs/reference/runtime/notification#removenotification)
|
||||||
|
// Removes a notification by its identifier (cross-platform convenience function).
|
||||||
|
export function RemoveNotification(identifier: string): Promise<void>;
|
||||||
298
frontend/src/wailsjs/wailsjs/runtime/runtime.js
Normal file
298
frontend/src/wailsjs/wailsjs/runtime/runtime.js
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The electron alternative for Go
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function LogPrint(message) {
|
||||||
|
window.runtime.LogPrint(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LogTrace(message) {
|
||||||
|
window.runtime.LogTrace(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LogDebug(message) {
|
||||||
|
window.runtime.LogDebug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LogInfo(message) {
|
||||||
|
window.runtime.LogInfo(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LogWarning(message) {
|
||||||
|
window.runtime.LogWarning(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LogError(message) {
|
||||||
|
window.runtime.LogError(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LogFatal(message) {
|
||||||
|
window.runtime.LogFatal(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EventsOnMultiple(eventName, callback, maxCallbacks) {
|
||||||
|
return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EventsOn(eventName, callback) {
|
||||||
|
return EventsOnMultiple(eventName, callback, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EventsOff(eventName, ...additionalEventNames) {
|
||||||
|
return window.runtime.EventsOff(eventName, ...additionalEventNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EventsOffAll() {
|
||||||
|
return window.runtime.EventsOffAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EventsOnce(eventName, callback) {
|
||||||
|
return EventsOnMultiple(eventName, callback, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EventsEmit(eventName) {
|
||||||
|
let args = [eventName].slice.call(arguments);
|
||||||
|
return window.runtime.EventsEmit.apply(null, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowReload() {
|
||||||
|
window.runtime.WindowReload();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowReloadApp() {
|
||||||
|
window.runtime.WindowReloadApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetAlwaysOnTop(b) {
|
||||||
|
window.runtime.WindowSetAlwaysOnTop(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetSystemDefaultTheme() {
|
||||||
|
window.runtime.WindowSetSystemDefaultTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetLightTheme() {
|
||||||
|
window.runtime.WindowSetLightTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetDarkTheme() {
|
||||||
|
window.runtime.WindowSetDarkTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowCenter() {
|
||||||
|
window.runtime.WindowCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetTitle(title) {
|
||||||
|
window.runtime.WindowSetTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowFullscreen() {
|
||||||
|
window.runtime.WindowFullscreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowUnfullscreen() {
|
||||||
|
window.runtime.WindowUnfullscreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowIsFullscreen() {
|
||||||
|
return window.runtime.WindowIsFullscreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowGetSize() {
|
||||||
|
return window.runtime.WindowGetSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetSize(width, height) {
|
||||||
|
window.runtime.WindowSetSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetMaxSize(width, height) {
|
||||||
|
window.runtime.WindowSetMaxSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetMinSize(width, height) {
|
||||||
|
window.runtime.WindowSetMinSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetPosition(x, y) {
|
||||||
|
window.runtime.WindowSetPosition(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowGetPosition() {
|
||||||
|
return window.runtime.WindowGetPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowHide() {
|
||||||
|
window.runtime.WindowHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowShow() {
|
||||||
|
window.runtime.WindowShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowMaximise() {
|
||||||
|
window.runtime.WindowMaximise();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowToggleMaximise() {
|
||||||
|
window.runtime.WindowToggleMaximise();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowUnmaximise() {
|
||||||
|
window.runtime.WindowUnmaximise();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowIsMaximised() {
|
||||||
|
return window.runtime.WindowIsMaximised();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowMinimise() {
|
||||||
|
window.runtime.WindowMinimise();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowUnminimise() {
|
||||||
|
window.runtime.WindowUnminimise();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowSetBackgroundColour(R, G, B, A) {
|
||||||
|
window.runtime.WindowSetBackgroundColour(R, G, B, A);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ScreenGetAll() {
|
||||||
|
return window.runtime.ScreenGetAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowIsMinimised() {
|
||||||
|
return window.runtime.WindowIsMinimised();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WindowIsNormal() {
|
||||||
|
return window.runtime.WindowIsNormal();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BrowserOpenURL(url) {
|
||||||
|
window.runtime.BrowserOpenURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Environment() {
|
||||||
|
return window.runtime.Environment();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Quit() {
|
||||||
|
window.runtime.Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Hide() {
|
||||||
|
window.runtime.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Show() {
|
||||||
|
window.runtime.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ClipboardGetText() {
|
||||||
|
return window.runtime.ClipboardGetText();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ClipboardSetText(text) {
|
||||||
|
return window.runtime.ClipboardSetText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @callback OnFileDropCallback
|
||||||
|
* @param {number} x - x coordinate of the drop
|
||||||
|
* @param {number} y - y coordinate of the drop
|
||||||
|
* @param {string[]} paths - A list of file paths.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
||||||
|
* @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target)
|
||||||
|
*/
|
||||||
|
export function OnFileDrop(callback, useDropTarget) {
|
||||||
|
return window.runtime.OnFileDrop(callback, useDropTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OnFileDropOff removes the drag and drop listeners and handlers.
|
||||||
|
*/
|
||||||
|
export function OnFileDropOff() {
|
||||||
|
return window.runtime.OnFileDropOff();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CanResolveFilePaths() {
|
||||||
|
return window.runtime.CanResolveFilePaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ResolveFilePaths(files) {
|
||||||
|
return window.runtime.ResolveFilePaths(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InitializeNotifications() {
|
||||||
|
return window.runtime.InitializeNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CleanupNotifications() {
|
||||||
|
return window.runtime.CleanupNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function IsNotificationAvailable() {
|
||||||
|
return window.runtime.IsNotificationAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RequestNotificationAuthorization() {
|
||||||
|
return window.runtime.RequestNotificationAuthorization();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CheckNotificationAuthorization() {
|
||||||
|
return window.runtime.CheckNotificationAuthorization();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SendNotification(options) {
|
||||||
|
return window.runtime.SendNotification(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SendNotificationWithActions(options) {
|
||||||
|
return window.runtime.SendNotificationWithActions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RegisterNotificationCategory(category) {
|
||||||
|
return window.runtime.RegisterNotificationCategory(category);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RemoveNotificationCategory(categoryId) {
|
||||||
|
return window.runtime.RemoveNotificationCategory(categoryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RemoveAllPendingNotifications() {
|
||||||
|
return window.runtime.RemoveAllPendingNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RemovePendingNotification(identifier) {
|
||||||
|
return window.runtime.RemovePendingNotification(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RemoveAllDeliveredNotifications() {
|
||||||
|
return window.runtime.RemoveAllDeliveredNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RemoveDeliveredNotification(identifier) {
|
||||||
|
return window.runtime.RemoveDeliveredNotification(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RemoveNotification(identifier) {
|
||||||
|
return window.runtime.RemoveNotification(identifier);
|
||||||
|
}
|
||||||
48
go.mod
Normal file
48
go.mod
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
module kvmote
|
||||||
|
|
||||||
|
go 1.23.8
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/atotto/clipboard v0.1.4
|
||||||
|
github.com/wailsapp/wails/v2 v2.12.0
|
||||||
|
golang.org/x/sys v0.30.0
|
||||||
|
tinygo.org/x/bluetooth v0.15.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
git.sr.ht/~jackmordaunt/go-toast/v2 v2.0.3 // indirect
|
||||||
|
github.com/bep/debounce v1.2.1 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||||
|
github.com/labstack/echo/v4 v4.13.3 // indirect
|
||||||
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
|
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
|
||||||
|
github.com/leaanthony/gosod v1.0.4 // indirect
|
||||||
|
github.com/leaanthony/slicer v1.6.0 // indirect
|
||||||
|
github.com/leaanthony/u v1.1.1 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/saltosystems/winrt-go v0.0.0-20260317170058-9c2fec580d96 // indirect
|
||||||
|
github.com/samber/lo v1.49.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
|
github.com/soypat/cyw43439 v0.1.0 // indirect
|
||||||
|
github.com/soypat/lneto v0.1.0 // indirect
|
||||||
|
github.com/soypat/seqs v0.0.0-20250124201400-0d65bc7c1710 // indirect
|
||||||
|
github.com/tinygo-org/cbgo v0.0.4 // indirect
|
||||||
|
github.com/tinygo-org/pio v0.3.0 // indirect
|
||||||
|
github.com/tkrajina/go-reflector v0.5.8 // indirect
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
|
github.com/wailsapp/go-webview2 v1.0.22 // indirect
|
||||||
|
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||||
|
golang.org/x/crypto v0.33.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d // indirect
|
||||||
|
golang.org/x/net v0.35.0 // indirect
|
||||||
|
golang.org/x/text v0.22.0 // indirect
|
||||||
|
)
|
||||||
113
go.sum
Normal file
113
go.sum
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
git.sr.ht/~jackmordaunt/go-toast/v2 v2.0.3 h1:N3IGoHHp9pb6mj1cbXbuaSXV/UMKwmbKLf53nQmtqMA=
|
||||||
|
git.sr.ht/~jackmordaunt/go-toast/v2 v2.0.3/go.mod h1:QtOLZGz8olr4qH2vWK0QH0w0O4T9fEIjMuWpKUsH7nc=
|
||||||
|
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||||
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
|
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||||
|
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||||
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
|
||||||
|
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
|
||||||
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
|
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||||
|
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||||
|
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||||
|
github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
|
||||||
|
github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
|
||||||
|
github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI=
|
||||||
|
github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw=
|
||||||
|
github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
|
||||||
|
github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
|
||||||
|
github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
|
||||||
|
github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
|
||||||
|
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
|
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
|
||||||
|
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||||
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||||
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/saltosystems/winrt-go v0.0.0-20260317170058-9c2fec580d96 h1:IXxzj3yjfDNXZJ35foY+RpFShqPsZZ81hhCckgfh5PI=
|
||||||
|
github.com/saltosystems/winrt-go v0.0.0-20260317170058-9c2fec580d96/go.mod h1:CIltaIm7qaANUIvzr0Vmz71lmQMAIbGJ7cvgzX7FMfA=
|
||||||
|
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
|
||||||
|
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
||||||
|
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/soypat/cyw43439 v0.1.0 h1:3Nyqg2LSndhCYgCr2VXuL2nn73vyaJXAnD02veMoLvA=
|
||||||
|
github.com/soypat/cyw43439 v0.1.0/go.mod h1:R2uSILRwSPmcmmKy5Z0FtK4ypgiPf5YqK+F+IKmXqxc=
|
||||||
|
github.com/soypat/lneto v0.1.0 h1:VAHCJ33hvC3wDqhM0Vm7w0k6vwNsOCAsQ8XTrXJpS7I=
|
||||||
|
github.com/soypat/lneto v0.1.0/go.mod h1:g/8Lk+hIsMZydyWDJjK2YfsCuG6jA5mWCO6U+4S7w1U=
|
||||||
|
github.com/soypat/seqs v0.0.0-20250124201400-0d65bc7c1710 h1:Y9fBuiR/urFY/m76+SAZTxk2xAOS2n85f+H1CugajeA=
|
||||||
|
github.com/soypat/seqs v0.0.0-20250124201400-0d65bc7c1710/go.mod h1:oCVCNGCHMKoBj97Zp9znLbQ1nHxpkmOY9X+UAGzOxc8=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/tinygo-org/cbgo v0.0.4 h1:3D76CRYbH03Rudi8sEgs/YO0x3JIMdyq8jlQtk/44fU=
|
||||||
|
github.com/tinygo-org/cbgo v0.0.4/go.mod h1:7+HgWIHd4nbAz0ESjGlJ1/v9LDU1Ox8MGzP9mah/fLk=
|
||||||
|
github.com/tinygo-org/pio v0.3.0 h1:opEnOtw58KGB4RJD3/n/Rd0/djYGX3DeJiXLI6y/yDI=
|
||||||
|
github.com/tinygo-org/pio v0.3.0/go.mod h1:wf6c6lKZp+pQOzKKcpzchmRuhiMc27ABRuo7KVnaMFU=
|
||||||
|
github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
|
||||||
|
github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
|
github.com/wailsapp/go-webview2 v1.0.22 h1:YT61F5lj+GGaat5OB96Aa3b4QA+mybD0Ggq6NZijQ58=
|
||||||
|
github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||||
|
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||||
|
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||||
|
github.com/wailsapp/wails/v2 v2.12.0 h1:BHO/kLNWFHYjCzucxbzAYZWUjub1Tvb4cSguQozHn5c=
|
||||||
|
github.com/wailsapp/wails/v2 v2.12.0/go.mod h1:mo1bzK1DEJrobt7YrBjgxvb5Sihb1mhAY09hppbibQg=
|
||||||
|
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||||
|
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||||
|
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
|
||||||
|
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||||
|
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||||
|
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
tinygo.org/x/bluetooth v0.15.0 h1:hLn8+iZFXvVxBzPIdZfvc6TD8JP32ixF22lCEWHAbIo=
|
||||||
|
tinygo.org/x/bluetooth v0.15.0/go.mod h1:meayNB+9rC1igTUNmNU7KftlSEzrFHe37rBSQZjHN8Y=
|
||||||
28
internal/input/input.go
Normal file
28
internal/input/input.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package input
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type Point struct {
|
||||||
|
X, Y int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type MouseEvent struct {
|
||||||
|
Message uint32
|
||||||
|
Point Point
|
||||||
|
Data uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type KeyboardEvent struct {
|
||||||
|
Message uint32
|
||||||
|
VKCode uint32
|
||||||
|
ScanCode uint32
|
||||||
|
Flags uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type InputHandler interface {
|
||||||
|
Install(ctx context.Context, onMouse func(MouseEvent) bool, onKey func(KeyboardEvent) bool) error
|
||||||
|
Uninstall()
|
||||||
|
SetCursorPos(x, y int32) bool
|
||||||
|
ShowCursor(show bool)
|
||||||
|
GetScreenResolution() (int32, int32)
|
||||||
|
}
|
||||||
171
internal/input/input_windows.go
Normal file
171
internal/input/input_windows.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
//go:build windows
|
||||||
|
package input
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
user32 = windows.NewLazySystemDLL("user32.dll")
|
||||||
|
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
|
|
||||||
|
procSetWindowsHookExW = user32.NewProc("SetWindowsHookExW")
|
||||||
|
procUnhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx")
|
||||||
|
procCallNextHookEx = user32.NewProc("CallNextHookEx")
|
||||||
|
procGetMessageW = user32.NewProc("GetMessageW")
|
||||||
|
procSetCursorPos = user32.NewProc("SetCursorPos")
|
||||||
|
procShowCursor = user32.NewProc("ShowCursor")
|
||||||
|
procGetModuleHandleW = kernel32.NewProc("GetModuleHandleW")
|
||||||
|
procGetSystemMetrics = user32.NewProc("GetSystemMetrics")
|
||||||
|
procSetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
|
||||||
|
procPostThreadMessageW = user32.NewProc("PostThreadMessageW")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
WH_KEYBOARD_LL = 13
|
||||||
|
WH_MOUSE_LL = 14
|
||||||
|
SM_CXSCREEN = 0
|
||||||
|
SM_CYSCREEN = 1
|
||||||
|
WM_QUIT = 0x0012
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
procSetProcessDPIAware.Call()
|
||||||
|
}
|
||||||
|
|
||||||
|
type MSLLHOOKSTRUCT struct {
|
||||||
|
Pt Point
|
||||||
|
MouseData uint32 // Mantemos uint32 mas vamos converter no callback
|
||||||
|
Flags uint32
|
||||||
|
Time uint32
|
||||||
|
DwExtraInfo uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type KBDLLHOOKSTRUCT struct {
|
||||||
|
VkCode uint32
|
||||||
|
ScanCode uint32
|
||||||
|
Flags uint32
|
||||||
|
Time uint32
|
||||||
|
DwExtraInfo uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type windowsInputHandler struct {
|
||||||
|
mouseHook uintptr
|
||||||
|
keyHook uintptr
|
||||||
|
tid uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInputHandler() InputHandler {
|
||||||
|
return &windowsInputHandler{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsInputHandler) Install(ctx context.Context, onMouse func(MouseEvent) bool, onKey func(KeyboardEvent) bool) error {
|
||||||
|
ready := make(chan error, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
h.tid = windows.GetCurrentThreadId()
|
||||||
|
hMod, _, _ := procGetModuleHandleW.Call(0)
|
||||||
|
|
||||||
|
mouseCallback := windows.NewCallback(func(nCode int, wParam uintptr, lParam uintptr) uintptr {
|
||||||
|
if nCode >= 0 {
|
||||||
|
info := (*MSLLHOOKSTRUCT)(unsafe.Pointer(lParam))
|
||||||
|
ev := MouseEvent{
|
||||||
|
Message: uint32(wParam),
|
||||||
|
Point: info.Pt,
|
||||||
|
Data: info.MouseData,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se a engine tratar o evento, não passamos para o próximo hook
|
||||||
|
if onMouse(ev) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret, _, _ := procCallNextHookEx.Call(h.mouseHook, uintptr(nCode), wParam, lParam)
|
||||||
|
return ret
|
||||||
|
})
|
||||||
|
|
||||||
|
keyCallback := windows.NewCallback(func(nCode int, wParam uintptr, lParam uintptr) uintptr {
|
||||||
|
if nCode >= 0 {
|
||||||
|
info := (*KBDLLHOOKSTRUCT)(unsafe.Pointer(lParam))
|
||||||
|
ev := KeyboardEvent{
|
||||||
|
Message: uint32(wParam),
|
||||||
|
VKCode: info.VkCode,
|
||||||
|
ScanCode: info.ScanCode,
|
||||||
|
Flags: info.Flags,
|
||||||
|
}
|
||||||
|
if onKey(ev) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret, _, _ := procCallNextHookEx.Call(h.keyHook, uintptr(nCode), wParam, lParam)
|
||||||
|
return ret
|
||||||
|
})
|
||||||
|
|
||||||
|
mh, _, _ := procSetWindowsHookExW.Call(WH_MOUSE_LL, mouseCallback, hMod, 0)
|
||||||
|
if mh == 0 {
|
||||||
|
ready <- fmt.Errorf("failed mouse hook")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.mouseHook = mh
|
||||||
|
|
||||||
|
kh, _, _ := procSetWindowsHookExW.Call(WH_KEYBOARD_LL, keyCallback, hMod, 0)
|
||||||
|
if kh == 0 {
|
||||||
|
ready <- fmt.Errorf("failed key hook")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.keyHook = kh
|
||||||
|
|
||||||
|
ready <- nil
|
||||||
|
|
||||||
|
var msg struct {
|
||||||
|
Hwnd windows.Handle
|
||||||
|
Message uint32
|
||||||
|
WParam uintptr
|
||||||
|
LParam uintptr
|
||||||
|
Time uint32
|
||||||
|
Pt Point
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
ret, _, _ := procGetMessageW.Call(uintptr(unsafe.Pointer(&msg)), 0, 0, 0)
|
||||||
|
if ret == 0 || msg.Message == WM_QUIT {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
procUnhookWindowsHookEx.Call(h.mouseHook)
|
||||||
|
procUnhookWindowsHookEx.Call(h.keyHook)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return <-ready
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsInputHandler) Uninstall() {
|
||||||
|
if h.tid != 0 {
|
||||||
|
procPostThreadMessageW.Call(uintptr(h.tid), WM_QUIT, 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsInputHandler) SetCursorPos(x, y int32) bool {
|
||||||
|
ret, _, _ := procSetCursorPos.Call(uintptr(x), uintptr(y))
|
||||||
|
return ret != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsInputHandler) ShowCursor(show bool) {
|
||||||
|
s := -1 // No Windows, ShowCursor(FALSE) decrementa um contador
|
||||||
|
if show {
|
||||||
|
s = 1
|
||||||
|
}
|
||||||
|
// Vamos usar uma abordagem mais direta se necessário, mas por enquanto:
|
||||||
|
procShowCursor.Call(uintptr(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsInputHandler) GetScreenResolution() (int32, int32) {
|
||||||
|
w, _, _ := procGetSystemMetrics.Call(SM_CXSCREEN)
|
||||||
|
h_res, _, _ := procGetSystemMetrics.Call(SM_CYSCREEN)
|
||||||
|
return int32(w), int32(h_res)
|
||||||
|
}
|
||||||
340
internal/kvm/engine.go
Normal file
340
internal/kvm/engine.go
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
package kvm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/atotto/clipboard"
|
||||||
|
"kvmote/internal/input"
|
||||||
|
"kvmote/internal/transport"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LogDebug(msg string) {
|
||||||
|
f, err := os.OpenFile("kvmote_debug.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
timestamp := time.Now().Format("15:04:05.000")
|
||||||
|
f.WriteString(fmt.Sprintf("[%s] %s\n", timestamp, msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClientPos int
|
||||||
|
|
||||||
|
const (
|
||||||
|
PosNone ClientPos = iota
|
||||||
|
PosLeft
|
||||||
|
PosRight
|
||||||
|
PosAbove
|
||||||
|
PosBelow
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClientLayout int
|
||||||
|
|
||||||
|
const (
|
||||||
|
LayoutUS ClientLayout = iota
|
||||||
|
LayoutAbnt2
|
||||||
|
LayoutUsIntl
|
||||||
|
)
|
||||||
|
|
||||||
|
type Engine struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
transport transport.Transport
|
||||||
|
inputHandler input.InputHandler
|
||||||
|
|
||||||
|
clientMode bool
|
||||||
|
clientPos ClientPos
|
||||||
|
clientLayout ClientLayout
|
||||||
|
|
||||||
|
ctrlHeld bool
|
||||||
|
shiftHeld bool
|
||||||
|
altHeld bool
|
||||||
|
clipboardReady bool
|
||||||
|
|
||||||
|
virtualX, virtualY int32
|
||||||
|
pendingDX, pendingDY int32
|
||||||
|
lastRawPos input.Point
|
||||||
|
edgeEntry input.Point
|
||||||
|
isWarping bool
|
||||||
|
lastModeChange time.Time
|
||||||
|
|
||||||
|
scrollActive bool
|
||||||
|
scrollTimer time.Time
|
||||||
|
wheelAccum int32
|
||||||
|
|
||||||
|
mouseThrottle time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEngine(t transport.Transport, h input.InputHandler) *Engine {
|
||||||
|
return &Engine{
|
||||||
|
transport: t,
|
||||||
|
inputHandler: h,
|
||||||
|
clientPos: PosRight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) Transport() transport.Transport {
|
||||||
|
return e.transport
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) Start(ctx context.Context) error {
|
||||||
|
w, h := e.inputHandler.GetScreenResolution()
|
||||||
|
LogDebug(fmt.Sprintf("Engine Iniciada. Tela: %dx%d. Pos: %v", w, h, e.clientPos))
|
||||||
|
return e.inputHandler.Install(ctx, e.onMouse, e.onKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) processarScroll(data uint32) {
|
||||||
|
e.scrollActive = true
|
||||||
|
e.scrollTimer = time.Now()
|
||||||
|
|
||||||
|
delta := int32(int16(data >> 16))
|
||||||
|
e.wheelAccum += delta
|
||||||
|
|
||||||
|
const Divisor = 40 // Bem sensível para touchpad
|
||||||
|
toSend := e.wheelAccum / Divisor
|
||||||
|
|
||||||
|
if toSend != 0 {
|
||||||
|
e.wheelAccum -= toSend * Divisor
|
||||||
|
err := e.transport.Send([]byte{'W', byte(int8(clamp(int(toSend), -127, 127)))})
|
||||||
|
if err == nil {
|
||||||
|
LogDebug(fmt.Sprintf("SCROLL: delta=%d enviado=%d", delta, toSend))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) onMouse(ev input.MouseEvent) bool {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
|
if !e.transport.IsConnected() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !e.clientMode {
|
||||||
|
if ev.Message == 0x0200 && e.isAtExitEdge(ev.Point) {
|
||||||
|
e.enterClientMode(ev.Point)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── MODO CLIENTE ATIVO ───
|
||||||
|
|
||||||
|
// Log de qualquer evento que não seja movimento simples (para descobrir o ID do touchpad)
|
||||||
|
if ev.Message != 0x0200 {
|
||||||
|
LogDebug(fmt.Sprintf("Evento Mouse: 0x%X | Data: %d", ev.Message, ev.Data))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ev.Message {
|
||||||
|
case 0x020A, 0x020E: // Roda Vertical ou Horizontal
|
||||||
|
e.processarScroll(ev.Data)
|
||||||
|
return true
|
||||||
|
|
||||||
|
case 0x0200: // Move
|
||||||
|
if e.isWarping { e.isWarping = false; return true }
|
||||||
|
|
||||||
|
if e.scrollActive {
|
||||||
|
if time.Since(e.scrollTimer) > 300*time.Millisecond {
|
||||||
|
e.scrollActive = false
|
||||||
|
e.virtualX, e.virtualY = 0, 0
|
||||||
|
}
|
||||||
|
e.lastRawPos = ev.Point
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
dx, dy := ev.Point.X - e.lastRawPos.X, ev.Point.Y - e.lastRawPos.Y
|
||||||
|
e.virtualX += dx
|
||||||
|
e.virtualY += dy
|
||||||
|
e.pendingDX += dx
|
||||||
|
e.pendingDY += dy
|
||||||
|
|
||||||
|
if e.shouldReturnToHost() {
|
||||||
|
if time.Since(e.lastModeChange) > 800*time.Millisecond {
|
||||||
|
e.exitClientMode()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
e.virtualX, e.virtualY = 0, 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
w, h := e.inputHandler.GetScreenResolution()
|
||||||
|
e.isWarping = true
|
||||||
|
e.inputHandler.SetCursorPos(w/2, h/2)
|
||||||
|
e.lastRawPos = input.Point{X: w / 2, Y: h / 2}
|
||||||
|
|
||||||
|
if time.Since(e.mouseThrottle) >= 40*time.Millisecond {
|
||||||
|
e.mouseThrottle = time.Now()
|
||||||
|
sdx, sdy := int8(clamp(int(e.pendingDX), -127, 127)), int8(clamp(int(e.pendingDY), -127, 127))
|
||||||
|
e.pendingDX, e.pendingDY = 0, 0
|
||||||
|
e.transport.SendLossy([]byte{'M', byte(sdx), byte(sdy)})
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case 0x0201: e.transport.Send([]byte{'D', 'L'}); return true
|
||||||
|
case 0x0202: e.transport.Send([]byte{'E', 'L'}); return true
|
||||||
|
case 0x0204: e.transport.Send([]byte{'D', 'R'}); return true
|
||||||
|
case 0x0205: e.transport.Send([]byte{'E', 'R'}); return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) isAtExitEdge(p input.Point) bool {
|
||||||
|
w, h := e.inputHandler.GetScreenResolution()
|
||||||
|
const Margin = 10
|
||||||
|
switch e.clientPos {
|
||||||
|
case PosLeft: return p.X <= 0
|
||||||
|
case PosRight: return p.X >= w-Margin
|
||||||
|
case PosAbove: return p.Y <= 0
|
||||||
|
case PosBelow: return p.Y >= h-Margin
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) shouldReturnToHost() bool {
|
||||||
|
switch e.clientPos {
|
||||||
|
case PosLeft: return e.virtualX > 600
|
||||||
|
case PosRight: return e.virtualX < -500
|
||||||
|
case PosBelow: return e.virtualY < -150
|
||||||
|
case PosAbove: return e.virtualY > 150
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) enterClientMode(p input.Point) {
|
||||||
|
LogDebug(fmt.Sprintf("Entrando Modo Cliente em (%d, %d)", p.X, p.Y))
|
||||||
|
e.clientMode = true
|
||||||
|
e.edgeEntry = p
|
||||||
|
e.lastModeChange = time.Now()
|
||||||
|
e.virtualX, e.virtualY = 0, 0
|
||||||
|
e.pendingDX, e.pendingDY = 0, 0
|
||||||
|
e.wheelAccum = 0
|
||||||
|
e.mouseThrottle = time.Now()
|
||||||
|
|
||||||
|
w, h := e.inputHandler.GetScreenResolution()
|
||||||
|
e.isWarping = true
|
||||||
|
e.inputHandler.SetCursorPos(w/2, h/2)
|
||||||
|
e.lastRawPos = input.Point{X: w / 2, Y: h / 2}
|
||||||
|
e.inputHandler.ShowCursor(false)
|
||||||
|
e.transport.Send([]byte{'O'})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) exitClientMode() {
|
||||||
|
LogDebug("Saindo Modo Cliente.")
|
||||||
|
e.clientMode = false
|
||||||
|
e.lastModeChange = time.Now()
|
||||||
|
e.inputHandler.ShowCursor(true)
|
||||||
|
w, h := e.inputHandler.GetScreenResolution()
|
||||||
|
var ret input.Point
|
||||||
|
const Offset = 120
|
||||||
|
switch e.clientPos {
|
||||||
|
case PosRight: ret = input.Point{X: w - Offset, Y: e.edgeEntry.Y}
|
||||||
|
case PosLeft: ret = input.Point{X: Offset, Y: e.edgeEntry.Y}
|
||||||
|
case PosAbove: ret = input.Point{X: e.edgeEntry.X, Y: Offset}
|
||||||
|
case PosBelow: ret = input.Point{X: e.edgeEntry.X, Y: h - Offset}
|
||||||
|
default: ret = input.Point{X: w / 2, Y: h / 2}
|
||||||
|
}
|
||||||
|
e.inputHandler.SetCursorPos(ret.X, ret.Y)
|
||||||
|
e.transport.Send([]byte{'H'})
|
||||||
|
e.transport.Send([]byte{'A'})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) onKey(ev input.KeyboardEvent) bool {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
if !e.transport.IsConnected() { return false }
|
||||||
|
isDown := ev.Message == 0x0100 || ev.Message == 0x0104
|
||||||
|
switch ev.VKCode {
|
||||||
|
case 0xA2, 0xA3, 0x11: e.ctrlHeld = isDown
|
||||||
|
case 0xA0, 0xA1, 0x10: e.shiftHeld = isDown
|
||||||
|
case 0xA4, 0xA5, 0x12: e.altHeld = isDown
|
||||||
|
}
|
||||||
|
if !e.clientMode {
|
||||||
|
if isDown && ev.VKCode == 0x43 && e.ctrlHeld { e.clipboardReady = true }
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if isDown && ev.VKCode == 0x56 && e.ctrlHeld && e.clipboardReady {
|
||||||
|
e.clipboardReady = false
|
||||||
|
go e.sendClipboard()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
code, ok := vkToArduino(ev.VKCode)
|
||||||
|
if ok {
|
||||||
|
cmd := byte('U'); if isDown { cmd = 'P' }
|
||||||
|
e.transport.Send([]byte{cmd, code})
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) sendClipboard() {
|
||||||
|
text, _ := clipboard.ReadAll()
|
||||||
|
if text == "" { return }
|
||||||
|
if len(text) > 2000 { text = text[:2000] }
|
||||||
|
data := []byte(text)
|
||||||
|
l := len(data)
|
||||||
|
e.transport.Send(append([]byte{'T', byte(l >> 8), byte(l & 0xFF)}, data...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func clamp(v, min, max int) int {
|
||||||
|
if v < min { return min }; if v > max { return max }; return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) SendCtrlAltDel() {
|
||||||
|
LogDebug("Enviando CTRL+ALT+DEL...")
|
||||||
|
if !e.transport.IsConnected() {
|
||||||
|
LogDebug("Erro: Transporte não conectado.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
e.transport.Send([]byte{'P', 0x80})
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
e.transport.Send([]byte{'P', 0x82})
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
e.transport.Send([]byte{'P', 0xD4})
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
e.transport.Send([]byte{'U', 0xD4})
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
e.transport.Send([]byte{'U', 0x82})
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
e.transport.Send([]byte{'U', 0x80})
|
||||||
|
LogDebug("Sequência CTRL+ALT+DEL enviada.")
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) SetPosition(pos int) {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
e.clientPos = ClientPos(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) SetLayout(layout int) {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
e.clientLayout = ClientLayout(layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyMap = map[uint32]byte{
|
||||||
|
0xA0: 0x81, 0xA1: 0x85, 0xA2: 0x80, 0xA3: 0x84, 0xA4: 0x82, 0xA5: 0x86, 0x5B: 0x83, 0x5C: 0x87,
|
||||||
|
0x10: 0x81, 0x11: 0x80, 0x12: 0x82, 0x70: 0xC2, 0x71: 0xC3, 0x72: 0xC4, 0x73: 0xC5, 0x74: 0xC6,
|
||||||
|
0x75: 0xC7, 0x76: 0xC8, 0x77: 0xC9, 0x78: 0xCA, 0x79: 0xCB, 0x7A: 0xCC, 0x7B: 0xCD, 0x26: 0xDA,
|
||||||
|
0x28: 0xD9, 0x25: 0xD8, 0x27: 0xD7, 0x24: 0xD2, 0x23: 0xD5, 0x21: 0xD3, 0x22: 0xD6, 0x2D: 0xD1,
|
||||||
|
0x2E: 0xD4, 0x0D: 0xB0, 0x1B: 0xB1, 0x08: 0xB2, 0x09: 0xB3, 0x14: 0xC1, 0x2C: 0xCE, 0x91: 0xCF, 0x13: 0xD0,
|
||||||
|
}
|
||||||
|
|
||||||
|
func vkToArduino(vk uint32) (byte, bool) {
|
||||||
|
if m, ok := keyMap[vk]; ok { return m, true }
|
||||||
|
if vk >= 0x41 && vk <= 0x5A { return byte(vk + 0x20), true }
|
||||||
|
if vk >= 0x30 && vk <= 0x39 { return byte(vk), true }
|
||||||
|
if vk >= 0x60 && vk <= 0x69 { return byte('0' + vk - 0x60), true }
|
||||||
|
switch vk {
|
||||||
|
case 0x20: return ' ', true; case 0xBD: return '-', true; case 0xBB: return '=', true
|
||||||
|
case 0xDB: return '[', true; case 0xDD: return ']', true; case 0xDC: return '\\', true
|
||||||
|
case 0xBA: return ';', true; case 0xDE: return '\'', true; case 0xBC: return ',', true
|
||||||
|
case 0xBE: return '.', true; case 0xBF: return '/', true; case 0xC0: return '`', true
|
||||||
|
case 0xE2: return 0xEC, true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
146
internal/transport/ble_windows.go
Normal file
146
internal/transport/ble_windows.go
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/bluetooth"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
NusServiceUUID = bluetooth.NewUUID([16]byte{0x6e, 0x40, 0x00, 0x01, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5, 0x0e, 0x24, 0xdc, 0xca, 0x9e})
|
||||||
|
NusRxUUID = bluetooth.NewUUID([16]byte{0x6e, 0x40, 0x00, 0x02, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5, 0x0e, 0x24, 0xdc, 0xca, 0x9e})
|
||||||
|
)
|
||||||
|
|
||||||
|
type RealBleTransport struct {
|
||||||
|
adapter *bluetooth.Adapter
|
||||||
|
device bluetooth.Device
|
||||||
|
rxChar bluetooth.DeviceCharacteristic
|
||||||
|
connected bool
|
||||||
|
mu sync.Mutex
|
||||||
|
address bluetooth.Address
|
||||||
|
found bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBleTransport() *RealBleTransport {
|
||||||
|
return &RealBleTransport{
|
||||||
|
adapter: bluetooth.DefaultAdapter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RealBleTransport) Detect(ctx context.Context) (bool, error) {
|
||||||
|
t.mu.Lock()
|
||||||
|
if t.found {
|
||||||
|
t.mu.Unlock()
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
t.mu.Unlock()
|
||||||
|
|
||||||
|
fmt.Println("[BLE] Iniciando Scan...")
|
||||||
|
if err := t.adapter.Enable(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
foundChan := make(chan bluetooth.Address, 1)
|
||||||
|
err := t.adapter.Scan(func(adapter *bluetooth.Adapter, result bluetooth.ScanResult) {
|
||||||
|
if result.LocalName() == "KVMote" {
|
||||||
|
adapter.StopScan()
|
||||||
|
foundChan <- result.Address
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case addr := <-foundChan:
|
||||||
|
t.mu.Lock()
|
||||||
|
t.address = addr
|
||||||
|
t.found = true
|
||||||
|
t.mu.Unlock()
|
||||||
|
fmt.Println("[BLE] Encontrado!")
|
||||||
|
return true, nil
|
||||||
|
case <-ctx.Done():
|
||||||
|
t.adapter.StopScan()
|
||||||
|
return false, ctx.Err()
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.adapter.StopScan()
|
||||||
|
return false, errors.New("não encontrado")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RealBleTransport) Connect(ctx context.Context) error {
|
||||||
|
t.mu.Lock()
|
||||||
|
addr := t.address
|
||||||
|
t.mu.Unlock()
|
||||||
|
|
||||||
|
fmt.Println("[BLE] Conectando...")
|
||||||
|
device, err := t.adapter.Connect(addr, bluetooth.ConnectionParams{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.mu.Lock()
|
||||||
|
t.device = device
|
||||||
|
t.mu.Unlock()
|
||||||
|
|
||||||
|
fmt.Println("[BLE] Buscando Serviço...")
|
||||||
|
services, err := device.DiscoverServices([]bluetooth.UUID{NusServiceUUID})
|
||||||
|
if err != nil || len(services) == 0 {
|
||||||
|
return errors.New("serviço não encontrado")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[BLE] Buscando RX...")
|
||||||
|
chars, err := services[0].DiscoverCharacteristics([]bluetooth.UUID{NusRxUUID})
|
||||||
|
if err != nil || len(chars) == 0 {
|
||||||
|
return errors.New("característica não encontrada")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.mu.Lock()
|
||||||
|
t.rxChar = chars[0]
|
||||||
|
t.connected = true
|
||||||
|
t.mu.Unlock()
|
||||||
|
|
||||||
|
fmt.Println("[BLE] PRONTO!")
|
||||||
|
t.Send([]byte{'H'})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RealBleTransport) Disconnect() error {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
if !t.connected { return nil }
|
||||||
|
|
||||||
|
// Proteção contra crash no Windows
|
||||||
|
go func() {
|
||||||
|
defer func() { recover() }()
|
||||||
|
t.device.Disconnect()
|
||||||
|
}()
|
||||||
|
|
||||||
|
t.connected = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RealBleTransport) IsConnected() bool {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
return t.connected
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RealBleTransport) Send(data []byte) error {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
if !t.connected { return nil }
|
||||||
|
_, err := t.rxChar.WriteWithoutResponse(data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RealBleTransport) SendLossy(data []byte) error {
|
||||||
|
return t.Send(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RealBleTransport) DeviceLabel() string { return "KVMote (BLE)" }
|
||||||
|
func (t *RealBleTransport) ClipboardConfig() (int, int, bool) { return 65536, 5, true }
|
||||||
16
internal/transport/transport.go
Normal file
16
internal/transport/transport.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Transport interface {
|
||||||
|
Detect(ctx context.Context) (bool, error)
|
||||||
|
Connect(ctx context.Context) error
|
||||||
|
Disconnect() error
|
||||||
|
IsConnected() bool
|
||||||
|
Send(data []byte) error
|
||||||
|
SendLossy(data []byte) error
|
||||||
|
DeviceLabel() string
|
||||||
|
ClipboardConfig() (int, int, bool) // maxChars, delayMs, supportsBatch
|
||||||
|
}
|
||||||
409
kvmote_debug.log
Normal file
409
kvmote_debug.log
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
[11:57:49.995] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[11:58:01.505] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:00:07.989] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:00:14.765] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:01:21.879] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:01:56.100] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:03:09.822] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:03:16.104] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:03:23.314] Mouse: (2800, 921) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:23.315] Mouse: (2800, 921) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:23.318] Mouse: (2820, 916) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:23.318] Mouse: (2820, 916) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:23.322] Mouse: (2841, 909) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:23.323] Mouse: (2841, 909) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:23.327] Mouse: (2861, 906) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:23.327] BORDA DETECTADA em (2861, 906). Entrando em Modo Cliente.
|
||||||
|
[12:03:35.377] RETORNO AO HOST. Virtual: (-42, -18).
|
||||||
|
[12:03:37.803] Mouse: (2783, 956) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:37.803] Mouse: (2783, 956) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:37.807] Mouse: (2795, 954) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:37.807] Mouse: (2795, 954) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:37.811] Mouse: (2814, 952) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:37.811] Mouse: (2814, 952) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:37.815] Mouse: (2839, 948) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:37.815] Mouse: (2839, 948) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:37.819] Mouse: (2865, 946) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:37.819] BORDA DETECTADA em (2865, 946). Entrando em Modo Cliente.
|
||||||
|
[12:03:39.322] RETORNO AO HOST. Virtual: (-59, -54).
|
||||||
|
[12:03:42.688] Mouse: (2784, 936) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.689] Mouse: (2784, 936) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.693] Mouse: (2798, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.693] Mouse: (2798, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.697] Mouse: (2812, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.697] Mouse: (2812, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.701] Mouse: (2824, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.701] Mouse: (2824, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.705] Mouse: (2836, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.705] Mouse: (2836, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.709] Mouse: (2846, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.709] Mouse: (2846, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.713] Mouse: (2856, 935) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:42.714] BORDA DETECTADA em (2856, 935). Entrando em Modo Cliente.
|
||||||
|
[12:03:46.594] RETORNO AO HOST. Virtual: (-32, 84).
|
||||||
|
[12:03:48.628] Mouse: (2784, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.628] Mouse: (2784, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.632] Mouse: (2790, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.633] Mouse: (2790, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.636] Mouse: (2795, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.636] Mouse: (2795, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.640] Mouse: (2798, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.641] Mouse: (2798, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.644] Mouse: (2802, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.644] Mouse: (2802, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.649] Mouse: (2806, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.649] Mouse: (2806, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.653] Mouse: (2808, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.653] Mouse: (2808, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.656] Mouse: (2811, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.657] Mouse: (2811, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.661] Mouse: (2813, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.662] Mouse: (2813, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.665] Mouse: (2815, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.665] Mouse: (2815, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.669] Mouse: (2817, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.669] Mouse: (2817, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.673] Mouse: (2817, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.673] Mouse: (2817, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.677] Mouse: (2819, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.678] Mouse: (2819, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.681] Mouse: (2820, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.681] Mouse: (2820, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.685] Mouse: (2821, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.686] Mouse: (2821, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.690] Mouse: (2822, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.690] Mouse: (2822, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.694] Mouse: (2823, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.694] Mouse: (2823, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.698] Mouse: (2823, 875) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.698] Mouse: (2823, 875) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.993] Mouse: (2834, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.994] Mouse: (2834, 873) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.997] Mouse: (2852, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:48.997] BORDA DETECTADA em (2852, 872). Entrando em Modo Cliente.
|
||||||
|
[12:03:51.189] RETORNO AO HOST. Virtual: (-31, 46).
|
||||||
|
[12:03:53.889] Mouse: (2788, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:53.889] Mouse: (2788, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:53.892] Mouse: (2807, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:53.893] Mouse: (2807, 872) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:53.897] Mouse: (2827, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:53.898] Mouse: (2827, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:53.902] Mouse: (2845, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:53.902] Mouse: (2845, 874) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:53.906] Mouse: (2861, 876) | Screen: (2880, 1800) | Pos Alvo: 2
|
||||||
|
[12:03:53.906] BORDA DETECTADA em (2861, 876). Entrando em Modo Cliente.
|
||||||
|
[12:03:56.084] RETORNO AO HOST. Virtual: (-37, -4).
|
||||||
|
[12:04:02.762] Posição alterada para: 1
|
||||||
|
[12:04:05.242] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 1
|
||||||
|
[12:04:16.367] Mouse: (96, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.367] Mouse: (96, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.368] Mouse: (96, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.370] Mouse: (76, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.371] Mouse: (76, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.371] Mouse: (76, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.375] Mouse: (56, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.376] Mouse: (56, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.376] Mouse: (56, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.380] Mouse: (37, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.380] Mouse: (37, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.381] Mouse: (37, 880) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.382] Mouse: (17, 879) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.383] Mouse: (17, 879) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.383] Mouse: (17, 879) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.387] Mouse: (-1, 878) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:16.387] BORDA DETECTADA em (-1, 878). Entrando em Modo Cliente.
|
||||||
|
[12:04:17.431] RETORNO AO HOST. Virtual: (31, 4).
|
||||||
|
[12:04:19.412] Mouse: (97, 869) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.413] Mouse: (97, 869) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.413] Mouse: (97, 869) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.416] Mouse: (89, 868) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.417] Mouse: (89, 868) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.417] Mouse: (89, 868) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.421] Mouse: (80, 867) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.421] Mouse: (80, 867) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.421] Mouse: (80, 867) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.424] Mouse: (74, 867) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.425] Mouse: (74, 867) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.425] Mouse: (74, 867) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.429] Mouse: (68, 865) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.429] Mouse: (68, 865) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.429] Mouse: (68, 865) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.433] Mouse: (61, 865) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.433] Mouse: (61, 865) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.434] Mouse: (61, 865) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.437] Mouse: (57, 864) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.438] Mouse: (57, 864) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.438] Mouse: (57, 864) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.441] Mouse: (52, 864) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.441] Mouse: (52, 864) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.441] Mouse: (52, 864) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.445] Mouse: (49, 863) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.445] Mouse: (49, 863) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.445] Mouse: (49, 863) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.450] Mouse: (46, 863) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.450] Mouse: (46, 863) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.451] Mouse: (46, 863) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.453] Mouse: (42, 862) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.454] Mouse: (42, 862) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.454] Mouse: (42, 862) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.458] Mouse: (39, 861) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.458] Mouse: (39, 861) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.458] Mouse: (39, 861) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.462] Mouse: (36, 861) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.462] Mouse: (36, 861) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.463] Mouse: (36, 861) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.465] Mouse: (34, 861) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.466] Mouse: (34, 861) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.466] Mouse: (34, 861) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.470] Mouse: (31, 860) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.471] Mouse: (31, 860) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.471] Mouse: (31, 860) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.474] Mouse: (30, 860) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.474] Mouse: (30, 860) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.474] Mouse: (30, 860) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.478] Mouse: (28, 860) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.478] Mouse: (28, 860) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.479] Mouse: (28, 860) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.482] Mouse: (26, 859) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.482] Mouse: (26, 859) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.482] Mouse: (26, 859) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.487] Mouse: (25, 859) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.488] Mouse: (25, 859) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.488] Mouse: (25, 859) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.491] Mouse: (24, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.491] Mouse: (24, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.491] Mouse: (24, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.494] Mouse: (23, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.495] Mouse: (23, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.495] Mouse: (23, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.498] Mouse: (23, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.499] Mouse: (23, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.499] Mouse: (23, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.503] Mouse: (22, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.503] Mouse: (22, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.503] Mouse: (22, 858) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.507] Mouse: (21, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.507] Mouse: (21, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.507] Mouse: (21, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.516] Mouse: (20, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.516] Mouse: (20, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.517] Mouse: (20, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.523] Mouse: (19, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.523] Mouse: (19, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.523] Mouse: (19, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.527] Mouse: (18, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.528] Mouse: (18, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.528] Mouse: (18, 857) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.531] Mouse: (18, 856) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.532] Mouse: (18, 856) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.532] Mouse: (18, 856) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.545] Mouse: (18, 855) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.545] Mouse: (18, 855) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.545] Mouse: (18, 855) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.897] Mouse: (10, 854) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.898] Mouse: (10, 854) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.898] Mouse: (10, 854) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.902] Mouse: (-4, 853) | Screen: (2880, 1800) | Pos Alvo: 1
|
||||||
|
[12:04:19.902] BORDA DETECTADA em (-4, 853). Entrando em Modo Cliente.
|
||||||
|
[12:04:21.156] RETORNO AO HOST. Virtual: (31, 7).
|
||||||
|
[12:08:55.556] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:09:07.216] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:09:11.273] BORDA DETECTADA em (2881, 768). Entrando em Modo Cliente.
|
||||||
|
[12:09:11.274] Executando enterClientMode...
|
||||||
|
[12:09:13.855] RETORNO AO HOST. Virtual: (-104, 62).
|
||||||
|
[12:09:13.855] Saindo do Modo Cliente (Retornando ao Host).
|
||||||
|
[12:09:18.233] BORDA DETECTADA em (2875, 910). Entrando em Modo Cliente.
|
||||||
|
[12:09:18.233] Executando enterClientMode...
|
||||||
|
[12:09:28.239] RETORNO AO HOST. Virtual: (-103, -73).
|
||||||
|
[12:09:28.240] Saindo do Modo Cliente (Retornando ao Host).
|
||||||
|
[12:09:48.125] Posição alterada para: 1
|
||||||
|
[12:09:50.114] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 1
|
||||||
|
[12:09:53.858] BORDA DETECTADA em (-5, 814). Entrando em Modo Cliente.
|
||||||
|
[12:09:53.858] Executando enterClientMode...
|
||||||
|
[12:11:23.447] RETORNO AO HOST. Virtual: (109, 340).
|
||||||
|
[12:11:23.448] Saindo do Modo Cliente (Retornando ao Host).
|
||||||
|
[12:11:39.432] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:11:43.252] Posição alterada para: 1
|
||||||
|
[12:11:45.237] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 1
|
||||||
|
[12:11:58.482] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 1
|
||||||
|
[12:12:26.021] BORDA DETECTADA em (-5, 1029). Entrando em Modo Cliente.
|
||||||
|
[12:12:26.021] Executando enterClientMode...
|
||||||
|
[12:13:10.104] RETORNO AO HOST. Virtual: (102, -89).
|
||||||
|
[12:13:10.105] Saindo do Modo Cliente (Retornando ao Host).
|
||||||
|
[12:13:18.341] BORDA DETECTADA em (-11, 921). Entrando em Modo Cliente.
|
||||||
|
[12:13:18.341] Executando enterClientMode...
|
||||||
|
[12:13:27.416] RETORNO AO HOST. Virtual: (108, -48).
|
||||||
|
[12:13:27.416] Saindo do Modo Cliente (Retornando ao Host).
|
||||||
|
[12:38:10.026] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:38:21.182] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:38:47.459] BORDA DETECTADA em (2878, 867). Entrando em Modo Cliente.
|
||||||
|
[12:38:47.459] Entrando Modo Cliente. EdgeEntry: (2878, 867)
|
||||||
|
[12:38:49.941] RETORNO AO HOST. Virtual: (-102, 50).
|
||||||
|
[12:38:49.941] Saindo Modo Cliente...
|
||||||
|
[12:38:50.862] BORDA DETECTADA em (2877, 869). Entrando em Modo Cliente.
|
||||||
|
[12:38:50.862] Entrando Modo Cliente. EdgeEntry: (2877, 869)
|
||||||
|
[12:39:12.965] RETORNO AO HOST. Virtual: (-108, 78).
|
||||||
|
[12:39:12.965] Saindo Modo Cliente...
|
||||||
|
[12:40:05.307] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 2
|
||||||
|
[12:40:10.496] Posição alterada para: 1
|
||||||
|
[12:40:15.610] Engine Iniciada. Resolução: 2880x1800. Posição Cliente: 1
|
||||||
|
[12:40:19.932] BORDA DETECTADA em (-1, 850). Entrando em Modo Cliente.
|
||||||
|
[12:40:19.932] Entrando Modo Cliente. EdgeEntry: (-1, 850)
|
||||||
|
[12:40:22.694] RETORNO AO HOST. Virtual: (109, 9).
|
||||||
|
[12:40:22.694] Saindo Modo Cliente...
|
||||||
|
[12:40:23.511] BORDA DETECTADA em (-11, 915). Entrando em Modo Cliente.
|
||||||
|
[12:40:23.511] Entrando Modo Cliente. EdgeEntry: (-11, 915)
|
||||||
|
[12:40:25.789] RETORNO AO HOST. Virtual: (101, -7).
|
||||||
|
[12:40:25.789] Saindo Modo Cliente...
|
||||||
|
[12:40:27.412] BORDA DETECTADA em (-10, 866). Entrando em Modo Cliente.
|
||||||
|
[12:40:27.412] Entrando Modo Cliente. EdgeEntry: (-10, 866)
|
||||||
|
[12:40:53.410] RETORNO AO HOST. Virtual: (111, 303).
|
||||||
|
[12:40:53.410] Saindo Modo Cliente...
|
||||||
|
[12:40:56.329] BORDA DETECTADA em (-6, 842). Entrando em Modo Cliente.
|
||||||
|
[12:40:56.329] Entrando Modo Cliente. EdgeEntry: (-6, 842)
|
||||||
|
[12:46:51.892] RETORNO AO HOST. Virtual: (125, 982).
|
||||||
|
[12:46:51.892] Saindo Modo Cliente...
|
||||||
|
[12:48:18.098] Ctrl+C detectado no Host. Clipboard marcado.
|
||||||
|
[12:48:18.098] Ctrl+C detectado no Host. Clipboard marcado.
|
||||||
|
[12:48:52.272] Ctrl+C detectado no Host. Clipboard marcado.
|
||||||
|
[12:48:52.273] Ctrl+C detectado no Host. Clipboard marcado.
|
||||||
|
[12:48:52.458] Ctrl+C detectado no Host. Clipboard marcado.
|
||||||
|
[12:48:52.459] Ctrl+C detectado no Host. Clipboard marcado.
|
||||||
|
[12:48:52.640] Ctrl+C detectado no Host. Clipboard marcado.
|
||||||
|
[12:48:52.640] Ctrl+C detectado no Host. Clipboard marcado.
|
||||||
|
[12:48:59.721] BORDA DETECTADA em (-10, 973). Entrando em Modo Cliente.
|
||||||
|
[12:48:59.722] Entrando Modo Cliente. EdgeEntry: (-10, 973)
|
||||||
|
[12:49:09.111] Ctrl+V detectado no Cliente. Iniciando Batch Paste...
|
||||||
|
[13:20:24.355] RETORNO AO HOST. Virtual: (130, 757).
|
||||||
|
[13:20:24.355] Saindo Modo Cliente...
|
||||||
|
[09:28:10.941] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[09:28:52.395] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[09:29:03.702] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[09:29:19.095] Entrando em Modo Cliente. Pos: (2906, 949)
|
||||||
|
[09:29:21.721] Saindo do Modo Cliente.
|
||||||
|
[09:29:22.884] Entrando em Modo Cliente. Pos: (2865, 860)
|
||||||
|
[09:29:27.340] Saindo do Modo Cliente.
|
||||||
|
[09:29:28.901] Entrando em Modo Cliente. Pos: (2868, 819)
|
||||||
|
[09:29:30.808] Saindo do Modo Cliente.
|
||||||
|
[09:30:17.696] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[09:30:22.777] Posição alterada para: 1
|
||||||
|
[09:30:33.630] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[09:42:33.108] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[09:42:38.444] Posição alterada para: 1
|
||||||
|
[09:42:43.199] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[09:42:46.978] Entrando em Modo Cliente. Pos: (-2, 865)
|
||||||
|
[09:42:49.387] Saindo do Modo Cliente.
|
||||||
|
[09:42:50.592] Entrando em Modo Cliente. Pos: (-6, 898)
|
||||||
|
[09:42:52.761] Saindo do Modo Cliente.
|
||||||
|
[09:42:54.791] Entrando em Modo Cliente. Pos: (-8, 942)
|
||||||
|
[09:42:59.488] Saindo do Modo Cliente.
|
||||||
|
[10:22:25.896] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[10:22:31.500] Posição alterada para: 1
|
||||||
|
[10:22:36.437] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[10:22:49.156] Entrando em Modo Cliente. Pos: (-1, 843)
|
||||||
|
[10:23:18.364] RETORNO AO HOST. VirtualX: 609. Pos: 1
|
||||||
|
[10:23:18.364] Saindo do Modo Cliente.
|
||||||
|
[10:23:32.467] Entrando em Modo Cliente. Pos: (-5, 848)
|
||||||
|
[10:23:36.996] RETORNO AO HOST. VirtualX: 607. Pos: 1
|
||||||
|
[10:23:36.998] Saindo do Modo Cliente.
|
||||||
|
[10:24:26.939] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[10:24:30.229] Posição alterada para: 1
|
||||||
|
[10:24:34.912] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[10:24:42.439] Entrando em Modo Cliente. Pos: (-14, 884)
|
||||||
|
[10:28:02.965] RETORNO AO HOST. VirtualX: 605. Pos: 1
|
||||||
|
[10:28:02.965] Saindo do Modo Cliente.
|
||||||
|
[11:05:31.633] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:05:34.898] Posição alterada para: 1
|
||||||
|
[11:05:39.630] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:06:44.696] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:06:48.495] Posição alterada para: 1
|
||||||
|
[11:06:55.700] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:07:00.222] Entrando em Modo Cliente. Pos: (-6, 891)
|
||||||
|
[11:07:14.399] RETORNO AO HOST. VirtualX: 620. Pos: 1
|
||||||
|
[11:07:14.399] Saindo do Modo Cliente.
|
||||||
|
[11:07:24.430] Entrando em Modo Cliente. Pos: (-5, 846)
|
||||||
|
[11:08:27.457] RETORNO AO HOST. VirtualX: 618. Pos: 1
|
||||||
|
[11:08:27.458] Saindo do Modo Cliente.
|
||||||
|
[11:14:48.874] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:19:37.432] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:19:46.914] Posição alterada para: 1
|
||||||
|
[11:19:50.268] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:19:55.967] Entrando Modo Cliente. Pos: (-9, 837)
|
||||||
|
[11:20:13.991] RETORNO AO HOST. VirtualX: 624
|
||||||
|
[11:20:13.992] Saindo do Modo Cliente.
|
||||||
|
[11:22:44.004] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:22:48.488] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:22:52.166] Entrando Modo Cliente. Pos: (-13, 806)
|
||||||
|
[11:22:59.135] Saindo Modo Cliente. VirtualX acumulado: 603
|
||||||
|
[11:27:30.261] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:27:35.447] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:28:35.980] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:29:09.690] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:29:14.965] Entrando Modo Cliente. Pos: (-14, 813)
|
||||||
|
[11:29:33.834] Saindo Modo Cliente.
|
||||||
|
[11:51:58.180] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:52:03.638] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:52:24.812] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:53:02.198] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:53:51.757] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:54:18.283] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[11:54:35.205] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[11:54:40.373] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[15:35:23.555] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[15:36:24.111] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[16:09:14.063] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[16:10:56.893] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[16:12:09.289] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[16:13:26.059] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[16:13:40.844] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[16:22:44.207] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[16:31:24.976] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[16:32:03.021] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[16:48:16.283] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[16:48:21.459] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[16:52:15.440] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[16:52:21.547] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[16:52:25.780] Entrando Modo Cliente em (-4, 938)
|
||||||
|
[16:52:31.097] Saindo Modo Cliente.
|
||||||
|
[17:06:27.261] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[17:06:42.837] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[17:07:16.443] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[17:08:11.678] Entrando Modo Cliente em (-10, 1162)
|
||||||
|
[17:08:15.576] Evento Mouse: 0x201 | Data: 0
|
||||||
|
[17:08:15.795] Evento Mouse: 0x202 | Data: 0
|
||||||
|
[17:08:18.563] Saindo Modo Cliente.
|
||||||
|
[17:25:17.509] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[17:25:46.407] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[17:37:23.957] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[17:37:27.573] Entrando Modo Cliente em (-10, 872)
|
||||||
|
[17:37:29.944] Evento Mouse: 0x201 | Data: 0
|
||||||
|
[17:37:30.166] Evento Mouse: 0x202 | Data: 0
|
||||||
|
[17:37:33.920] Saindo Modo Cliente.
|
||||||
|
[17:51:08.792] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[17:52:15.999] Engine Iniciada. Tela: 2880x1800. Pos: 1
|
||||||
|
[09:45:58.258] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[10:01:58.140] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[10:02:03.298] App: Chamando SendCtrlAltDel
|
||||||
|
[10:02:03.298] Enviando CTRL+ALT+DEL...
|
||||||
|
[10:02:03.298] Erro: Transporte não conectado.
|
||||||
|
[10:02:06.169] App: Chamando SendCtrlAltDel
|
||||||
|
[10:02:06.170] Enviando CTRL+ALT+DEL...
|
||||||
|
[10:02:06.170] Erro: Transporte não conectado.
|
||||||
|
[10:02:08.010] Engine Iniciada. Tela: 2880x1800. Pos: 2
|
||||||
|
[10:02:12.417] App: Chamando SendCtrlAltDel
|
||||||
|
[10:02:12.417] Enviando CTRL+ALT+DEL...
|
||||||
|
[10:02:12.581] Sequência CTRL+ALT+DEL enviada.
|
||||||
|
[10:02:15.538] Entrando Modo Cliente em (2879, 727)
|
||||||
|
[10:02:17.162] Evento Mouse: 0x201 | Data: 0
|
||||||
|
[10:02:17.378] Evento Mouse: 0x202 | Data: 0
|
||||||
|
[10:02:18.765] Saindo Modo Cliente.
|
||||||
|
[10:02:21.762] Entrando Modo Cliente em (2890, 954)
|
||||||
|
[10:02:28.196] Saindo Modo Cliente.
|
||||||
|
[10:02:35.501] Entrando Modo Cliente em (2876, 888)
|
||||||
|
[10:02:38.211] Evento Mouse: 0x201 | Data: 0
|
||||||
|
[10:02:38.429] Evento Mouse: 0x202 | Data: 0
|
||||||
|
[10:02:39.707] Evento Mouse: 0x201 | Data: 0
|
||||||
|
[10:02:39.926] Evento Mouse: 0x202 | Data: 0
|
||||||
|
[10:02:44.791] Saindo Modo Cliente.
|
||||||
|
[10:02:46.049] Entrando Modo Cliente em (2897, 760)
|
||||||
|
[10:02:48.162] Saindo Modo Cliente.
|
||||||
36
main.go
Normal file
36
main.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed all:frontend/dist
|
||||||
|
var assets embed.FS
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Create an instance of the app structure
|
||||||
|
app := NewApp()
|
||||||
|
|
||||||
|
// Create application with options
|
||||||
|
err := wails.Run(&options.App{
|
||||||
|
Title: "KVMote",
|
||||||
|
Width: 400,
|
||||||
|
Height: 550,
|
||||||
|
AssetServer: &assetserver.Options{
|
||||||
|
Assets: assets,
|
||||||
|
},
|
||||||
|
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
|
||||||
|
OnStartup: app.startup,
|
||||||
|
Bind: []interface{}{
|
||||||
|
app,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
println("Error:", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
20
wails.json
Normal file
20
wails.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "KVMote",
|
||||||
|
"assetdir": "frontend/dist",
|
||||||
|
"frontend:install": "",
|
||||||
|
"frontend:build": "",
|
||||||
|
"frontend:dev:watcher": "",
|
||||||
|
"frontend:dev:serverUrl": "",
|
||||||
|
"author": {
|
||||||
|
"name": "KVMote Team",
|
||||||
|
"email": ""
|
||||||
|
},
|
||||||
|
"wailsjsdir": "frontend/src/wailsjs",
|
||||||
|
"outputfilename": "kvmote",
|
||||||
|
"info": {
|
||||||
|
"productName": "KVMote",
|
||||||
|
"productVersion": "1.0.0",
|
||||||
|
"copyright": "Copyright 2026",
|
||||||
|
"comments": "KVM over Bluetooth Bridge"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user