之前分析的InputReader读取底层事件可以得知 InputReaderThead启动之后会通过mEventHub->getEvents读取设备节点的所有事件,通过parsekey方法解析kl文件存入数据结构map,在读取节点事件之前先扫描设备,如果没有打开则打开设备,在打开设备时会将scancode和keycode一一映射,此篇文章记录他们是如何建立映射关系的起来的
/frameworks/native/services/inputflinger/InputReader.cpp

void InputReader::loopOnce() {......
343      size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
344
345      { // acquire lock
346          AutoMutex _l(mLock);
347          mReaderIsAliveCondition.broadcast();
348
349          if (count) {350              processEventsLocked(mEventBuffer, count);
351          }
352

/frameworks/native/services/inputflinger/EventHub.cpp
mEventHub->getEvents

851  size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {852          ......
860      bool awoken = false;
861      for (;;) {862          nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);......
875          // Report any devices that had last been added/removed.
876          while (mClosingDevices) {877              Device* device = mClosingDevices;
878              ALOGV("Reporting device closed: id=%d, name=%s\n",
879                   device->id, device->path.c_str());
880          ......
891          }
892
893          if (mNeedToScanDevices) {894              mNeedToScanDevices = false;
895              scanDevicesLocked();
896              mNeedToSendFinishedDeviceScan = true;
897          }......}

/frameworks/native/services/inputflinger/EventHub.cpp
扫描设备"/dev/input"

static const char *DEVICE_PATH = "/dev/input";
1130  void EventHub::scanDevicesLocked() {//DEVICE_PATH = "/dev/input"
1131      status_t result = scanDirLocked(DEVICE_PATH);
1132      ......
1144  }
1908  status_t EventHub::scanDirLocked(const char *dirname)
1909  {1910      ......//扫描/dev/input/下的所有设备
1920      while((de = readdir(dir))) {1921          if(de->d_name[0] == '.' &&
1922             (de->d_name[1] == '\0' ||
1923              (de->d_name[1] == '.' && de->d_name[2] == '\0')))
1924              continue;
1925          strcpy(filename, de->d_name);//打开设备
1926          openDeviceLocked(devname);
1927      }
1928      closedir(dir);
1929      return 0;
1930  }

打开设备

1237  status_t EventHub::openDeviceLocked(const char* devicePath) {1238        //省略了很多代码,主要看loadKeyMapLocked
1258        ......
1350        ......
1429      // Load the key map.
1430      // We need to do this for joysticks too because the key layout may specify axes.
1431      status_t keyMapStatus = NAME_NOT_FOUND;
1432      if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {1433          // Load the keymap for the device.
1434          keyMapStatus = loadKeyMapLocked(device);
1435      }
}

主要看scancode和keycode如何一一映射的

1685  status_t EventHub::loadKeyMapLocked(Device* device) {1686      return device->keyMap.load(device->identifier, device->configuration);
1687  }

继续调到Device的keyMap的load函数,Device是EventHub内部的结构体
/frameworks/native/services/inputflinger/EventHub.h

325  private:
326      struct Device {327          Device* next;.......
328          KeyMap keyMap;.......}

继续看KeyMap的load函数
/frameworks/native/libs/input/Keyboard.cpp

41  status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
42          const PropertyMap* deviceConfiguration) {43      // Use the configured key layout if available.
44      if (deviceConfiguration) {45          String8 keyLayoutName;//通过设备的配置文件去加载配置文件内制定好的映射表
46          if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
47                  keyLayoutName)) {48              status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str());
49           if (status == NAME_NOT_FOUND) {52                deviceIdenfifier.name.c_str(), keyLayoutName.string());
53              }
54          }
55
56          String8 keyCharacterMapName;
57          if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
58                  keyCharacterMapName)) {59              status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str());
60              if (status == NAME_NOT_FOUND) {61                  ALOGE("Configuration for keyboard device '%s' requested keyboard character "
62                          "map '%s' but it was not found.",
63                          deviceIdenfifier.name.c_str(), keyLayoutName.string());
64              }
65          }
67          if (isComplete()) {68              return OK;
69          }
70      }
72      // Try searching by device identifier.通过设备信息查找对应的映射表
73      if (probeKeyMap(deviceIdenfifier, "")) {74          return OK;
75      }
77      // Fall back on the Generic key map.
78      // TODO Apply some additional heuristics here to figure out what kind of
79      //      generic key map to use (US English, etc.) for typical external keyboards.查找通用的映射表
80      if (probeKeyMap(deviceIdenfifier, "Generic")) {81          return OK;
82      }
83
84      // Try the Virtual key map as a last resort.查找虚拟映射表
85      if (probeKeyMap(deviceIdenfifier, "Virtual")) {86          return OK;
87      }
88
89      // Give up!
90      ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
91              deviceIdenfifier.name.c_str());
92      return NAME_NOT_FOUND;
93  }

可以看到我这个设备有四个设备节点,所以
mtk-tpd,ACCDET,fts_ts,mtk-kpd以及通用表都会解析的

Tokyo_TF:/system/usr $ getevent
add device 1: /dev/input/event3name:     "mtk-tpd"
add device 2: /dev/input/event0name:     "ACCDET"
add device 3: /dev/input/event1name:     "mtk-kpd"
add device 4: /dev/input/event2name:     "fts_ts"
/dev/input/event1: 0001 0074 00000001
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0074 00000000
/dev/input/event1: 0000 0000 00000000
Tokyo_TF:/system/usr $
Tokyo_TF:/system/usr $ find -name "mtk-kpd*"
./keylayout/mtk-kpd.kl
Tokyo_TF:/system/usr $ 

probeKeyMap函数

95  bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
96          const std::string& keyMapName) {97      if (!haveKeyLayout()) {98          loadKeyLayout(deviceIdentifier, keyMapName);
99      }
100      if (!haveKeyCharacterMap()) {101          loadKeyCharacterMap(deviceIdentifier, keyMapName);
102      }
103      return isComplete();
104  }

loadKeyLayout()函数

106  status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
107          const std::string& name) {108      std::string path(getPath(deviceIdentifier, name,
109              INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
110      if (path.empty()) {111          return NAME_NOT_FOUND;
112      }
113
114      status_t status = KeyLayoutMap::load(path, &keyLayoutMap);
115      if (status) {116          return status;
117      }
118
119      keyLayoutFile = path;
120      return OK;
121  }

继续KeyLayoutMap::load
/frameworks/native/libs/input/KeyLayoutMap.cpp

52  status_t KeyLayoutMap::load(const std::string& filename, sp<KeyLayoutMap>* outMap) {54        ......
55      Tokenizer* tokenizer;
56      status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
57      if (status) {58        ......
59      } else {60          sp<KeyLayoutMap> map = new KeyLayoutMap();
61          if (!map.get()) {62              ......
64          } else {68              Parser parser(map.get(), tokenizer);//解析map
69              status = parser.parse();
70              ......
82      return status;
83  }

继续parser.parse(),开始解析映射表

199  status_t KeyLayoutMap::Parser::parse() {//while循环,一行一行地解析映射表项
200  while (!mTokenizer->isEof()) {201  #if DEBUG_PARSER/*11-22 04:27:06.719   908  1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:160: '# key 138 "KEY_HELP"'.
11-22 04:27:06.719   908  1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:161: 'key 139   MENU'.
11-22 04:27:06.719   908  1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:151: '# key 129 "KEY_AGAIN"'.
11-22 04:27:06.719   908  1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:152: '# key 130 "KEY_PROPS"'.
11-22 04:27:06.719   908  1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:153: '# key 131 "KEY_UNDO"'.
11-22 04:27:06.719   908  1162 D KeyLayoutMap: Parsing /system/usr/keylayout/Generic.kl:154: '# key 132 "KEY_FRONT"'.*///这条log的输入,部分
202          ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
203                  mTokenizer->peekRemainderOfLine().string());
204  #endif
206          mTokenizer->skipDelimiters(WHITESPACE);
208          if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {209              String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
210              if (keywordToken == "key") {211                  mTokenizer->skipDelimiters(WHITESPACE);
212                  status_t status = parseKey();
213                  if (status) return status;
214              } else if (keywordToken == "axis") {215                  mTokenizer->skipDelimiters(WHITESPACE);
216                  status_t status = parseAxis();
217                  if (status) return status;
218              } else if (keywordToken == "led") {219                  mTokenizer->skipDelimiters(WHITESPACE);
220                  status_t status = parseLed();
221                  if (status) return status;
222              } else {223                  ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
224                          keywordToken.string());
225                  return BAD_VALUE;
226              }
227
228              mTokenizer->skipDelimiters(WHITESPACE);
229              if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {230                  ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
231                          mTokenizer->getLocation().string(),
232                          mTokenizer->peekRemainderOfLine().string());
233                  return BAD_VALUE;
234              }
235          }
237          mTokenizer->nextLine();
238      }
239      return NO_ERROR;
240  }

mTokenizer->getLocation()这代表哪一张映射表,mTokenizer->peekRemainderOfLine()代表映射表中的scancode,
解析的规则如下:
keyword是"key",调用parseKey解析,如果解析出错则返回错误
keyword是"axis",调用parseAxis解析,如果解析出错则返回错误
keyword是"led",调用parseAxis解析,如果解析出错则返回错误
如果还有其他不按规则的符号则返回BAD_VALUE

继续parseKey()函数

242  status_t KeyLayoutMap::Parser::parseKey() {243      ......
256      //此函数解析得到keycode
267      int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
268      ......//11-22 04:55:50.301   852  1162 D KeyLayoutMap: Parsed key scan code: code=85, keyCode=211, flags=0x00000000.
294  #if DEBUG_PARSER
295      ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
296              mapUsage ? "usage" : "scan code", code, keyCode, flags);
297  #endif
298      Key key;
299      key.keyCode = keyCode;
300      key.flags = flags;
301      map.add(code, key);
302      return NO_ERROR;
303  }

打开上面的log开关得到如下输出:scancode和keycode的映射终于得到了,继续看函数getKeyCodeByLabel

11-22 04:55:50.301   852  1162 D KeyLayoutMap: Parsed key scan code: code=83, keyCode=158, flags=0x00000000.
11-22 04:55:50.301   852  1162 D KeyLayoutMap: Parsed key scan code: code=85, keyCode=211, flags=0x00000000.
11-22 04:55:50.306   852  1162 D KeyLayoutMap: Parsed key scan code: code=173, keyCode=285, flags=0x00000000.
11-22 04:55:50.316   852  1162 D KeyLayoutMap: Parsed key scan code: code=483, keyCode=47, flags=0x00000004.

/frameworks/native/include/input/InputEventLabels.h

434  static inline int32_t getKeyCodeByLabel(const char* label) {435      return int32_t(lookupValueByLabel(label, KEYCODES));
436  }

调用了lookupValueByLabel函数,我们来看 KEYCODES是什么,里面是所有的键

23  #define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }
39  static const InputEventLabel KEYCODES[] = {40      // NOTE: If you add a new keycode here you must also add it to several other files.
41      //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
44      ......
45      DEFINE_KEYCODE(HOME),
46      DEFINE_KEYCODE(BACK),
47      DEFINE_KEYCODE(CALL),
48      DEFINE_KEYCODE(ENDCALL),
49      DEFINE_KEYCODE(0),
50      DEFINE_KEYCODE(1),
51      DEFINE_KEYCODE(2),
52      DEFINE_KEYCODE(3),
53      DEFINE_KEYCODE(4),
54      DEFINE_KEYCODE(5),
55      DEFINE_KEYCODE(6),
56      DEFINE_KEYCODE(7),
57      DEFINE_KEYCODE(8),
58      DEFINE_KEYCODE(9),
59      DEFINE_KEYCODE(STAR),
60      DEFINE_KEYCODE(POUND),
61      DEFINE_KEYCODE(DPAD_UP),
62      DEFINE_KEYCODE(DPAD_DOWN),
63      DEFINE_KEYCODE(DPAD_LEFT),
64      DEFINE_KEYCODE(DPAD_RIGHT),
65      DEFINE_KEYCODE(DPAD_CENTER),
66      DEFINE_KEYCODE(VOLUME_UP),
67      DEFINE_KEYCODE(VOLUME_DOWN),
68      DEFINE_KEYCODE(POWER),
69      DEFINE_KEYCODE(CAMERA),
70      DEFINE_KEYCODE(CLEAR),......

DEFINE_KEYCODE这个宏定义作用是将传进去的键名称拼接为AKEYCODE_XXX,比如我们传一个POWER进去得到的就是{ “POWER”, AKEYCODE_POWER }

而AKEYCODE_POWER,我们全局搜索一下,可以发现定义在
/frameworks/native/include/android/keycodes.h

51  /**
52   * Key codes.
53   */
54  enum {55      /** Unknown key code. */
56      AKEYCODE_UNKNOWN         = 0,
57      /** Soft Left key.
58       * Usually situated below the display on phones and used as a multi-function
59       * feature key for selecting a software defined function shown on the bottom left
60       * of the display. */
61      AKEYCODE_SOFT_LEFT       = 1,
62      /** Soft Right key.
63       * Usually situated below the display on phones and used as a multi-function
64       * feature key for selecting a software defined function shown on the bottom right
65       * of the display. */
66      AKEYCODE_SOFT_RIGHT      = 2,
67      /** Home key.
68       * This key is handled by the framework and is never delivered to applications. */
69      AKEYCODE_HOME            = 3,
70      /** Back key. */
71      AKEYCODE_BACK            = 4,
72      /** Call key. */
73      AKEYCODE_CALL            = 5,
74      /** End Call key. */
75      AKEYCODE_ENDCALL         = 6,
76      /** '0' key. */
77      AKEYCODE_0               = 7,
78      /** '1' key. */
79      AKEYCODE_1               = 8,
80      /** '2' key. */
81      AKEYCODE_2               = 9,
82      /** '3' key. */
83      AKEYCODE_3               = 10,
84      /** '4' key. */
85      AKEYCODE_4               = 11,
86      /** '5' key. */
87      AKEYCODE_5               = 12,
88      /** '6' key. */
89      AKEYCODE_6               = 13,
90      /** '7' key. */
91      AKEYCODE_7               = 14,
92      /** '8' key. */
93      AKEYCODE_8               = 15,
94      /** '9' key. */
95      AKEYCODE_9               = 16,
96      /** '*' key. */
97      AKEYCODE_STAR            = 17,
98      /** '#' key. */
99      AKEYCODE_POUND           = 18,
100      /** Directional Pad Up key.
101       * May also be synthesized from trackball motions. */
102      AKEYCODE_DPAD_UP         = 19,
103      /** Directional Pad Down key.
104       * May also be synthesized from trackball motions. */
105      AKEYCODE_DPAD_DOWN       = 20,
106      /** Directional Pad Left key.
107       * May also be synthesized from trackball motions. */
108      AKEYCODE_DPAD_LEFT       = 21,
109      /** Directional Pad Right key.
110       * May also be synthesized from trackball motions. */
111      AKEYCODE_DPAD_RIGHT      = 22,
112      /** Directional Pad Center key.
113       * May also be synthesized from trackball motions. */
114      AKEYCODE_DPAD_CENTER     = 23,
115      /** Volume Up key.
116       * Adjusts the speaker volume up. */
117      AKEYCODE_VOLUME_UP       = 24,
118      /** Volume Down key.
119       * Adjusts the speaker volume down. */
120      AKEYCODE_VOLUME_DOWN     = 25,
121      /** Power key. */
122      AKEYCODE_POWER           = 26,......}

并且在java层也是用的映射的keycode,这都是和native层一致的
frameworks/base/core/java/android/view/KeyEvent.java

88  public class KeyEvent extends InputEvent implements Parcelable {89      /** Key code constant: Unknown key code. */
90      public static final int KEYCODE_UNKNOWN         = 0;
91      /** Key code constant: Soft Left key.
92       * Usually situated below the display on phones and used as a multi-function
93       * feature key for selecting a software defined function shown on the bottom left
94       * of the display. */
95      public static final int KEYCODE_SOFT_LEFT       = 1;
96      /** Key code constant: Soft Right key.
97       * Usually situated below the display on phones and used as a multi-function
98       * feature key for selecting a software defined function shown on the bottom right
99       * of the display. */
100      public static final int KEYCODE_SOFT_RIGHT      = 2;
101      /** Key code constant: Home key.
102       * This key is handled by the framework and is never delivered to applications. */
103      public static final int KEYCODE_HOME            = 3;
104      /** Key code constant: Back key. */
105      public static final int KEYCODE_BACK            = 4;
106      /** Key code constant: Call key. */
107      public static final int KEYCODE_CALL            = 5;
108      /** Key code constant: End Call key. */
109      public static final int KEYCODE_ENDCALL         = 6;
110      /** Key code constant: '0' key. */
111      public static final int KEYCODE_0               = 7;
112      /** Key code constant: '1' key. */
113      public static final int KEYCODE_1               = 8;
114      /** Key code constant: '2' key. */
115      public static final int KEYCODE_2               = 9;
116      /** Key code constant: '3' key. */
117      public static final int KEYCODE_3               = 10;
118      /** Key code constant: '4' key. */
119      public static final int KEYCODE_4               = 11;
120      /** Key code constant: '5' key. */
121      public static final int KEYCODE_5               = 12;
122      /** Key code constant: '6' key. */
123      public static final int KEYCODE_6               = 13;
124      /** Key code constant: '7' key. */
125      public static final int KEYCODE_7               = 14;
126      /** Key code constant: '8' key. */
127      public static final int KEYCODE_8               = 15;
128      /** Key code constant: '9' key. */
129      public static final int KEYCODE_9               = 16;
130      /** Key code constant: '*' key. */
131      public static final int KEYCODE_STAR            = 17;
132      /** Key code constant: '#' key. */
133      public static final int KEYCODE_POUND           = 18;
134      /** Key code constant: Directional Pad Up key.
135       * May also be synthesized from trackball motions. */
136      public static final int KEYCODE_DPAD_UP         = 19;
137      /** Key code constant: Directional Pad Down key.
138       * May also be synthesized from trackball motions. */
139      public static final int KEYCODE_DPAD_DOWN       = 20;
140      /** Key code constant: Directional Pad Left key.
141       * May also be synthesized from trackball motions. */
142      public static final int KEYCODE_DPAD_LEFT       = 21;
143      /** Key code constant: Directional Pad Right key.
144       * May also be synthesized from trackball motions. */
145      public static final int KEYCODE_DPAD_RIGHT      = 22;
146      /** Key code constant: Directional Pad Center key.
147       * May also be synthesized from trackball motions. */
148      public static final int KEYCODE_DPAD_CENTER     = 23;
149      /** Key code constant: Volume Up key.
150       * Adjusts the speaker volume up. */
151      public static final int KEYCODE_VOLUME_UP       = 24;
152      /** Key code constant: Volume Down key.
153       * Adjusts the speaker volume down. */
154      public static final int KEYCODE_VOLUME_DOWN     = 25;
155      /** Key code constant: Power key. */
156      public static final int KEYCODE_POWER           = 26;......
}

到这里scancode与keycode的映射就创建完成,
用一个实际例子来总结一下映射关系

Tokyo_TF:/ $ getevent
add device 1: /dev/input/event3name:     "mtk-tpd"
add device 2: /dev/input/event0name:     "ACCDET"
add device 3: /dev/input/event1name:     "mtk-kpd"
add device 4: /dev/input/event2name:     "fts_ts"
/dev/input/event1: 0001 0074 00000001
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0001 0074 00000000
/dev/input/event1: 0000 0000 00000000
Tokyo_TF:/ $ cat system/usr/keylayout/mtk-kpd.kl |grep -i POWER
key 116   POWER

16进制74对应10进制116,按键名称POWER,经过scancode到keycode的映射,POWER事件传到native层变为了AKEYCODE_POWER,到java层变为了KEYCODE_POWER,keycode都一样等于26,到此底层对上层事件的映射就已经完成,之后会接着InputReader读取设备事件,分析InputDispatcher是如何将事件给到应用窗口的。

Scancode到Keycode的映射相关推荐

  1. android修改默认遥控器键值,android 中遥控器键值的添加和修改

    前言:TV 上遥控器键值怎么样对应到android的系统中,最近一个客户需要在我们的平台上修改,所以,我顺便做了一下总结,方便以后参考. 请转载的朋友一定加上出处,十分感谢~~ 第一步: init.r ...

  2. android 按键映射文件,《android 的按键映射表》.doc

    <android 的按键映射表>.doc Keymaps and Keyboard Input This document describes how keyboard input get ...

  3. java scan map_键盘键位(Scancode Map)详细介绍

    键位的Scancode Map介绍(英文): http://download.microsoft.com/download/whistler/hwdev3/1.0/WXP/EN-US/scancode ...

  4. android touch screen keyboard input移植记录

    android touch screen keyboard input移植记录  仅仅是作为记录: Andorid 的 touchscreen 事件必须要有  BTN_TOUCH 才可以. 所以初始化 ...

  5. [arm 驱动]Linux输入子系统分析

    首先说明一下,本文是基于Linux-2.6.38版本内核来分析Linux输入子系统架构和原理的.这阵子本来没有打算花时间来分析Linux input system的,然而当在研究S3C6410触摸屏驱 ...

  6. Input调用流程(好文)

    原址 先介绍一下每个模块的工作职责:EventHub, InputReader, InputManager... 1 模块功能 1.1 EventHub 它是系统中所有事件的中央处理站.它管理所有系统 ...

  7. android获取按键键值,android中按键的扫描码和键值

    kernel中的按键驱动通过input子系统上报的键值叫做扫描码(ScanCode),对应头文件在 kernel/include/uapi/linux/input.h andorid中的用到的按键才叫 ...

  8. 按键,触摸屏流程分析

    按键触摸屏流程分析: WindowManagerService类的构造函数 WindowManagerService()   mQueue = new KeyQ(); 因为 WindowManager ...

  9. android 4.4 按键分析三

    .5         Android Framework层消息处理 3.5.1         基本介绍 关于Android消息处理机制的全面分析,可参考另外的文档,这里着重介绍事件处理相关问题,作为 ...

最新文章

  1. 010 并发的三个特性
  2. JQuery EasyUI学习框架
  3. python经典好书-7本有关Python的经典好书推荐,适合各类人群
  4. Oracle数据库之集合运算
  5. 造成内存泄漏_如何造成内存泄漏
  6. 黔南民族师范学院计算机与信息学院,黔南民族师范学院
  7. 必看!程序员逃生指南!
  8. 华为中级编程题目python_华为研发工程师编程题2019(python3)
  9. Android Studio如何去除界面默认标题栏
  10. 在linux本地下载ftp中的文件
  11. org.apache.commons.fileupload.DiskFileUpload1
  12. 框架设计--第八章 动态SQL--习题答案
  13. 【数学】求导公式+积分公式
  14. Java应用中CPU使用率过高该怎么解决
  15. 基于ArcGIS JS API实现的两种距离和面积测量方式
  16. 甜心奶酪用英文怎么说_您组织中没有人会碰到什么奶酪,更不用说动弹了?
  17. [毅周总结]数据结构(1)
  18. pip使用豆瓣源进行安装下载
  19. 2019.01.17【BZOJ4399】 魔法少女LJJ(FHQ_treap)(ODT)
  20. OpenGL4.0学习5.1--纹理(Targa图片贴图)

热门文章

  1. RuntimeError: CUDA error: no kernel image is available for execution on the driver
  2. Linux Power supply子系统分析之一
  3. 使用Proxmox搭建私有云平台
  4. Baidu Apollo代码解析之Planning的结构与调用流程(1)
  5. 博客与计算机相关的内容无法进行查看,博客检索的关键技术研究-计算机科学与技术专业论文.docx...
  6. Centos7 下mysql8.0的安装以及修改初始密码;
  7. html 微信登陆,登录包含微信登录.html
  8. 上海市政府颁布《上海市居住证申办实施细则》
  9. 游戏开发——孤岛算法实现SLG游戏大世界多类型地表边缘拼接效果
  10. 文本PDG文件名构成