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