Compare commits

..

7 Commits
v0.9 ... master

Author SHA1 Message Date
96376a4d7d Merge branch 'master' of https://long-cat.net/gitea/moosecrab/webmouse 2021-02-18 21:52:05 -08:00
a808748f6c Removed the unused 'menu' button on the web page 2021-02-18 21:49:20 -08:00
Frank Schmeling
751a0383cb Merge branch 'master' of https://long-cat.net/gitea/moosecrab/webcrab 2020-06-19 22:22:30 -07:00
Frank Schmeling
91f1ee82af Removed some unneeded text decoding in the /text operation. 2020-06-19 22:15:50 -07:00
5682dc722d Added info on the 'seq' argument to readme.txt. 2020-06-18 16:11:38 -07:00
5f0d133580 Changed packet sequence numbers to only apply to mouse movements, and they now reset with every tap.
Switched the JS code to calling fetch() directly.
Minor style changes.
2020-06-18 12:52:20 -07:00
3eb86784b6 Rewrote a lot of the interaction code to make it easier to modify by the end-user.
Added a readme explaining the above.
Added YouTube key controls to the default page.
Added a setting to save tap tolerance between restarts.
2020-06-17 02:35:33 -07:00
7 changed files with 177 additions and 110 deletions

View File

@ -13,6 +13,9 @@
<setting name="listenport" serializeAs="String"> <setting name="listenport" serializeAs="String">
<value>8080</value> <value>8080</value>
</setting> </setting>
<setting name="taptolerance" serializeAs="String">
<value>5</value>
</setting>
</webcrab.My.MySettings> </webcrab.My.MySettings>
</userSettings> </userSettings>
</configuration> </configuration>

View File

@ -65,6 +65,18 @@ Namespace My
Me("listenport") = value Me("listenport") = value
End Set End Set
End Property End Property
<Global.System.Configuration.UserScopedSettingAttribute(), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Configuration.DefaultSettingValueAttribute("5")> _
Public Property taptolerance() As Integer
Get
Return CType(Me("taptolerance"),Integer)
End Get
Set
Me("taptolerance") = value
End Set
End Property
End Class End Class
End Namespace End Namespace

View File

@ -5,5 +5,8 @@
<Setting Name="listenport" Type="System.UInt16" Scope="User"> <Setting Name="listenport" Type="System.UInt16" Scope="User">
<Value Profile="(Default)">8080</Value> <Value Profile="(Default)">8080</Value>
</Setting> </Setting>
<Setting Name="taptolerance" Type="System.Int32" Scope="User">
<Value Profile="(Default)">5</Value>
</Setting>
</Settings> </Settings>
</SettingsFile> </SettingsFile>

View File

@ -5,7 +5,8 @@ Public Class main
Dim weblistener As HttpListener Dim weblistener As HttpListener
Dim lastpos As New Point(0, 0) Dim lastpos As New Point(0, 0)
Dim startpos As New Point(0, 0) Dim startpos As New Point(0, 0)
Dim leftclicking As Boolean = False Dim lastmouseseq As Integer = 0
Dim nexttoggleclick As UInteger = MouseEventFlags.MOUSEEVENTF_LEFTDOWN Or MouseEventFlags.MOUSEEVENTF_RIGHTDOWN Or MouseEventFlags.MOUSEEVENTF_MIDDLEDOWN Or MouseEventFlags.MOUSEEVENTF_XDOWN
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles StartButton.Click Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles StartButton.Click
If Not weblistener Is Nothing Then If Not weblistener Is Nothing Then
@ -19,9 +20,13 @@ Public Class main
Else Else
Dim listenport As UShort = My.Settings("listenport") Dim listenport As UShort = My.Settings("listenport")
PortInput.Value = listenport PortInput.Value = listenport
weblistener = New HttpListener Try
weblistener.Prefixes.Add("http://*:" & listenport & "/") weblistener = New HttpListener
weblistener.Start() weblistener.Prefixes.Add("http://*:" & listenport & "/")
weblistener.Start()
Catch ex As Exception
log(ex.ToString)
End Try
Dim listenthread As New Thread(AddressOf listenforconnection) Dim listenthread As New Thread(AddressOf listenforconnection)
listenthread.Start() listenthread.Start()
log("Started") log("Started")
@ -35,8 +40,6 @@ Public Class main
Dim context As HttpListenerContext = Nothing Dim context As HttpListenerContext = Nothing
Dim resp As HttpListenerResponse Dim resp As HttpListenerResponse
Dim respstr As String = String.Empty Dim respstr As String = String.Empty
Dim lastpacket As Long = -1
Dim lastpack As Long
Dim leftclicking As Boolean = False Dim leftclicking As Boolean = False
While weblistener.IsListening While weblistener.IsListening
Try Try
@ -53,13 +56,8 @@ Public Class main
If path = "/" Then If path = "/" Then
respstr = FileIO.FileSystem.ReadAllText("res/page.html") respstr = FileIO.FileSystem.ReadAllText("res/page.html")
lastpacket = 0
Else Else
Dim pack As Long = context.Request.QueryString("seq") respstr = handleinput(context.Request)
If pack > lastpack Then
respstr = handleinput(context.Request)
lastpack = pack
End If
End If End If
If String.IsNullOrEmpty(respstr) Then If String.IsNullOrEmpty(respstr) Then
@ -75,6 +73,7 @@ Public Class main
End Sub End Sub
Private Sub Form1_FormClosing(sender As System.Object, e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing Private Sub Form1_FormClosing(sender As System.Object, e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
My.Settings.taptolerance = TapInput.Value
If Not weblistener Is Nothing Then If Not weblistener Is Nothing Then
weblistener.Abort() weblistener.Abort()
End If End If
@ -82,6 +81,8 @@ Public Class main
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Control.CheckForIllegalCrossThreadCalls = False Control.CheckForIllegalCrossThreadCalls = False
Dim taptolerance As Integer = My.Settings.taptolerance
TapInput.Value = taptolerance
Button1_Click(sender, e) Button1_Click(sender, e)
End Sub End Sub
Private Sub log(str As String) Private Sub log(str As String)
@ -110,11 +111,16 @@ Public Class main
lastpos.Y = req.QueryString("y") lastpos.Y = req.QueryString("y")
startpos.X = req.QueryString("x") startpos.X = req.QueryString("x")
startpos.Y = req.QueryString("y") startpos.Y = req.QueryString("y")
lastmouseseq = 0
Case "move" 'trackpad touch move Case "move" 'trackpad touch move
mouse_event(MouseEventFlags.MOUSEEVENTF_MOVE, req.QueryString("x") - lastpos.X, req.QueryString("y") - lastpos.Y, 0, 0) Dim seq As Integer = req.QueryString("seq")
lastpos.X = req.QueryString("x") If seq > lastmouseseq Then
lastpos.Y = req.QueryString("y") mouse_event(MouseEventFlags.MOUSEEVENTF_MOVE, req.QueryString("x") - lastpos.X, req.QueryString("y") - lastpos.Y, 0, 0)
lastpos.X = req.QueryString("x")
lastpos.Y = req.QueryString("y")
lastmouseseq = seq
End If
Case "end" Case "end"
Dim tol As Integer = TapInput.Value Dim tol As Integer = TapInput.Value
@ -124,64 +130,77 @@ Public Class main
mouse_event(MouseEventFlags.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0) mouse_event(MouseEventFlags.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
End If End If
Case "left" Case "click"
If leftclicking Then Dim eventflag As UInteger = 0
mouse_event(MouseEventFlags.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0) Select Case req.QueryString("button")
leftclicking = False Case "left"
Else eventflag = MouseEventFlags.MOUSEEVENTF_LEFTDOWN
mouse_event(MouseEventFlags.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0) Case "right"
leftclicking = True eventflag = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN
End If Case "middle"
eventflag = MouseEventFlags.MOUSEEVENTF_MIDDLEDOWN
Case "middle" Case "x"
mouse_event(MouseEventFlags.MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0) eventflag = MouseEventFlags.MOUSEEVENTF_XDOWN
Case Else
Return "unknown mouse button"
End Select
mouse_event(eventflag, 0, 0, 0, 0)
System.Threading.Thread.Sleep(10) System.Threading.Thread.Sleep(10)
mouse_event(MouseEventFlags.MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0) ' bit shift to the left is the corresponding button up event
mouse_event(eventflag << 1, 0, 0, 0, 0)
Case "right" Case "toggle"
mouse_event(MouseEventFlags.MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0) Dim eventflagmask As UInteger = 0
System.Threading.Thread.Sleep(10) 'buttonmask is just the 2 bits for the selected button
mouse_event(MouseEventFlags.MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0) Select Case req.QueryString("button")
Case "left"
eventflagmask = MouseEventFlags.MOUSEEVENTF_LEFTDOWN Or MouseEventFlags.MOUSEEVENTF_LEFTUP
Case "right"
eventflagmask = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN Or MouseEventFlags.MOUSEEVENTF_RIGHTUP
Case "middle"
eventflagmask = MouseEventFlags.MOUSEEVENTF_MIDDLEDOWN Or MouseEventFlags.MOUSEEVENTF_MIDDLEUP
Case "x"
eventflagmask = MouseEventFlags.MOUSEEVENTF_XDOWN Or MouseEventFlags.MOUSEEVENTF_XUP
Case Else
Return "unknown mouse button"
End Select
'nexttoggleclick is either button up or down for each button
mouse_event(eventflagmask And nexttoggleclick, 0, 0, 0, 0)
'invert nexttoggleclick for the selected button only
nexttoggleclick = nexttoggleclick Xor eventflagmask
Case "wheel" Case "wheel"
mouse_event(MouseEventFlags.MOUSEEVENTF_WHEEL, 0, 0, WHEEL_DELTA * req.QueryString("d"), 0) Dim eventflag As UInteger = 0
Select Case req.QueryString("axis")
Case "vert"
eventflag = MouseEventFlags.MOUSEEVENTF_WHEEL
Case "horiz"
eventflag = MouseEventFlags.MOUSEEVENTF_HWHEEL
Case "volume"
If req.QueryString("d") = -1 Then
keybd_press(VK.VOLUME_DOWN)
ElseIf req.QueryString("d") = 0 Then
keybd_press(VK.VOLUME_MUTE)
ElseIf req.QueryString("d") = 1 Then
keybd_press(VK.VOLUME_UP)
End If
Case "media"
Select Case req.QueryString("act")
Case "stop"
keybd_press(VK.MEDIA_STOP)
Case "prev"
keybd_press(VK.MEDIA_PREV_TRACK)
Case "play"
keybd_press(VK.MEDIA_PLAY_PAUSE)
Case "next"
keybd_press(VK.MEDIA_NEXT_TRACK)
End Select End Select
mouse_event(eventflag, 0, 0, req.QueryString("delta"), 0)
Case "key" Case "key"
Select Case req.QueryString("k") Try
Case "del" Dim vk As Byte = req.QueryString("code")
keybd_press(VK.DELETE) keybd_press(vk)
Case "bksp" Catch ex As Exception
keybd_press(VK.KEY_BACK) log(ex.ToString)
Case "enter" End Try
keybd_press(VK.RETURN_KEY)
End Select
Case "text" Case "text"
Dim encodedtext As String = req.QueryString("t") Dim text As String = req.QueryString("text")
Dim decodedtext As String = Uri.UnescapeDataString(encodedtext)
Try Try
SendKeysEscaped(decodedtext) SendKeysEscaped(text)
Catch ex As Exception
log(ex.ToString)
End Try
Case "sendkeys"
Dim keys As String = req.QueryString("keys")
Try
SendKeys.SendWait(keys)
Catch ex As Exception Catch ex As Exception
log(ex.ToString) log(ex.ToString)
End Try End Try

View File

@ -14,6 +14,9 @@ body {
margin: 0; margin: 0;
background-color: black; background-color: black;
color: gray; color: gray;
display: flex;
flex-direction: column;
} }
button{ button{
text-align: center; text-align: center;
@ -27,64 +30,61 @@ button{
button:active { button:active {
background-color: silver; background-color: silver;
} }
button:focus, button:hover, button:focus-visible {
}
.touchpad { .touchpad {
height: 60%;
display: flex; display: flex;
} }
#canvas { #canvas {
width: 100%; width: 100%;
background-color: #111; background-color: #111;
outline: gray solid 1px;
} }
.buttonrow { div{
height: 10%;
display: flex; display: flex;
align-items: stretch;
} }
.buttonrow input{ input{
background-color: #111; background-color: #111;
color: gray; color: gray;
outline: gray solid 1px; border: 1px solid gray;
border: none; border: none;
} }
</style> </style>
</head> </head>
<body> <body>
<div class="buttonrow"> <div style="flex:2">
<button style="flex:1">menu</button> <button onclick="fetch('/key?code=46')" style="flex:1">del</button>
<button onclick="sendmessage('key', 'k=del')" style="flex:1">del</button> <button onclick="fetch('/key?code=8')" style="flex:1">bksp</button>
<button onclick="sendmessage('key', 'k=bksp')" style="flex:1">bksp</button> <button onclick="fetch('/key?code=13')" style="flex:1">enter</button>
<button onclick="sendmessage('key', 'k=enter')" style="flex:1">enter</button>
<input id="typebox" placeholder="type here" size=8 style="flex:2"> <input id="typebox" placeholder="type here" size=8 style="flex:2">
</div> </div>
<div class="touchpad"> <div style="flex:1">
<button onclick="fetch('/sendkeys?keys=j')" style="flex:1">j</button>
<button onclick="fetch('/sendkeys?keys={LEFT}')" style="flex:1">&larr;</button>
<button onclick="fetch('/sendkeys?keys=k')" style="flex:1">k</button>
<button onclick="fetch('/sendkeys?keys={RIGHT}')" style="flex:1">&rarr;</button>
<button onclick="fetch('/sendkeys?keys=l')" style="flex:1">l</button>
</div>
<div style="flex:12">
<span id="canvas"></span> <span id="canvas"></span>
</div> </div>
<div class="buttonrow"> <div style="flex:2">
<button onclick="sendmessage('left', '')" style="flex:2">left (toggle)</button> <button onclick="fetch('/toggle?button=left')" style="flex:2">left (toggle)</button>
<button onclick="sendmessage('wheel', 'd=1')" style="flex:1">up</button> <button onclick="fetch('/wheel?axis=vert&delta=120')" style="flex:1">up</button>
<button onclick="sendmessage('middle', '')" style="flex:1">mid</button> <button onclick="fetch('/click?button=middle')" style="flex:1">mid</button>
<button onclick="sendmessage('wheel', 'd=-1')" style="flex:1">dn</button> <button onclick="fetch('/wheel?axis=vert&delta=-120')" style="flex:1">dn</button>
<button onclick="sendmessage('right', '')" style="flex:2">right</button> <button onclick="fetch('/click?button=right')" style="flex:2">right</button>
</div> </div>
<div class="buttonrow"> <div style="flex:2">
<button onclick="sendmessage('volume', 'd=-1')" style="flex:2">vol -</button> <button onclick="fetch('/key?code=174')" style="flex:2">vol -</button>
<button onclick="sendmessage('volume', 'd=0')" style="flex:1">mute</button> <button onclick="fetch('/key?code=173')" style="flex:1">mute</button>
<button onclick="sendmessage('volume', 'd=1')" style="flex:2">vol +</button> <button onclick="fetch('/key?code=175')" style="flex:2">vol +</button>
<!--<button onclick="sendmessage('volume', 1, 0)" style="flex:2">vol +</button>-->
</div> </div>
<div class="buttonrow"> <div style="flex:2">
<button onclick="sendmessage('media', 'act=stop')" style="flex:1">stop</button> <button onclick="fetch('/key?code=178')" style="flex:1">stop</button>
<button onclick="sendmessage('media', 'act=prev')" style="flex:1">prev</button> <button onclick="fetch('/key?code=177')" style="flex:1">prev</button>
<button onclick="sendmessage('media', 'act=play')" style="flex:1">play/pause</button> <button onclick="fetch('/key?code=179')" style="flex:1">play/pause</button>
<button onclick="sendmessage('media', 'act=next')" style="flex:1">next</button> <button onclick="fetch('/key?code=176')" style="flex:1">next</button>
</div> </div>
<script> <script type="text/javascript">
function startup() { function startup() {
var el = document.getElementById("canvas"); var el = document.getElementById("canvas");
el.addEventListener("touchstart", handleStart, false); el.addEventListener("touchstart", handleStart, false);
@ -105,8 +105,9 @@ var packetnum = 0;
function handleStart(evt) { function handleStart(evt) {
if (currenttouch == null) { if (currenttouch == null) {
currenttouch = evt.changedTouches[0]; currenttouch = evt.changedTouches[0];
sendmessage("start", "x=" + currenttouch.pageX + "&y=" + currenttouch.pageY) packetnum = 0;
fetch("/start?x=" + currenttouch.pageX + "&y=" + currenttouch.pageY);
} }
} }
@ -117,8 +118,9 @@ function handleMove(evt) {
} }
for (var i = 0; i < touches.length; i++) { for (var i = 0; i < touches.length; i++) {
if (touches[i].identifier == currenttouch.identifier) { if (touches[i].identifier == currenttouch.identifier) {
currenttouch = evt.changedTouches[0]; currenttouch = evt.changedTouches[0];
sendmessage("move", "x=" + currenttouch.pageX + "&y=" + currenttouch.pageY) packetnum++;
fetch("/move?x=" + currenttouch.pageX + "&y=" + currenttouch.pageY + "&seq=" + packetnum);
} }
} }
} }
@ -128,7 +130,7 @@ function handleEnd(evt) {
for (var i = 0; i < touches.length; i++) { for (var i = 0; i < touches.length; i++) {
if (touches[i].identifier == currenttouch.identifier) { if (touches[i].identifier == currenttouch.identifier) {
currenttouch = evt.changedTouches[0]; currenttouch = evt.changedTouches[0];
sendmessage("end", "x=" + currenttouch.pageX + "&y=" + currenttouch.pageY) fetch("/end?x=" + currenttouch.pageX + "&y=" + currenttouch.pageY)
currenttouch = null; currenttouch = null;
} }
} }
@ -139,7 +141,7 @@ function handleCancel(evt) {
for (var i = 0; i < touches.length; i++) { for (var i = 0; i < touches.length; i++) {
if (touches[i].identifier == currenttouch.identifier) { if (touches[i].identifier == currenttouch.identifier) {
currenttouch = evt.changedTouches[0]; currenttouch = evt.changedTouches[0];
sendmessage("end", "x=" + currenttouch.pageX + "&y=" + currenttouch.pageY) fetch("/end?x=" + currenttouch.pageX + "&y=" + currenttouch.pageY)
currenttouch = null; currenttouch = null;
} }
} }
@ -147,17 +149,10 @@ function handleCancel(evt) {
function handlekeypress(evt) { function handlekeypress(evt) {
evt.preventDefault(); evt.preventDefault();
sendmessage("text", "t=" + encodeURIComponent(evt.target.value)); fetch("/text?text=" + encodeURIComponent(evt.target.value));
evt.target.value = ""; evt.target.value = "";
} }
function sendmessage(opt, q) {
fetch("/" + opt + "/?" + q + "&seq=" + packetnum);
packetnum++;
}
</script> </script>
</body> </body>

32
webcrab/res/readme.txt Executable file
View File

@ -0,0 +1,32 @@
Page.html is the page sent to the browser when the control site is opened.
It is easy to customize to add or remove buttons, actions, clicks, etc. to your page.
The PC side of the program recognizes several actions.
Mouse messages are:
start - start a trackpad movement
move - continue a trackpad movement
end - end a trackpad movement
All of the above take 2 arguments: x and y.
Each touch has a "seq" argument that starts at 0 and increments with each move, to avoid out-of-order movements.
Mouse movement is relative so don't worry about the absolute values.
X is positive left, and Y is positive down.
Mouse button messages are:
click - click and release a mouse button
toggle - toggle a mouse button to either the clicked or released state
Both take a single argument: "button", which can be any of "left", "right", "middle", or "x".
Mouse wheel is a single message type:
wheel - command a mouse wheel movement
It takes two arguments: "axis" which is either "vert" or "horiz", and "delta" which is how far the wheel moves.
The default delta in Windows is 120.
Vert is positive away from the user, horiz is positive to the right.
Keyboard input has several message types:
key - send a single keystroke via the numeric key code (argument "code")
text - send raw typed text (argument "text", make sure to use encodeURIComponent() or similar)
sendkeys - send typed text but escaped according to the SendKeys() method (argument "keys")
"key" can be used to send off keys such as media and IME keys not available through the other methods. A full list of codes is here: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
"text" sends raw text, such as those typed using the phone keyboard.
"sendkeys" send keystrokes, but can use modifiers or non-text keys using escape characters. See more information here: https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.devices.keyboard.sendkeys

View File

@ -153,6 +153,9 @@
<Content Include="res\page.html"> <Content Include="res\page.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="res\readme.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.