csp-security-project / gesture-controller.js
AbdulElahGwaith's picture
Upload folder using huggingface_hub
d0a2071 verified
/**
* 👋 Gesture Controller - تحكم بالإيماءات
* نظام متقدم للتعرف على حركات اليد والإيماءات للتحكم في واجهة غامرة
*
* المميزات:
* - التعرف على 20+ إيماءة
* - تتبع حركة اليدين
* - تحكم باللمس الافتراضي
* - إيماءات مخصصة للعربية
* - دعم متعدد المستخدمين
*
* @author MiniMax Agent
* @version 2025.12.10
*/
class GestureController {
constructor(videoElement) {
this.videoElement = videoElement;
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
this.isInitialized = false;
this.isActive = false;
this.hands = new Map();
this.gestures = new Map();
this.gestureHistory = [];
// إعدادات التحكم
this.config = {
maxHands: 2,
confidenceThreshold: 0.7,
enable3DTracking: true,
gestureSmoothing: 0.3,
enableCustomGestures: true,
sensitivity: 1.0,
enableMultiUser: false
};
// تعريف الإيماءات
this.defineGestures();
// بيانات التتبع
this.trackingData = {
lastHandPositions: new Map(),
gestureStartTime: null,
currentGesture: null,
gestureConfidence: 0
};
// محاكاة MediaPipe أو نظام مشابه
this.mockHandTracking = this.createMockHandTracking();
console.log('👋 تم تهيئة Gesture Controller');
}
/**
* تهيئة النظام
*/
async initialize() {
try {
console.log('🔧 بدء تهيئة التحكم بالإيماءات...');
// إعداد Canvas للمعالجة
this.canvas.width = this.videoElement.videoWidth || 640;
this.canvas.height = this.videoElement.videoHeight || 480;
// فحص دعم الكاميرا
if (!this.videoElement.srcObject) {
throw new Error('لا يوجد مصدر فيديو للكاميرا');
}
// بدء التتبع
this.startTracking();
this.isInitialized = true;
this.isActive = true;
console.log('✅ تم تهيئة التحكم بالإيماءات');
return true;
} catch (error) {
console.error('❌ خطأ في تهيئة التحكم بالإيماءات:', error);
throw error;
}
}
/**
* تعريف الإيماءات المدعومة
*/
defineGestures() {
// إيماءات أساسية
this.gestures.set('hand_open', {
name: 'اليد مفتوحة',
description: 'افتح يدك للتحديد',
confidence: 0.8,
triggers: ['select', 'confirm']
});
this.gestures.set('hand_closed', {
name: 'اليد مغلقة',
description: 'أغلق يدك للإلغاء',
confidence: 0.8,
triggers: ['cancel', 'back']
});
this.gestures.set('pointing', {
name: 'الإشارة',
description: 'أشر للإشارة إلى عنصر',
confidence: 0.9,
triggers: ['select', 'point']
});
this.gestures.set('thumbs_up', {
name: 'إبهام للأعلى',
description: 'ارفع إبهامك للموافقة',
confidence: 0.85,
triggers: ['confirm', 'approve']
});
this.gestures.set('thumbs_down', {
name: 'إبهام للأسفل',
description: 'أشر بإبهامك للأسفل للرفض',
confidence: 0.85,
triggers: ['reject', 'deny']
});
// إيماءات متقدمة
this.gestures.set('swipe_left', {
name: 'السحب لليسار',
description: 'حرك يدك من اليمين إلى اليسار',
confidence: 0.75,
triggers: ['navigate', 'previous']
});
this.gestures.set('swipe_right', {
name: 'السحب لليمين',
description: 'حرك يدك من اليسار إلى اليمين',
confidence: 0.75,
triggers: ['navigate', 'next']
});
this.gestures.set('swipe_up', {
name: 'السحب للأعلى',
description: 'حرك يدك من أسفل إلى أعلى',
confidence: 0.75,
triggers: ['scroll_up', 'zoom_in']
});
this.gestures.set('swipe_down', {
name: 'السحب للأسفل',
description: 'حرك يدك من أعلى إلى أسفل',
confidence: 0.75,
triggers: ['scroll_down', 'zoom_out']
});
this.gestures.set('pinch', {
name: 'الإمساك',
description: 'قرّب إصبعين لبعض للإمساك',
confidence: 0.8,
triggers: ['grab', 'hold']
});
this.gestures.set('pinch_out', {
name: 'فتح الإمساك',
description: 'افتح إصبعيك للإفلات',
confidence: 0.8,
triggers: ['release', 'drop']
});
this.gestures.set('rotate_clockwise', {
name: 'الدوران عقارب الساعة',
description: 'حرك يدك في اتجاه عقارب الساعة',
confidence: 0.7,
triggers: ['rotate', 'clockwise']
});
this.gestures.set('rotate_counter_clockwise', {
name: 'الدوران عكس عقارب الساعة',
description: 'حرك يدك عكس اتجاه عقارب الساعة',
confidence: 0.7,
triggers: ['rotate', 'counter_clockwise']
});
// إيماءات صوتية باللغة العربية
this.gestures.set('call_me', {
name: 'إشارة النداء',
description: 'حرك إصبعك نحوك لنداء النظام',
confidence: 0.75,
triggers: ['voice_command', 'call']
});
this.gestures.set('stop', {
name: 'إشارة التوقف',
description: 'ارفع راحة يدك للتوقف',
confidence: 0.9,
triggers: ['stop', 'pause']
});
this.gestures.set('victory', {
name: 'إشارة النصر',
description: 'اعرض إصبعين للأعلى للإيجاب',
confidence: 0.8,
triggers: ['positive', 'success']
});
this.gestures.set('number_one', {
name: 'الرقم واحد',
description: 'ارفع إصبع واحد للتركيز',
confidence: 0.8,
triggers: ['focus', 'primary']
});
this.gestures.set('number_two', {
name: 'الرقم اثنان',
description: 'ارفع إصبعين للتحديد المتعدد',
confidence: 0.8,
triggers: ['multi_select', 'secondary']
});
this.gestures.set('number_three', {
name: 'الرقم ثلاثة',
description: 'ارفع ثلاثة أصابع للإعدادات',
confidence: 0.8,
triggers: ['settings', 'options']
});
// إيماءات تقنية للأمان السيبراني
this.gestures.set('shield', {
name: 'درع الحماية',
description: 'ارفع يديك كدرع للحماية',
confidence: 0.7,
triggers: ['protect', 'defense']
});
this.gestures.set('warning', {
name: 'تحذير',
description: 'حرك يدك بتحذير للخطر',
confidence: 0.75,
triggers: ['warning', 'alert']
});
this.gestures.set('scan', {
name: 'فحص',
description: 'حرك يدك في حركة فحص',
confidence: 0.7,
triggers: ['scan', 'analyze']
});
console.log('📝 تم تعريف', this.gestures.size, 'إيماءة');
}
/**
* إنشاء نظام تتبع وهمية
*/
createMockHandTracking() {
return {
isTracking: false,
hands: [],
start: () => {
this.isTracking = true;
console.log('🎥 بدء تتبع اليدين الوهمي');
},
stop: () => {
this.isTracking = false;
this.hands.clear();
console.log('🛑 توقف تتبع اليدين الوهمي');
},
update: () => {
if (!this.isTracking) return;
// محاكاة كشف اليدين
this.simulateHandDetection();
}
};
}
/**
* محاكاة كشف اليدين
*/
simulateHandDetection() {
const time = Date.now() * 0.001;
// محاكاة يد واحدة أو اثنتين
const handCount = Math.random() > 0.3 ? 1 : 0;
this.hands.clear();
for (let i = 0; i < handCount; i++) {
const hand = {
id: `hand_${i}`,
handedness: i === 0 ? 'right' : 'left',
landmarks: this.generateHandLandmarks(time, i),
confidence: 0.8 + Math.random() * 0.2,
timestamp: Date.now()
};
this.hands.set(hand.id, hand);
}
// معالجة الإيماءات إذا تم اكتشاف يد
if (this.hands.size > 0) {
this.processGestures();
}
}
/**
* توليد معالم اليد الوهمية
*/
generateHandLandmarks(time, handIndex) {
const landmarks = [];
// 21 نقطة معلم لليد (MediaPipe Hands format)
for (let i = 0; i < 21; i++) {
// محاكاة حركة طبيعية لليد
const baseX = 0.3 + handIndex * 0.4;
const baseY = 0.5;
const baseZ = 0;
let x, y, z;
if (i < 5) {
// الإبهام
x = baseX + Math.sin(time * 0.5 + i * 0.3) * 0.1;
y = baseY + Math.cos(time * 0.7 + i * 0.2) * 0.05;
} else if (i < 9) {
// السبابة
x = baseX + Math.sin(time * 0.6 + (i-5) * 0.2) * 0.08;
y = baseY - 0.1 - (i-5) * 0.03 + Math.sin(time * 0.8) * 0.02;
} else if (i < 13) {
// الأوسط
x = baseX + Math.sin(time * 0.4 + (i-9) * 0.25) * 0.08;
y = baseY - 0.12 - (i-9) * 0.03 + Math.cos(time * 0.9) * 0.02;
} else if (i < 17) {
// البنصر
x = baseX + Math.sin(time * 0.5 + (i-13) * 0.2) * 0.07;
y = baseY - 0.11 - (i-13) * 0.03 + Math.sin(time * 1.0) * 0.02;
} else {
// الخنصر
x = baseX + Math.sin(time * 0.7 + (i-17) * 0.15) * 0.06;
y = baseY - 0.1 - (i-17) * 0.03 + Math.cos(time * 1.2) * 0.02;
}
z = baseZ + Math.sin(time * 0.3 + i * 0.1) * 0.02;
landmarks.push({ x, y, z });
}
return landmarks;
}
/**
* بدء التتبع
*/
startTracking() {
if (!this.isInitialized) {
throw new Error('Gesture Controller غير مهيأ');
}
this.isActive = true;
this.mockHandTracking.start();
this.startTrackingLoop();
console.log('🎯 بدء تتبع الإيماءات');
this.emit('tracking_started');
}
/**
* إيقاف التتبع
*/
stopTracking() {
this.isActive = false;
this.mockHandTracking.stop();
console.log('🛑 توقف تتبع الإيماءات');
this.emit('tracking_stopped');
}
/**
* بدء حلقة التتبع
*/
startTrackingLoop() {
const track = () => {
if (!this.isActive) return;
try {
// تحديث التتبع
this.mockHandTracking.update();
// تحديث المعالم
this.updateHandLandmarks();
// طلب الإطار التالي
requestAnimationFrame(track);
} catch (error) {
console.error('خطأ في حلقة التتبع:', error);
setTimeout(track, 100); // محاولة إعادة التتبع
}
};
track();
}
/**
* تحديث معالم اليد
*/
updateHandLandmarks() {
this.hands.forEach((hand, handId) => {
// تطبيق التنعيم على المعالم
hand.landmarks = this.smoothLandmarks(hand.landmarks, handId);
// تحديد موقع اليد في الشاشة
hand.screenPosition = this.calculateScreenPosition(hand.landmarks);
});
}
/**
* تنعيم المعالم
*/
smoothLandmarks(landmarks, handId) {
const lastPositions = this.trackingData.lastHandPositions.get(handId) || [];
const smoothed = [];
for (let i = 0; i < landmarks.length; i++) {
const current = landmarks[i];
const last = lastPositions[i] || current;
// تطبيق التنعيم
const alpha = this.config.gestureSmoothing;
const smoothedPoint = {
x: last.x * (1 - alpha) + current.x * alpha,
y: last.y * (1 - alpha) + current.y * alpha,
z: last.z * (1 - alpha) + current.z * alpha
};
smoothed.push(smoothedPoint);
}
// حفظ المواقع المحدثة
this.trackingData.lastHandPositions.set(handId, smoothed);
return smoothed;
}
/**
* حساب موقع الشاشة
*/
calculateScreenPosition(landmarks) {
if (landmarks.length === 0) return null;
// استخدام نقطة منتصف راحة اليد (النقطة 9)
const palm = landmarks[9];
// تحويل من إحداثيات معيارية إلى إحداثيات شاشة
const x = palm.x * this.canvas.width;
const y = palm.y * this.canvas.height;
return { x, y };
}
/**
* معالجة الإيماءات
*/
processGestures() {
this.hands.forEach(hand => {
const gesture = this.recognizeGesture(hand);
if (gesture) {
this.handleRecognizedGesture(hand, gesture);
}
});
}
/**
* التعرف على الإيماءة
*/
recognizeGesture(hand) {
const landmarks = hand.landmarks;
if (landmarks.length < 21) return null;
// فحص الإيماءات المختلفة
for (const [gestureId, gestureData] of this.gestures) {
const confidence = this.calculateGestureConfidence(gestureId, landmarks);
if (confidence >= gestureData.confidence * this.config.sensitivity) {
return {
id: gestureId,
data: gestureData,
confidence: confidence,
hand: hand
};
}
}
return null;
}
/**
* حساب الثقة في الإيماءة
*/
calculateGestureConfidence(gestureId, landmarks) {
switch (gestureId) {
case 'hand_open':
return this.checkHandOpen(landmarks);
case 'hand_closed':
return this.checkHandClosed(landmarks);
case 'pointing':
return this.checkPointing(landmarks);
case 'swipe_left':
return this.checkSwipeGesture(landmarks, 'left');
case 'swipe_right':
return this.checkSwipeGesture(landmarks, 'right');
case 'swipe_up':
return this.checkSwipeGesture(landmarks, 'up');
case 'swipe_down':
return this.checkSwipeGesture(landmarks, 'down');
case 'pinch':
return this.checkPinch(landmarks);
case 'pinch_out':
return this.checkPinchOut(landmarks);
case 'thumbs_up':
return this.checkThumbsUp(landmarks);
case 'thumbs_down':
return this.checkThumbsDown(landmarks);
case 'victory':
return this.checkVictory(landmarks);
case 'number_one':
return this.checkNumberOne(landmarks);
case 'number_two':
return this.checkNumberTwo(landmarks);
case 'number_three':
return this.checkNumberThree(landmarks);
default:
return 0;
}
}
/**
* فحص اليد المفتوحة
*/
checkHandOpen(landmarks) {
// فحص المسافة بين أطراف الأصابع والرسغ
const wrist = landmarks[0];
let fingerCount = 0;
const fingerTips = [4, 8, 12, 16, 20]; // أطراف الأصابع
for (const tip of fingerTips) {
const distance = this.calculateDistance(landmarks[tip], wrist);
if (distance > 0.1) fingerCount++;
}
return fingerCount >= 4 ? 0.9 : 0.3;
}
/**
* فحص اليد المغلقة
*/
checkHandClosed(landmarks) {
// فحص اقتراب أطراف الأصابع من راحة اليد
const palm = landmarks[9];
let closeCount = 0;
const fingerTips = [4, 8, 12, 16, 20];
for (const tip of fingerTips) {
const distance = this.calculateDistance(landmarks[tip], palm);
if (distance < 0.05) closeCount++;
}
return closeCount >= 4 ? 0.9 : 0.2;
}
/**
* فحص الإشارة
*/
checkPointing(landmarks) {
// فحص امتداد السبابة مع بقية الأصابع مطوية
const indexTip = landmarks[8];
const indexPip = landmarks[6];
const middleTip = landmarks[12];
const ringTip = landmarks[16];
const pinkyTip = landmarks[20];
const indexExtended = this.calculateDistance(indexTip, indexPip) > 0.08;
const othersClosed = this.calculateDistance(middleTip, landmarks[9]) < 0.06 &&
this.calculateDistance(ringTip, landmarks[9]) < 0.06 &&
this.calculateDistance(pinkyTip, landmarks[9]) < 0.06;
return (indexExtended && othersClosed) ? 0.85 : 0.2;
}
/**
* فحص إيماءة السحب
*/
checkSwipeGesture(landmarks, direction) {
const time = Date.now() * 0.001;
const currentPos = landmarks[9]; // راحة اليد
// مقارنة مع الموقع السابق
const lastPos = this.trackingData.lastHandPositions.get('swipe_history') || [];
if (lastPos.length < 2) return 0;
const deltaX = currentPos.x - lastPos[lastPos.length - 2].x;
const deltaY = currentPos.y - lastPos[lastPos.length - 2].y;
// حفظ الموقع الحالي
lastPos.push(currentPos);
if (lastPos.length > 10) lastPos.shift();
this.trackingData.lastHandPositions.set('swipe_history', lastPos);
const threshold = 0.05;
switch (direction) {
case 'left':
return deltaX < -threshold ? 0.8 : 0.1;
case 'right':
return deltaX > threshold ? 0.8 : 0.1;
case 'up':
return deltaY < -threshold ? 0.8 : 0.1;
case 'down':
return deltaY > threshold ? 0.8 : 0.1;
default:
return 0;
}
}
/**
* فحص الإمساك
*/
checkPinch(landmarks) {
const thumbTip = landmarks[4];
const indexTip = landmarks[8];
const distance = this.calculateDistance(thumbTip, indexTip);
return distance < 0.03 ? 0.9 : 0.2;
}
/**
* فحص فتح الإمساك
*/
checkPinchOut(landmarks) {
const thumbTip = landmarks[4];
const indexTip = landmarks[8];
const distance = this.calculateDistance(thumbTip, indexTip);
return distance > 0.08 ? 0.9 : 0.2;
}
/**
* فحص الإبهام للأعلى
*/
checkThumbsUp(landmarks) {
const thumbTip = landmarks[4];
const thumbIp = landmarks[3];
const indexTip = landmarks[8];
const middleTip = landmarks[12];
const thumbUp = thumbTip.y < thumbIp.y - 0.02;
const othersDown = this.calculateDistance(indexTip, landmarks[9]) < 0.06 &&
this.calculateDistance(middleTip, landmarks[9]) < 0.06;
return (thumbUp && othersDown) ? 0.85 : 0.2;
}
/**
* فحص الإبهام للأسفل
*/
checkThumbsDown(landmarks) {
const thumbTip = landmarks[4];
const thumbIp = landmarks[3];
const indexTip = landmarks[8];
const middleTip = landmarks[12];
const thumbDown = thumbTip.y > thumbIp.y + 0.02;
const othersDown = this.calculateDistance(indexTip, landmarks[9]) < 0.06 &&
this.calculateDistance(middleTip, landmarks[9]) < 0.06;
return (thumbDown && othersDown) ? 0.85 : 0.2;
}
/**
* فحص إشارة النصر
*/
checkVictory(landmarks) {
const indexTip = landmarks[8];
const middleTip = landmarks[12];
const indexPip = landmarks[6];
const middlePip = landmarks[10];
const bothUp = indexTip.y < indexPip.y && middleTip.y < middlePip.y;
const distance = this.calculateDistance(indexTip, middleTip);
const closeTogether = distance < 0.04;
return (bothUp && closeTogether) ? 0.8 : 0.2;
}
/**
* فحص الرقم واحد
*/
checkNumberOne(landmarks) {
const indexTip = landmarks[8];
const indexPip = landmarks[6];
const middleTip = landmarks[12];
const ringTip = landmarks[16];
const pinkyTip = landmarks[20];
const indexExtended = indexTip.y < indexPip.y - 0.02;
const othersDown = this.calculateDistance(middleTip, landmarks[9]) < 0.06 &&
this.calculateDistance(ringTip, landmarks[9]) < 0.06 &&
this.calculateDistance(pinkyTip, landmarks[9]) < 0.06;
return (indexExtended && othersDown) ? 0.8 : 0.2;
}
/**
* فحص الرقم اثنان
*/
checkNumberTwo(landmarks) {
const indexTip = landmarks[8];
const middleTip = landmarks[12];
const indexPip = landmarks[6];
const middlePip = landmarks[10];
const indexUp = indexTip.y < indexPip.y - 0.02;
const middleUp = middleTip.y < middlePip.y - 0.02;
const ringDown = this.calculateDistance(landmarks[16], landmarks[9]) < 0.06;
const pinkyDown = this.calculateDistance(landmarks[20], landmarks[9]) < 0.06;
return (indexUp && middleUp && ringDown && pinkyDown) ? 0.8 : 0.2;
}
/**
* فحص الرقم ثلاثة
*/
checkNumberThree(landmarks) {
const indexTip = landmarks[8];
const middleTip = landmarks[12];
const ringTip = landmarks[16];
const indexPip = landmarks[6];
const middlePip = landmarks[10];
const ringPip = landmarks[14];
const indexUp = indexTip.y < indexPip.y - 0.02;
const middleUp = middleTip.y < middlePip.y - 0.02;
const ringUp = ringTip.y < ringPip.y - 0.02;
const pinkyDown = this.calculateDistance(landmarks[20], landmarks[9]) < 0.06;
return (indexUp && middleUp && ringUp && pinkyDown) ? 0.8 : 0.2;
}
/**
* حساب المسافة بين نقطتين
*/
calculateDistance(point1, point2) {
const dx = point1.x - point2.x;
const dy = point1.y - point2.y;
const dz = point1.z - point2.z;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
/**
* معالجة الإيماءة المعترف بها
*/
handleRecognizedGesture(hand, gesture) {
const now = Date.now();
// فحص التكرار والإيماءة الجديدة
const lastGesture = this.gestureHistory[this.gestureHistory.length - 1];
if (!lastGesture || lastGesture.id !== gesture.id ||
(now - lastGesture.timestamp) > 1000) { // ثانية واحدة بين الإيماءات
console.log('👋 إيماءة معترف بها:', gesture.data.name, `(الثقة: ${Math.round(gesture.confidence * 100)}%)`);
// حفظ في التاريخ
this.gestureHistory.push({
id: gesture.id,
data: gesture.data,
confidence: gesture.confidence,
hand: hand,
timestamp: now,
screenPosition: hand.screenPosition
});
// الاحتفاظ بآخر 50 إيماءة فقط
if (this.gestureHistory.length > 50) {
this.gestureHistory.shift();
}
// إرسال الأحداث
this.emit('gesture_recognized', gesture);
// تنفيذ الإجراءات المرتبطة
this.executeGestureActions(gesture);
}
}
/**
* تنفيذ إجراءات الإيماءة
*/
executeGestureActions(gesture) {
const actions = gesture.data.triggers;
actions.forEach(action => {
console.log('⚡ تنفيذ إجراء:', action);
this.emit(`gesture_${action}`, gesture);
});
// إجراءات خاصة بالإيماءة
switch (gesture.id) {
case 'pointing':
this.emit('hand_detected', {
position: gesture.hand.screenPosition,
confidence: gesture.confidence
});
break;
case 'swipe_left':
this.emit('swipe_left', gesture);
break;
case 'swipe_right':
this.emit('swipe_right', gesture);
break;
case 'pinch':
this.emit('pinch', {
position: gesture.hand.screenPosition,
confidence: gesture.confidence
});
break;
case 'pinch_out':
this.emit('pinch_out', gesture);
break;
case 'call_me':
this.emit('voice_command', gesture);
break;
case 'stop':
this.emit('emergency_stop', gesture);
break;
}
}
/**
* الحصول على قائمة الإيماءات المدعومة
*/
getSupportedGestures() {
const gestures = [];
this.gestures.forEach((data, id) => {
gestures.push({
id: id,
name: data.name,
description: data.description,
triggers: data.triggers
});
});
return gestures;
}
/**
* الحصول على تاريخ الإيماءات
*/
getGestureHistory(limit = 10) {
return this.gestureHistory.slice(-limit);
}
/**
* الحصول على حالة التتبع
*/
getTrackingState() {
return {
isActive: this.isActive,
isInitialized: this.isInitialized,
handsDetected: this.hands.size,
lastGesture: this.gestureHistory[this.gestureHistory.length - 1] || null,
supportedGestures: this.gestures.size,
config: this.config
};
}
/**
* تحديث إعدادات التحكم
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
console.log('🔧 تم تحديث إعدادات التحكم بالإيماءات:', this.config);
}
/**
* إضافة إيماءة مخصصة
*/
addCustomGesture(id, name, description, callback) {
this.gestures.set(id, {
name: name,
description: description,
confidence: 0.7,
triggers: ['custom'],
callback: callback
});
console.log('✨ تم إضافة إيماءة مخصصة:', id);
}
/**
* محاكاة إيماءة للاختبار
*/
simulateGesture(gestureId) {
const gesture = this.gestures.get(gestureId);
if (!gesture) {
console.warn('إيماءة غير موجودة:', gestureId);
return;
}
const mockHand = {
id: 'mock_hand',
handedness: 'right',
landmarks: this.generateHandLandmarks(Date.now() * 0.001, 0),
confidence: 0.9,
screenPosition: { x: 320, y: 240 },
timestamp: Date.now()
};
const recognizedGesture = {
id: gestureId,
data: gesture,
confidence: 0.9,
hand: mockHand
};
this.handleRecognizedGesture(mockHand, recognizedGesture);
console.log('🎭 تم محاكاة إيماءة:', gestureId);
}
/**
* نظام الأحداث
*/
emit(eventName, data) {
if (this.eventListeners[eventName]) {
this.eventListeners[eventName].forEach(callback => {
try {
callback(data);
} catch (error) {
console.error('خطأ في مستمع الحدث:', error);
}
});
}
}
on(eventName, callback) {
if (!this.eventListeners[eventName]) {
this.eventListeners[eventName] = [];
}
this.eventListeners[eventName].push(callback);
}
off(eventName, callback) {
if (this.eventListeners[eventName]) {
this.eventListeners[eventName] = this.eventListeners[eventName].filter(cb => cb !== callback);
}
}
/**
* تدمير النظام
*/
destroy() {
console.log('🗑️ تدمير Gesture Controller...');
this.stopTracking();
this.hands.clear();
this.gestureHistory = [];
this.trackingData.lastHandPositions.clear();
console.log('✅ تم تدمير Gesture Controller');
}
}
// تصدير للاستخدام في الوحدات الأخرى
if (typeof module !== 'undefined' && module.exports) {
module.exports = GestureController;
}