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