2014-09-29 13:22:23 +10:00
|
|
|
// Copyright 2014 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// +build darwin
|
|
|
|
|
|
|
|
package app
|
|
|
|
|
2014-10-13 09:24:05 +11:00
|
|
|
// Simple on-screen app debugging for OS X. Not an officially supported
|
|
|
|
// development target for apps, as screens with mice are very different
|
|
|
|
// than screens with touch panels.
|
|
|
|
|
2014-09-29 13:22:23 +10:00
|
|
|
/*
|
|
|
|
#cgo CFLAGS: -x objective-c
|
2015-10-06 15:33:51 -04:00
|
|
|
#cgo LDFLAGS: -framework Cocoa -framework OpenGL
|
2015-06-30 14:24:27 -04:00
|
|
|
#import <Carbon/Carbon.h> // for HIToolbox/Events.h
|
2014-09-29 13:22:23 +10:00
|
|
|
#import <Cocoa/Cocoa.h>
|
2014-10-22 20:24:05 -04:00
|
|
|
#include <pthread.h>
|
2014-09-29 13:22:23 +10:00
|
|
|
|
|
|
|
void runApp(void);
|
2015-06-30 12:09:44 -04:00
|
|
|
void stopApp(void);
|
2015-05-28 06:08:52 -04:00
|
|
|
void makeCurrentContext(GLintptr);
|
2014-10-22 20:24:05 -04:00
|
|
|
uint64 threadID();
|
2014-09-29 13:22:23 +10:00
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
import (
|
2014-10-22 20:24:05 -04:00
|
|
|
"log"
|
2014-09-29 13:22:23 +10:00
|
|
|
"runtime"
|
|
|
|
"sync"
|
|
|
|
|
2015-06-30 14:24:27 -04:00
|
|
|
"golang.org/x/mobile/event/key"
|
2015-07-15 17:17:08 +10:00
|
|
|
"golang.org/x/mobile/event/lifecycle"
|
|
|
|
"golang.org/x/mobile/event/paint"
|
2015-08-13 19:59:18 +10:00
|
|
|
"golang.org/x/mobile/event/size"
|
2015-07-15 17:17:08 +10:00
|
|
|
"golang.org/x/mobile/event/touch"
|
2014-11-10 08:55:57 +11:00
|
|
|
"golang.org/x/mobile/geom"
|
2014-09-29 13:22:23 +10:00
|
|
|
)
|
|
|
|
|
2014-10-22 20:24:05 -04:00
|
|
|
var initThreadID uint64
|
|
|
|
|
2014-09-29 13:22:23 +10:00
|
|
|
func init() {
|
2014-10-22 20:24:05 -04:00
|
|
|
// Lock the goroutine responsible for initialization to an OS thread.
|
2015-06-30 12:09:44 -04:00
|
|
|
// This means the goroutine running main (and calling runApp below)
|
|
|
|
// is locked to the OS thread that started the program. This is
|
2014-10-22 20:24:05 -04:00
|
|
|
// necessary for the correct delivery of Cocoa events to the process.
|
|
|
|
//
|
|
|
|
// A discussion on this topic:
|
|
|
|
// https://groups.google.com/forum/#!msg/golang-nuts/IiWZ2hUuLDA/SNKYYZBelsYJ
|
2014-09-29 13:22:23 +10:00
|
|
|
runtime.LockOSThread()
|
2014-10-22 20:24:05 -04:00
|
|
|
initThreadID = uint64(C.threadID())
|
2014-09-29 13:22:23 +10:00
|
|
|
}
|
|
|
|
|
2015-06-27 18:32:29 -04:00
|
|
|
func main(f func(App)) {
|
2014-10-22 20:24:05 -04:00
|
|
|
if tid := uint64(C.threadID()); tid != initThreadID {
|
2015-06-27 07:44:56 -04:00
|
|
|
log.Fatalf("app.Main called on thread %d, but app.init ran on %d", tid, initThreadID)
|
2014-10-22 20:24:05 -04:00
|
|
|
}
|
2015-06-27 07:44:56 -04:00
|
|
|
|
|
|
|
go func() {
|
2015-09-22 13:19:05 -04:00
|
|
|
f(theApp)
|
2015-06-30 12:09:44 -04:00
|
|
|
C.stopApp()
|
2015-06-27 07:44:56 -04:00
|
|
|
// TODO(crawshaw): trigger runApp to return
|
|
|
|
}()
|
|
|
|
|
2014-09-29 13:22:23 +10:00
|
|
|
C.runApp()
|
|
|
|
}
|
|
|
|
|
2015-06-30 12:09:44 -04:00
|
|
|
// loop is the primary drawing loop.
|
|
|
|
//
|
|
|
|
// After Cocoa has captured the initial OS thread for processing Cocoa
|
|
|
|
// events in runApp, it starts loop on another goroutine. It is locked
|
|
|
|
// to an OS thread for its OpenGL context.
|
|
|
|
//
|
2015-10-06 15:33:51 -04:00
|
|
|
// The loop processes GL calls until a publish event appears.
|
|
|
|
// Then it runs any remaining GL calls and flushes the screen.
|
|
|
|
//
|
|
|
|
// As NSOpenGLCPSwapInterval is set to 1, the call to CGLFlushDrawable
|
|
|
|
// blocks until the screen refresh.
|
2015-10-06 12:17:06 -04:00
|
|
|
func (a *app) loop(ctx C.GLintptr) {
|
2015-06-30 12:09:44 -04:00
|
|
|
runtime.LockOSThread()
|
|
|
|
C.makeCurrentContext(ctx)
|
|
|
|
|
2015-10-06 12:17:06 -04:00
|
|
|
workAvailable := a.worker.WorkAvailable()
|
2015-10-06 15:33:51 -04:00
|
|
|
|
app: change EndPaint to Publish.
More than a name change, the painting model changes so that the app, not
the library, is responsible for driving painting. If the app is
animating and wants paint events at 60 Hz, it has to ask for that. If
the app is not animating and doesn't need to update its screen, it
shouldn't get any paint events.
Plenty of TODOs, and this CL doesn't get us to a perfect place, but it
is a checkpoint along the way.
The darwin_*.go code changes were minimal. I don't even have a Mac or
iOS device to test that this even builds. Even so, the TODOs about not
sending paint.Events unconditionally are important TODOs. That's the
whole point of switching to this model. I'll leave the actual
implementation to you (crawshaw).
Out of all the example apps, the change to example/network/main.go is
probably the most interesting.
It seems like there ought to be some way to reduce the copy/paste
between all of the example app code, but I'll leave that for future CLs.
Change-Id: I17e11c06174110c68e17f7183b2d8af19b6a170e
Reviewed-on: https://go-review.googlesource.com/14300
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-09-04 17:13:09 +10:00
|
|
|
for {
|
|
|
|
select {
|
2015-08-08 10:18:15 -04:00
|
|
|
case <-workAvailable:
|
2015-10-06 12:17:06 -04:00
|
|
|
a.worker.DoWork()
|
2015-10-06 15:33:51 -04:00
|
|
|
case <-theApp.publish:
|
app: change EndPaint to Publish.
More than a name change, the painting model changes so that the app, not
the library, is responsible for driving painting. If the app is
animating and wants paint events at 60 Hz, it has to ask for that. If
the app is not animating and doesn't need to update its screen, it
shouldn't get any paint events.
Plenty of TODOs, and this CL doesn't get us to a perfect place, but it
is a checkpoint along the way.
The darwin_*.go code changes were minimal. I don't even have a Mac or
iOS device to test that this even builds. Even so, the TODOs about not
sending paint.Events unconditionally are important TODOs. That's the
whole point of switching to this model. I'll leave the actual
implementation to you (crawshaw).
Out of all the example apps, the change to example/network/main.go is
probably the most interesting.
It seems like there ought to be some way to reduce the copy/paste
between all of the example app code, but I'll leave that for future CLs.
Change-Id: I17e11c06174110c68e17f7183b2d8af19b6a170e
Reviewed-on: https://go-review.googlesource.com/14300
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-09-04 17:13:09 +10:00
|
|
|
loop1:
|
|
|
|
for {
|
|
|
|
select {
|
2015-08-08 10:18:15 -04:00
|
|
|
case <-workAvailable:
|
2015-10-06 12:17:06 -04:00
|
|
|
a.worker.DoWork()
|
2015-10-06 15:33:51 -04:00
|
|
|
default:
|
app: change EndPaint to Publish.
More than a name change, the painting model changes so that the app, not
the library, is responsible for driving painting. If the app is
animating and wants paint events at 60 Hz, it has to ask for that. If
the app is not animating and doesn't need to update its screen, it
shouldn't get any paint events.
Plenty of TODOs, and this CL doesn't get us to a perfect place, but it
is a checkpoint along the way.
The darwin_*.go code changes were minimal. I don't even have a Mac or
iOS device to test that this even builds. Even so, the TODOs about not
sending paint.Events unconditionally are important TODOs. That's the
whole point of switching to this model. I'll leave the actual
implementation to you (crawshaw).
Out of all the example apps, the change to example/network/main.go is
probably the most interesting.
It seems like there ought to be some way to reduce the copy/paste
between all of the example app code, but I'll leave that for future CLs.
Change-Id: I17e11c06174110c68e17f7183b2d8af19b6a170e
Reviewed-on: https://go-review.googlesource.com/14300
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-09-04 17:13:09 +10:00
|
|
|
break loop1
|
|
|
|
}
|
2015-06-30 12:09:44 -04:00
|
|
|
}
|
2015-10-06 15:33:51 -04:00
|
|
|
C.CGLFlushDrawable(C.CGLGetCurrentContext())
|
|
|
|
theApp.publishResult <- PublishResult{}
|
|
|
|
select {
|
|
|
|
case drawDone <- struct{}{}:
|
|
|
|
default:
|
|
|
|
}
|
2015-06-30 12:09:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-06 15:33:51 -04:00
|
|
|
var drawDone = make(chan struct{})
|
2015-06-30 12:09:44 -04:00
|
|
|
|
2015-10-06 15:33:51 -04:00
|
|
|
// drawgl is used by Cocoa to occasionally request screen updates.
|
|
|
|
//
|
2015-06-30 12:09:44 -04:00
|
|
|
//export drawgl
|
|
|
|
func drawgl() {
|
2015-10-06 15:33:51 -04:00
|
|
|
switch theApp.lifecycleStage {
|
|
|
|
case lifecycle.StageFocused, lifecycle.StageVisible:
|
2015-10-06 15:57:53 -04:00
|
|
|
theApp.Send(paint.Event{
|
|
|
|
External: true,
|
|
|
|
})
|
2015-10-06 15:33:51 -04:00
|
|
|
<-drawDone
|
|
|
|
}
|
2015-06-30 12:09:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
//export startloop
|
|
|
|
func startloop(ctx C.GLintptr) {
|
2015-10-06 12:17:06 -04:00
|
|
|
go theApp.loop(ctx)
|
2015-06-30 12:09:44 -04:00
|
|
|
}
|
|
|
|
|
2015-07-31 14:44:31 +10:00
|
|
|
var windowHeightPx float32
|
2015-06-27 07:44:56 -04:00
|
|
|
|
2014-09-29 13:22:23 +10:00
|
|
|
//export setGeom
|
2015-08-10 11:18:50 -04:00
|
|
|
func setGeom(pixelsPerPt float32, widthPx, heightPx int) {
|
2015-07-31 14:44:31 +10:00
|
|
|
windowHeightPx = float32(heightPx)
|
2015-09-22 13:19:05 -04:00
|
|
|
theApp.eventsIn <- size.Event{
|
2015-07-27 16:51:44 +10:00
|
|
|
WidthPx: widthPx,
|
|
|
|
HeightPx: heightPx,
|
|
|
|
WidthPt: geom.Pt(float32(widthPx) / pixelsPerPt),
|
2015-07-31 14:44:31 +10:00
|
|
|
HeightPt: geom.Pt(float32(heightPx) / pixelsPerPt),
|
2015-06-27 07:44:56 -04:00
|
|
|
PixelsPerPt: pixelsPerPt,
|
2015-05-05 06:52:19 -07:00
|
|
|
}
|
2014-09-29 13:22:23 +10:00
|
|
|
}
|
|
|
|
|
2014-12-21 18:00:15 +01:00
|
|
|
var touchEvents struct {
|
2014-10-22 20:24:05 -04:00
|
|
|
sync.Mutex
|
2015-07-15 17:17:08 +10:00
|
|
|
pending []touch.Event
|
2014-10-22 20:24:05 -04:00
|
|
|
}
|
2014-09-29 13:22:23 +10:00
|
|
|
|
2015-07-15 17:17:08 +10:00
|
|
|
func sendTouch(t touch.Type, x, y float32) {
|
2015-09-22 13:19:05 -04:00
|
|
|
theApp.eventsIn <- touch.Event{
|
2015-07-31 14:44:31 +10:00
|
|
|
X: x,
|
|
|
|
Y: windowHeightPx - y,
|
2015-07-15 17:17:08 +10:00
|
|
|
Sequence: 0,
|
|
|
|
Type: t,
|
2015-06-27 07:44:56 -04:00
|
|
|
}
|
2014-09-29 13:22:23 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
//export eventMouseDown
|
2015-07-17 15:14:56 +10:00
|
|
|
func eventMouseDown(x, y float32) { sendTouch(touch.TypeBegin, x, y) }
|
2014-09-29 13:22:23 +10:00
|
|
|
|
2014-10-22 20:24:05 -04:00
|
|
|
//export eventMouseDragged
|
2015-07-15 17:17:08 +10:00
|
|
|
func eventMouseDragged(x, y float32) { sendTouch(touch.TypeMove, x, y) }
|
2014-09-29 13:22:23 +10:00
|
|
|
|
|
|
|
//export eventMouseEnd
|
2015-07-15 17:17:08 +10:00
|
|
|
func eventMouseEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) }
|
2014-09-29 13:22:23 +10:00
|
|
|
|
2015-06-30 12:09:44 -04:00
|
|
|
//export lifecycleDead
|
2015-09-22 13:19:05 -04:00
|
|
|
func lifecycleDead() { theApp.sendLifecycle(lifecycle.StageDead) }
|
2015-05-28 06:08:52 -04:00
|
|
|
|
2015-06-30 14:24:27 -04:00
|
|
|
//export eventKey
|
|
|
|
func eventKey(runeVal int32, direction uint8, code uint16, flags uint32) {
|
|
|
|
var modifiers key.Modifiers
|
|
|
|
for _, mod := range mods {
|
|
|
|
if flags&mod.flags == mod.flags {
|
|
|
|
modifiers |= mod.mod
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-22 13:19:05 -04:00
|
|
|
theApp.eventsIn <- key.Event{
|
2015-06-30 14:24:27 -04:00
|
|
|
Rune: convRune(rune(runeVal)),
|
|
|
|
Code: convVirtualKeyCode(code),
|
|
|
|
Modifiers: modifiers,
|
|
|
|
Direction: key.Direction(direction),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//export eventFlags
|
|
|
|
func eventFlags(flags uint32) {
|
|
|
|
for _, mod := range mods {
|
|
|
|
if flags&mod.flags == mod.flags && lastFlags&mod.flags != mod.flags {
|
|
|
|
eventKey(-1, uint8(key.DirPress), mod.code, flags)
|
|
|
|
}
|
|
|
|
if lastFlags&mod.flags == mod.flags && flags&mod.flags != mod.flags {
|
|
|
|
eventKey(-1, uint8(key.DirRelease), mod.code, flags)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lastFlags = flags
|
|
|
|
}
|
|
|
|
|
|
|
|
var lastFlags uint32
|
|
|
|
|
|
|
|
var mods = [...]struct {
|
|
|
|
flags uint32
|
|
|
|
code uint16
|
|
|
|
mod key.Modifiers
|
|
|
|
}{
|
|
|
|
// Left and right variants of modifier keys have their own masks,
|
|
|
|
// but they are not documented. These were determined empirically.
|
|
|
|
{1<<17 | 0x102, C.kVK_Shift, key.ModShift},
|
|
|
|
{1<<17 | 0x104, C.kVK_RightShift, key.ModShift},
|
|
|
|
{1<<18 | 0x101, C.kVK_Control, key.ModControl},
|
|
|
|
// TODO key.ControlRight
|
|
|
|
{1<<19 | 0x120, C.kVK_Option, key.ModAlt},
|
|
|
|
{1<<19 | 0x140, C.kVK_RightOption, key.ModAlt},
|
|
|
|
{1<<20 | 0x108, C.kVK_Command, key.ModMeta},
|
|
|
|
{1<<20 | 0x110, C.kVK_Command, key.ModMeta}, // TODO: missing kVK_RightCommand
|
|
|
|
}
|
|
|
|
|
2015-06-30 12:09:44 -04:00
|
|
|
//export lifecycleAlive
|
2015-09-22 13:19:05 -04:00
|
|
|
func lifecycleAlive() { theApp.sendLifecycle(lifecycle.StageAlive) }
|
2014-09-29 13:22:23 +10:00
|
|
|
|
2015-06-30 12:09:44 -04:00
|
|
|
//export lifecycleVisible
|
app: change EndPaint to Publish.
More than a name change, the painting model changes so that the app, not
the library, is responsible for driving painting. If the app is
animating and wants paint events at 60 Hz, it has to ask for that. If
the app is not animating and doesn't need to update its screen, it
shouldn't get any paint events.
Plenty of TODOs, and this CL doesn't get us to a perfect place, but it
is a checkpoint along the way.
The darwin_*.go code changes were minimal. I don't even have a Mac or
iOS device to test that this even builds. Even so, the TODOs about not
sending paint.Events unconditionally are important TODOs. That's the
whole point of switching to this model. I'll leave the actual
implementation to you (crawshaw).
Out of all the example apps, the change to example/network/main.go is
probably the most interesting.
It seems like there ought to be some way to reduce the copy/paste
between all of the example app code, but I'll leave that for future CLs.
Change-Id: I17e11c06174110c68e17f7183b2d8af19b6a170e
Reviewed-on: https://go-review.googlesource.com/14300
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-09-04 17:13:09 +10:00
|
|
|
func lifecycleVisible() {
|
2015-09-22 13:19:05 -04:00
|
|
|
theApp.sendLifecycle(lifecycle.StageVisible)
|
app: change EndPaint to Publish.
More than a name change, the painting model changes so that the app, not
the library, is responsible for driving painting. If the app is
animating and wants paint events at 60 Hz, it has to ask for that. If
the app is not animating and doesn't need to update its screen, it
shouldn't get any paint events.
Plenty of TODOs, and this CL doesn't get us to a perfect place, but it
is a checkpoint along the way.
The darwin_*.go code changes were minimal. I don't even have a Mac or
iOS device to test that this even builds. Even so, the TODOs about not
sending paint.Events unconditionally are important TODOs. That's the
whole point of switching to this model. I'll leave the actual
implementation to you (crawshaw).
Out of all the example apps, the change to example/network/main.go is
probably the most interesting.
It seems like there ought to be some way to reduce the copy/paste
between all of the example app code, but I'll leave that for future CLs.
Change-Id: I17e11c06174110c68e17f7183b2d8af19b6a170e
Reviewed-on: https://go-review.googlesource.com/14300
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-09-04 17:13:09 +10:00
|
|
|
}
|
2015-06-27 07:44:56 -04:00
|
|
|
|
2015-06-30 12:09:44 -04:00
|
|
|
//export lifecycleFocused
|
2015-09-22 13:19:05 -04:00
|
|
|
func lifecycleFocused() { theApp.sendLifecycle(lifecycle.StageFocused) }
|
2015-06-30 14:24:27 -04:00
|
|
|
|
|
|
|
// convRune marks the Carbon/Cocoa private-range unicode rune representing
|
|
|
|
// a non-unicode key event to -1, used for Rune in the key package.
|
|
|
|
//
|
|
|
|
// http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT
|
|
|
|
func convRune(r rune) rune {
|
|
|
|
if '\uE000' <= r && r <= '\uF8FF' {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
// convVirtualKeyCode converts a Carbon/Cocoa virtual key code number
|
|
|
|
// into the standard keycodes used by the key package.
|
|
|
|
//
|
|
|
|
// To get a sense of the key map, see the diagram on
|
|
|
|
// http://boredzo.org/blog/archives/2007-05-22/virtual-key-codes
|
2015-07-22 16:44:22 -04:00
|
|
|
func convVirtualKeyCode(vkcode uint16) key.Code {
|
2015-06-30 14:24:27 -04:00
|
|
|
switch vkcode {
|
|
|
|
case C.kVK_ANSI_A:
|
|
|
|
return key.CodeA
|
|
|
|
case C.kVK_ANSI_B:
|
|
|
|
return key.CodeB
|
|
|
|
case C.kVK_ANSI_C:
|
|
|
|
return key.CodeC
|
|
|
|
case C.kVK_ANSI_D:
|
|
|
|
return key.CodeD
|
|
|
|
case C.kVK_ANSI_E:
|
|
|
|
return key.CodeE
|
|
|
|
case C.kVK_ANSI_F:
|
|
|
|
return key.CodeF
|
|
|
|
case C.kVK_ANSI_G:
|
|
|
|
return key.CodeG
|
|
|
|
case C.kVK_ANSI_H:
|
|
|
|
return key.CodeH
|
|
|
|
case C.kVK_ANSI_I:
|
|
|
|
return key.CodeI
|
|
|
|
case C.kVK_ANSI_J:
|
|
|
|
return key.CodeJ
|
|
|
|
case C.kVK_ANSI_K:
|
|
|
|
return key.CodeK
|
|
|
|
case C.kVK_ANSI_L:
|
|
|
|
return key.CodeL
|
|
|
|
case C.kVK_ANSI_M:
|
|
|
|
return key.CodeM
|
|
|
|
case C.kVK_ANSI_N:
|
|
|
|
return key.CodeN
|
|
|
|
case C.kVK_ANSI_O:
|
|
|
|
return key.CodeO
|
|
|
|
case C.kVK_ANSI_P:
|
|
|
|
return key.CodeP
|
|
|
|
case C.kVK_ANSI_Q:
|
|
|
|
return key.CodeQ
|
|
|
|
case C.kVK_ANSI_R:
|
|
|
|
return key.CodeR
|
|
|
|
case C.kVK_ANSI_S:
|
|
|
|
return key.CodeS
|
|
|
|
case C.kVK_ANSI_T:
|
|
|
|
return key.CodeT
|
|
|
|
case C.kVK_ANSI_U:
|
|
|
|
return key.CodeU
|
|
|
|
case C.kVK_ANSI_V:
|
|
|
|
return key.CodeV
|
|
|
|
case C.kVK_ANSI_W:
|
|
|
|
return key.CodeW
|
|
|
|
case C.kVK_ANSI_X:
|
|
|
|
return key.CodeX
|
|
|
|
case C.kVK_ANSI_Y:
|
|
|
|
return key.CodeY
|
|
|
|
case C.kVK_ANSI_Z:
|
|
|
|
return key.CodeZ
|
|
|
|
case C.kVK_ANSI_1:
|
|
|
|
return key.Code1
|
|
|
|
case C.kVK_ANSI_2:
|
|
|
|
return key.Code2
|
|
|
|
case C.kVK_ANSI_3:
|
|
|
|
return key.Code3
|
|
|
|
case C.kVK_ANSI_4:
|
|
|
|
return key.Code4
|
|
|
|
case C.kVK_ANSI_5:
|
|
|
|
return key.Code5
|
|
|
|
case C.kVK_ANSI_6:
|
|
|
|
return key.Code6
|
|
|
|
case C.kVK_ANSI_7:
|
|
|
|
return key.Code7
|
|
|
|
case C.kVK_ANSI_8:
|
|
|
|
return key.Code8
|
|
|
|
case C.kVK_ANSI_9:
|
|
|
|
return key.Code9
|
|
|
|
case C.kVK_ANSI_0:
|
|
|
|
return key.Code0
|
|
|
|
// TODO: move the rest of these codes to constants in key.go
|
|
|
|
// if we are happy with them.
|
|
|
|
case C.kVK_Return:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeReturnEnter
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_Escape:
|
|
|
|
return key.CodeEscape
|
|
|
|
case C.kVK_Delete:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeDeleteBackspace
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_Tab:
|
|
|
|
return key.CodeTab
|
|
|
|
case C.kVK_Space:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeSpacebar
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_Minus:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeHyphenMinus
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_Equal:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeEqualSign
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_LeftBracket:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeLeftSquareBracket
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_RightBracket:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeRightSquareBracket
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_Backslash:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeBackslash
|
2015-06-30 14:24:27 -04:00
|
|
|
// 50: Keyboard Non-US "#" and ~
|
|
|
|
case C.kVK_ANSI_Semicolon:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeSemicolon
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_Quote:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeApostrophe
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_Grave:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeGraveAccent
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_Comma:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeComma
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_Period:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeFullStop
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_Slash:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeSlash
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_CapsLock:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeCapsLock
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_F1:
|
|
|
|
return key.CodeF1
|
|
|
|
case C.kVK_F2:
|
|
|
|
return key.CodeF2
|
|
|
|
case C.kVK_F3:
|
|
|
|
return key.CodeF3
|
|
|
|
case C.kVK_F4:
|
|
|
|
return key.CodeF4
|
|
|
|
case C.kVK_F5:
|
|
|
|
return key.CodeF5
|
|
|
|
case C.kVK_F6:
|
|
|
|
return key.CodeF6
|
|
|
|
case C.kVK_F7:
|
|
|
|
return key.CodeF7
|
|
|
|
case C.kVK_F8:
|
|
|
|
return key.CodeF8
|
|
|
|
case C.kVK_F9:
|
|
|
|
return key.CodeF9
|
|
|
|
case C.kVK_F10:
|
|
|
|
return key.CodeF10
|
|
|
|
case C.kVK_F11:
|
|
|
|
return key.CodeF11
|
|
|
|
case C.kVK_F12:
|
|
|
|
return key.CodeF12
|
|
|
|
// 70: PrintScreen
|
|
|
|
// 71: Scroll Lock
|
|
|
|
// 72: Pause
|
|
|
|
// 73: Insert
|
|
|
|
case C.kVK_Home:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeHome
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_PageUp:
|
|
|
|
return key.CodePageUp
|
|
|
|
case C.kVK_ForwardDelete:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeDeleteForward
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_End:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeEnd
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_PageDown:
|
|
|
|
return key.CodePageDown
|
|
|
|
case C.kVK_RightArrow:
|
|
|
|
return key.CodeRightArrow
|
|
|
|
case C.kVK_LeftArrow:
|
|
|
|
return key.CodeLeftArrow
|
|
|
|
case C.kVK_DownArrow:
|
|
|
|
return key.CodeDownArrow
|
|
|
|
case C.kVK_UpArrow:
|
|
|
|
return key.CodeUpArrow
|
|
|
|
case C.kVK_ANSI_KeypadClear:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeKeypadNumLock
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_KeypadDivide:
|
|
|
|
return key.CodeKeypadSlash
|
|
|
|
case C.kVK_ANSI_KeypadMultiply:
|
|
|
|
return key.CodeKeypadAsterisk
|
|
|
|
case C.kVK_ANSI_KeypadMinus:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeKeypadHyphenMinus
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_KeypadPlus:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeKeypadPlusSign
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_ANSI_KeypadEnter:
|
|
|
|
return key.CodeKeypadEnter
|
|
|
|
case C.kVK_ANSI_Keypad1:
|
|
|
|
return key.CodeKeypad1
|
|
|
|
case C.kVK_ANSI_Keypad2:
|
|
|
|
return key.CodeKeypad2
|
|
|
|
case C.kVK_ANSI_Keypad3:
|
|
|
|
return key.CodeKeypad3
|
|
|
|
case C.kVK_ANSI_Keypad4:
|
|
|
|
return key.CodeKeypad4
|
|
|
|
case C.kVK_ANSI_Keypad5:
|
|
|
|
return key.CodeKeypad5
|
|
|
|
case C.kVK_ANSI_Keypad6:
|
|
|
|
return key.CodeKeypad6
|
|
|
|
case C.kVK_ANSI_Keypad7:
|
|
|
|
return key.CodeKeypad7
|
|
|
|
case C.kVK_ANSI_Keypad8:
|
|
|
|
return key.CodeKeypad8
|
|
|
|
case C.kVK_ANSI_Keypad9:
|
|
|
|
return key.CodeKeypad9
|
|
|
|
case C.kVK_ANSI_Keypad0:
|
|
|
|
return key.CodeKeypad0
|
|
|
|
case C.kVK_ANSI_KeypadDecimal:
|
|
|
|
return key.CodeKeypadFullStop
|
|
|
|
case C.kVK_ANSI_KeypadEquals:
|
|
|
|
return key.CodeKeypadEqualSign
|
|
|
|
case C.kVK_F13:
|
|
|
|
return key.CodeF13
|
|
|
|
case C.kVK_F14:
|
|
|
|
return key.CodeF14
|
|
|
|
case C.kVK_F15:
|
|
|
|
return key.CodeF15
|
|
|
|
case C.kVK_F16:
|
|
|
|
return key.CodeF16
|
|
|
|
case C.kVK_F17:
|
|
|
|
return key.CodeF17
|
|
|
|
case C.kVK_F18:
|
|
|
|
return key.CodeF18
|
|
|
|
case C.kVK_F19:
|
|
|
|
return key.CodeF19
|
|
|
|
case C.kVK_F20:
|
|
|
|
return key.CodeF20
|
|
|
|
// 116: Keyboard Execute
|
|
|
|
case C.kVK_Help:
|
|
|
|
return key.CodeHelp
|
|
|
|
// 118: Keyboard Menu
|
|
|
|
// 119: Keyboard Select
|
|
|
|
// 120: Keyboard Stop
|
|
|
|
// 121: Keyboard Again
|
|
|
|
// 122: Keyboard Undo
|
|
|
|
// 123: Keyboard Cut
|
|
|
|
// 124: Keyboard Copy
|
|
|
|
// 125: Keyboard Paste
|
|
|
|
// 126: Keyboard Find
|
|
|
|
case C.kVK_Mute:
|
|
|
|
return key.CodeMute
|
|
|
|
case C.kVK_VolumeUp:
|
|
|
|
return key.CodeVolumeUp
|
|
|
|
case C.kVK_VolumeDown:
|
|
|
|
return key.CodeVolumeDown
|
|
|
|
// 130: Keyboard Locking Caps Lock
|
|
|
|
// 131: Keyboard Locking Num Lock
|
|
|
|
// 132: Keyboard Locking Scroll Lock
|
|
|
|
// 133: Keyboard Comma
|
|
|
|
// 134: Keyboard Equal Sign
|
|
|
|
// ...: Bunch of stuff
|
|
|
|
case C.kVK_Control:
|
|
|
|
return key.CodeLeftControl
|
|
|
|
case C.kVK_Shift:
|
|
|
|
return key.CodeLeftShift
|
|
|
|
case C.kVK_Option:
|
|
|
|
return key.CodeLeftAlt
|
|
|
|
case C.kVK_Command:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeLeftGUI
|
2015-06-30 14:24:27 -04:00
|
|
|
case C.kVK_RightControl:
|
|
|
|
return key.CodeRightControl
|
|
|
|
case C.kVK_RightShift:
|
|
|
|
return key.CodeRightShift
|
|
|
|
case C.kVK_RightOption:
|
|
|
|
return key.CodeRightAlt
|
2015-07-22 16:44:22 -04:00
|
|
|
// TODO key.CodeRightGUI
|
2015-06-30 14:24:27 -04:00
|
|
|
default:
|
2015-07-22 16:44:22 -04:00
|
|
|
return key.CodeUnknown
|
2015-06-30 14:24:27 -04:00
|
|
|
}
|
|
|
|
}
|