Compare commits
4 commits
a2b086a779
...
579869f2f0
| Author | SHA1 | Date | |
|---|---|---|---|
| 579869f2f0 | |||
| 6d466c65a4 | |||
| d0a458b450 | |||
| 5f89601ef2 |
28 changed files with 1310 additions and 4356 deletions
1
.direnv/flake-inputs/bpq48947cigxsm1y1qzz3jxgka63a2dd-source
Symbolic link
1
.direnv/flake-inputs/bpq48947cigxsm1y1qzz3jxgka63a2dd-source
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/bpq48947cigxsm1y1qzz3jxgka63a2dd-source
|
||||||
1
.direnv/flake-inputs/d8j9587fki8g877fjwm5a1l29f29xckm-source
Symbolic link
1
.direnv/flake-inputs/d8j9587fki8g877fjwm5a1l29f29xckm-source
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/d8j9587fki8g877fjwm5a1l29f29xckm-source
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
/nix/store/jh41lavwqi3qdwypiv713yipf3dxi3nx-source
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
/nix/store/npfcdcbsyzm1cnh0jqqn3jf2wx49hgwp-source
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
/nix/store/mq0i12vdknm9wx5w5n7md59xn1z15ag3-my-project-env
|
/nix/store/4kycd6brixc98xkpd97bz3yx8ln96f08-my-project-env
|
||||||
|
|
@ -18,7 +18,7 @@ DEVENV_DOTFILE='/home/nionidh/projects/rust-tomfoolery/cursor-mover-app/.devenv'
|
||||||
export DEVENV_DOTFILE
|
export DEVENV_DOTFILE
|
||||||
DEVENV_FLAKE_SHELL='default'
|
DEVENV_FLAKE_SHELL='default'
|
||||||
export DEVENV_FLAKE_SHELL
|
export DEVENV_FLAKE_SHELL
|
||||||
DEVENV_PROFILE='/nix/store/7wyfm3pdjlbl7747ghfqlvz2rfsf013l-devenv-profile'
|
DEVENV_PROFILE='/nix/store/mpwh8x3hcqkkqcl8aah6c28m54mfdiw0-devenv-profile'
|
||||||
export DEVENV_PROFILE
|
export DEVENV_PROFILE
|
||||||
DEVENV_ROOT='/home/nionidh/projects/rust-tomfoolery/cursor-mover-app'
|
DEVENV_ROOT='/home/nionidh/projects/rust-tomfoolery/cursor-mover-app'
|
||||||
export DEVENV_ROOT
|
export DEVENV_ROOT
|
||||||
|
|
@ -31,7 +31,7 @@ export DEVENV_TASKS
|
||||||
DEVENV_TASK_FILE='/nix/store/r04g3f96h64qk8xzpm7z0vd17w5b494d-tasks.json'
|
DEVENV_TASK_FILE='/nix/store/r04g3f96h64qk8xzpm7z0vd17w5b494d-tasks.json'
|
||||||
export DEVENV_TASK_FILE
|
export DEVENV_TASK_FILE
|
||||||
HOSTTYPE='x86_64'
|
HOSTTYPE='x86_64'
|
||||||
HOST_PATH='/nix/store/idl8schy78hxa05jyndj4nmb4wzgcln2-compiler-rt-libc-21.1.8/bin:/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9/bin:/nix/store/16wfacfgap3chf7mcjnd8dwi85dj4qqi-findutils-4.10.0/bin:/nix/store/3p87h6dn5i87i3iq9364imzbqgwvkg2p-diffutils-3.12/bin:/nix/store/ryz8kcrm2bxpccllfqlb7qldsfnqp5c2-gnused-4.9/bin:/nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12/bin:/nix/store/2xq9rayckw8zq26k274xxlikn77jn60j-gawk-5.3.2/bin:/nix/store/qyg62bc2xnpwz0fa9prqxvvk00zj4g9q-gnutar-1.35/bin:/nix/store/84yyzmxs7mb8nhkvcfv9n1l9irpb6mnq-gzip-1.14/bin:/nix/store/90yw24gqmwph4xjp4mqhpx1y1gcrvqla-bzip2-1.0.8-bin/bin:/nix/store/vbah5c4rzy1q1hbqhginyxjhj8d4dj8j-gnumake-4.4.1/bin:/nix/store/f15k3dpilmiyv6zgpib289rnjykgr1r4-bash-5.3p9/bin:/nix/store/wwij6563c6wbg4kzgjhng7vlhf7api19-patch-2.8/bin:/nix/store/zys6d102zp171wpwcs08g632886w2qxs-xz-5.8.2-bin/bin:/nix/store/nyy0bvgjwd98x7ih8pl6pr79qjljgsf7-file-5.45/bin'
|
HOST_PATH='/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9/bin:/nix/store/16wfacfgap3chf7mcjnd8dwi85dj4qqi-findutils-4.10.0/bin:/nix/store/3p87h6dn5i87i3iq9364imzbqgwvkg2p-diffutils-3.12/bin:/nix/store/ryz8kcrm2bxpccllfqlb7qldsfnqp5c2-gnused-4.9/bin:/nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12/bin:/nix/store/2xq9rayckw8zq26k274xxlikn77jn60j-gawk-5.3.2/bin:/nix/store/qyg62bc2xnpwz0fa9prqxvvk00zj4g9q-gnutar-1.35/bin:/nix/store/84yyzmxs7mb8nhkvcfv9n1l9irpb6mnq-gzip-1.14/bin:/nix/store/90yw24gqmwph4xjp4mqhpx1y1gcrvqla-bzip2-1.0.8-bin/bin:/nix/store/vbah5c4rzy1q1hbqhginyxjhj8d4dj8j-gnumake-4.4.1/bin:/nix/store/f15k3dpilmiyv6zgpib289rnjykgr1r4-bash-5.3p9/bin:/nix/store/wwij6563c6wbg4kzgjhng7vlhf7api19-patch-2.8/bin:/nix/store/zys6d102zp171wpwcs08g632886w2qxs-xz-5.8.2-bin/bin:/nix/store/nyy0bvgjwd98x7ih8pl6pr79qjljgsf7-file-5.45/bin'
|
||||||
export HOST_PATH
|
export HOST_PATH
|
||||||
IFS='
|
IFS='
|
||||||
'
|
'
|
||||||
|
|
@ -53,13 +53,13 @@ NIX_CC='/nix/store/a245z3cvf9x9sn0xlk6k8j9xhxbhda1z-gcc-wrapper-15.2.0'
|
||||||
export NIX_CC
|
export NIX_CC
|
||||||
NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu='1'
|
NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu='1'
|
||||||
export NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
|
export NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
|
||||||
NIX_CFLAGS_COMPILE=' -frandom-seed=mq0i12vdkn -isystem /nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/include -isystem /nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/include -isystem /nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev/include -isystem /nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev/include -isystem /nix/store/rszqwjpka3yy6x72d4n3j12a3gxkqbpn-clang-21.1.8-dev/include -isystem /nix/store/rszqwjpka3yy6x72d4n3j12a3gxkqbpn-clang-21.1.8-dev/include -isystem /nix/store/i5vppnbl2qnrvm4h5azwq83rr9gm7sdy-compiler-rt-libc-21.1.8-dev/include -isystem /nix/store/i5vppnbl2qnrvm4h5azwq83rr9gm7sdy-compiler-rt-libc-21.1.8-dev/include -isystem /nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/include -isystem /nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/include -isystem /nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev/include -isystem /nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev/include -isystem /nix/store/rszqwjpka3yy6x72d4n3j12a3gxkqbpn-clang-21.1.8-dev/include -isystem /nix/store/rszqwjpka3yy6x72d4n3j12a3gxkqbpn-clang-21.1.8-dev/include -isystem /nix/store/i5vppnbl2qnrvm4h5azwq83rr9gm7sdy-compiler-rt-libc-21.1.8-dev/include -isystem /nix/store/i5vppnbl2qnrvm4h5azwq83rr9gm7sdy-compiler-rt-libc-21.1.8-dev/include'
|
NIX_CFLAGS_COMPILE=' -frandom-seed=4kycd6brix -isystem /nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/include -isystem /nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev/include -isystem /nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/include -isystem /nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev/include'
|
||||||
export NIX_CFLAGS_COMPILE
|
export NIX_CFLAGS_COMPILE
|
||||||
NIX_ENFORCE_NO_NATIVE='1'
|
NIX_ENFORCE_NO_NATIVE='1'
|
||||||
export NIX_ENFORCE_NO_NATIVE
|
export NIX_ENFORCE_NO_NATIVE
|
||||||
NIX_HARDENING_ENABLE='bindnow format fortify fortify3 libcxxhardeningextensive libcxxhardeningfast pic relro stackclashprotection stackprotector strictoverflow zerocallusedregs'
|
NIX_HARDENING_ENABLE='bindnow format fortify fortify3 libcxxhardeningextensive libcxxhardeningfast pic relro stackclashprotection stackprotector strictoverflow zerocallusedregs'
|
||||||
export NIX_HARDENING_ENABLE
|
export NIX_HARDENING_ENABLE
|
||||||
NIX_LDFLAGS='-rpath /home/nionidh/projects/rust-tomfoolery/cursor-mover-app/outputs/out/lib -L/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/lib -L/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/lib -L/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/lib -L/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/lib -L/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/lib -L/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/lib -L/nix/store/xibf2ayyaljj1r7wgjf4n7n4vg5z8n2v-clang-21.1.8-lib/lib -L/nix/store/xibf2ayyaljj1r7wgjf4n7n4vg5z8n2v-clang-21.1.8-lib/lib -L/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/lib -L/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/lib -L/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/lib -L/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/lib -L/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/lib -L/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/lib -L/nix/store/xibf2ayyaljj1r7wgjf4n7n4vg5z8n2v-clang-21.1.8-lib/lib -L/nix/store/xibf2ayyaljj1r7wgjf4n7n4vg5z8n2v-clang-21.1.8-lib/lib'
|
NIX_LDFLAGS='-rpath /home/nionidh/projects/rust-tomfoolery/cursor-mover-app/outputs/out/lib -L/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/lib -L/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/lib -L/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/lib -L/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/lib -L/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/lib -L/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/lib'
|
||||||
export NIX_LDFLAGS
|
export NIX_LDFLAGS
|
||||||
NIX_NO_SELF_RPATH='1'
|
NIX_NO_SELF_RPATH='1'
|
||||||
NIX_PKG_CONFIG_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu='1'
|
NIX_PKG_CONFIG_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu='1'
|
||||||
|
|
@ -76,7 +76,7 @@ OLDPWD=''
|
||||||
export OLDPWD
|
export OLDPWD
|
||||||
OPTERR='1'
|
OPTERR='1'
|
||||||
OSTYPE='linux-gnu'
|
OSTYPE='linux-gnu'
|
||||||
PATH='/nix/store/xgixy092whsar7fwm9lmcn4mv9kqn983-process-compose-1.87.0/bin:/nix/store/f53d7gw5jh2yc1rv62kp670gnqq3vwwz-checkall/bin:/nix/store/py79xv22ipf2ycg4qks55wwai9g4w2qg-dioxus-cli-0.7.3/bin:/nix/store/9dpg06rzbppmxi5q8rms8zyybz56sa6r-cargo-expand-1.0.119/bin:/nix/store/fl02yv3ax1qf1xkq64ik8qz5bjxyyd71-cargo-deny-0.19.0/bin:/nix/store/hadf76x1xknx2w6ydp05gzl2w3j40hqy-cargo-nextest-0.9.124/bin:/nix/store/s4rgqv7brrcq2jm8m00dyair22knq10s-typos-1.42.3/bin:/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/bin:/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/bin:/nix/store/m05d7wi0zxg35937jbp6rp7zsvbb5qv4-rust-analyzer-nightly-a96b6a9b887008bae01839543f9ca8e1f67f4ebe/bin:/nix/store/8njkmn9yfcka8yid251wk109n7a6sz1y-wasm-bindgen-cli-0.2.114/bin:/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/bin:/nix/store/6n5r46icm0bl55s9p5z2zgcv93m39r5l-clang-wrapper-21.1.8/bin:/nix/store/rm8isfm4fd14is3fv3h4m459rbiy91bx-clang-21.1.8/bin:/nix/store/0bdqq2z98kg2hfn3k60if6pb5fd5p10h-glibc-2.42-47-bin/bin:/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9/bin:/nix/store/m0rbbdfsbkdqpr6bs621jwi21ra1br4g-binutils-wrapper-2.44/bin:/nix/store/47mn80zqpygykqailwzw8zlag4cgl75q-binutils-2.44/bin:/nix/store/rszqwjpka3yy6x72d4n3j12a3gxkqbpn-clang-21.1.8-dev/bin:/nix/store/rvp7qlpf5jqvdckjy1afjb6aha6j8dxg-pkg-config-wrapper-0.29.2/bin:/nix/store/c2p7haf4zzkbrir9zs662r68c5dmylbq-patchelf-0.15.2/bin:/nix/store/a245z3cvf9x9sn0xlk6k8j9xhxbhda1z-gcc-wrapper-15.2.0/bin:/nix/store/mjf8jlq9grydcdvyw6hb063x5c34g5gf-gcc-15.2.0/bin:/nix/store/i6ppbrlpp6yki8qvka7nyv091xa8dchx-binutils-wrapper-2.44/bin:/nix/store/idl8schy78hxa05jyndj4nmb4wzgcln2-compiler-rt-libc-21.1.8/bin:/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9/bin:/nix/store/16wfacfgap3chf7mcjnd8dwi85dj4qqi-findutils-4.10.0/bin:/nix/store/3p87h6dn5i87i3iq9364imzbqgwvkg2p-diffutils-3.12/bin:/nix/store/ryz8kcrm2bxpccllfqlb7qldsfnqp5c2-gnused-4.9/bin:/nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12/bin:/nix/store/2xq9rayckw8zq26k274xxlikn77jn60j-gawk-5.3.2/bin:/nix/store/qyg62bc2xnpwz0fa9prqxvvk00zj4g9q-gnutar-1.35/bin:/nix/store/84yyzmxs7mb8nhkvcfv9n1l9irpb6mnq-gzip-1.14/bin:/nix/store/90yw24gqmwph4xjp4mqhpx1y1gcrvqla-bzip2-1.0.8-bin/bin:/nix/store/vbah5c4rzy1q1hbqhginyxjhj8d4dj8j-gnumake-4.4.1/bin:/nix/store/f15k3dpilmiyv6zgpib289rnjykgr1r4-bash-5.3p9/bin:/nix/store/wwij6563c6wbg4kzgjhng7vlhf7api19-patch-2.8/bin:/nix/store/zys6d102zp171wpwcs08g632886w2qxs-xz-5.8.2-bin/bin:/nix/store/nyy0bvgjwd98x7ih8pl6pr79qjljgsf7-file-5.45/bin'
|
PATH='/nix/store/xgixy092whsar7fwm9lmcn4mv9kqn983-process-compose-1.87.0/bin:/nix/store/czivij0a8n2z7al3d11m97l4p7x417ak-checkall/bin:/nix/store/py79xv22ipf2ycg4qks55wwai9g4w2qg-dioxus-cli-0.7.3/bin:/nix/store/9dpg06rzbppmxi5q8rms8zyybz56sa6r-cargo-expand-1.0.119/bin:/nix/store/fl02yv3ax1qf1xkq64ik8qz5bjxyyd71-cargo-deny-0.19.0/bin:/nix/store/hadf76x1xknx2w6ydp05gzl2w3j40hqy-cargo-nextest-0.9.124/bin:/nix/store/s4rgqv7brrcq2jm8m00dyair22knq10s-typos-1.42.3/bin:/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125/bin:/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/bin:/nix/store/m05d7wi0zxg35937jbp6rp7zsvbb5qv4-rust-analyzer-nightly-a96b6a9b887008bae01839543f9ca8e1f67f4ebe/bin:/nix/store/8njkmn9yfcka8yid251wk109n7a6sz1y-wasm-bindgen-cli-0.2.114/bin:/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/bin:/nix/store/rvp7qlpf5jqvdckjy1afjb6aha6j8dxg-pkg-config-wrapper-0.29.2/bin:/nix/store/c2p7haf4zzkbrir9zs662r68c5dmylbq-patchelf-0.15.2/bin:/nix/store/a245z3cvf9x9sn0xlk6k8j9xhxbhda1z-gcc-wrapper-15.2.0/bin:/nix/store/mjf8jlq9grydcdvyw6hb063x5c34g5gf-gcc-15.2.0/bin:/nix/store/0bdqq2z98kg2hfn3k60if6pb5fd5p10h-glibc-2.42-47-bin/bin:/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9/bin:/nix/store/i6ppbrlpp6yki8qvka7nyv091xa8dchx-binutils-wrapper-2.44/bin:/nix/store/47mn80zqpygykqailwzw8zlag4cgl75q-binutils-2.44/bin:/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9/bin:/nix/store/16wfacfgap3chf7mcjnd8dwi85dj4qqi-findutils-4.10.0/bin:/nix/store/3p87h6dn5i87i3iq9364imzbqgwvkg2p-diffutils-3.12/bin:/nix/store/ryz8kcrm2bxpccllfqlb7qldsfnqp5c2-gnused-4.9/bin:/nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12/bin:/nix/store/2xq9rayckw8zq26k274xxlikn77jn60j-gawk-5.3.2/bin:/nix/store/qyg62bc2xnpwz0fa9prqxvvk00zj4g9q-gnutar-1.35/bin:/nix/store/84yyzmxs7mb8nhkvcfv9n1l9irpb6mnq-gzip-1.14/bin:/nix/store/90yw24gqmwph4xjp4mqhpx1y1gcrvqla-bzip2-1.0.8-bin/bin:/nix/store/vbah5c4rzy1q1hbqhginyxjhj8d4dj8j-gnumake-4.4.1/bin:/nix/store/f15k3dpilmiyv6zgpib289rnjykgr1r4-bash-5.3p9/bin:/nix/store/wwij6563c6wbg4kzgjhng7vlhf7api19-patch-2.8/bin:/nix/store/zys6d102zp171wpwcs08g632886w2qxs-xz-5.8.2-bin/bin:/nix/store/nyy0bvgjwd98x7ih8pl6pr79qjljgsf7-file-5.45/bin'
|
||||||
export PATH
|
export PATH
|
||||||
PC_CONFIG_FILES='/nix/store/f90qf91rzv18zpk3y4yf5saigawqw9nm-process-compose.yaml'
|
PC_CONFIG_FILES='/nix/store/f90qf91rzv18zpk3y4yf5saigawqw9nm-process-compose.yaml'
|
||||||
export PC_CONFIG_FILES
|
export PC_CONFIG_FILES
|
||||||
|
|
@ -101,7 +101,7 @@ STRINGS='strings'
|
||||||
export STRINGS
|
export STRINGS
|
||||||
STRIP='strip'
|
STRIP='strip'
|
||||||
export STRIP
|
export STRIP
|
||||||
XDG_DATA_DIRS='/nix/store/xgixy092whsar7fwm9lmcn4mv9kqn983-process-compose-1.87.0/share:/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/share:/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/share:/nix/store/rm8isfm4fd14is3fv3h4m459rbiy91bx-clang-21.1.8/share:/nix/store/rvp7qlpf5jqvdckjy1afjb6aha6j8dxg-pkg-config-wrapper-0.29.2/share:/nix/store/c2p7haf4zzkbrir9zs662r68c5dmylbq-patchelf-0.15.2/share'
|
XDG_DATA_DIRS='/nix/store/xgixy092whsar7fwm9lmcn4mv9kqn983-process-compose-1.87.0/share:/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed/share:/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0/share:/nix/store/rvp7qlpf5jqvdckjy1afjb6aha6j8dxg-pkg-config-wrapper-0.29.2/share:/nix/store/c2p7haf4zzkbrir9zs662r68c5dmylbq-patchelf-0.15.2/share'
|
||||||
export XDG_DATA_DIRS
|
export XDG_DATA_DIRS
|
||||||
__structuredAttrs=''
|
__structuredAttrs=''
|
||||||
export __structuredAttrs
|
export __structuredAttrs
|
||||||
|
|
@ -151,8 +151,8 @@ export dontAddDisableDepTrack
|
||||||
declare -a envBuildBuildHooks=()
|
declare -a envBuildBuildHooks=()
|
||||||
declare -a envBuildHostHooks=()
|
declare -a envBuildHostHooks=()
|
||||||
declare -a envBuildTargetHooks=()
|
declare -a envBuildTargetHooks=()
|
||||||
declare -a envHostHostHooks=('ccWrapper_addCVars' 'bintoolsWrapper_addLDVars' 'pkgConfigWrapper_addPkgConfigPath' 'ccWrapper_addCVars' 'bintoolsWrapper_addLDVars' )
|
declare -a envHostHostHooks=('pkgConfigWrapper_addPkgConfigPath' 'ccWrapper_addCVars' 'bintoolsWrapper_addLDVars' )
|
||||||
declare -a envHostTargetHooks=('ccWrapper_addCVars' 'bintoolsWrapper_addLDVars' 'pkgConfigWrapper_addPkgConfigPath' 'ccWrapper_addCVars' 'bintoolsWrapper_addLDVars' )
|
declare -a envHostTargetHooks=('pkgConfigWrapper_addPkgConfigPath' 'ccWrapper_addCVars' 'bintoolsWrapper_addLDVars' )
|
||||||
declare -a envTargetTargetHooks=()
|
declare -a envTargetTargetHooks=()
|
||||||
declare -a fixupOutputHooks=('if [ -z "${dontPatchELF-}" ]; then patchELF "$prefix"; fi' 'if [[ -z "${noAuditTmpdir-}" && -e "$prefix" ]]; then auditTmpdir "$prefix"; fi' 'if [ -z "${dontGzipMan-}" ]; then compressManPages "$prefix"; fi' '_moveLib64' '_moveSbin' '_moveSystemdUserUnits' 'patchShebangsAuto' '_pruneLibtoolFiles' '_doStrip' )
|
declare -a fixupOutputHooks=('if [ -z "${dontPatchELF-}" ]; then patchELF "$prefix"; fi' 'if [[ -z "${noAuditTmpdir-}" && -e "$prefix" ]]; then auditTmpdir "$prefix"; fi' 'if [ -z "${dontGzipMan-}" ]; then compressManPages "$prefix"; fi' '_moveLib64' '_moveSbin' '_moveSystemdUserUnits' 'patchShebangsAuto' '_pruneLibtoolFiles' '_doStrip' )
|
||||||
hardeningDisable=''
|
hardeningDisable=''
|
||||||
|
|
@ -162,7 +162,7 @@ mesonFlags=''
|
||||||
export mesonFlags
|
export mesonFlags
|
||||||
name='my-project-env'
|
name='my-project-env'
|
||||||
export name
|
export name
|
||||||
nativeBuildInputs='/nix/store/xgixy092whsar7fwm9lmcn4mv9kqn983-process-compose-1.87.0 /nix/store/f53d7gw5jh2yc1rv62kp670gnqq3vwwz-checkall /nix/store/py79xv22ipf2ycg4qks55wwai9g4w2qg-dioxus-cli-0.7.3 /nix/store/9dpg06rzbppmxi5q8rms8zyybz56sa6r-cargo-expand-1.0.119 /nix/store/fl02yv3ax1qf1xkq64ik8qz5bjxyyd71-cargo-deny-0.19.0 /nix/store/hadf76x1xknx2w6ydp05gzl2w3j40hqy-cargo-nextest-0.9.124 /nix/store/s4rgqv7brrcq2jm8m00dyair22knq10s-typos-1.42.3 /nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125 /nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed /nix/store/m05d7wi0zxg35937jbp6rp7zsvbb5qv4-rust-analyzer-nightly-a96b6a9b887008bae01839543f9ca8e1f67f4ebe /nix/store/8njkmn9yfcka8yid251wk109n7a6sz1y-wasm-bindgen-cli-0.2.114 /nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev /nix/store/6n5r46icm0bl55s9p5z2zgcv93m39r5l-clang-wrapper-21.1.8 /nix/store/rszqwjpka3yy6x72d4n3j12a3gxkqbpn-clang-21.1.8-dev /nix/store/rvp7qlpf5jqvdckjy1afjb6aha6j8dxg-pkg-config-wrapper-0.29.2'
|
nativeBuildInputs='/nix/store/xgixy092whsar7fwm9lmcn4mv9kqn983-process-compose-1.87.0 /nix/store/czivij0a8n2z7al3d11m97l4p7x417ak-checkall /nix/store/py79xv22ipf2ycg4qks55wwai9g4w2qg-dioxus-cli-0.7.3 /nix/store/9dpg06rzbppmxi5q8rms8zyybz56sa6r-cargo-expand-1.0.119 /nix/store/fl02yv3ax1qf1xkq64ik8qz5bjxyyd71-cargo-deny-0.19.0 /nix/store/hadf76x1xknx2w6ydp05gzl2w3j40hqy-cargo-nextest-0.9.124 /nix/store/s4rgqv7brrcq2jm8m00dyair22knq10s-typos-1.42.3 /nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125 /nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed /nix/store/m05d7wi0zxg35937jbp6rp7zsvbb5qv4-rust-analyzer-nightly-a96b6a9b887008bae01839543f9ca8e1f67f4ebe /nix/store/8njkmn9yfcka8yid251wk109n7a6sz1y-wasm-bindgen-cli-0.2.114 /nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev /nix/store/rvp7qlpf5jqvdckjy1afjb6aha6j8dxg-pkg-config-wrapper-0.29.2'
|
||||||
export nativeBuildInputs
|
export nativeBuildInputs
|
||||||
out='/home/nionidh/projects/rust-tomfoolery/cursor-mover-app/outputs/out'
|
out='/home/nionidh/projects/rust-tomfoolery/cursor-mover-app/outputs/out'
|
||||||
export out
|
export out
|
||||||
|
|
@ -183,9 +183,9 @@ phases='buildPhase'
|
||||||
export phases
|
export phases
|
||||||
pkg='/nix/store/a245z3cvf9x9sn0xlk6k8j9xhxbhda1z-gcc-wrapper-15.2.0'
|
pkg='/nix/store/a245z3cvf9x9sn0xlk6k8j9xhxbhda1z-gcc-wrapper-15.2.0'
|
||||||
declare -a pkgsBuildBuild=()
|
declare -a pkgsBuildBuild=()
|
||||||
declare -a pkgsBuildHost=('/nix/store/xgixy092whsar7fwm9lmcn4mv9kqn983-process-compose-1.87.0' '/nix/store/f53d7gw5jh2yc1rv62kp670gnqq3vwwz-checkall' '/nix/store/py79xv22ipf2ycg4qks55wwai9g4w2qg-dioxus-cli-0.7.3' '/nix/store/9dpg06rzbppmxi5q8rms8zyybz56sa6r-cargo-expand-1.0.119' '/nix/store/fl02yv3ax1qf1xkq64ik8qz5bjxyyd71-cargo-deny-0.19.0' '/nix/store/hadf76x1xknx2w6ydp05gzl2w3j40hqy-cargo-nextest-0.9.124' '/nix/store/s4rgqv7brrcq2jm8m00dyair22knq10s-typos-1.42.3' '/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125' '/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed' '/nix/store/m05d7wi0zxg35937jbp6rp7zsvbb5qv4-rust-analyzer-nightly-a96b6a9b887008bae01839543f9ca8e1f67f4ebe' '/nix/store/8njkmn9yfcka8yid251wk109n7a6sz1y-wasm-bindgen-cli-0.2.114' '/nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev' '/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0' '/nix/store/6n5r46icm0bl55s9p5z2zgcv93m39r5l-clang-wrapper-21.1.8' '/nix/store/m0rbbdfsbkdqpr6bs621jwi21ra1br4g-binutils-wrapper-2.44' '/nix/store/rszqwjpka3yy6x72d4n3j12a3gxkqbpn-clang-21.1.8-dev' '/nix/store/xibf2ayyaljj1r7wgjf4n7n4vg5z8n2v-clang-21.1.8-lib' '/nix/store/rm8isfm4fd14is3fv3h4m459rbiy91bx-clang-21.1.8' '/nix/store/rvp7qlpf5jqvdckjy1afjb6aha6j8dxg-pkg-config-wrapper-0.29.2' '/nix/store/c2p7haf4zzkbrir9zs662r68c5dmylbq-patchelf-0.15.2' '/nix/store/y03z7y8cgdck7vk8qpim30vps4d22gzv-update-autotools-gnu-config-scripts-hook' '/nix/store/0y5xmdb7qfvimjwbq7ibg1xdgkgjwqng-no-broken-symlinks.sh' '/nix/store/cv1d7p48379km6a85h4zp6kr86brh32q-audit-tmpdir.sh' '/nix/store/85clx3b0xkdf58jn161iy80y5223ilbi-compress-man-pages.sh' '/nix/store/p3l1a5y7nllfyrjn2krlwgcc3z0cd3fq-make-symlinks-relative.sh' '/nix/store/5yzw0vhkyszf2d179m0qfkgxmp5wjjx4-move-docs.sh' '/nix/store/fyaryjvghbkpfnsyw97hb3lyb37s1pd6-move-lib64.sh' '/nix/store/kd4xwxjpjxi71jkm6ka0np72if9rm3y0-move-sbin.sh' '/nix/store/pag6l61paj1dc9sv15l7bm5c17xn5kyk-move-systemd-user-units.sh' '/nix/store/cmzya9irvxzlkh7lfy6i82gbp0saxqj3-multiple-outputs.sh' '/nix/store/x8c40nfigps493a07sdr2pm5s9j1cdc0-patch-shebangs.sh' '/nix/store/cickvswrvann041nqxb0rxilc46svw1n-prune-libtool-files.sh' '/nix/store/xyff06pkhki3qy1ls77w10s0v79c9il0-reproducible-builds.sh' '/nix/store/z7k98578dfzi6l3hsvbivzm7hfqlk0zc-set-source-date-epoch-to-latest.sh' '/nix/store/pilsssjjdxvdphlg2h19p0bfx5q0jzkn-strip.sh' '/nix/store/a245z3cvf9x9sn0xlk6k8j9xhxbhda1z-gcc-wrapper-15.2.0' '/nix/store/i6ppbrlpp6yki8qvka7nyv091xa8dchx-binutils-wrapper-2.44' )
|
declare -a pkgsBuildHost=('/nix/store/xgixy092whsar7fwm9lmcn4mv9kqn983-process-compose-1.87.0' '/nix/store/czivij0a8n2z7al3d11m97l4p7x417ak-checkall' '/nix/store/py79xv22ipf2ycg4qks55wwai9g4w2qg-dioxus-cli-0.7.3' '/nix/store/9dpg06rzbppmxi5q8rms8zyybz56sa6r-cargo-expand-1.0.119' '/nix/store/fl02yv3ax1qf1xkq64ik8qz5bjxyyd71-cargo-deny-0.19.0' '/nix/store/hadf76x1xknx2w6ydp05gzl2w3j40hqy-cargo-nextest-0.9.124' '/nix/store/s4rgqv7brrcq2jm8m00dyair22knq10s-typos-1.42.3' '/nix/store/4jp1vkr9gj5n3zbpp2xvkp8n3g56lpv0-binaryen-125' '/nix/store/fwhb4yynphdqiqb48mlh0v5wlwz50s22-rust-mixed' '/nix/store/m05d7wi0zxg35937jbp6rp7zsvbb5qv4-rust-analyzer-nightly-a96b6a9b887008bae01839543f9ca8e1f67f4ebe' '/nix/store/8njkmn9yfcka8yid251wk109n7a6sz1y-wasm-bindgen-cli-0.2.114' '/nix/store/vi6gkki39fqlm3fhvrgkgfpb2b4f4x89-libxkbcommon-1.11.0-dev' '/nix/store/ni6pwnn5cg4mwm2fkmqrm2bzjvj16b64-libxkbcommon-1.11.0' '/nix/store/rvp7qlpf5jqvdckjy1afjb6aha6j8dxg-pkg-config-wrapper-0.29.2' '/nix/store/c2p7haf4zzkbrir9zs662r68c5dmylbq-patchelf-0.15.2' '/nix/store/y03z7y8cgdck7vk8qpim30vps4d22gzv-update-autotools-gnu-config-scripts-hook' '/nix/store/0y5xmdb7qfvimjwbq7ibg1xdgkgjwqng-no-broken-symlinks.sh' '/nix/store/cv1d7p48379km6a85h4zp6kr86brh32q-audit-tmpdir.sh' '/nix/store/85clx3b0xkdf58jn161iy80y5223ilbi-compress-man-pages.sh' '/nix/store/p3l1a5y7nllfyrjn2krlwgcc3z0cd3fq-make-symlinks-relative.sh' '/nix/store/5yzw0vhkyszf2d179m0qfkgxmp5wjjx4-move-docs.sh' '/nix/store/fyaryjvghbkpfnsyw97hb3lyb37s1pd6-move-lib64.sh' '/nix/store/kd4xwxjpjxi71jkm6ka0np72if9rm3y0-move-sbin.sh' '/nix/store/pag6l61paj1dc9sv15l7bm5c17xn5kyk-move-systemd-user-units.sh' '/nix/store/cmzya9irvxzlkh7lfy6i82gbp0saxqj3-multiple-outputs.sh' '/nix/store/x8c40nfigps493a07sdr2pm5s9j1cdc0-patch-shebangs.sh' '/nix/store/cickvswrvann041nqxb0rxilc46svw1n-prune-libtool-files.sh' '/nix/store/xyff06pkhki3qy1ls77w10s0v79c9il0-reproducible-builds.sh' '/nix/store/z7k98578dfzi6l3hsvbivzm7hfqlk0zc-set-source-date-epoch-to-latest.sh' '/nix/store/pilsssjjdxvdphlg2h19p0bfx5q0jzkn-strip.sh' '/nix/store/a245z3cvf9x9sn0xlk6k8j9xhxbhda1z-gcc-wrapper-15.2.0' '/nix/store/i6ppbrlpp6yki8qvka7nyv091xa8dchx-binutils-wrapper-2.44' )
|
||||||
declare -a pkgsBuildTarget=()
|
declare -a pkgsBuildTarget=()
|
||||||
declare -a pkgsHostHost=('/nix/store/i5vppnbl2qnrvm4h5azwq83rr9gm7sdy-compiler-rt-libc-21.1.8-dev' '/nix/store/idl8schy78hxa05jyndj4nmb4wzgcln2-compiler-rt-libc-21.1.8' )
|
declare -a pkgsHostHost=()
|
||||||
declare -a pkgsHostTarget=()
|
declare -a pkgsHostTarget=()
|
||||||
declare -a pkgsTargetTarget=()
|
declare -a pkgsTargetTarget=()
|
||||||
declare -a postFixupHooks=('noBrokenSymlinksInAllOutputs' '_makeSymlinksRelative' '_multioutPropagateDev' )
|
declare -a postFixupHooks=('noBrokenSymlinksInAllOutputs' '_makeSymlinksRelative' '_multioutPropagateDev' )
|
||||||
|
|
@ -231,9 +231,9 @@ if [ ! type -p direnv &>/dev/null && -f .envrc ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$DEVENV_STATE"
|
mkdir -p "$DEVENV_STATE"
|
||||||
if [ ! -L "$DEVENV_DOTFILE/profile" ] || [ "$(/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9/bin/readlink $DEVENV_DOTFILE/profile)" != "/nix/store/7wyfm3pdjlbl7747ghfqlvz2rfsf013l-devenv-profile" ]
|
if [ ! -L "$DEVENV_DOTFILE/profile" ] || [ "$(/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9/bin/readlink $DEVENV_DOTFILE/profile)" != "/nix/store/mpwh8x3hcqkkqcl8aah6c28m54mfdiw0-devenv-profile" ]
|
||||||
then
|
then
|
||||||
ln -snf /nix/store/7wyfm3pdjlbl7747ghfqlvz2rfsf013l-devenv-profile "$DEVENV_DOTFILE/profile"
|
ln -snf /nix/store/mpwh8x3hcqkkqcl8aah6c28m54mfdiw0-devenv-profile "$DEVENV_DOTFILE/profile"
|
||||||
fi
|
fi
|
||||||
unset HOST_PATH NIX_BUILD_CORES __structuredAttrs buildInputs buildPhase builder depsBuildBuild depsBuildBuildPropagated depsBuildTarget depsBuildTargetPropagated depsHostHost depsHostHostPropagated depsTargetTarget depsTargetTargetPropagated dontAddDisableDepTrack doCheck doInstallCheck nativeBuildInputs out outputs patches phases preferLocalBuild propagatedBuildInputs propagatedNativeBuildInputs shell shellHook stdenv strictDeps
|
unset HOST_PATH NIX_BUILD_CORES __structuredAttrs buildInputs buildPhase builder depsBuildBuild depsBuildBuildPropagated depsBuildTarget depsBuildTargetPropagated depsHostHost depsHostHostPropagated depsTargetTarget depsTargetTargetPropagated dontAddDisableDepTrack doCheck doInstallCheck nativeBuildInputs out outputs patches phases preferLocalBuild propagatedBuildInputs propagatedNativeBuildInputs shell shellHook stdenv strictDeps
|
||||||
|
|
||||||
|
|
@ -241,10 +241,10 @@ mkdir -p /tmp/devenv-b51d30d
|
||||||
ln -snf /tmp/devenv-b51d30d /home/nionidh/projects/rust-tomfoolery/cursor-mover-app/.devenv/run
|
ln -snf /tmp/devenv-b51d30d /home/nionidh/projects/rust-tomfoolery/cursor-mover-app/.devenv/run
|
||||||
|
|
||||||
|
|
||||||
export PATH=/nix/store/c0xxs40qc5szabj2yiimh0cziknji84q-devenv-flake-compat/bin:$PATH
|
export PATH=/nix/store/f7qg5ng20s1mi9438padw0iy5gx3pci1-devenv-flake-compat/bin:$PATH
|
||||||
|
|
||||||
if [ -z "${DEVENV_SKIP_TASKS:-}" ]; then
|
if [ -z "${DEVENV_SKIP_TASKS:-}" ]; then
|
||||||
/nix/store/vjc136ikp6is5m8jv4r5s24gwcfl2naf-devenv-tasks-2.0.0/bin/devenv-tasks run devenv:enterShell --mode all --cache-dir /home/nionidh/projects/rust-tomfoolery/cursor-mover-app/.devenv --runtime-dir /tmp/devenv-b51d30d || exit $?
|
/nix/store/2a3cn42zhsg4yckjvy9yp5qh62xy0qx3-devenv-tasks-2.0.0/bin/devenv-tasks run devenv:enterShell --mode all --cache-dir /home/nionidh/projects/rust-tomfoolery/cursor-mover-app/.devenv --runtime-dir /tmp/devenv-b51d30d || exit $?
|
||||||
if [ -f "$DEVENV_DOTFILE/load-exports" ]; then
|
if [ -f "$DEVENV_DOTFILE/load-exports" ]; then
|
||||||
source "$DEVENV_DOTFILE/load-exports"
|
source "$DEVENV_DOTFILE/load-exports"
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
2652
Cargo.lock
generated
2652
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
26
Cargo.toml
26
Cargo.toml
|
|
@ -1,19 +1,21 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["crates/cursor-mover-app"
|
members = ["crates/cursor-move-webapp"]
|
||||||
, "crates/cursor-move-webapp"]
|
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
the-lib = {path="crates/the-lib", version="0.0.0"}
|
the-lib = {path="crates/the-lib", version="0.0.0"}
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
all = "warn"
|
all = {level = "warn", priority = -1}
|
||||||
correctness = "deny"
|
correctness = {level = "deny", priority = -1}
|
||||||
suspicious = "warn"
|
suspicious = {level = "warn", priority = -1}
|
||||||
complexity = "warn"
|
complexity = {level = "warn", priority = -1}
|
||||||
perf = "warn"
|
perf = {level = "warn", priority = -1}
|
||||||
style = "warn"
|
style = {level = "warn", priority = -1}
|
||||||
pedantic = "warn"
|
pedantic = {level = "warn", priority = -1}
|
||||||
restriction = "allow"
|
restriction = {level = "allow", priority = -1}
|
||||||
cargo = "warn"
|
cargo = {level = "warn", priority = -1}
|
||||||
nursery = "warn"
|
nursery = {level = "warn", priority = -1}
|
||||||
|
|
||||||
|
# cargo deny takes care of that
|
||||||
|
multiple-crate-versions = "allow"
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,27 @@ name = "cursor-move-webapp"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Mona Mayrhofer <mona.mayrhofer@proton.me>"]
|
authors = ["Mona Mayrhofer <mona.mayrhofer@proton.me>"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
repository = "https://github.com/mona-mayrhofer/cursor-mover-app"
|
||||||
|
categories = ["tools"]
|
||||||
|
keywords = ["tools", "cursor", "remote"]
|
||||||
|
license = "EUPL-1.2"
|
||||||
|
description = "A web application for controlling your cursor and keyboard via a smartphone browser."
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus = { version = "0.7.3", features = ["router", "fullstack", "logger"] }
|
dioxus = { version = "0.7.3", features = ["router", "fullstack", "logger"] }
|
||||||
|
dioxus-html = { version = "0.7.3", features = ["serialize"] }
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
wasmtimer = "0.4.3"
|
||||||
|
|
||||||
|
|
||||||
wayland-client = { version = "0.31.12", optional = true }
|
wayland-client = { version = "0.31.12", optional = true }
|
||||||
wayland-protocols-wlr = { version = "0.3.10", features = ["client"], optional = true }
|
wayland-protocols-wlr = { version = "0.3.10", features = ["client"], optional = true }
|
||||||
tokio = {version = "1.49.0", optional = true}
|
tokio = {version = "1.49.0", optional = true}
|
||||||
rustix = { version = "1.1.4", optional = true, features = ["time"] }
|
rustix = { version = "1.1.4", optional = true, features = ["time"], default-features = false }
|
||||||
wayland-protocols-misc = { version = "0.3.10", features = ["client"], optional = true }
|
wayland-protocols-misc = { version = "0.3.10", features = ["client"], optional = true }
|
||||||
wayland-protocols = { version = "0.32.10", features = ["client", "staging"], optional = true }
|
wayland-protocols = { version = "0.32.10", features = ["client", "staging"], optional = true }
|
||||||
xkb = {version = "0.3.0", optional = true}
|
|
||||||
memfile = {version = "0.3.2", optional = true}
|
memfile = {version = "0.3.2", optional = true}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
@ -24,9 +31,9 @@ default = ["web"]
|
||||||
# The feature that are only required for the web = ["dioxus/web"] build target should be optional and only enabled in the web = ["dioxus/web"] feature
|
# The feature that are only required for the web = ["dioxus/web"] build target should be optional and only enabled in the web = ["dioxus/web"] feature
|
||||||
web = ["dioxus/web"]
|
web = ["dioxus/web"]
|
||||||
# The feature that are only required for the desktop = ["dioxus/desktop"] build target should be optional and only enabled in the desktop = ["dioxus/desktop"] feature
|
# The feature that are only required for the desktop = ["dioxus/desktop"] build target should be optional and only enabled in the desktop = ["dioxus/desktop"] feature
|
||||||
desktop = ["dioxus/desktop"]
|
#desktop = ["dioxus/desktop"]
|
||||||
# The feature that are only required for the mobile = ["dioxus/mobile"] build target should be optional and only enabled in the mobile = ["dioxus/mobile"] feature
|
# The feature that are only required for the mobile = ["dioxus/mobile"] build target should be optional and only enabled in the mobile = ["dioxus/mobile"] feature
|
||||||
mobile = ["dioxus/mobile"]
|
#mobile = ["dioxus/mobile"]
|
||||||
# The feature that are only required for the server = ["dioxus/server"] build target should be optional and only enabled in the server = ["dioxus/server"] feature
|
# The feature that are only required for the server = ["dioxus/server"] build target should be optional and only enabled in the server = ["dioxus/server"] feature
|
||||||
server = ["dioxus/server",
|
server = ["dioxus/server",
|
||||||
"dep:wayland-client",
|
"dep:wayland-client",
|
||||||
|
|
@ -35,7 +42,6 @@ server = ["dioxus/server",
|
||||||
"dep:wayland-protocols",
|
"dep:wayland-protocols",
|
||||||
"dep:tokio",
|
"dep:tokio",
|
||||||
"dep:rustix",
|
"dep:rustix",
|
||||||
"dep:xkb",
|
|
||||||
"dep:memfile"
|
"dep:memfile"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.controls {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
.keyboard-area {
|
||||||
|
height: 48px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,8 +3,9 @@ body,
|
||||||
#main {
|
#main {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
min-height: 100vh;
|
min-height: 100dvh;
|
||||||
width: 100vw;
|
width: 100dvw;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main {
|
#main {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.mouse-area {
|
.mouse-area {
|
||||||
background-color: white;
|
background: radial-gradient(#0004 15%, transparent 20%), white;
|
||||||
|
background-size: 15px 15px;
|
||||||
|
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
|
|
||||||
96
crates/cursor-move-webapp/src/components/controls.rs
Normal file
96
crates/cursor-move-webapp/src/components/controls.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
use dioxus::{
|
||||||
|
fullstack::{CborEncoding, WebSocketOptions, Websocket, extract::State, use_websocket},
|
||||||
|
html::input_data::MouseButton,
|
||||||
|
logger::tracing,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::components::{KeyboardArea, MouseArea};
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Controls() -> Element {
|
||||||
|
#[css_module("/assets/styling/controls.module.css")]
|
||||||
|
struct Styles;
|
||||||
|
|
||||||
|
let mut socket = use_websocket(move || mouse_move(WebSocketOptions::new()));
|
||||||
|
|
||||||
|
use_future(move || async move {
|
||||||
|
loop {
|
||||||
|
// Wait for the socket to connect
|
||||||
|
_ = socket.connect().await;
|
||||||
|
|
||||||
|
// Loop poll with recv. Throws an error when the connection closes, making it possible
|
||||||
|
// to run code before the socket re-connects when the name input changes
|
||||||
|
while let Ok(message) = socket.recv().await {
|
||||||
|
tracing::info!("Received message: {:?}", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let event_handler = use_callback(move |evt| {
|
||||||
|
spawn(async move {
|
||||||
|
_ = socket.send(evt).await;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: Styles::controls,
|
||||||
|
MouseArea { onevent: event_handler }
|
||||||
|
KeyboardArea { onevent: event_handler }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub enum ClientEvent {
|
||||||
|
MouseMove { dx: f64, dy: f64 },
|
||||||
|
MouseScroll { dx: f64, dy: f64 },
|
||||||
|
Click { button: MouseButton },
|
||||||
|
KeyPressEvent { key: String },
|
||||||
|
TextInputStartEvent,
|
||||||
|
TextInputEvent { text: String },
|
||||||
|
TextInputDoneEvent { text: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
enum ServerEvent {
|
||||||
|
Ping,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(clippy::unused_async)]
|
||||||
|
#[get("/api/mouse_move_ws", mouse_service: State<crate::server::input_proxy_service::InputProxyService>)]
|
||||||
|
async fn mouse_move(
|
||||||
|
options: WebSocketOptions
|
||||||
|
) -> Result<Websocket<ClientEvent, ServerEvent, CborEncoding>> {
|
||||||
|
Ok(options.on_upgrade(move |mut socket| async move {
|
||||||
|
_ = socket.send(ServerEvent::Ping).await;
|
||||||
|
|
||||||
|
while let Ok(event) = socket.recv().await {
|
||||||
|
match event {
|
||||||
|
ClientEvent::MouseMove { dx, dy } => {
|
||||||
|
mouse_service.move_mouse(dx, dy).await;
|
||||||
|
},
|
||||||
|
ClientEvent::MouseScroll { dx, dy } => {
|
||||||
|
mouse_service.mouse_scroll(dx, dy).await;
|
||||||
|
},
|
||||||
|
ClientEvent::Click { button } => {
|
||||||
|
mouse_service.click(button).await;
|
||||||
|
},
|
||||||
|
ClientEvent::KeyPressEvent { key } => {
|
||||||
|
mouse_service.key_press_event(key).await;
|
||||||
|
},
|
||||||
|
ClientEvent::TextInputEvent { text } => {
|
||||||
|
mouse_service.text_input(text).await;
|
||||||
|
},
|
||||||
|
ClientEvent::TextInputStartEvent => {
|
||||||
|
mouse_service.text_input_start().await;
|
||||||
|
},
|
||||||
|
ClientEvent::TextInputDoneEvent { text } => {
|
||||||
|
mouse_service.text_input_end(text).await;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
57
crates/cursor-move-webapp/src/components/keyboard_area.rs
Normal file
57
crates/cursor-move-webapp/src/components/keyboard_area.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
use crate::components::controls::ClientEvent;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn KeyboardArea(onevent: EventHandler<ClientEvent>) -> Element {
|
||||||
|
#[css_module("/assets/styling/keyboard_area.module.css")]
|
||||||
|
struct Styles;
|
||||||
|
|
||||||
|
let mut input_state = use_signal(String::new);
|
||||||
|
let input_handler = use_callback(move |evt: Event<FormData>| {
|
||||||
|
let v = evt.value();
|
||||||
|
input_state.set(v.clone());
|
||||||
|
|
||||||
|
onevent.call(ClientEvent::TextInputEvent { text: v });
|
||||||
|
});
|
||||||
|
let key_press_handler = use_callback(move |evt: Event<KeyboardData>| {
|
||||||
|
if input_state.read().is_empty() {
|
||||||
|
match evt.key() {
|
||||||
|
Key::Character(_) => {},
|
||||||
|
_ => {
|
||||||
|
onevent.call(ClientEvent::KeyPressEvent {
|
||||||
|
key: evt.key().to_string(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else if evt.key() == Key::Enter {
|
||||||
|
onevent.call(ClientEvent::TextInputDoneEvent {
|
||||||
|
text: input_state.replace(String::new()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let input_focus_handler = use_callback(move |_: Event<FocusData>| {
|
||||||
|
input_state.set(String::new());
|
||||||
|
onevent.call(ClientEvent::TextInputStartEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
let input_blur_handler = use_callback(move |_: Event<FocusData>| {
|
||||||
|
onevent.call(ClientEvent::TextInputDoneEvent {
|
||||||
|
text: input_state.replace(String::new()),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: Styles::keyboard_area,
|
||||||
|
|
||||||
|
input {
|
||||||
|
oninput: input_handler,
|
||||||
|
value: input_state,
|
||||||
|
onkeydown: key_press_handler,
|
||||||
|
onfocus: input_focus_handler,
|
||||||
|
onblur: input_blur_handler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,2 +1,6 @@
|
||||||
|
mod controls;
|
||||||
|
mod keyboard_area;
|
||||||
mod mouse_area;
|
mod mouse_area;
|
||||||
|
pub use controls::Controls;
|
||||||
|
pub use keyboard_area::KeyboardArea;
|
||||||
pub use mouse_area::MouseArea;
|
pub use mouse_area::MouseArea;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
use std::{collections::HashMap, ops::Sub, time::Duration};
|
||||||
|
|
||||||
use dioxus::{
|
use dioxus::{
|
||||||
fullstack::{CborEncoding, WebSocketOptions, Websocket, extract::State, use_websocket},
|
|
||||||
html::{
|
html::{
|
||||||
geometry::{ElementSpace, euclid::Point2D},
|
geometry::{ElementSpace, euclid::Point2D},
|
||||||
input_data::MouseButton,
|
input_data::MouseButton,
|
||||||
|
|
@ -7,131 +8,162 @@ use dioxus::{
|
||||||
logger::tracing,
|
logger::tracing,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use dioxus_html::geometry::euclid::Vector2D;
|
||||||
|
|
||||||
|
use crate::{components::controls::ClientEvent, utils::mouse_filter_buffer::MouseFilterBuffer};
|
||||||
|
|
||||||
|
const FLING_START_THRESHOLD_VELOCITY: f64 = 500.0;
|
||||||
|
const FLING_STOP_THRESHOLD_VELOCITY: f64 = 100.0;
|
||||||
|
const FLING_DAMPENING: f64 = 0.98;
|
||||||
|
|
||||||
|
const CURSOR_SPEED_MULTIPLIER: f64 = 1.5;
|
||||||
|
|
||||||
|
pub struct PointerRegistryData {
|
||||||
|
initial_position: Point2D<f64, ElementSpace>,
|
||||||
|
|
||||||
|
last_positions: MouseFilterBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FlingerData {
|
||||||
|
velocity: Vector2D<f64, ElementSpace>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct PointerRegistry {
|
||||||
|
pointers: HashMap<i32, PointerRegistryData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct FlingerRegistry {
|
||||||
|
flinger: Option<FlingerData>,
|
||||||
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn MouseArea() -> Element {
|
pub fn MouseArea(onevent: EventHandler<ClientEvent>) -> Element {
|
||||||
#[css_module("/assets/styling/mouse_area.module.css")]
|
#[css_module("/assets/styling/mouse_area.module.css")]
|
||||||
struct Styles;
|
struct Styles;
|
||||||
|
|
||||||
let mut last_cursor_position = use_signal::<Option<Point2D<f64, ElementSpace>>>(|| None);
|
let mut registry = use_signal::<PointerRegistry>(PointerRegistry::default);
|
||||||
|
let mut flingers = use_signal::<FlingerRegistry>(FlingerRegistry::default);
|
||||||
let mut socket = use_websocket(move || mouse_move(WebSocketOptions::new()));
|
|
||||||
|
|
||||||
use_future(move || async move {
|
|
||||||
loop {
|
|
||||||
// Wait for the socket to connect
|
|
||||||
_ = socket.connect().await;
|
|
||||||
|
|
||||||
// Loop poll with recv. Throws an error when the connection closes, making it possible
|
|
||||||
// to run code before the socket re-connects when the name input changes
|
|
||||||
while let Ok(message) = socket.recv().await {
|
|
||||||
tracing::info!("Received message: {:?}", message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let pointer_move_handler = use_callback(move |evt: Event<PointerData>| {
|
let pointer_move_handler = use_callback(move |evt: Event<PointerData>| {
|
||||||
if evt.held_buttons().contains(MouseButton::Primary) {
|
let mut registry = registry.write();
|
||||||
|
if let Some(data) = registry.pointers.get_mut(&evt.pointer_id()) {
|
||||||
evt.prevent_default();
|
evt.prevent_default();
|
||||||
let point = evt.element_coordinates();
|
let point = evt.element_coordinates();
|
||||||
let last_position = last_cursor_position.write().replace(point);
|
let last_position = data.last_positions.back();
|
||||||
|
let delta = point - last_position.position;
|
||||||
|
|
||||||
if let Some(last_position) = last_position {
|
data.last_positions
|
||||||
let delta = point - last_position;
|
.push(point, wasmtimer::std::SystemTime::now());
|
||||||
|
|
||||||
spawn(async move {
|
if registry.pointers.len() == 1 {
|
||||||
_ = socket
|
onevent.call(ClientEvent::MouseMove {
|
||||||
.send(ClientEvent::MouseMove {
|
dx: delta.x * CURSOR_SPEED_MULTIPLIER,
|
||||||
dx: delta.x,
|
dy: delta.y * CURSOR_SPEED_MULTIPLIER,
|
||||||
dy: delta.y,
|
});
|
||||||
})
|
} else if registry.pointers.len() == 2 {
|
||||||
.await;
|
onevent.call(ClientEvent::MouseScroll {
|
||||||
|
dx: -delta.x,
|
||||||
|
dy: -delta.y,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let pointer_down_handler = use_callback(move |evt: Event<PointerData>| {
|
let pointer_down_handler = use_callback(move |evt: Event<PointerData>| {
|
||||||
|
//If any pointer is down, we cancel the flingers
|
||||||
|
flingers.write().flinger.take();
|
||||||
|
|
||||||
let point = evt.element_coordinates();
|
let point = evt.element_coordinates();
|
||||||
*last_cursor_position.write() = Some(point);
|
|
||||||
|
registry.write().pointers.insert(
|
||||||
|
evt.pointer_id(),
|
||||||
|
PointerRegistryData {
|
||||||
|
last_positions: MouseFilterBuffer::new(
|
||||||
|
10,
|
||||||
|
point,
|
||||||
|
wasmtimer::std::SystemTime::now(),
|
||||||
|
),
|
||||||
|
initial_position: point,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
let pointer_up_handler = use_callback(move |evt: Event<PointerData>| {
|
||||||
|
let point = evt.element_coordinates();
|
||||||
|
let mut registry = registry.write();
|
||||||
|
let data = registry.pointers.remove(&evt.pointer_id());
|
||||||
|
if let Some(data) = data {
|
||||||
|
let distance_moved = data.initial_position - point;
|
||||||
|
let release_velocity = data.last_positions.average_velocity_since(
|
||||||
|
wasmtimer::std::SystemTime::now().sub(Duration::from_millis(100)),
|
||||||
|
);
|
||||||
|
tracing::info!("Release Velocity: {:?}", release_velocity.length());
|
||||||
|
|
||||||
|
if distance_moved.length() <= 1.0 {
|
||||||
|
match registry.pointers.len() {
|
||||||
|
0 => {
|
||||||
|
onevent.call(ClientEvent::Click {
|
||||||
|
button: MouseButton::Primary,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
1 => {
|
||||||
|
onevent.call(ClientEvent::Click {
|
||||||
|
button: MouseButton::Secondary,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
} else if release_velocity.length() > FLING_START_THRESHOLD_VELOCITY {
|
||||||
|
//We only fling if there are no other pointers
|
||||||
|
if registry.pointers.is_empty() {
|
||||||
|
flingers.write().flinger = Some(FlingerData {
|
||||||
|
velocity: release_velocity,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let pointer_click_handler = use_callback(move |evt: Event<MouseData>| {
|
use_future(move || async move {
|
||||||
spawn(async move {
|
let mut last_frame_time = wasmtimer::std::SystemTime::now();
|
||||||
_ = socket.send(ClientEvent::Click).await;
|
|
||||||
});
|
loop {
|
||||||
|
wasmtimer::tokio::sleep(Duration::from_millis(16)).await;
|
||||||
|
let new_frame_time = wasmtimer::std::SystemTime::now();
|
||||||
|
let delta_seconds = new_frame_time
|
||||||
|
.duration_since(last_frame_time)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs_f64();
|
||||||
|
last_frame_time = new_frame_time;
|
||||||
|
|
||||||
|
let mut flinger = flingers.write();
|
||||||
|
let new_flinger = flinger.flinger.as_ref().and_then(|flinger| {
|
||||||
|
if flinger.velocity.length() < FLING_STOP_THRESHOLD_VELOCITY {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
onevent.call(ClientEvent::MouseMove {
|
||||||
|
dx: flinger.velocity.x * delta_seconds * CURSOR_SPEED_MULTIPLIER,
|
||||||
|
dy: flinger.velocity.y * delta_seconds * CURSOR_SPEED_MULTIPLIER,
|
||||||
});
|
});
|
||||||
|
|
||||||
let key_down_handler = use_callback(move |evt: Event<KeyboardData>| {
|
//tracing::info!("Fling: {:?}", flinger.velocity);
|
||||||
tracing::info!("Keydown");
|
Some(FlingerData {
|
||||||
spawn(async move {
|
velocity: flinger.velocity * FLING_DAMPENING,
|
||||||
_ = socket
|
|
||||||
.send(ClientEvent::KeyEvent {
|
|
||||||
key: evt.key().to_string(),
|
|
||||||
is_pressed: true,
|
|
||||||
})
|
})
|
||||||
.await;
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let key_up_handler = use_callback(move |evt: Event<KeyboardData>| {
|
|
||||||
spawn(async move {
|
|
||||||
_ = socket
|
|
||||||
.send(ClientEvent::KeyEvent {
|
|
||||||
key: evt.key().to_string(),
|
|
||||||
is_pressed: false,
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
});
|
});
|
||||||
|
flinger.flinger = new_flinger;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
|
||||||
input { onkeydown: key_down_handler, onkeyup: key_up_handler}
|
|
||||||
div {
|
div {
|
||||||
class: Styles::mouse_area,
|
class: Styles::mouse_area,
|
||||||
|
|
||||||
onpointermove: pointer_move_handler,
|
onpointermove: pointer_move_handler,
|
||||||
onpointerdown: pointer_down_handler,
|
onpointerdown: pointer_down_handler,
|
||||||
onclick: pointer_click_handler
|
onpointerup: pointer_up_handler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
enum ClientEvent {
|
|
||||||
MouseMove { dx: f64, dy: f64 },
|
|
||||||
Click,
|
|
||||||
KeyEvent { key: String, is_pressed: bool },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
enum ServerEvent {
|
|
||||||
Ping,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[expect(clippy::unused_async)]
|
|
||||||
#[get("/api/mouse_move_ws", mouse_service: State<crate::server::input_proxy_service::InputProxyService>)]
|
|
||||||
async fn mouse_move(
|
|
||||||
options: WebSocketOptions
|
|
||||||
) -> Result<Websocket<ClientEvent, ServerEvent, CborEncoding>> {
|
|
||||||
Ok(options.on_upgrade(move |mut socket| async move {
|
|
||||||
_ = socket.send(ServerEvent::Ping).await;
|
|
||||||
|
|
||||||
while let Ok(event) = socket.recv().await {
|
|
||||||
match event {
|
|
||||||
ClientEvent::MouseMove { dx, dy } => {
|
|
||||||
mouse_service.move_mouse(dx, dy).await;
|
|
||||||
},
|
|
||||||
ClientEvent::Click => {
|
|
||||||
mouse_service.click().await;
|
|
||||||
},
|
|
||||||
ClientEvent::KeyEvent { key, is_pressed } => {
|
|
||||||
mouse_service.key_event(key, is_pressed).await;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use dioxus::prelude::*;
|
||||||
use views::{Home, Navbar};
|
use views::{Home, Navbar};
|
||||||
|
|
||||||
mod components;
|
mod components;
|
||||||
|
mod utils;
|
||||||
mod views;
|
mod views;
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
|
|
@ -45,6 +46,7 @@ fn App() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
document::Link { rel: "icon", href: FAVICON }
|
document::Link { rel: "icon", href: FAVICON }
|
||||||
document::Link { rel: "stylesheet", href: MAIN_CSS }
|
document::Link { rel: "stylesheet", href: MAIN_CSS }
|
||||||
|
document::Meta { name: "viewport", content: "width=device-width, initial-scale=1.0" }
|
||||||
|
|
||||||
Router::<Route> {}
|
Router::<Route> {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,44 @@
|
||||||
use std::{io::Write, str::FromStr, sync::Arc, time::Duration};
|
use std::{io::Write, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use dioxus::{
|
use dioxus::{
|
||||||
fullstack::{FullstackContext, extract::FromRef},
|
fullstack::{FullstackContext, extract::FromRef},
|
||||||
html::Key,
|
|
||||||
logger::tracing,
|
logger::tracing,
|
||||||
};
|
};
|
||||||
|
use dioxus_html::input_data::MouseButton;
|
||||||
use memfile::MemFile;
|
use memfile::MemFile;
|
||||||
use rustix::time::{ClockId, clock_gettime};
|
use rustix::time::{ClockId, clock_gettime};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
Connection, Dispatch, EventQueue, Proxy, QueueHandle,
|
Connection, Dispatch, EventQueue, Proxy, QueueHandle,
|
||||||
protocol::{
|
protocol::{
|
||||||
wl_pointer::ButtonState,
|
wl_pointer::{Axis, ButtonState},
|
||||||
wl_registry::{Event, WlRegistry},
|
wl_registry::{Event, WlRegistry},
|
||||||
wl_seat::{self, WlSeat},
|
wl_seat::{self, WlSeat},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::{
|
use wayland_protocols_misc::{
|
||||||
|
zwp_input_method_v2::client::{
|
||||||
|
zwp_input_method_manager_v2::ZwpInputMethodManagerV2, zwp_input_method_v2::ZwpInputMethodV2,
|
||||||
|
},
|
||||||
|
zwp_virtual_keyboard_v1::client::{
|
||||||
zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1,
|
zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1,
|
||||||
zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
|
zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use wayland_protocols_wlr::virtual_pointer::v1::client::{
|
use wayland_protocols_wlr::virtual_pointer::v1::client::{
|
||||||
zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1,
|
zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1,
|
||||||
zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1,
|
zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::server::keymap;
|
use crate::server::keymap::{self, web_key_to_linux_keycode};
|
||||||
|
|
||||||
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
|
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
|
||||||
const BUTTON_LEFT: u32 = 0x110;
|
const BUTTON_LEFT: u32 = 0x110;
|
||||||
const BTN_RIGHT: u32 = 0x111;
|
const BUTTON_RIGHT: u32 = 0x111;
|
||||||
const BTN_MIDDLE: u32 = 0x112;
|
const BUTTON_MIDDLE: u32 = 0x112;
|
||||||
|
|
||||||
// https://wayland.app/protocols/wayland#wl_keyboard:enum:keymap_format
|
// https://wayland.app/protocols/wayland#wl_keyboard:enum:keymap_format
|
||||||
|
#[expect(unused)]
|
||||||
const NO_KEYMAP: u32 = 0;
|
const NO_KEYMAP: u32 = 0;
|
||||||
const XKB_V1: u32 = 1;
|
const XKB_V1: u32 = 1;
|
||||||
|
|
||||||
|
|
@ -74,33 +80,103 @@ impl InputProxyService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn click(&self) {
|
pub async fn mouse_scroll(
|
||||||
|
&self,
|
||||||
|
dx: f64,
|
||||||
|
dy: f64,
|
||||||
|
) {
|
||||||
let guard = self.input_proxy_service_state.lock().await;
|
let guard = self.input_proxy_service_state.lock().await;
|
||||||
if let Some(pointer) = &guard.state.virtual_pointer() {
|
if let Some(pointer) = &guard.state.virtual_pointer() {
|
||||||
tracing::info!("Do click");
|
|
||||||
let time = get_wayland_timestamp();
|
let time = get_wayland_timestamp();
|
||||||
|
pointer.axis(time, Axis::HorizontalScroll, dx);
|
||||||
pointer.button(time, BUTTON_LEFT, ButtonState::Pressed);
|
pointer.axis(time, Axis::VerticalScroll, dy);
|
||||||
pointer.frame();
|
|
||||||
pointer.button(time, BUTTON_LEFT, ButtonState::Released);
|
|
||||||
pointer.frame();
|
pointer.frame();
|
||||||
guard.event_queue.flush().unwrap();
|
guard.event_queue.flush().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn key_event(
|
pub async fn click(
|
||||||
&self,
|
&self,
|
||||||
key: String,
|
button: MouseButton,
|
||||||
is_pressed: bool,
|
|
||||||
) {
|
) {
|
||||||
let guard = self.input_proxy_service_state.lock().await;
|
let guard = self.input_proxy_service_state.lock().await;
|
||||||
if let Some(keyboard) = &guard.state.virtual_keyboard() {
|
if let Some(pointer) = &guard.state.virtual_pointer() {
|
||||||
|
tracing::info!("Do click");
|
||||||
let time = get_wayland_timestamp();
|
let time = get_wayland_timestamp();
|
||||||
|
|
||||||
let key = Key::from_str(key.as_str()).unwrap().legacy_charcode();
|
let button = match button {
|
||||||
|
MouseButton::Primary => BUTTON_LEFT,
|
||||||
|
MouseButton::Secondary => BUTTON_RIGHT,
|
||||||
|
MouseButton::Auxiliary => BUTTON_MIDDLE,
|
||||||
|
MouseButton::Fourth | MouseButton::Fifth | MouseButton::Unknown => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
keyboard.key(time, key, if is_pressed { 1 } else { 0 });
|
pointer.button(time, button, ButtonState::Pressed);
|
||||||
|
pointer.frame();
|
||||||
|
pointer.button(time, button, ButtonState::Released);
|
||||||
|
pointer.frame();
|
||||||
|
guard.event_queue.flush().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn key_press_event(
|
||||||
|
&self,
|
||||||
|
key: String,
|
||||||
|
) {
|
||||||
|
let guard = self.input_proxy_service_state.lock().await;
|
||||||
|
|
||||||
|
if let Some(keyboard) = guard.state.virtual_keyboard() {
|
||||||
|
let time = get_wayland_timestamp();
|
||||||
|
let key = web_key_to_linux_keycode(key.as_str()).unwrap();
|
||||||
|
keyboard.key(time, key, 1);
|
||||||
|
keyboard.key(time, key, 0);
|
||||||
|
|
||||||
|
guard.event_queue.flush().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn text_input_start(&self) {
|
||||||
|
let mut guard = self.input_proxy_service_state.lock().await;
|
||||||
|
|
||||||
|
if let Some(ime) = guard.state.input_method_mut() {
|
||||||
|
ime.input_method_state += 1;
|
||||||
|
|
||||||
|
tracing::info!("Text Input Start");
|
||||||
|
ime.input_method.delete_surrounding_text(4, 4);
|
||||||
|
ime.input_method.commit(ime.input_method_state);
|
||||||
|
|
||||||
|
guard.event_queue.flush().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn text_input(
|
||||||
|
&self,
|
||||||
|
key: String,
|
||||||
|
) {
|
||||||
|
let mut guard = self.input_proxy_service_state.lock().await;
|
||||||
|
|
||||||
|
if let Some(ime) = guard.state.input_method_mut() {
|
||||||
|
ime.input_method_state += 1;
|
||||||
|
|
||||||
|
tracing::info!("Text Input {key}");
|
||||||
|
ime.input_method.set_preedit_string(key, 0, 0);
|
||||||
|
ime.input_method.commit(ime.input_method_state);
|
||||||
|
guard.event_queue.flush().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn text_input_end(
|
||||||
|
&self,
|
||||||
|
text: String,
|
||||||
|
) {
|
||||||
|
let mut guard = self.input_proxy_service_state.lock().await;
|
||||||
|
|
||||||
|
if let Some(ime) = guard.state.input_method_mut() {
|
||||||
|
ime.input_method_state += 1;
|
||||||
|
|
||||||
|
tracing::info!("Text Input End");
|
||||||
|
ime.input_method.commit_string(text);
|
||||||
|
ime.input_method.commit(ime.input_method_state);
|
||||||
guard.event_queue.flush().unwrap();
|
guard.event_queue.flush().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -143,21 +219,32 @@ struct Keymap {
|
||||||
size: u32,
|
size: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct InputMethod {
|
||||||
|
input_method: ZwpInputMethodV2,
|
||||||
|
input_method_state: u32,
|
||||||
|
}
|
||||||
|
|
||||||
enum InputProxyServiceState {
|
enum InputProxyServiceState {
|
||||||
Incomplete {
|
Incomplete {
|
||||||
queue_handle: QueueHandle<Self>,
|
queue_handle: QueueHandle<Self>,
|
||||||
seat: Option<WlSeat>,
|
seat: Option<WlSeat>,
|
||||||
virtual_pointer_manager: Option<ZwlrVirtualPointerManagerV1>,
|
virtual_pointer_manager: Option<ZwlrVirtualPointerManagerV1>,
|
||||||
virtual_keyboard_manager: Option<ZwpVirtualKeyboardManagerV1>,
|
virtual_keyboard_manager: Option<ZwpVirtualKeyboardManagerV1>,
|
||||||
|
input_method_manager: Option<ZwpInputMethodManagerV2>,
|
||||||
keymap: Keymap,
|
keymap: Keymap,
|
||||||
},
|
},
|
||||||
Running {
|
Running {
|
||||||
|
#[expect(unused)]
|
||||||
seat: WlSeat,
|
seat: WlSeat,
|
||||||
|
#[expect(unused)]
|
||||||
virtual_pointer_manager: ZwlrVirtualPointerManagerV1,
|
virtual_pointer_manager: ZwlrVirtualPointerManagerV1,
|
||||||
|
#[expect(unused)]
|
||||||
virtual_keyboard_manager: ZwpVirtualKeyboardManagerV1,
|
virtual_keyboard_manager: ZwpVirtualKeyboardManagerV1,
|
||||||
|
|
||||||
virtual_pointer: ZwlrVirtualPointerV1,
|
virtual_pointer: ZwlrVirtualPointerV1,
|
||||||
virtual_keyboard: ZwpVirtualKeyboardV1,
|
virtual_keyboard: ZwpVirtualKeyboardV1,
|
||||||
|
|
||||||
|
input_method: InputMethod,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
impl InputProxyServiceState {
|
impl InputProxyServiceState {
|
||||||
|
|
@ -177,6 +264,7 @@ impl InputProxyServiceState {
|
||||||
seat: None,
|
seat: None,
|
||||||
virtual_pointer_manager: None,
|
virtual_pointer_manager: None,
|
||||||
virtual_keyboard_manager: None,
|
virtual_keyboard_manager: None,
|
||||||
|
input_method_manager: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,6 +286,13 @@ impl InputProxyServiceState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn input_method_mut(&mut self) -> Option<&mut InputMethod> {
|
||||||
|
match self {
|
||||||
|
Self::Running { input_method, .. } => Some(input_method),
|
||||||
|
Self::Incomplete { .. } => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_seat(
|
pub fn set_seat(
|
||||||
&mut self,
|
&mut self,
|
||||||
seat: WlSeat,
|
seat: WlSeat,
|
||||||
|
|
@ -249,35 +344,63 @@ impl InputProxyServiceState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_input_method_manager(
|
||||||
|
&mut self,
|
||||||
|
input_method_manager: ZwpInputMethodManagerV2,
|
||||||
|
) {
|
||||||
|
if let Self::Incomplete {
|
||||||
|
input_method_manager: existing @ None,
|
||||||
|
..
|
||||||
|
} = self
|
||||||
|
{
|
||||||
|
*existing = Some(input_method_manager);
|
||||||
|
tracing::info!("Obtained Input Method Manager!");
|
||||||
|
self.try_upgrade();
|
||||||
|
} else {
|
||||||
|
tracing::info!("Received duplicate ZwpInputMethodManagerV2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn try_upgrade(&mut self) {
|
pub fn try_upgrade(&mut self) {
|
||||||
if let Self::Incomplete {
|
if let Self::Incomplete {
|
||||||
queue_handle,
|
queue_handle,
|
||||||
keymap,
|
keymap,
|
||||||
seat: oseat @ Some(..),
|
seat: seat @ Some(..),
|
||||||
virtual_pointer_manager: ovpm @ Some(..),
|
virtual_pointer_manager: vpm @ Some(..),
|
||||||
virtual_keyboard_manager: ovkm @ Some(..),
|
virtual_keyboard_manager: vkm @ Some(..),
|
||||||
|
input_method_manager: imm @ Some(..),
|
||||||
} = self
|
} = self
|
||||||
{
|
{
|
||||||
let virtual_keyboard = ovkm.as_ref().unwrap().create_virtual_keyboard(
|
let virtual_keyboard = vkm.as_ref().unwrap().create_virtual_keyboard(
|
||||||
oseat.as_ref().unwrap(),
|
seat.as_ref().unwrap(),
|
||||||
queue_handle,
|
queue_handle,
|
||||||
(),
|
(),
|
||||||
);
|
);
|
||||||
|
|
||||||
virtual_keyboard.keymap(XKB_V1, keymap.file.as_fd(), keymap.size);
|
virtual_keyboard.keymap(XKB_V1, keymap.file.as_fd(), keymap.size);
|
||||||
|
|
||||||
let virtual_pointer = ovpm.as_ref().unwrap().create_virtual_pointer(
|
let virtual_pointer = vpm.as_ref().unwrap().create_virtual_pointer(
|
||||||
Some(oseat.as_ref().unwrap()),
|
Some(seat.as_ref().unwrap()),
|
||||||
queue_handle,
|
queue_handle,
|
||||||
(),
|
(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let input_method =
|
||||||
|
imm.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.get_input_method(seat.as_ref().unwrap(), queue_handle, ());
|
||||||
|
|
||||||
tracing::info!("InputProxyServiceState upgraded to running");
|
tracing::info!("InputProxyServiceState upgraded to running");
|
||||||
*self = Self::Running {
|
*self = Self::Running {
|
||||||
seat: oseat.take().unwrap(),
|
seat: seat.take().unwrap(),
|
||||||
virtual_pointer_manager: ovpm.take().unwrap(),
|
virtual_pointer_manager: vpm.take().unwrap(),
|
||||||
virtual_keyboard_manager: ovkm.take().unwrap(),
|
virtual_keyboard_manager: vkm.take().unwrap(),
|
||||||
virtual_pointer,
|
virtual_pointer,
|
||||||
virtual_keyboard,
|
virtual_keyboard,
|
||||||
|
input_method: InputMethod {
|
||||||
|
input_method,
|
||||||
|
input_method_state: 0,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -339,6 +462,32 @@ impl Dispatch<ZwpVirtualKeyboardManagerV1, ()> for InputProxyServiceState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Dispatch<ZwpInputMethodManagerV2, ()> for InputProxyServiceState {
|
||||||
|
fn event(
|
||||||
|
_state: &mut Self,
|
||||||
|
_proxy: &ZwpInputMethodManagerV2,
|
||||||
|
_event: <ZwpInputMethodManagerV2 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &Connection,
|
||||||
|
_qhandle: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
tracing::warn!("Unknown event received from ZwpInputMethodManagerV2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatch<ZwpInputMethodV2, ()> for InputProxyServiceState {
|
||||||
|
fn event(
|
||||||
|
_state: &mut Self,
|
||||||
|
_proxy: &ZwpInputMethodV2,
|
||||||
|
_event: <ZwpInputMethodV2 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &Connection,
|
||||||
|
_qhandle: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
tracing::warn!("Unknown event received from ZwpInputMethodV2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Dispatch<WlSeat, ()> for InputProxyServiceState {
|
impl Dispatch<WlSeat, ()> for InputProxyServiceState {
|
||||||
fn event(
|
fn event(
|
||||||
_state: &mut Self,
|
_state: &mut Self,
|
||||||
|
|
@ -399,6 +548,15 @@ impl Dispatch<WlRegistry, ()> for InputProxyServiceState {
|
||||||
);
|
);
|
||||||
app_data.set_virtual_keyboard_manager(manager);
|
app_data.set_virtual_keyboard_manager(manager);
|
||||||
},
|
},
|
||||||
|
"zwp_input_method_manager_v2" => {
|
||||||
|
let manager = registry.bind::<ZwpInputMethodManagerV2, _, _>(
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
queue_handle,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
app_data.set_input_method_manager(manager);
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
Event::GlobalRemove { .. } => todo!(),
|
Event::GlobalRemove { .. } => todo!(),
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
1
crates/cursor-move-webapp/src/utils/mod.rs
Normal file
1
crates/cursor-move-webapp/src/utils/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod mouse_filter_buffer;
|
||||||
78
crates/cursor-move-webapp/src/utils/mouse_filter_buffer.rs
Normal file
78
crates/cursor-move-webapp/src/utils/mouse_filter_buffer.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use dioxus_html::geometry::{
|
||||||
|
ElementSpace,
|
||||||
|
euclid::{Point2D, Vector2D},
|
||||||
|
};
|
||||||
|
use wasmtimer::std::SystemTime;
|
||||||
|
|
||||||
|
pub struct MouseFilterBufferEntry {
|
||||||
|
pub position: Point2D<f64, ElementSpace>,
|
||||||
|
pub time: SystemTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MouseFilterBuffer {
|
||||||
|
buffer: VecDeque<MouseFilterBufferEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MouseFilterBuffer {
|
||||||
|
pub fn new(
|
||||||
|
size: usize,
|
||||||
|
initial: Point2D<f64, ElementSpace>,
|
||||||
|
initial_timestamp: SystemTime,
|
||||||
|
) -> Self {
|
||||||
|
let mut buffer = VecDeque::with_capacity(size);
|
||||||
|
buffer.push_back(MouseFilterBufferEntry {
|
||||||
|
position: initial,
|
||||||
|
time: initial_timestamp,
|
||||||
|
});
|
||||||
|
Self { buffer }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(
|
||||||
|
&mut self,
|
||||||
|
point: Point2D<f64, ElementSpace>,
|
||||||
|
time: SystemTime,
|
||||||
|
) {
|
||||||
|
if self.buffer.len() == self.buffer.capacity() {
|
||||||
|
self.buffer.pop_front();
|
||||||
|
}
|
||||||
|
self.buffer.push_back(MouseFilterBufferEntry {
|
||||||
|
position: point,
|
||||||
|
time,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn back(&self) -> &MouseFilterBufferEntry {
|
||||||
|
self.buffer
|
||||||
|
.back()
|
||||||
|
.expect("Mouse filter buffer may never have less than one element")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn average_velocity_since(
|
||||||
|
&self,
|
||||||
|
start_time: SystemTime,
|
||||||
|
) -> Vector2D<f64, ElementSpace> {
|
||||||
|
let mut total_distance = Vector2D::zero();
|
||||||
|
|
||||||
|
let mut i = self.buffer.iter();
|
||||||
|
|
||||||
|
let Some(mut last) = i.find(|it| it.time >= start_time) else {
|
||||||
|
return Vector2D::zero();
|
||||||
|
};
|
||||||
|
let start_time = last.time;
|
||||||
|
let mut last_time = last.time;
|
||||||
|
|
||||||
|
for point in i {
|
||||||
|
total_distance += point.position - last.position;
|
||||||
|
last = point;
|
||||||
|
last_time = point.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if total_distance == Vector2D::zero() {
|
||||||
|
return Vector2D::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
total_distance / (last_time.duration_since(start_time).unwrap().as_secs_f64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::components::MouseArea;
|
use crate::components::Controls;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
/// The Home page component that will be rendered when the current route is `[Route::Home]`
|
/// The Home page component that will be rendered when the current route is `[Route::Home]`
|
||||||
|
|
@ -10,7 +10,7 @@ pub fn Home() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
class: Styles::container,
|
class: Styles::container,
|
||||||
MouseArea { }
|
Controls { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "cursor-mover-app"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
license = "EUPL-1.2"
|
|
||||||
description = "A web-application that lets you remotely control your cursor."
|
|
||||||
repository = "https://forgejo.monalith.xyz/Nionidh/cursor-mover-app"
|
|
||||||
keywords = ["web", "application", "cursor", "control"]
|
|
||||||
categories = ["web-programming"]
|
|
||||||
readme = "README.md"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
tokio = { version = "1.49.0", features = ["full"] }
|
|
||||||
wayland-client = "0.31.12"
|
|
||||||
wayland-protocols-wlr = { version = "0.3.10", features = ["client"] }
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
The main application
|
|
||||||
|
|
@ -1,133 +0,0 @@
|
||||||
use std::{
|
|
||||||
alloc::System,
|
|
||||||
f64,
|
|
||||||
future::poll_fn,
|
|
||||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
|
||||||
};
|
|
||||||
|
|
||||||
use tokio::{
|
|
||||||
select,
|
|
||||||
time::{self, Instant},
|
|
||||||
};
|
|
||||||
use wayland_client::{Connection, Dispatch, Proxy, QueueHandle, protocol::wl_registry};
|
|
||||||
use wayland_protocols_wlr::virtual_pointer::v1::client::{
|
|
||||||
zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1,
|
|
||||||
zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct AppData {
|
|
||||||
virtual_pointer: Option<ZwlrVirtualPointerV1>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<ZwlrVirtualPointerV1, ()> for AppData {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
proxy: &ZwlrVirtualPointerV1,
|
|
||||||
event: <ZwlrVirtualPointerV1 as Proxy>::Event,
|
|
||||||
data: &(),
|
|
||||||
conn: &Connection,
|
|
||||||
qhandle: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
println!("VPointerData");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<ZwlrVirtualPointerManagerV1, ()> for AppData {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
proxy: &ZwlrVirtualPointerManagerV1,
|
|
||||||
event: <ZwlrVirtualPointerManagerV1 as Proxy>::Event,
|
|
||||||
data: &(),
|
|
||||||
conn: &Connection,
|
|
||||||
qhandle: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
println!("ZwlrEvent")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatch<wl_registry::WlRegistry, ()> for AppData {
|
|
||||||
fn event(
|
|
||||||
app_data: &mut Self,
|
|
||||||
registry: &wl_registry::WlRegistry,
|
|
||||||
event: wl_registry::Event,
|
|
||||||
_: &(),
|
|
||||||
_: &Connection,
|
|
||||||
queue_handle: &QueueHandle<Self>,
|
|
||||||
) {
|
|
||||||
println!("WlRegistry Event");
|
|
||||||
if let wl_registry::Event::Global {
|
|
||||||
name,
|
|
||||||
interface,
|
|
||||||
version,
|
|
||||||
} = event
|
|
||||||
&& interface == "zwlr_virtual_pointer_manager_v1"
|
|
||||||
{
|
|
||||||
app_data.virtual_pointer.get_or_insert_with(|| {
|
|
||||||
let manager = registry.bind::<ZwlrVirtualPointerManagerV1, _, _>(
|
|
||||||
name,
|
|
||||||
version,
|
|
||||||
queue_handle,
|
|
||||||
(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let pointer = manager.create_virtual_pointer(None, queue_handle, ());
|
|
||||||
|
|
||||||
println!("Virtual pointer manager created");
|
|
||||||
pointer
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
let connection = Connection::connect_to_env().unwrap();
|
|
||||||
let display = connection.display();
|
|
||||||
|
|
||||||
let mut event_queue = connection.new_event_queue();
|
|
||||||
let queue_handle = event_queue.handle();
|
|
||||||
let _registry = display.get_registry(&queue_handle, ());
|
|
||||||
println!("Advertized globals:");
|
|
||||||
|
|
||||||
let mut appdata = AppData::default();
|
|
||||||
event_queue.roundtrip(&mut appdata).unwrap();
|
|
||||||
|
|
||||||
let mut interval = time::interval(Duration::from_millis(15));
|
|
||||||
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if Instant::now().duration_since(start) > Duration::from_secs(5) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
select! {
|
|
||||||
poll = poll_fn(|cx| event_queue.poll_dispatch_pending(cx, &mut appdata)) => {
|
|
||||||
println!("Did the mash");
|
|
||||||
},
|
|
||||||
now = interval.tick() => {
|
|
||||||
if let Some(pointer) = appdata.virtual_pointer.as_mut() {
|
|
||||||
handle_pointer_motion(now, &pointer);
|
|
||||||
}
|
|
||||||
event_queue.flush().unwrap();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_pointer_motion(
|
|
||||||
time: Instant,
|
|
||||||
pointer: &ZwlrVirtualPointerV1,
|
|
||||||
) {
|
|
||||||
let time = SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.unwrap()
|
|
||||||
.as_millis();
|
|
||||||
|
|
||||||
let x = ((time as f64 / 1000.0 * f64::consts::PI).sin() * 10.0);
|
|
||||||
let y = ((time as f64 / 1000.0 * f64::consts::PI).cos() * 10.0);
|
|
||||||
|
|
||||||
pointer.motion(time as u32, x, y);
|
|
||||||
pointer.frame();
|
|
||||||
}
|
|
||||||
31
deny.toml
31
deny.toml
|
|
@ -20,18 +20,21 @@ allow = [
|
||||||
"Unicode-3.0",
|
"Unicode-3.0",
|
||||||
#"0BSD",
|
#"0BSD",
|
||||||
#"Apache-2.0 WITH LLVM-exception",
|
#"Apache-2.0 WITH LLVM-exception",
|
||||||
#"Apache-2.0",
|
"Apache-2.0",
|
||||||
# "BSD-2-Clause",
|
"BSD-2-Clause",
|
||||||
#"BSD-3-Clause",
|
"BSD-3-Clause",
|
||||||
#"BSL-1.0",
|
"BSL-1.0",
|
||||||
#"CC0-1.0",
|
"CC0-1.0",
|
||||||
#"ISC",
|
"ISC",
|
||||||
# "MIT-0",
|
# "MIT-0",
|
||||||
"MIT",
|
"MIT",
|
||||||
#"MPL-2.0",
|
#"MPL-2.0",
|
||||||
#"Unicode-3.0",
|
#"Unicode-3.0",
|
||||||
"Unlicense",
|
"Unlicense",
|
||||||
#"Zlib",
|
"Zlib",
|
||||||
|
|
||||||
|
#TODO Read up on that one
|
||||||
|
"CDLA-Permissive-2.0"
|
||||||
]
|
]
|
||||||
exceptions = [
|
exceptions = [
|
||||||
# { name = "unicode-ident", allow = ["Unicode-DFS-2016"] }
|
# { name = "unicode-ident", allow = ["Unicode-DFS-2016"] }
|
||||||
|
|
@ -42,6 +45,20 @@ multiple-versions = "warn"
|
||||||
wildcards = "deny"
|
wildcards = "deny"
|
||||||
# Certain crates that we do not want multiple versions of in the dependency tree
|
# Certain crates that we do not want multiple versions of in the dependency tree
|
||||||
deny = []
|
deny = []
|
||||||
|
skip = [
|
||||||
|
{ crate = "windows-sys", reason = "dioxus still depends on an old version" },
|
||||||
|
|
||||||
|
{ crate = "tungstenite", reason = "dioxus internally depends on two versions" },
|
||||||
|
{ crate = "tokio-tungstenite", reason = "dioxus internally depends on two versions" },
|
||||||
|
{ crate = "thiserror-impl", reason = "dioxus internally depends on two versions" },
|
||||||
|
{ crate = "thiserror", reason = "dioxus internally depends on two versions" },
|
||||||
|
{ crate = "rustc-hash", reason = "dioxus internally depends on two versions" },
|
||||||
|
{ crate = "hashbrown", reason = "dioxus internally depends on two versions" },
|
||||||
|
{ crate = "getrandom", reason = "dioxus internally depends on two versions" },
|
||||||
|
{ crate = "convert_case", reason = "dioxus internally depends on two versions" },
|
||||||
|
{ crate = "const-serialize", reason = "dioxus internally depends on two versions" },
|
||||||
|
{ crate = "const-serialize-macro", reason = "dioxus internally depends on two versions" },
|
||||||
|
]
|
||||||
|
|
||||||
[sources]
|
[sources]
|
||||||
unknown-registry = "warn"
|
unknown-registry = "warn"
|
||||||
|
|
|
||||||
17
flake.nix
17
flake.nix
|
|
@ -45,11 +45,11 @@
|
||||||
|
|
||||||
perSystem =
|
perSystem =
|
||||||
{
|
{
|
||||||
config,
|
#config,
|
||||||
self',
|
#self',
|
||||||
inputs',
|
inputs',
|
||||||
pkgs,
|
pkgs,
|
||||||
system,
|
#system,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|
@ -117,10 +117,6 @@
|
||||||
wasmBindgen
|
wasmBindgen
|
||||||
|
|
||||||
pkgs.libxkbcommon
|
pkgs.libxkbcommon
|
||||||
|
|
||||||
pkgs.clang
|
|
||||||
pkgs.llvmPackages.libclang
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
scripts.checkall.exec = ''
|
scripts.checkall.exec = ''
|
||||||
|
|
@ -129,8 +125,11 @@
|
||||||
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||||
cargo deny check all -D warnings
|
cargo deny check all -D warnings
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
cargo nextest run --workspace --all-targets --all-features --status-level all
|
cargo nextest run --workspace --all-targets --all-features --status-level all --no-tests warn
|
||||||
cargo test
|
|
||||||
|
# TODO Doctests
|
||||||
|
|
||||||
|
echo "==== checkall success ===="
|
||||||
'';
|
'';
|
||||||
# DO NOT ENABLE RUST because devenv messes up the ability
|
# DO NOT ENABLE RUST because devenv messes up the ability
|
||||||
# to build rust-src
|
# to build rust-src
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue