From c73f3e75b63dd43bb46bb4a7303489811578f27e Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 26 May 2015 14:33:20 -0400 Subject: [PATCH] app: support iOS touch events Change-Id: I6e8effb1da24e9073454dd2643efdd3c3b3a5ded Reviewed-on: https://go-review.googlesource.com/10480 Reviewed-by: Hyang-Ah Hana Kim --- app/darwin_armx.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++ app/darwin_armx.m | 26 +++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/app/darwin_armx.go b/app/darwin_armx.go index eef2af8..92d57c6 100644 --- a/app/darwin_armx.go +++ b/app/darwin_armx.go @@ -27,6 +27,7 @@ import ( "sync" "unsafe" + "golang.org/x/mobile/event" "golang.org/x/mobile/geom" "golang.org/x/mobile/gl" ) @@ -50,6 +51,7 @@ func run(callbacks []Callbacks) { log.Fatalf("app.Run called on thread %d, but app.init ran on %d", tid, initThreadID) } cb = callbacks + close(mainCalled) C.runApp() } @@ -123,6 +125,55 @@ func initGL() { var cb []Callbacks var initGLOnce sync.Once +// touchIDs is the current active touches. The position in the array +// is the ID, the value is the UITouch* pointer value. +// +// It is widely reported that the iPhone can handle up to 5 simultaneous +// touch events, while the iPad can handle 11. +var touchIDs [11]uintptr + +var touchEvents struct { + sync.Mutex + pending []event.Touch +} + +//export sendTouch +func sendTouch(touch uintptr, touchType int, x, y float32) { + id := -1 + for i, val := range touchIDs { + if val == touch { + id = i + break + } + } + if id == -1 { + for i, val := range touchIDs { + if val == 0 { + touchIDs[i] = touch + id = i + break + } + } + panic("out of touchIDs") + } + + ty := event.TouchType(touchType) + if ty == event.TouchEnd { + touchIDs[id] = 0 + } + + touchEvents.Lock() + touchEvents.pending = append(touchEvents.pending, event.Touch{ + ID: event.TouchSequenceID(id), + Type: ty, + Loc: geom.Point{ + X: geom.Pt(x / geom.PixelsPerPt), + Y: geom.Pt(y / geom.PixelsPerPt), + }, + }) + touchEvents.Unlock() +} + //export drawgl func drawgl(ctx uintptr) { // The call to lockContext loads the OpenGL context into @@ -134,6 +185,18 @@ func drawgl(ctx uintptr) { initGLOnce.Do(initGL) + touchEvents.Lock() + pending := touchEvents.pending + touchEvents.pending = nil + touchEvents.Unlock() + for _, cb := range callbacks { + if cb.Touch != nil { + for _, e := range pending { + cb.Touch(e) + } + } + } + // TODO not here? gl.ClearColor(0, 0, 0, 1) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) diff --git a/app/darwin_armx.m b/app/darwin_armx.m index ec0d812..07ad56c 100644 --- a/app/darwin_armx.m +++ b/app/darwin_armx.m @@ -44,7 +44,9 @@ struct utsname sysInfo; GLKView *view = (GLKView *)self.view; view.context = self.context; view.drawableDepthFormat = GLKViewDrawableDepthFormat24; + view.multipleTouchEnabled = true; // TODO expose setting to user. } + - (void)update { GLKView *view = (GLKView *)self.view; int w = [view drawableWidth]; @@ -53,6 +55,30 @@ struct utsname sysInfo; drawgl((GoUintptr)self.context); } + +#define TOUCH_START 0 // event.TouchStart +#define TOUCH_MOVE 1 // event.TouchMove +#define TOUCH_END 2 // event.TouchEnd + +static void sendTouches(int ty, NSSet* touches) { + CGFloat scale = [UIScreen mainScreen].scale; + for (UITouch* touch in touches) { + CGPoint p = [touch locationInView:touch.view]; + sendTouch((GoUintptr)touch, ty, p.x*scale, p.y*scale); + } +} + +- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { + sendTouches(TOUCH_START, touches); +} + +- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { + sendTouches(TOUCH_MOVE, touches); +} + +- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { + sendTouches(TOUCH_END, touches); +} @end void runApp(void) {