ntfy.sh is perfect for this. Here's a preliminary implementation (text-only):
Code: Select all
#Requires AutoHotkey v2
#SingleInstance Force
Persistent
HOST := "ntfy.sh"
SECRET := "XXXXXXXX" ; Replace this with an arbitrary string
OnClipboardChange ClipSender
ClipSender(DataType) {
Global CS
If DataType != 1
Return
CS.Disconnect()
WHR := ComObject("WinHttp.WinHttpRequest.5.1")
WHR.Open("POST", "https://" HOST "/" SECRET, true)
Clip := A_Clipboard
If Clip != ""
WHR.Send(Clip)
WHR.WaitForResponse()
If WHR.Status == 200
Toast("Clipboard Sent")
CS.Connect(CS.URL)
}
CS := ClipReceiver("wss://" HOST "/" SECRET "/ws")
class ClipReceiver extends WebSocket
{
OnMessage(Data) {
Data := this.doc.parentWindow.JSON.parse(Data)
If Data.event == "message" {
OnClipboardChange ClipSender, 0
If Data.hasOwnProperty("attachment") {
A_Clipboard := Data.attachment.url
WHR := ComObject("WinHttp.WinHttpRequest.5.1")
WHR.Open("GET", Data.attachment.url, true)
WHR.Send()
WHR.WaitForResponse()
If WHR.Status != 200
Return
A_Clipboard := WHR.ResponseText
} Else {
A_Clipboard := Data.message
}
Toast("Clipboard Received")
OnClipboardChange ClipSender, 1
}
}
}
Toast(Text := "", Timeout := 1500, Block := false) {
If (Text == "")
Return
UI := GUI("-Caption +AlwaysOnTop -Disabled +ToolWindow +E0x20 +E0x02000000 +E0x00080000")
UI.OnEvent("Size", (GUIObj, MinMax, W, H) => WinSetRegion("0-0 W" W " H" H " r9-9", UI.Hwnd))
UI.MarginX := "40", UI.MarginY := "10"
UI.SetFont("cWhite")
UI.BackColor := "Black"
UI.SetFont("s16", "Segoe UI")
UI.Add("Text", "Center", Text)
UI.Show("NA Hide y" A_ScreenHeight * 0.8)
UI.Show("NA y" A_ScreenHeight * 0.8)
FadeIn()
If (!Block) {
If (Timeout != -1)
SetTimer Dismiss, -Timeout
} Else {
Sleep Timeout
Dismiss()
}
Return UI
Dismiss() {
FadeOut()
UI.Destroy()
}
FadeIn() {
LBound := 0, UBound := 50, I := LBound
While UBound>=++I {
WinSetTransparent(Floor(EaseOutQuart(I / UBound) * 255), UI.Hwnd)
Sleep 1
}
}
FadeOut() {
LBound := 0, UBound := 100, I := UBound
While LBound<--I {
WinSetTransparent(Floor(EaseInQuart(I / UBound) * 255), UI.Hwnd)
Sleep 1
}
}
EaseOutQuart(x) => 1 - (1 - x) ** 4
EaseInQuart(x) => x ** 4
}
/*
* @description websocket Implemented By JS
* @file ws-min.ahk
* @author thqby
* @date 2021/10/04
* @version 0.0.1
*/
class WebSocket {
doc := "", BlockSleep := 50, Timeout := 15000
; usage1
; WebSocket("ws://xxx.xx.xx.xx:xxxx", {Message: (self,data)=>MsgBox(data), Close: (*)=>Msgbox("websocket close")})
; usage2
; class socketinst extends WebSocket
; {
; OnMessage(data)=>MsgBox(data)
; }
; socketinst("ws://xxx.xx.xx.xx:xxxx")
__New(ws_url, Callbacks := "", Timeout := "") {
this.doc := ComObject("htmlfile"), this.doc.write("<meta http-equiv='X-UA-Compatible'content='IE=edge'><body><script>errorinfo='';function tojson(obj){var keys=[];for (k in obj){if (typeof obj[k]!=='function'){keys.push(k);}};return JSON.stringify(obj,keys);}function Connectsocket(url){errorinfo='';try{url=typeof url=='undefined'||url==''?ws.url:url;ws=new WebSocket(url);ws.onopen=function(event){ahk_event('Open',tojson(event));};ws.onclose=function(event){ahk_event('Close',tojson(event));};ws.onerror=function(event){ahk_event('Error',tojson(event));};ws.onmessage=function(event){ahk_event('Message',event.data);};}catch(err){errorinfo=err.message;}}</script></body>")
if IsObject(Callbacks)
for k, v in Type(Callbacks) = "Map" ? Callbacks : Callbacks.OwnProps()
RegExMatch(k, "i)(Open|Close|Message|Error)", &mat) ? (this.%"on" mat[1]% := v) : ""
this.doc.parentWindow.ahk_event := ObjBindMethod(this, "onEvent"), this.Timeout := IsInteger(Timeout) ? Timeout : this.Timeout, this.Connect(ws_url)
}
Connect(ws_url := "") {
this.doc.parentWindow.Connectsocket(ws_url), err := this.doc.parentWindow.errorinfo, endt := A_TickCount + this.Timeout
switch err
{
case "SecurityError":
throw Error("Try to uncheck `"Include all sites that bypass the proxy server`" at Internet Options -> Security -> Local intranet -> Sites")
case "SyntaxError":
throw Error("Invalid WebSocket address")
case "": ; nothing
default:
throw Error(err)
}
while (this.readyState = 0 && A_TickCount < endt)
Sleep(this.BlockSleep)
if (this.readyState = 0) {
this.Disconnect()
throw Error("Connection timed out")
}
}
Send(Data) => this.doc.parentWindow.ws.send(Data)
__Delete() => (this.doc := (this.readyState = 1) ? (this.Disconnect(), "") : "")
Disconnect() => ((this.readyState = 1) ? this.doc.parentWindow.ws.close() : "")
onEvent(EventName, Event) {
if this.HasProp("on" EventName)
this.on%EventName%(Event)
}
bufferedAmount => this.doc.parentWindow.ws.bufferedAmount
readyState => this.doc.parentWindow.ws.readyState
protocol => this.doc.parentWindow.ws.protocol
url => this.doc.parentWindow.ws.url
}
You can also just use the web ui at
https://ntfy.sh/app