Skip to content

Commit

Permalink
Merge pull request #92 from owulveryck/swipeDetection
Browse files Browse the repository at this point in the history
goMarkableStream ♥ reveal.js
  • Loading branch information
owulveryck authored Nov 24, 2023
2 parents adbedee + 8e22ab5 commit e02b4df
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 17 deletions.
2 changes: 2 additions & 0 deletions client/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const messageDiv = document.getElementById('message');
// Initialize the worker
const streamWorker = new Worker('worker_stream_processing.js');
const eventWorker = new Worker('worker_event_processing.js');
const gestureWorker = new Worker('worker_gesture_processing.js');
function getQueryParamOrDefault(param, defaultValue) {
const urlParams = new URLSearchParams(window.location.search);
const value = urlParams.get(param);
Expand Down Expand Up @@ -49,4 +50,5 @@ window.addEventListener('beforeunload', () => {
// Send a termination signal to the worker before the page is unloaded
streamWorker.postMessage({ type: 'terminate' });
eventWorker.postMessage({ type: 'terminate' });
gestureWorker.postMessage({ type: 'terminate' });
});
65 changes: 65 additions & 0 deletions client/worker_gesture_processing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
let wsURL;
// Constants for the maximum values from the WebSocket messages
const SWIPE_DISTANCE = 200;

onmessage = (event) => {
const data = event.data;

switch (data.type) {
case 'init':
wsURL = event.data.wsURL;
fetchStream();
break;
case 'terminate':
console.log("terminating worker");
close();
break;
}
};

async function fetchStream() {
const response = await fetch('/gestures');

const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let buffer = '';

while (true) {
const { value, done } = await reader.read();
if (done) break;

buffer += decoder.decode(value, { stream: true });

while (buffer.includes('\n')) {
const index = buffer.indexOf('\n');
const jsonStr = buffer.slice(0, index);
buffer = buffer.slice(index + 1);

try {
const json = JSON.parse(jsonStr);
let swipe = checkSwipeDirection(json);
if (swipe != 'none') {
postMessage({ type: 'gesture', value: swipe}) ;
}
} catch (e) {
console.error('Error parsing JSON:', e);
}
}
}
}


function checkSwipeDirection(json) {
if (json.left > 200 && json.right < 75 && json.up < 100 && json.down < 100) {
return 'left';
} else if (json.right > 200 && json.left < 75 && json.up < 100 && json.down < 100) {
return 'right';
} else if (json.up > 200 && json.right < 100 && json.left < 100 && json.down < 75) {
return 'up';
} else if (json.down > 200 && json.right < 100 && json.up < 75 && json.left < 100) {
return 'down';
} else {
return 'none';
}
}

23 changes: 23 additions & 0 deletions client/workersHandling.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ streamWorker.onmessage = (event) => {
// Determine the WebSocket protocol based on the current window protocol
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsURL = `${wsProtocol}//${window.location.host}/events`;
const wsGestureURL = `${wsProtocol}//${window.location.host}/gestures`;
// Send the OffscreenCanvas to the worker for initialization
eventWorker.postMessage({
type: 'init',
Expand All @@ -42,6 +43,28 @@ eventWorker.postMessage({
portrait: portrait,
wsURL: wsURL
});
gestureWorker.postMessage({
type: 'init',
wsURL: wsGestureURL
});

gestureWorker.onmessage = (event) => {
const data = event.data;

switch (data.type) {
case 'gesture':
if (event.data.value == 'left') {
document.getElementById('content').contentWindow.postMessage( JSON.stringify({ method: 'left' }), '*' );
} else if (event.data.value == 'right') {
document.getElementById('content').contentWindow.postMessage( JSON.stringify({ method: 'right' }), '*' );
}
break;
case 'error':
console.error('Error from worker:', event.data.message);
break;
}

}

let messageTimeout;

Expand Down
2 changes: 2 additions & 0 deletions http.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ func setMuxer(eventPublisher *pubsub.PubSub) *http.ServeMux {

wsHandler := eventhttphandler.NewEventHandler(eventPublisher)
mux.Handle("/events", wsHandler)
gestureHandler := eventhttphandler.NewGestureHandler(eventPublisher)
mux.Handle("/gestures", gestureHandler)

if c.DevMode {
rawHandler := stream.NewRawHandler(file, pointerAddr)
Expand Down
148 changes: 148 additions & 0 deletions internal/eventhttphandler/gesture_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package eventhttphandler

import (
"encoding/json"
"fmt"
"net/http"
"syscall"
"time"

"github.com/owulveryck/goMarkableStream/internal/events"
"github.com/owulveryck/goMarkableStream/internal/pubsub"
)

type SwipeDirection string

const (
SwipeLeft SwipeDirection = "Swipe Left"
SwipeRight SwipeDirection = "Swipe Right"
)

// NewGestureHandler creates an event habdler that subscribes from the inputEvents
func NewGestureHandler(inputEvents *pubsub.PubSub) *GestureHandler {
return &GestureHandler{
inputEventBus: inputEvents,
}
}

// GestureHandler is a http.Handler that detect touch gestures
type GestureHandler struct {
inputEventBus *pubsub.PubSub
}

type gesture struct {
leftDistance, rightDistance, upDistance, downDistance int
}

func (g *gesture) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{ "left": %v, "right": %v, "up": %v, "down": %v}`+"\n", g.leftDistance, g.rightDistance, g.upDistance, g.downDistance)), nil
}

func (g *gesture) String() string {
return fmt.Sprintf("Left: %v, Right: %v, Up: %v, Down: %v", g.leftDistance, g.rightDistance, g.upDistance, g.downDistance)
}

func (g *gesture) sum() int {
return g.leftDistance + g.rightDistance + g.upDistance + g.downDistance
}

func (g *gesture) reset() {
g.leftDistance = 0
g.rightDistance = 0
g.upDistance = 0
g.downDistance = 0
}

// ServeHTTP implements http.Handler
func (h *GestureHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
eventC := h.inputEventBus.Subscribe("eventListener")
defer func() {
h.inputEventBus.Unsubscribe(eventC)
}()
const (
codeXAxis uint16 = 54
codeYAxis uint16 = 53
maxStepDist int32 = 150
// a gesture in a set of event separated by 100 millisecond
gestureMaxInterval = 150 * time.Millisecond
)

tick := time.NewTicker(gestureMaxInterval)
defer tick.Stop()
currentGesture := &gesture{}
lastEventX := events.InputEventFromSource{}
lastEventY := events.InputEventFromSource{}

enc := json.NewEncoder(w)
w.Header().Set("Content-Type", "application/x-ndjson")

for {
select {
case <-r.Context().Done():
return
case <-tick.C:
// TODO send last event
if currentGesture.sum() != 0 {
err := enc.Encode(currentGesture)
if err != nil {
http.Error(w, "cannot send json encode the message "+err.Error(), http.StatusInternalServerError)
return
}
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
}
currentGesture.reset()
lastEventX = events.InputEventFromSource{}
lastEventY = events.InputEventFromSource{}
case event := <-eventC:
if event.Source != events.Touch {
continue
}
if event.Type != events.EvAbs {
continue
}
switch event.Code {
case codeXAxis:
// This is the initial event, do not compute the distance
if lastEventX.Value == 0 {
lastEventX = event
continue
}
distance := event.Value - lastEventX.Value
if distance < 0 {
currentGesture.rightDistance += -int(distance)
} else {
currentGesture.leftDistance += int(distance)
}
lastEventX = event
case codeYAxis:
// This is the initial event, do not compute the distance
if lastEventY.Value == 0 {
lastEventY = event
continue
}
distance := event.Value - lastEventY.Value
if distance < 0 {
currentGesture.upDistance += -int(distance)
} else {
currentGesture.downDistance += int(distance)
}
lastEventY = event
}
tick.Reset(gestureMaxInterval)
}
}
}

func abs(x int32) int32 {
if x < 0 {
return -x
}
return x
}

// timevalToTime converts syscall.Timeval to time.Time
func timevalToTime(tv syscall.Timeval) time.Time {
return time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,29 @@ func (h *EventHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.inputEventBus.Unsubscribe(eventC)
}()

for event := range eventC {
// Serialize the structure as JSON
if event.Source != events.Pen {
continue
}
if event.Type != events.EvAbs {
continue
}
jsonMessage, err := json.Marshal(event)
if err != nil {
http.Error(w, "cannot send json encode the message "+err.Error(), http.StatusInternalServerError)
return
}
// Send the JSON message to the WebSocket client
err = wsutil.WriteServerText(conn, jsonMessage)
if err != nil {
log.Println(err)
for {
select {
case <-r.Context().Done():
return
case event := <-eventC:
// Serialize the structure as JSON
if event.Source != events.Pen {
continue
}
if event.Type != events.EvAbs {
continue
}
jsonMessage, err := json.Marshal(event)
if err != nil {
http.Error(w, "cannot send json encode the message "+err.Error(), http.StatusInternalServerError)
return
}
// Send the JSON message to the WebSocket client
err = wsutil.WriteServerText(conn, jsonMessage)
if err != nil {
log.Println(err)
return
}
}
}
}

0 comments on commit e02b4df

Please sign in to comment.