日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Scancode到Keycode的映射

發(fā)布時(shí)間:2023/12/14 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Scancode到Keycode的映射 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前分析的InputReader讀取底層事件可以得知 InputReaderThead啟動(dòng)之后會(huì)通過(guò)mEventHub->getEvents讀取設(shè)備節(jié)點(diǎn)的所有事件,通過(guò)parsekey方法解析kl文件存入數(shù)據(jù)結(jié)構(gòu)map,在讀取節(jié)點(diǎn)事件之前先掃描設(shè)備,如果沒(méi)有打開(kāi)則打開(kāi)設(shè)備,在打開(kāi)設(shè)備時(shí)會(huì)將scancode和keycode一一映射,此篇文章記錄他們是如何建立映射關(guān)系的起來(lái)的
/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
掃描設(shè)備"/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/下的所有設(shè)備 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);//打開(kāi)設(shè)備 1926 openDeviceLocked(devname); 1927 } 1928 closedir(dir); 1929 return 0; 1930 }

打開(kāi)設(shè)備

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 }

繼續(xù)調(diào)到Device的keyMap的load函數(shù),Device是EventHub內(nèi)部的結(jié)構(gòu)體
/frameworks/native/services/inputflinger/EventHub.h

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

繼續(xù)看KeyMap的load函數(shù)
/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;//通過(guò)設(shè)備的配置文件去加載配置文件內(nèi)制定好的映射表 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.通過(guò)設(shè)備信息查找對(duì)應(yīng)的映射表 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 }

可以看到我這個(gè)設(shè)備有四個(gè)設(shè)備節(jié)點(diǎn),所以
mtk-tpd,ACCDET,fts_ts,mtk-kpd以及通用表都會(huì)解析的

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函數(shù)

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()函數(shù)

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 }

繼續(xù)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 }

繼續(xù)parser.parse(),開(kāi)始解析映射表

199 status_t KeyLayoutMap::Parser::parse() {//while循環(huán),一行一行地解析映射表項(xiàng) 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,
解析的規(guī)則如下:
keyword是"key",調(diào)用parseKey解析,如果解析出錯(cuò)則返回錯(cuò)誤
keyword是"axis",調(diào)用parseAxis解析,如果解析出錯(cuò)則返回錯(cuò)誤
keyword是"led",調(diào)用parseAxis解析,如果解析出錯(cuò)則返回錯(cuò)誤
如果還有其他不按規(guī)則的符號(hào)則返回BAD_VALUE

繼續(xù)parseKey()函數(shù)

242 status_t KeyLayoutMap::Parser::parseKey() { 243 ...... 256 //此函數(shù)解析得到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 }

打開(kāi)上面的log開(kāi)關(guān)得到如下輸出:scancode和keycode的映射終于得到了,繼續(xù)看函數(shù)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 }

調(diào)用了lookupValueByLabel函數(shù),我們來(lái)看 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這個(gè)宏定義作用是將傳進(jìn)去的鍵名稱拼接為AKEYCODE_XXX,比如我們傳一個(gè)POWER進(jìn)去得到的就是{ “POWER”, AKEYCODE_POWER }

而AKEYCODE_POWER,我們?nèi)炙阉饕幌?#xff0c;可以發(fā)現(xiàn)定義在
/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的映射就創(chuàng)建完成,
用一個(gè)實(shí)際例子來(lái)總結(jié)一下映射關(guān)系

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進(jìn)制74對(duì)應(yīng)10進(jìn)制116,按鍵名稱POWER,經(jīng)過(guò)scancode到keycode的映射,POWER事件傳到native層變?yōu)榱薃KEYCODE_POWER,到j(luò)ava層變?yōu)榱薑EYCODE_POWER,keycode都一樣等于26,到此底層對(duì)上層事件的映射就已經(jīng)完成,之后會(huì)接著InputReader讀取設(shè)備事件,分析InputDispatcher是如何將事件給到應(yīng)用窗口的。

總結(jié)

以上是生活随笔為你收集整理的Scancode到Keycode的映射的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。