版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Chromium網(wǎng)頁(yè)輸入事件捕捉和手勢(shì)檢測(cè)過(guò)程分析連續(xù)的輸入事件可能會(huì)產(chǎn)生一定的手勢(shì)操作,例如滑動(dòng)手勢(shì)和捏合手勢(shì)。在Chromium中,網(wǎng)頁(yè)的輸入事件是在Browser進(jìn)程中捕捉的。Browser進(jìn)程捕獲輸入事件之后,會(huì)進(jìn)行手勢(shì)操作檢測(cè)。檢測(cè)出來(lái)的手勢(shì)操作將會(huì)發(fā)送給Render進(jìn)程處理,因?yàn)樗鼈冃枰獞?yīng)用在網(wǎng)頁(yè)之上。與此同時(shí),Browser進(jìn)程也會(huì)將原始的輸入事件發(fā)送給Render進(jìn)程處理。本文接下來(lái)就分析Browser進(jìn)程處理網(wǎng)頁(yè)輸入事件的過(guò)程。接下來(lái)我們將以Chromium自帶的Content Shell APK為例,說(shuō)明Chromium的Browser進(jìn)程捕獲網(wǎng)頁(yè)輸入事件以及檢測(cè)手勢(shì)操作的
2、過(guò)程,如圖1所示:從前面文章中一文可以知道,Content Shell APK將網(wǎng)頁(yè)渲染在一個(gè)SurfaceView控件上。這個(gè)SurfaceView又是嵌入在一個(gè)ContentView控件里面的。當(dāng)用戶在網(wǎng)頁(yè)上觸發(fā)了一個(gè)輸入事件時(shí),例如觸發(fā)一個(gè)Touch事件時(shí),這個(gè)Touch事件就會(huì)被系統(tǒng)分發(fā)給上述ContentView控件處理,表現(xiàn)為該ContentView控件的成員函數(shù)onTouchEvent被調(diào)用。 ContentView控件得到Touch事件之后,會(huì)將它傳遞到Chromium的C+層去處理。Java層的每一個(gè)ContentView控件在C+層都對(duì)應(yīng)一個(gè)ContentViewCore對(duì)
3、象。C+層的ContentViewCore對(duì)象得到Touch事件之后,就會(huì)通過(guò)一個(gè)Gesture Dector和一個(gè)Scale Gesture Detector進(jìn)行滑動(dòng)(Scroll)和捏合(Pinch)手勢(shì)檢測(cè)。檢測(cè)出來(lái)的滑動(dòng)和捏合手勢(shì)將會(huì)統(tǒng)一保存在一個(gè)Gestrue Packet中。這個(gè)Gestrue Packet接下來(lái)會(huì)被一個(gè)Input Router封裝在一個(gè)類型為InputMsg_HandleInputEvent的IPC消息中,發(fā)送給Render進(jìn)程處理。 注意,Touch事件經(jīng)過(guò)手勢(shì)檢測(cè)之后,它本身也會(huì)被上述Input Router通過(guò)另外一個(gè)InputMsg_HandleInput
4、Event消息發(fā)送給Render進(jìn)程處理。這意味著在這種情況下,Render進(jìn)程將收到兩個(gè)InputMsg_HandleInputEvent消息。 接下來(lái),我們就從ContentView類的成員函數(shù)onTouchEvent開(kāi)始,分析Browser進(jìn)程處理網(wǎng)頁(yè)輸入事件的過(guò)程,如下所示:java view plain copypublic class ContentView extends FrameLayout implements ContentViewCore.InternalAccessDelegate, SmartClipProvider . Override public boolea
5、n onTouchEvent(MotionEvent event) return mContentViewCore.onTouchEvent(event); . 這個(gè)函數(shù)定義在文件external/chromium_org/content/public/Android/java/src/org/chromium/content/browser/ContentView.java中。 參數(shù)event指向的MotionEvent對(duì)象描述的就是當(dāng)前發(fā)生的Touch事件。ContentView類的成員變量mContentViewCore指向的是一個(gè)ContentViewCore對(duì)象,ContentVie
6、w類的成員函數(shù)onTouchEvent調(diào)用這個(gè)ContentViewCore對(duì)象的成員函數(shù)onTouchEvent處理參數(shù)event所描述的Touch事件。 ContentViewCore類的成員函數(shù)onTouchEvent的實(shí)現(xiàn)如下所示:java view plain copypublic class ContentViewCore implements NavigationClient, AccessibilityStateChangeListener, ScreenOrientationObserver . public boolean onTouchEvent(MotionEvent
7、event) TraceEvent.begin("onTouchEvent"); try . final int pointerCount = event.getPointerCount(); final boolean consumed = nativeOnTouchEvent(mNativeContentViewCore, event, event.getEventTime(), eventAction, pointerCount, event.getHistorySize(), event.getActionIndex(), event.getX(), event.g
8、etY(), pointerCount > 1 ? event.getX(1) : 0, pointerCount > 1 ? event.getY(1) : 0, event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1, event.getTouchMajor(), pointerCount > 1 ? event.getTouchMajor(1) : 0, event.getRawX(), event.getRawY(), event.getToolType(0), pointerCo
9、unt > 1 ? event.getToolType(1) : MotionEvent.TOOL_TYPE_UNKNOWN, event.getButtonState(); . return consumed; finally TraceEvent.end("onTouchEvent"); . 這個(gè)函數(shù)定義在文件external/chromium_org/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java中。 ContentViewCore類的成員函數(shù)on
10、TouchEvent主要是調(diào)用另外一個(gè)成員函數(shù)nativeOnTouchEvent處理參數(shù)event描述的Touch事件。 ContentViewCore類的成員函數(shù)nativeOnTouchEvent是一個(gè)JNI函數(shù),它由C+層的函數(shù)Java_com_android_org_chromium_content_browser_ContentViewCore_nativeOnTouchEvent實(shí)現(xiàn),如下所示:cpp view plain copy_attribute_(visibility("default") jboolean Java_com_android_org_c
11、hromium_content_browser_ContentViewCore_nativeOnTouchEvent(JNIEnv* env, jobject jcaller, jlong nativeContentViewCoreImpl, jobject event, jlong timeMs, jint action, jint pointerCount, jint historySize, jint actionIndex, jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint pointerId0, jint pointerId1, jfl
12、oat touchMajor0, jfloat touchMajor1, jfloat rawX, jfloat rawY, jint androidToolType0, jint androidToolType1, jint androidButtonState) ContentViewCoreImpl* native = reinterpret_cast<ContentViewCoreImpl*>(nativeContentViewCoreImpl); CHECK_NATIVE_PTR(env, jcaller, native, "OnTouchEvent"
13、, false); return native->OnTouchEvent(env, jcaller, event, timeMs, action, pointerCount, historySize, actionIndex, x0, y0, x1, y1, pointerId0, pointerId1, touchMajor0, touchMajor1, rawX, rawY, androidToolType0, androidToolType1, androidButtonState); 這個(gè)函數(shù)定義在文件out/target/product/generic/obj/GYP/sha
14、red_intermediates/content/jni/ContentViewCore_jni.h中。 參數(shù)nativeContentViewCoreImpl描述的是C+層的一個(gè)ContentViewCoreImpl對(duì)象,函數(shù)Java_com_android_org_chromium_content_browser_ContentViewCore_nativeOnTouchEvent調(diào)用這個(gè)ContentViewCoreImpl對(duì)象的成員函數(shù)OnTouchEvent處理其它參數(shù)所描述的Touch事件。 ContentViewCoreImpl類的成員函數(shù)OnTouchEvent的實(shí)現(xiàn)如下所示
15、:cpp view plain copyjboolean ContentViewCoreImpl:OnTouchEvent(JNIEnv* env, jobject obj, jobject motion_event, jlong time_ms, jint android_action, jint pointer_count, jint history_size, jint action_index, jfloat pos_x_0, jfloat pos_y_0, jfloat pos_x_1, jfloat pos_y_1, jint pointer_id_0, jint pointer_
16、id_1, jfloat touch_major_0, jfloat touch_major_1, jfloat raw_pos_x, jfloat raw_pos_y, jint android_tool_type_0, jint android_tool_type_1, jint android_button_state) RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid(); . MotionEventAndroid event(1.f / dpi_scale(), env, motion_event,
17、time_ms, android_action, pointer_count, history_size, action_index, pos_x_0, pos_y_0, pos_x_1, pos_y_1, pointer_id_0, pointer_id_1, touch_major_0, touch_major_1, raw_pos_x, raw_pos_y, android_tool_type_0, android_tool_type_1, android_button_state); return rwhv->OnTouchEvent(event); 這個(gè)函數(shù)定義在文件exter
18、nal/chromium_org/content/browser/android/content_view_core_impl.cc中。 ContentViewCoreImpl類的成員函數(shù)OnTouchEvent首先調(diào)用成員函數(shù)GetRenderWidgetHostViewAndroid獲得一個(gè)RenderWidgetHostViewAndroid對(duì)象。這個(gè)RenderWidgetHostViewAndroid對(duì)象用來(lái)在C+層描述加載網(wǎng)頁(yè)的控件,它的創(chuàng)建過(guò)程可以參考前面文章中一文。 ContentViewCoreImpl類的成員函數(shù)OnTouchEvent接下來(lái)又將參數(shù)描述的Touch事件封裝
19、在一個(gè)MotionEventAndroid對(duì)象中,然后將該MotionEventAndroid對(duì)象傳遞給前面獲得的RenderWidgetHostViewAndroid對(duì)象的成員函數(shù)OnTouchEvent處理。 RenderWidgetHostViewAndroid對(duì)象的成員函數(shù)OnTouchEvent的實(shí)現(xiàn)如下所示:cpp view plain copybool RenderWidgetHostViewAndroid:OnTouchEvent( const ui:MotionEvent& event) . if (!gesture_provider_.OnTouchEvent(ev
20、ent) return false; . / Short-circuit touch forwarding if no touch handlers exist. if (!host_->ShouldForwardTouchEvent() const bool event_consumed = false; gesture_provider_.OnTouchEventAck(event_consumed); return true; SendTouchEvent(CreateWebTouchEventFromMotionEvent(event); return true; 這個(gè)函數(shù)定義在
21、文件external/chromium_org/content/browser/renderer_host/render_widget_host_view_android.cc中。 RenderWidgetHostViewAndroid類的成員變量gesture_provider_描述的是一個(gè)FilteredGestureProvider對(duì)象。RenderWidgetHostViewAndroid類的成員函數(shù)OnTouchEvent首先調(diào)用這個(gè)FilteredGestureProvider對(duì)象的成員函數(shù)OnTouchEvent檢測(cè)參數(shù)event描述的Touch事件是否產(chǎn)生了手勢(shì)操作。如果有發(fā)生
22、,那么就會(huì)將它們發(fā)送給Render進(jìn)程處理。 RenderWidgetHostViewAndroid類的成員變量host_指向的是一個(gè)RenderWidgetHostImpl對(duì)象。這個(gè)RenderWidgetHostImpl對(duì)象也是用來(lái)在C+層描述加載網(wǎng)頁(yè)的控件的,它的創(chuàng)建過(guò)程可以參考前面文章中一文。RenderWidgetHostViewAndroid類的成員函數(shù)OnTouchEvent接下來(lái)調(diào)用這個(gè)RenderWidgetHostImpl對(duì)象的成員函數(shù)ShouldForwardTouchEvent檢查Render進(jìn)程是否注冊(cè)了處理Touch事件的Handler。如果沒(méi)有注冊(cè)的話,那么就不需
23、要將參數(shù)event描述的Touch事件發(fā)送給它處理了。 我們假設(shè)Render進(jìn)程注冊(cè)了處理Touch事件的Handler。在這種情況下,RenderWidgetHostViewAndroid類的成員函數(shù)OnTouchEvent就會(huì)調(diào)用函數(shù)CreateWebTouchEventFromMotionEvent將參數(shù)event描述的Touch事件封裝成一個(gè)blink:WebTouchEvent對(duì)象,并且調(diào)用另外一個(gè)成員函數(shù)SendTouchEvent將該blink:WebTouchEvent對(duì)象發(fā)送給Render進(jìn)程處理。注意,這個(gè)blink:WebTouchEvent對(duì)象描述的是原始的Touch事
24、件,它不是一個(gè)手勢(shì)操作。 接下來(lái),我們先分析FilteredGestureProvider類的成員函數(shù)OnTouchEvent檢測(cè)手勢(shì)操作的過(guò)程,接著再分析函數(shù)CreateWebTouchEventFromMotionEvent創(chuàng)建blink:WebTouchEvent對(duì)象的過(guò)程,以及RenderWidgetHostViewAndroid類的成員函數(shù)SendTouchEvent向Render進(jìn)程發(fā)送Touch事件的過(guò)程。 FilteredGestureProvider類的成員函數(shù)OnTouchEvent的實(shí)現(xiàn)如下所示:cpp view plain copybool FilteredGestur
25、eProvider:OnTouchEvent(const MotionEvent& event) DCHECK(!handling_event_); base:AutoReset<bool> handling_event(&handling_event_, true); pending_gesture_packet_ = GestureEventDataPacket:FromTouch(event); if (!gesture_provider_.OnTouchEvent(event) return false; TouchDispositionGestureFil
26、ter:PacketResult result = gesture_filter_.OnGesturePacket(pending_gesture_packet_); if (result != TouchDispositionGestureFilter:SUCCESS) NOTREACHED() << "Invalid touch gesture sequence detected." return false; return true; 這個(gè)函數(shù)定義在文件external/chromium_org/ui/events/gesture_detection/fi
27、ltered_gesture_provider.cc中。 FilteredGestureProvider類的成員函數(shù)OnTouchEvent首先將成員變量handling_event_的值設(shè)置為true,表示當(dāng)前正處于收集手勢(shì)操作的過(guò)程中,不要將正在收集的手勢(shì)操作發(fā)送給Render進(jìn)程處理,而是等到全部收集完畢再一起發(fā)送給Render進(jìn)程處理。注意,當(dāng)FilteredGestureProvider類的成員函數(shù)OnTouchEvent的調(diào)用結(jié)束后,F(xiàn)ilteredGestureProvider類的成員變量handling_event的值將自動(dòng)恢復(fù)為false。 FilteredGesturePr
28、ovider類的成員函數(shù)OnTouchEvent接下來(lái)調(diào)用GestureEventDataPacket類的靜態(tài)成員函數(shù)FromTouch創(chuàng)建一個(gè)用來(lái)保存手勢(shì)操作的Gesture Event Data Packet,如下所示:cpp view plain copyGestureEventDataPacket GestureEventDataPacket:FromTouch( const ui:MotionEvent& touch) return GestureEventDataPacket(touch.GetEventTime(), ToGestureSource(touch), gfx
29、:PointF(touch.GetX(), touch.GetY(), gfx:PointF(touch.GetRawX(), touch.GetRawY(); 這個(gè)函數(shù)定義在文件external/chromium_org/ui/events/gesture_detection/gesture_event_data_packet.cc中。 GestureEventDataPacket類的靜態(tài)成員函數(shù)FromTouch首先調(diào)用函數(shù)ToGestureSource獲得接下來(lái)要?jiǎng)?chuàng)建的Gesture Event Data Packet的類型,接著創(chuàng)建一個(gè)該類型的Gesture Event Data Pa
30、cket返回給調(diào)用者。 函數(shù)ToGestureSource的實(shí)現(xiàn)如下所示:cpp view plain copyGestureEventDataPacket:GestureSource ToGestureSource( const ui:MotionEvent& event) switch (event.GetAction() case ui:MotionEvent:ACTION_DOWN: return GestureEventDataPacket:TOUCH_SEQUENCE_START; case ui:MotionEvent:ACTION_UP: return GestureE
31、ventDataPacket:TOUCH_SEQUENCE_END; case ui:MotionEvent:ACTION_MOVE: return GestureEventDataPacket:TOUCH_MOVE; case ui:MotionEvent:ACTION_CANCEL: return GestureEventDataPacket:TOUCH_SEQUENCE_CANCEL; case ui:MotionEvent:ACTION_POINTER_DOWN: return GestureEventDataPacket:TOUCH_START; case ui:MotionEven
32、t:ACTION_POINTER_UP: return GestureEventDataPacket:TOUCH_END; ; NOTREACHED() << "Invalid ui:MotionEvent action: " << event.GetAction(); return GestureEventDataPacket:INVALID; 這個(gè)函數(shù)定義在文件external/chromium_org/ui/events/gesture_detection/gesture_event_data_packet.cc中。 函數(shù)ToGestureSo
33、urce返回的Gesture Event Data Packet的類型與參數(shù)evnet描述的Touch事件的類型有關(guān)。例如,假設(shè)event描述的是一個(gè)ACTION_MOVE類型的Touch事件,那么函數(shù)ToGestureSource返回的Gesture Event Data Packet的類型就為GestureEventDataPacket:TOUCH_MOVE。 在接下來(lái)的分析中,我們就假設(shè)當(dāng)前要處理的是一個(gè)ACTION_MOVE類型的Touch事件,這意味著FilteredGestureProvider類的成員函數(shù)OnTouchEvent調(diào)用GestureEventDataPacket類的
34、靜態(tài)成員函數(shù)FromTouch獲得的是一個(gè)類型為GestureEventDataPacket:TOUCH_MOVE的Gesture Event Data Packet。這個(gè)Gesture Event Data Packet保存在FilteredGestureProvider類的成員變量pending_gesture_packet_中。 回到FilteredGestureProvider類的成員函數(shù)OnTouchEvent中,它接下來(lái)調(diào)用成員變量gesture_provider_描述的一個(gè)GestureProvider對(duì)象的成員函數(shù)OnTouchEvent檢查參數(shù)event描述的Touch事件是
35、否產(chǎn)生了手勢(shì)操作。如果產(chǎn)生了,那么就會(huì)將它們保存在成員變量pending_gesture_packet_描述的Gesture Event Data Packet中。 FilteredGestureProvider類的成員變量gesture_filter_描述的是一個(gè)TouchDispositionGestureFilter對(duì)象,F(xiàn)ilteredGestureProvider類的成員函數(shù)OnTouchEvent最后調(diào)用這個(gè)TouchDispositionGestureFilter對(duì)象的成員函數(shù)OnGesturePacket將成員變量pending_gesture_packet_描述的Gestur
36、e Event Data Packet發(fā)送給Render進(jìn)程處理,也就是將前面檢測(cè)到的手勢(shì)操作發(fā)送給Render進(jìn)程處理。 接下來(lái),我們先分析GestureProvider對(duì)象的成員函數(shù)OnTouchEvent檢測(cè)手勢(shì)操作的過(guò)程,接下來(lái)再分析TouchDispositionGestureFilter類的成員函數(shù)OnGesturePacket發(fā)送手勢(shì)操作給Render進(jìn)程的過(guò)程。 GestureProvider類的成員函數(shù)OnTouchEvent的實(shí)現(xiàn)如下所示:cpp view plain copybool GestureProvider:OnTouchEvent(const MotionEve
37、nt& event) . gesture_listener_->OnTouchEvent(event, in_scale_gesture); scale_gesture_listener_->OnTouchEvent(event); . return true; 這個(gè)函數(shù)定義在文件external/chromium_org/ui/events/gesture_detection/gesture_provider.cc中。 GestureProvider類的成員變量gesture_listener_指向的是一個(gè)GestureListenerImpl對(duì)象。這個(gè)GestureLi
38、stenerImpl對(duì)象負(fù)責(zé)檢測(cè)參數(shù)event描述的Touch事件是否產(chǎn)生滑動(dòng)手勢(shì)操作。這是通過(guò)調(diào)用它的成員函數(shù)OnTouchEvent實(shí)現(xiàn)的。 GestureProvider類的成員變量scale_gesture_listener_指向的是一個(gè)ScaleGestureListenerImpl對(duì)象。這個(gè)ScaleGestureListenerImpl對(duì)象負(fù)責(zé)檢測(cè)參數(shù)event描述的Touch事件是否產(chǎn)生捏合手勢(shì)操作。這是通過(guò)調(diào)用它的成員函數(shù)OnTouchEvent實(shí)現(xiàn)的。 接下來(lái),我們就分別分析GestureListenerImpl類和ScaleGestureListenerImpl類的成員函
39、數(shù)OnTouchEvent的實(shí)現(xiàn),以便了解滑動(dòng)和捏合手勢(shì)操作的檢測(cè)過(guò)程。 GestureListenerImpl類的成員函數(shù)OnTouchEvent的實(shí)現(xiàn)如下所示:cpp view plain copyclass GestureProvider:GestureListenerImpl : public GestureDetector:GestureListener, public GestureDetector:DoubleTapListener public: . bool OnTouchEvent(const MotionEvent& e, bool is_scale_gestur
40、e_detection_in_progress) . return gesture_detector_.OnTouchEvent(e); private: . GestureDetector gesture_detector_; . ; 這個(gè)函數(shù)定義在文件external/chromium_org/ui/events/gesture_detection/gesture_provider.cc中。 GestureListenerImpl類的成員函數(shù)OnTouchEvent通過(guò)調(diào)用成員變量gesture_detector_描述的一個(gè)GestureDetector對(duì)象的成員函數(shù)OnTouchEven
41、t檢測(cè)測(cè)參數(shù)e描述的Touch事件是否產(chǎn)生了滑動(dòng)手勢(shì)操作。 GestureDetector類的成員函數(shù)OnTouchEvent的實(shí)現(xiàn)如下所示:cpp view plain copybool GestureDetector:OnTouchEvent(const MotionEvent& ev) const MotionEvent:Action action = ev.GetAction(); . const bool pointer_up = action = MotionEvent:ACTION_POINTER_UP; const int skip_index = pointer_up
42、 ? ev.GetActionIndex() : -1; / Determine focal point. float sum_x = 0, sum_y = 0; const int count = static_cast<int>(ev.GetPointerCount(); for (int i = 0; i < count; i+) if (skip_index = i) continue; sum_x += ev.GetX(i); sum_y += ev.GetY(i); const int div = pointer_up ? count - 1 : count; c
43、onst float focus_x = sum_x / div; const float focus_y = sum_y / div; bool handled = false; switch (action) . case MotionEvent:ACTION_MOVE: const float scroll_x = last_focus_x_ - focus_x; const float scroll_y = last_focus_y_ - focus_y; if (is_double_tapping_) / Give the move events of the double-tap.
44、 DCHECK(double_tap_listener_); handled |= double_tap_listener_->OnDoubleTapEvent(ev); else if (always_in_tap_region_) const float delta_x = focus_x - down_focus_x_; const float delta_y = focus_y - down_focus_y_; const float distance_square = delta_x * delta_x + delta_y * delta_y; if (distance_squ
45、are > touch_slop_square_) handled = listener_->OnScroll( *current_down_event_, ev, scroll_x, scroll_y); last_focus_x_ = focus_x; last_focus_y_ = focus_y; always_in_tap_region_ = false; . . else if (std:abs(scroll_x) > kScrollEpsilon | std:abs(scroll_y) > kScrollEpsilon) handled = listene
46、r_->OnScroll(*current_down_event_, ev, scroll_x, scroll_y); last_focus_x_ = focus_x; last_focus_y_ = focus_y; . break; . return handled; 這個(gè)函數(shù)定義在文件external/chromium_org/ui/events/gesture_detection/gesture_detector.cc中。 前面我們假設(shè)參數(shù)ev描述的是一個(gè)ACTION_MOVE類型的Touch事件。GestureDetector類的成員函數(shù)OnTouchEvent首先會(huì)計(jì)算這個(gè)T
47、ouch事件的位置(focus_x, focus_y)。注意,這個(gè)Touch事件可能包含了多個(gè)觸摸點(diǎn),因此在計(jì)算它的位置時(shí),通過(guò)將所有的觸摸點(diǎn)進(jìn)行算術(shù)平均得到。 GestureDetector類的成員變量last_focus_x_和last_focus_y_記錄的是上一個(gè)類型為ACTION_MOVE的Touch事件的位置(last_focus_x_, last_focus_y_)。GestureDetector類的成員函數(shù)OnTouchEvent通過(guò)比較(last_focus_x_, last_focus_y_)和(focus_x, focus_y)的值,得到連續(xù)兩個(gè)類型為ACTION_MOVE的Touch事件在網(wǎng)頁(yè)的X軸和Y軸上所產(chǎn)生的滑動(dòng)量scroll_x和scroll_y。 GestureDetector類的成員變量is_double_tapping_是一個(gè)布爾變量。當(dāng)它的值等于true的時(shí)候,表示用戶在規(guī)定的時(shí)間和空間內(nèi)連續(xù)點(diǎn)擊了兩次網(wǎng)頁(yè)。這種情況稱為Double Ta
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年大學(xué)大一(思想政治教育)教育學(xué)原理階段測(cè)試試題及答案
- 2025-2026年小學(xué)三年級(jí)語(yǔ)文(篇章理解)上學(xué)期期中測(cè)試卷
- 2025年大學(xué)養(yǎng)老服務(wù)管理(管理研究實(shí)務(wù))試題及答案
- 中職第二學(xué)年(物流服務(wù)與管理)貨運(yùn)代理實(shí)務(wù)2026年綜合測(cè)試題及答案
- 2025年大學(xué)視覺(jué)傳達(dá)設(shè)計(jì)(平面設(shè)計(jì))試題及答案
- 2025門診個(gè)人年終總結(jié)報(bào)告
- 深度解析(2026)《GBT 17980.85-2004農(nóng)藥 田間藥效試驗(yàn)準(zhǔn)則(二) 第85部分殺菌劑防治花生葉斑病》
- 深度解析(2026)《GBT 17503-2009海上平臺(tái)場(chǎng)址工程地質(zhì)勘察規(guī)范》(2026年)深度解析
- 福建農(nóng)業(yè)職業(yè)技術(shù)學(xué)院《臨床免疫學(xué)及檢驗(yàn)》2025-2026學(xué)年第一學(xué)期期末試卷
- 齊齊哈爾大學(xué)《中國(guó)傳統(tǒng)城市設(shè)計(jì)理論與方法》2025-2026學(xué)年第一學(xué)期期末試卷
- 數(shù)控車零基礎(chǔ)培訓(xùn)
- 基于STM32智能語(yǔ)音臺(tái)燈設(shè)計(jì)
- 健康證的衛(wèi)生知識(shí)培訓(xùn)課件
- 小兒腎積水護(hù)理課件
- 2025年機(jī)械式停車設(shè)備司機(jī)證考試題庫(kù)及機(jī)械式停車設(shè)備司機(jī)試題及答案解析
- 2025年國(guó)家監(jiān)理考試題目及答案
- 足跟壓瘡護(hù)理
- 幼兒園暑期維修改造項(xiàng)目初步設(shè)計(jì)
- 2025年全國(guó)高校黃大年式教師團(tuán)隊(duì)申報(bào)表
- 印刷業(yè)法律法規(guī)實(shí)施與影響考核試卷
- 水庫(kù)竣工驗(yàn)收設(shè)計(jì)
評(píng)論
0/150
提交評(píng)論