android.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:build android
  5. // +build android
  6. /*
  7. Android Apps are built with -buildmode=c-shared. They are loaded by a
  8. running Java process.
  9. Before any entry point is reached, a global constructor initializes the
  10. Go runtime, calling all Go init functions. All cgo calls will block
  11. until this is complete. Next JNI_OnLoad is called. When that is
  12. complete, one of two entry points is called.
  13. All-Go apps built using NativeActivity enter at ANativeActivity_onCreate.
  14. Go libraries (for example, those built with gomobile bind) do not use
  15. the app package initialization.
  16. */
  17. package app
  18. /*
  19. #cgo LDFLAGS: -landroid -llog -lEGL -lGLESv2
  20. #include <android/configuration.h>
  21. #include <android/input.h>
  22. #include <android/keycodes.h>
  23. #include <android/looper.h>
  24. #include <android/native_activity.h>
  25. #include <android/native_window.h>
  26. #include <EGL/egl.h>
  27. #include <jni.h>
  28. #include <pthread.h>
  29. #include <stdlib.h>
  30. extern EGLDisplay display;
  31. extern EGLSurface surface;
  32. char* createEGLSurface(ANativeWindow* window);
  33. char* destroyEGLSurface();
  34. int32_t getKeyRune(JNIEnv* env, AInputEvent* e);
  35. */
  36. import "C"
  37. import (
  38. "fmt"
  39. "log"
  40. "os"
  41. "time"
  42. "unsafe"
  43. "golang.org/x/mobile/app/internal/callfn"
  44. "golang.org/x/mobile/event/key"
  45. "golang.org/x/mobile/event/lifecycle"
  46. "golang.org/x/mobile/event/paint"
  47. "golang.org/x/mobile/event/size"
  48. "golang.org/x/mobile/event/touch"
  49. "golang.org/x/mobile/geom"
  50. "golang.org/x/mobile/internal/mobileinit"
  51. )
  52. // RunOnJVM runs fn on a new goroutine locked to an OS thread with a JNIEnv.
  53. //
  54. // RunOnJVM blocks until the call to fn is complete. Any Java
  55. // exception or failure to attach to the JVM is returned as an error.
  56. //
  57. // The function fn takes vm, the current JavaVM*,
  58. // env, the current JNIEnv*, and
  59. // ctx, a jobject representing the global android.context.Context.
  60. func RunOnJVM(fn func(vm, jniEnv, ctx uintptr) error) error {
  61. return mobileinit.RunOnJVM(fn)
  62. }
  63. //export setCurrentContext
  64. func setCurrentContext(vm *C.JavaVM, ctx C.jobject) {
  65. mobileinit.SetCurrentContext(unsafe.Pointer(vm), uintptr(ctx))
  66. }
  67. //export callMain
  68. func callMain(mainPC uintptr) {
  69. for _, name := range []string{"TMPDIR", "PATH", "LD_LIBRARY_PATH"} {
  70. n := C.CString(name)
  71. os.Setenv(name, C.GoString(C.getenv(n)))
  72. C.free(unsafe.Pointer(n))
  73. }
  74. // Set timezone.
  75. //
  76. // Note that Android zoneinfo is stored in /system/usr/share/zoneinfo,
  77. // but it is in some kind of packed TZiff file that we do not support
  78. // yet. As a stopgap, we build a fixed zone using the tm_zone name.
  79. var curtime C.time_t
  80. var curtm C.struct_tm
  81. C.time(&curtime)
  82. C.localtime_r(&curtime, &curtm)
  83. tzOffset := int(curtm.tm_gmtoff)
  84. tz := C.GoString(curtm.tm_zone)
  85. time.Local = time.FixedZone(tz, tzOffset)
  86. go callfn.CallFn(mainPC)
  87. }
  88. //export onStart
  89. func onStart(activity *C.ANativeActivity) {
  90. }
  91. //export onResume
  92. func onResume(activity *C.ANativeActivity) {
  93. }
  94. //export onSaveInstanceState
  95. func onSaveInstanceState(activity *C.ANativeActivity, outSize *C.size_t) unsafe.Pointer {
  96. return nil
  97. }
  98. //export onPause
  99. func onPause(activity *C.ANativeActivity) {
  100. }
  101. //export onStop
  102. func onStop(activity *C.ANativeActivity) {
  103. }
  104. //export onCreate
  105. func onCreate(activity *C.ANativeActivity) {
  106. // Set the initial configuration.
  107. //
  108. // Note we use unbuffered channels to talk to the activity loop, and
  109. // NativeActivity calls these callbacks sequentially, so configuration
  110. // will be set before <-windowRedrawNeeded is processed.
  111. windowConfigChange <- windowConfigRead(activity)
  112. }
  113. //export onDestroy
  114. func onDestroy(activity *C.ANativeActivity) {
  115. }
  116. //export onWindowFocusChanged
  117. func onWindowFocusChanged(activity *C.ANativeActivity, hasFocus C.int) {
  118. }
  119. //export onNativeWindowCreated
  120. func onNativeWindowCreated(activity *C.ANativeActivity, window *C.ANativeWindow) {
  121. }
  122. //export onNativeWindowRedrawNeeded
  123. func onNativeWindowRedrawNeeded(activity *C.ANativeActivity, window *C.ANativeWindow) {
  124. // Called on orientation change and window resize.
  125. // Send a request for redraw, and block this function
  126. // until a complete draw and buffer swap is completed.
  127. // This is required by the redraw documentation to
  128. // avoid bad draws.
  129. windowRedrawNeeded <- window
  130. <-windowRedrawDone
  131. }
  132. //export onNativeWindowDestroyed
  133. func onNativeWindowDestroyed(activity *C.ANativeActivity, window *C.ANativeWindow) {
  134. windowDestroyed <- window
  135. }
  136. //export onInputQueueCreated
  137. func onInputQueueCreated(activity *C.ANativeActivity, q *C.AInputQueue) {
  138. inputQueue <- q
  139. <-inputQueueDone
  140. }
  141. //export onInputQueueDestroyed
  142. func onInputQueueDestroyed(activity *C.ANativeActivity, q *C.AInputQueue) {
  143. inputQueue <- nil
  144. <-inputQueueDone
  145. }
  146. //export onContentRectChanged
  147. func onContentRectChanged(activity *C.ANativeActivity, rect *C.ARect) {
  148. }
  149. type windowConfig struct {
  150. orientation size.Orientation
  151. pixelsPerPt float32
  152. }
  153. func windowConfigRead(activity *C.ANativeActivity) windowConfig {
  154. aconfig := C.AConfiguration_new()
  155. C.AConfiguration_fromAssetManager(aconfig, activity.assetManager)
  156. orient := C.AConfiguration_getOrientation(aconfig)
  157. density := C.AConfiguration_getDensity(aconfig)
  158. C.AConfiguration_delete(aconfig)
  159. // Calculate the screen resolution. This value is approximate. For example,
  160. // a physical resolution of 200 DPI may be quantized to one of the
  161. // ACONFIGURATION_DENSITY_XXX values such as 160 or 240.
  162. //
  163. // A more accurate DPI could possibly be calculated from
  164. // https://developer.android.com/reference/android/util/DisplayMetrics.html#xdpi
  165. // but this does not appear to be accessible via the NDK. In any case, the
  166. // hardware might not even provide a more accurate number, as the system
  167. // does not apparently use the reported value. See golang.org/issue/13366
  168. // for a discussion.
  169. var dpi int
  170. switch density {
  171. case C.ACONFIGURATION_DENSITY_DEFAULT:
  172. dpi = 160
  173. case C.ACONFIGURATION_DENSITY_LOW,
  174. C.ACONFIGURATION_DENSITY_MEDIUM,
  175. 213, // C.ACONFIGURATION_DENSITY_TV
  176. C.ACONFIGURATION_DENSITY_HIGH,
  177. 320, // ACONFIGURATION_DENSITY_XHIGH
  178. 480, // ACONFIGURATION_DENSITY_XXHIGH
  179. 640: // ACONFIGURATION_DENSITY_XXXHIGH
  180. dpi = int(density)
  181. case C.ACONFIGURATION_DENSITY_NONE:
  182. log.Print("android device reports no screen density")
  183. dpi = 72
  184. default:
  185. log.Printf("android device reports unknown density: %d", density)
  186. // All we can do is guess.
  187. if density > 0 {
  188. dpi = int(density)
  189. } else {
  190. dpi = 72
  191. }
  192. }
  193. o := size.OrientationUnknown
  194. switch orient {
  195. case C.ACONFIGURATION_ORIENTATION_PORT:
  196. o = size.OrientationPortrait
  197. case C.ACONFIGURATION_ORIENTATION_LAND:
  198. o = size.OrientationLandscape
  199. }
  200. return windowConfig{
  201. orientation: o,
  202. pixelsPerPt: float32(dpi) / 72,
  203. }
  204. }
  205. //export onConfigurationChanged
  206. func onConfigurationChanged(activity *C.ANativeActivity) {
  207. // A rotation event first triggers onConfigurationChanged, then
  208. // calls onNativeWindowRedrawNeeded. We extract the orientation
  209. // here and save it for the redraw event.
  210. windowConfigChange <- windowConfigRead(activity)
  211. }
  212. //export onLowMemory
  213. func onLowMemory(activity *C.ANativeActivity) {
  214. }
  215. var (
  216. inputQueue = make(chan *C.AInputQueue)
  217. inputQueueDone = make(chan struct{})
  218. windowDestroyed = make(chan *C.ANativeWindow)
  219. windowRedrawNeeded = make(chan *C.ANativeWindow)
  220. windowRedrawDone = make(chan struct{})
  221. windowConfigChange = make(chan windowConfig)
  222. )
  223. func init() {
  224. theApp.registerGLViewportFilter()
  225. }
  226. func main(f func(App)) {
  227. mainUserFn = f
  228. // TODO: merge the runInputQueue and mainUI functions?
  229. go func() {
  230. if err := mobileinit.RunOnJVM(runInputQueue); err != nil {
  231. log.Fatalf("app: %v", err)
  232. }
  233. }()
  234. // Preserve this OS thread for:
  235. // 1. the attached JNI thread
  236. // 2. the GL context
  237. if err := mobileinit.RunOnJVM(mainUI); err != nil {
  238. log.Fatalf("app: %v", err)
  239. }
  240. }
  241. var mainUserFn func(App)
  242. func mainUI(vm, jniEnv, ctx uintptr) error {
  243. workAvailable := theApp.worker.WorkAvailable()
  244. donec := make(chan struct{})
  245. go func() {
  246. // close the donec channel in a defer statement
  247. // so that we could still be able to return even
  248. // if mainUserFn panics.
  249. defer close(donec)
  250. mainUserFn(theApp)
  251. }()
  252. var pixelsPerPt float32
  253. var orientation size.Orientation
  254. for {
  255. select {
  256. case <-donec:
  257. return nil
  258. case cfg := <-windowConfigChange:
  259. pixelsPerPt = cfg.pixelsPerPt
  260. orientation = cfg.orientation
  261. case w := <-windowRedrawNeeded:
  262. if C.surface == nil {
  263. if errStr := C.createEGLSurface(w); errStr != nil {
  264. return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
  265. }
  266. }
  267. theApp.sendLifecycle(lifecycle.StageFocused)
  268. widthPx := int(C.ANativeWindow_getWidth(w))
  269. heightPx := int(C.ANativeWindow_getHeight(w))
  270. theApp.eventsIn <- size.Event{
  271. WidthPx: widthPx,
  272. HeightPx: heightPx,
  273. WidthPt: geom.Pt(float32(widthPx) / pixelsPerPt),
  274. HeightPt: geom.Pt(float32(heightPx) / pixelsPerPt),
  275. PixelsPerPt: pixelsPerPt,
  276. Orientation: orientation,
  277. }
  278. theApp.eventsIn <- paint.Event{External: true}
  279. case <-windowDestroyed:
  280. if C.surface != nil {
  281. if errStr := C.destroyEGLSurface(); errStr != nil {
  282. return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
  283. }
  284. }
  285. C.surface = nil
  286. theApp.sendLifecycle(lifecycle.StageAlive)
  287. case <-workAvailable:
  288. theApp.worker.DoWork()
  289. case <-theApp.publish:
  290. // TODO: compare a generation number to redrawGen for stale paints?
  291. if C.surface != nil {
  292. // eglSwapBuffers blocks until vsync.
  293. if C.eglSwapBuffers(C.display, C.surface) == C.EGL_FALSE {
  294. log.Printf("app: failed to swap buffers (%s)", eglGetError())
  295. }
  296. }
  297. select {
  298. case windowRedrawDone <- struct{}{}:
  299. default:
  300. }
  301. theApp.publishResult <- PublishResult{}
  302. }
  303. }
  304. }
  305. func runInputQueue(vm, jniEnv, ctx uintptr) error {
  306. env := (*C.JNIEnv)(unsafe.Pointer(jniEnv)) // not a Go heap pointer
  307. // Android loopers select on OS file descriptors, not Go channels, so we
  308. // translate the inputQueue channel to an ALooper_wake call.
  309. l := C.ALooper_prepare(C.ALOOPER_PREPARE_ALLOW_NON_CALLBACKS)
  310. pending := make(chan *C.AInputQueue, 1)
  311. go func() {
  312. for q := range inputQueue {
  313. pending <- q
  314. C.ALooper_wake(l)
  315. }
  316. }()
  317. var q *C.AInputQueue
  318. for {
  319. if C.ALooper_pollAll(-1, nil, nil, nil) == C.ALOOPER_POLL_WAKE {
  320. select {
  321. default:
  322. case p := <-pending:
  323. if q != nil {
  324. processEvents(env, q)
  325. C.AInputQueue_detachLooper(q)
  326. }
  327. q = p
  328. if q != nil {
  329. C.AInputQueue_attachLooper(q, l, 0, nil, nil)
  330. }
  331. inputQueueDone <- struct{}{}
  332. }
  333. }
  334. if q != nil {
  335. processEvents(env, q)
  336. }
  337. }
  338. }
  339. func processEvents(env *C.JNIEnv, q *C.AInputQueue) {
  340. var e *C.AInputEvent
  341. for C.AInputQueue_getEvent(q, &e) >= 0 {
  342. if C.AInputQueue_preDispatchEvent(q, e) != 0 {
  343. continue
  344. }
  345. processEvent(env, e)
  346. C.AInputQueue_finishEvent(q, e, 0)
  347. }
  348. }
  349. func processEvent(env *C.JNIEnv, e *C.AInputEvent) {
  350. switch C.AInputEvent_getType(e) {
  351. case C.AINPUT_EVENT_TYPE_KEY:
  352. processKey(env, e)
  353. case C.AINPUT_EVENT_TYPE_MOTION:
  354. // At most one of the events in this batch is an up or down event; get its index and change.
  355. upDownIndex := C.size_t(C.AMotionEvent_getAction(e)&C.AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> C.AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT
  356. upDownType := touch.TypeMove
  357. switch C.AMotionEvent_getAction(e) & C.AMOTION_EVENT_ACTION_MASK {
  358. case C.AMOTION_EVENT_ACTION_DOWN, C.AMOTION_EVENT_ACTION_POINTER_DOWN:
  359. upDownType = touch.TypeBegin
  360. case C.AMOTION_EVENT_ACTION_UP, C.AMOTION_EVENT_ACTION_POINTER_UP:
  361. upDownType = touch.TypeEnd
  362. }
  363. for i, n := C.size_t(0), C.AMotionEvent_getPointerCount(e); i < n; i++ {
  364. t := touch.TypeMove
  365. if i == upDownIndex {
  366. t = upDownType
  367. }
  368. theApp.eventsIn <- touch.Event{
  369. X: float32(C.AMotionEvent_getX(e, i)),
  370. Y: float32(C.AMotionEvent_getY(e, i)),
  371. Sequence: touch.Sequence(C.AMotionEvent_getPointerId(e, i)),
  372. Type: t,
  373. }
  374. }
  375. default:
  376. log.Printf("unknown input event, type=%d", C.AInputEvent_getType(e))
  377. }
  378. }
  379. func processKey(env *C.JNIEnv, e *C.AInputEvent) {
  380. deviceID := C.AInputEvent_getDeviceId(e)
  381. if deviceID == 0 {
  382. // Software keyboard input, leaving for scribe/IME.
  383. return
  384. }
  385. k := key.Event{
  386. Rune: rune(C.getKeyRune(env, e)),
  387. Code: convAndroidKeyCode(int32(C.AKeyEvent_getKeyCode(e))),
  388. }
  389. switch C.AKeyEvent_getAction(e) {
  390. case C.AKEY_EVENT_ACTION_DOWN:
  391. k.Direction = key.DirPress
  392. case C.AKEY_EVENT_ACTION_UP:
  393. k.Direction = key.DirRelease
  394. default:
  395. k.Direction = key.DirNone
  396. }
  397. // TODO(crawshaw): set Modifiers.
  398. theApp.eventsIn <- k
  399. }
  400. func eglGetError() string {
  401. switch errNum := C.eglGetError(); errNum {
  402. case C.EGL_SUCCESS:
  403. return "EGL_SUCCESS"
  404. case C.EGL_NOT_INITIALIZED:
  405. return "EGL_NOT_INITIALIZED"
  406. case C.EGL_BAD_ACCESS:
  407. return "EGL_BAD_ACCESS"
  408. case C.EGL_BAD_ALLOC:
  409. return "EGL_BAD_ALLOC"
  410. case C.EGL_BAD_ATTRIBUTE:
  411. return "EGL_BAD_ATTRIBUTE"
  412. case C.EGL_BAD_CONTEXT:
  413. return "EGL_BAD_CONTEXT"
  414. case C.EGL_BAD_CONFIG:
  415. return "EGL_BAD_CONFIG"
  416. case C.EGL_BAD_CURRENT_SURFACE:
  417. return "EGL_BAD_CURRENT_SURFACE"
  418. case C.EGL_BAD_DISPLAY:
  419. return "EGL_BAD_DISPLAY"
  420. case C.EGL_BAD_SURFACE:
  421. return "EGL_BAD_SURFACE"
  422. case C.EGL_BAD_MATCH:
  423. return "EGL_BAD_MATCH"
  424. case C.EGL_BAD_PARAMETER:
  425. return "EGL_BAD_PARAMETER"
  426. case C.EGL_BAD_NATIVE_PIXMAP:
  427. return "EGL_BAD_NATIVE_PIXMAP"
  428. case C.EGL_BAD_NATIVE_WINDOW:
  429. return "EGL_BAD_NATIVE_WINDOW"
  430. case C.EGL_CONTEXT_LOST:
  431. return "EGL_CONTEXT_LOST"
  432. default:
  433. return fmt.Sprintf("Unknown EGL err: %d", errNum)
  434. }
  435. }
  436. func convAndroidKeyCode(aKeyCode int32) key.Code {
  437. // Many Android key codes do not map into USB HID codes.
  438. // For those, key.CodeUnknown is returned. This switch has all
  439. // cases, even the unknown ones, to serve as a documentation
  440. // and search aid.
  441. switch aKeyCode {
  442. case C.AKEYCODE_UNKNOWN:
  443. case C.AKEYCODE_SOFT_LEFT:
  444. case C.AKEYCODE_SOFT_RIGHT:
  445. case C.AKEYCODE_HOME:
  446. return key.CodeHome
  447. case C.AKEYCODE_BACK:
  448. case C.AKEYCODE_CALL:
  449. case C.AKEYCODE_ENDCALL:
  450. case C.AKEYCODE_0:
  451. return key.Code0
  452. case C.AKEYCODE_1:
  453. return key.Code1
  454. case C.AKEYCODE_2:
  455. return key.Code2
  456. case C.AKEYCODE_3:
  457. return key.Code3
  458. case C.AKEYCODE_4:
  459. return key.Code4
  460. case C.AKEYCODE_5:
  461. return key.Code5
  462. case C.AKEYCODE_6:
  463. return key.Code6
  464. case C.AKEYCODE_7:
  465. return key.Code7
  466. case C.AKEYCODE_8:
  467. return key.Code8
  468. case C.AKEYCODE_9:
  469. return key.Code9
  470. case C.AKEYCODE_STAR:
  471. case C.AKEYCODE_POUND:
  472. case C.AKEYCODE_DPAD_UP:
  473. case C.AKEYCODE_DPAD_DOWN:
  474. case C.AKEYCODE_DPAD_LEFT:
  475. case C.AKEYCODE_DPAD_RIGHT:
  476. case C.AKEYCODE_DPAD_CENTER:
  477. case C.AKEYCODE_VOLUME_UP:
  478. return key.CodeVolumeUp
  479. case C.AKEYCODE_VOLUME_DOWN:
  480. return key.CodeVolumeDown
  481. case C.AKEYCODE_POWER:
  482. case C.AKEYCODE_CAMERA:
  483. case C.AKEYCODE_CLEAR:
  484. case C.AKEYCODE_A:
  485. return key.CodeA
  486. case C.AKEYCODE_B:
  487. return key.CodeB
  488. case C.AKEYCODE_C:
  489. return key.CodeC
  490. case C.AKEYCODE_D:
  491. return key.CodeD
  492. case C.AKEYCODE_E:
  493. return key.CodeE
  494. case C.AKEYCODE_F:
  495. return key.CodeF
  496. case C.AKEYCODE_G:
  497. return key.CodeG
  498. case C.AKEYCODE_H:
  499. return key.CodeH
  500. case C.AKEYCODE_I:
  501. return key.CodeI
  502. case C.AKEYCODE_J:
  503. return key.CodeJ
  504. case C.AKEYCODE_K:
  505. return key.CodeK
  506. case C.AKEYCODE_L:
  507. return key.CodeL
  508. case C.AKEYCODE_M:
  509. return key.CodeM
  510. case C.AKEYCODE_N:
  511. return key.CodeN
  512. case C.AKEYCODE_O:
  513. return key.CodeO
  514. case C.AKEYCODE_P:
  515. return key.CodeP
  516. case C.AKEYCODE_Q:
  517. return key.CodeQ
  518. case C.AKEYCODE_R:
  519. return key.CodeR
  520. case C.AKEYCODE_S:
  521. return key.CodeS
  522. case C.AKEYCODE_T:
  523. return key.CodeT
  524. case C.AKEYCODE_U:
  525. return key.CodeU
  526. case C.AKEYCODE_V:
  527. return key.CodeV
  528. case C.AKEYCODE_W:
  529. return key.CodeW
  530. case C.AKEYCODE_X:
  531. return key.CodeX
  532. case C.AKEYCODE_Y:
  533. return key.CodeY
  534. case C.AKEYCODE_Z:
  535. return key.CodeZ
  536. case C.AKEYCODE_COMMA:
  537. return key.CodeComma
  538. case C.AKEYCODE_PERIOD:
  539. return key.CodeFullStop
  540. case C.AKEYCODE_ALT_LEFT:
  541. return key.CodeLeftAlt
  542. case C.AKEYCODE_ALT_RIGHT:
  543. return key.CodeRightAlt
  544. case C.AKEYCODE_SHIFT_LEFT:
  545. return key.CodeLeftShift
  546. case C.AKEYCODE_SHIFT_RIGHT:
  547. return key.CodeRightShift
  548. case C.AKEYCODE_TAB:
  549. return key.CodeTab
  550. case C.AKEYCODE_SPACE:
  551. return key.CodeSpacebar
  552. case C.AKEYCODE_SYM:
  553. case C.AKEYCODE_EXPLORER:
  554. case C.AKEYCODE_ENVELOPE:
  555. case C.AKEYCODE_ENTER:
  556. return key.CodeReturnEnter
  557. case C.AKEYCODE_DEL:
  558. return key.CodeDeleteBackspace
  559. case C.AKEYCODE_GRAVE:
  560. return key.CodeGraveAccent
  561. case C.AKEYCODE_MINUS:
  562. return key.CodeHyphenMinus
  563. case C.AKEYCODE_EQUALS:
  564. return key.CodeEqualSign
  565. case C.AKEYCODE_LEFT_BRACKET:
  566. return key.CodeLeftSquareBracket
  567. case C.AKEYCODE_RIGHT_BRACKET:
  568. return key.CodeRightSquareBracket
  569. case C.AKEYCODE_BACKSLASH:
  570. return key.CodeBackslash
  571. case C.AKEYCODE_SEMICOLON:
  572. return key.CodeSemicolon
  573. case C.AKEYCODE_APOSTROPHE:
  574. return key.CodeApostrophe
  575. case C.AKEYCODE_SLASH:
  576. return key.CodeSlash
  577. case C.AKEYCODE_AT:
  578. case C.AKEYCODE_NUM:
  579. case C.AKEYCODE_HEADSETHOOK:
  580. case C.AKEYCODE_FOCUS:
  581. case C.AKEYCODE_PLUS:
  582. case C.AKEYCODE_MENU:
  583. case C.AKEYCODE_NOTIFICATION:
  584. case C.AKEYCODE_SEARCH:
  585. case C.AKEYCODE_MEDIA_PLAY_PAUSE:
  586. case C.AKEYCODE_MEDIA_STOP:
  587. case C.AKEYCODE_MEDIA_NEXT:
  588. case C.AKEYCODE_MEDIA_PREVIOUS:
  589. case C.AKEYCODE_MEDIA_REWIND:
  590. case C.AKEYCODE_MEDIA_FAST_FORWARD:
  591. case C.AKEYCODE_MUTE:
  592. case C.AKEYCODE_PAGE_UP:
  593. return key.CodePageUp
  594. case C.AKEYCODE_PAGE_DOWN:
  595. return key.CodePageDown
  596. case C.AKEYCODE_PICTSYMBOLS:
  597. case C.AKEYCODE_SWITCH_CHARSET:
  598. case C.AKEYCODE_BUTTON_A:
  599. case C.AKEYCODE_BUTTON_B:
  600. case C.AKEYCODE_BUTTON_C:
  601. case C.AKEYCODE_BUTTON_X:
  602. case C.AKEYCODE_BUTTON_Y:
  603. case C.AKEYCODE_BUTTON_Z:
  604. case C.AKEYCODE_BUTTON_L1:
  605. case C.AKEYCODE_BUTTON_R1:
  606. case C.AKEYCODE_BUTTON_L2:
  607. case C.AKEYCODE_BUTTON_R2:
  608. case C.AKEYCODE_BUTTON_THUMBL:
  609. case C.AKEYCODE_BUTTON_THUMBR:
  610. case C.AKEYCODE_BUTTON_START:
  611. case C.AKEYCODE_BUTTON_SELECT:
  612. case C.AKEYCODE_BUTTON_MODE:
  613. case C.AKEYCODE_ESCAPE:
  614. return key.CodeEscape
  615. case C.AKEYCODE_FORWARD_DEL:
  616. return key.CodeDeleteForward
  617. case C.AKEYCODE_CTRL_LEFT:
  618. return key.CodeLeftControl
  619. case C.AKEYCODE_CTRL_RIGHT:
  620. return key.CodeRightControl
  621. case C.AKEYCODE_CAPS_LOCK:
  622. return key.CodeCapsLock
  623. case C.AKEYCODE_SCROLL_LOCK:
  624. case C.AKEYCODE_META_LEFT:
  625. return key.CodeLeftGUI
  626. case C.AKEYCODE_META_RIGHT:
  627. return key.CodeRightGUI
  628. case C.AKEYCODE_FUNCTION:
  629. case C.AKEYCODE_SYSRQ:
  630. case C.AKEYCODE_BREAK:
  631. case C.AKEYCODE_MOVE_HOME:
  632. case C.AKEYCODE_MOVE_END:
  633. case C.AKEYCODE_INSERT:
  634. return key.CodeInsert
  635. case C.AKEYCODE_FORWARD:
  636. case C.AKEYCODE_MEDIA_PLAY:
  637. case C.AKEYCODE_MEDIA_PAUSE:
  638. case C.AKEYCODE_MEDIA_CLOSE:
  639. case C.AKEYCODE_MEDIA_EJECT:
  640. case C.AKEYCODE_MEDIA_RECORD:
  641. case C.AKEYCODE_F1:
  642. return key.CodeF1
  643. case C.AKEYCODE_F2:
  644. return key.CodeF2
  645. case C.AKEYCODE_F3:
  646. return key.CodeF3
  647. case C.AKEYCODE_F4:
  648. return key.CodeF4
  649. case C.AKEYCODE_F5:
  650. return key.CodeF5
  651. case C.AKEYCODE_F6:
  652. return key.CodeF6
  653. case C.AKEYCODE_F7:
  654. return key.CodeF7
  655. case C.AKEYCODE_F8:
  656. return key.CodeF8
  657. case C.AKEYCODE_F9:
  658. return key.CodeF9
  659. case C.AKEYCODE_F10:
  660. return key.CodeF10
  661. case C.AKEYCODE_F11:
  662. return key.CodeF11
  663. case C.AKEYCODE_F12:
  664. return key.CodeF12
  665. case C.AKEYCODE_NUM_LOCK:
  666. return key.CodeKeypadNumLock
  667. case C.AKEYCODE_NUMPAD_0:
  668. return key.CodeKeypad0
  669. case C.AKEYCODE_NUMPAD_1:
  670. return key.CodeKeypad1
  671. case C.AKEYCODE_NUMPAD_2:
  672. return key.CodeKeypad2
  673. case C.AKEYCODE_NUMPAD_3:
  674. return key.CodeKeypad3
  675. case C.AKEYCODE_NUMPAD_4:
  676. return key.CodeKeypad4
  677. case C.AKEYCODE_NUMPAD_5:
  678. return key.CodeKeypad5
  679. case C.AKEYCODE_NUMPAD_6:
  680. return key.CodeKeypad6
  681. case C.AKEYCODE_NUMPAD_7:
  682. return key.CodeKeypad7
  683. case C.AKEYCODE_NUMPAD_8:
  684. return key.CodeKeypad8
  685. case C.AKEYCODE_NUMPAD_9:
  686. return key.CodeKeypad9
  687. case C.AKEYCODE_NUMPAD_DIVIDE:
  688. return key.CodeKeypadSlash
  689. case C.AKEYCODE_NUMPAD_MULTIPLY:
  690. return key.CodeKeypadAsterisk
  691. case C.AKEYCODE_NUMPAD_SUBTRACT:
  692. return key.CodeKeypadHyphenMinus
  693. case C.AKEYCODE_NUMPAD_ADD:
  694. return key.CodeKeypadPlusSign
  695. case C.AKEYCODE_NUMPAD_DOT:
  696. return key.CodeKeypadFullStop
  697. case C.AKEYCODE_NUMPAD_COMMA:
  698. case C.AKEYCODE_NUMPAD_ENTER:
  699. return key.CodeKeypadEnter
  700. case C.AKEYCODE_NUMPAD_EQUALS:
  701. return key.CodeKeypadEqualSign
  702. case C.AKEYCODE_NUMPAD_LEFT_PAREN:
  703. case C.AKEYCODE_NUMPAD_RIGHT_PAREN:
  704. case C.AKEYCODE_VOLUME_MUTE:
  705. return key.CodeMute
  706. case C.AKEYCODE_INFO:
  707. case C.AKEYCODE_CHANNEL_UP:
  708. case C.AKEYCODE_CHANNEL_DOWN:
  709. case C.AKEYCODE_ZOOM_IN:
  710. case C.AKEYCODE_ZOOM_OUT:
  711. case C.AKEYCODE_TV:
  712. case C.AKEYCODE_WINDOW:
  713. case C.AKEYCODE_GUIDE:
  714. case C.AKEYCODE_DVR:
  715. case C.AKEYCODE_BOOKMARK:
  716. case C.AKEYCODE_CAPTIONS:
  717. case C.AKEYCODE_SETTINGS:
  718. case C.AKEYCODE_TV_POWER:
  719. case C.AKEYCODE_TV_INPUT:
  720. case C.AKEYCODE_STB_POWER:
  721. case C.AKEYCODE_STB_INPUT:
  722. case C.AKEYCODE_AVR_POWER:
  723. case C.AKEYCODE_AVR_INPUT:
  724. case C.AKEYCODE_PROG_RED:
  725. case C.AKEYCODE_PROG_GREEN:
  726. case C.AKEYCODE_PROG_YELLOW:
  727. case C.AKEYCODE_PROG_BLUE:
  728. case C.AKEYCODE_APP_SWITCH:
  729. case C.AKEYCODE_BUTTON_1:
  730. case C.AKEYCODE_BUTTON_2:
  731. case C.AKEYCODE_BUTTON_3:
  732. case C.AKEYCODE_BUTTON_4:
  733. case C.AKEYCODE_BUTTON_5:
  734. case C.AKEYCODE_BUTTON_6:
  735. case C.AKEYCODE_BUTTON_7:
  736. case C.AKEYCODE_BUTTON_8:
  737. case C.AKEYCODE_BUTTON_9:
  738. case C.AKEYCODE_BUTTON_10:
  739. case C.AKEYCODE_BUTTON_11:
  740. case C.AKEYCODE_BUTTON_12:
  741. case C.AKEYCODE_BUTTON_13:
  742. case C.AKEYCODE_BUTTON_14:
  743. case C.AKEYCODE_BUTTON_15:
  744. case C.AKEYCODE_BUTTON_16:
  745. case C.AKEYCODE_LANGUAGE_SWITCH:
  746. case C.AKEYCODE_MANNER_MODE:
  747. case C.AKEYCODE_3D_MODE:
  748. case C.AKEYCODE_CONTACTS:
  749. case C.AKEYCODE_CALENDAR:
  750. case C.AKEYCODE_MUSIC:
  751. case C.AKEYCODE_CALCULATOR:
  752. }
  753. /* Defined in an NDK API version beyond what we use today:
  754. C.AKEYCODE_ASSIST
  755. C.AKEYCODE_BRIGHTNESS_DOWN
  756. C.AKEYCODE_BRIGHTNESS_UP
  757. C.AKEYCODE_EISU
  758. C.AKEYCODE_HENKAN
  759. C.AKEYCODE_KANA
  760. C.AKEYCODE_KATAKANA_HIRAGANA
  761. C.AKEYCODE_MEDIA_AUDIO_TRACK
  762. C.AKEYCODE_MUHENKAN
  763. C.AKEYCODE_RO
  764. C.AKEYCODE_YEN
  765. C.AKEYCODE_ZENKAKU_HANKAKU
  766. */
  767. return key.CodeUnknown
  768. }