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