WebHID API की मदद से, वेबसाइटें अन्य सहायक कीबोर्ड और एक्सोटिक गेमपैड ऐक्सेस कर सकती हैं.
ह्यूमन इंटरफ़ेस डिवाइस (एचआईडी) की एक लंबी सूची है. जैसे, वैकल्पिक कीबोर्ड या एक्सोटिक गेमपैड. ये डिवाइस बहुत नए, बहुत पुराने या बहुत असामान्य होते हैं, इसलिए सिस्टम के डिवाइस ड्राइवर इन्हें ऐक्सेस नहीं कर पाते. WebHID API, JavaScript में डिवाइस के हिसाब से लॉजिक लागू करने का तरीका उपलब्ध कराकर, इस समस्या को हल करता है.
इस्तेमाल के सुझाए गए उदाहरण
एचआईडी डिवाइस, इंसानों से इनपुट लेता है या उन्हें आउटपुट उपलब्ध कराता है. डिवाइसों के उदाहरणों में, कीबोर्ड, पॉइंटिंग डिवाइस (माउस, टचस्क्रीन वगैरह), और गेमपैड शामिल हैं. एचआईडी प्रोटोकॉल की मदद से, ऑपरेटिंग सिस्टम ड्राइवर का इस्तेमाल करके, डेस्कटॉप कंप्यूटर पर इन डिवाइसों को ऐक्सेस किया जा सकता है. वेब प्लैटफ़ॉर्म, इन ड्राइवर के आधार पर एचआईडी डिवाइसों के साथ काम करता है.
असामान्य एचआईडी डिवाइसों को ऐक्सेस न कर पाना, खास तौर पर तब परेशानी का सबब बनता है, जब बात वैकल्पिक सहायक कीबोर्ड (जैसे, Elgato Stream Deck, Jabra हेडसेट, X-keys) और गेमपैड के असामान्य सपोर्ट की आती है. डेस्कटॉप के लिए डिज़ाइन किए गए गेमपैड, अक्सर गेमपैड इनपुट (बटन, जॉयस्टिक, ट्रिगर) और आउटपुट (एलईडी, रंबल) के लिए एचआईडी का इस्तेमाल करते हैं. माफ़ करें, गेमपैड के इनपुट और आउटपुट को अच्छी तरह से स्टैंडर्ड नहीं किया गया है. साथ ही, वेब ब्राउज़र को अक्सर खास डिवाइसों के लिए कस्टम लॉजिक की ज़रूरत होती है. यह लंबे समय तक काम नहीं करता. इसकी वजह से, पुराने और असामान्य डिवाइसों के लॉन्ग टेल के लिए भी यह काम नहीं करता. इससे ब्राउज़र, कुछ डिवाइसों के व्यवहार में होने वाली गड़बड़ियों पर भी निर्भर हो जाता है.
शब्दावली
एचआईडी में दो बुनियादी कॉन्सेप्ट होते हैं: रिपोर्ट और रिपोर्ट डिस्क्रिप्टर. रिपोर्ट वह डेटा है जो डिवाइस और सॉफ़्टवेयर क्लाइंट के बीच लेन-देन होता है. रिपोर्ट डिस्क्रिप्टर, डिवाइस के साथ काम करने वाले डेटा के फ़ॉर्मैट और उसके मतलब के बारे में बताता है.
एचआईडी (ह्यूमन इंटरफ़ेस डिवाइस) एक तरह का डिवाइस है, जो लोगों से इनपुट लेता है या उन्हें आउटपुट देता है. यह एचआईडी प्रोटोकॉल भी है. यह प्रोटोकॉल, होस्ट और डिवाइस के बीच, दोनों तरफ़ से कम्यूनिकेशन के लिए एक स्टैंडर्ड है. इसे इंस्टॉलेशन की प्रोसेस को आसान बनाने के लिए डिज़ाइन किया गया है. एचआईडी प्रोटोकॉल को मूल रूप से यूएसबी डिवाइसों के लिए डिज़ाइन किया गया था. हालांकि, अब इसे कई अन्य प्रोटोकॉल के साथ भी इस्तेमाल किया जा सकता है. इनमें ब्लूटूथ भी शामिल है.
ऐप्लिकेशन और एचआईडी डिवाइस, तीन तरह की रिपोर्ट के ज़रिए बाइनरी डेटा का आदान-प्रदान करते हैं:
रिपोर्ट का टाइप | ब्यौरा |
---|---|
इनपुट रिपोर्ट | डिवाइस से ऐप्लिकेशन को भेजा जाने वाला डेटा. उदाहरण के लिए, कोई बटन दबाया गया. |
आउटपुट रिपोर्ट | ऐप्लिकेशन से डिवाइस पर भेजा गया डेटा. उदाहरण के लिए, कीबोर्ड की बैकलाइट चालू करने का अनुरोध. |
सुविधाओं की रिपोर्ट | वह डेटा जिसे दोनों दिशाओं में भेजा जा सकता है. यह फ़ॉर्मैट, डिवाइस के हिसाब से तय होता है. |
रिपोर्ट डिस्क्रिप्टर, डिवाइस पर काम करने वाली रिपोर्ट के बाइनरी फ़ॉर्मैट के बारे में बताता है. इसकी बनावट हैरारकी है और यह टॉप लेवल कलेक्शन में, अलग-अलग कलेक्शन के तौर पर रिपोर्ट को एक साथ ग्रुप कर सकती है. डिस्क्रिप्टर का फ़ॉर्मैट, एचआईडी स्पेसिफ़िकेशन से तय होता है.
एचआईडी का इस्तेमाल, एक संख्या होती है. यह स्टैंडर्ड इनपुट या आउटपुट को दिखाती है. इस्तेमाल की वैल्यू की मदद से, किसी डिवाइस की रिपोर्ट में डिवाइस के इस्तेमाल के मकसद और हर फ़ील्ड के मकसद के बारे में बताया जा सकता है. उदाहरण के लिए, माउस के बाएं बटन के लिए एक कोड तय किया गया है. इस्तेमाल को इस्तेमाल वाले पेजों में भी व्यवस्थित किया जाता है. इनसे डिवाइस या रिपोर्ट की हाई-लेवल कैटगरी का पता चलता है.
WebHID API का इस्तेमाल करना
फ़ीचर का पता लगाना
यह देखने के लिए कि WebHID API काम करता है या नहीं, इनका इस्तेमाल करें:
if ("hid" in navigator) {
// The WebHID API is supported.
}
एचआईडी कनेक्शन खोलना
WebHID API, डिज़ाइन के हिसाब से असाइनक्रोनस है, ताकि इनपुट के इंतज़ार में वेबसाइट के यूज़र इंटरफ़ेस (यूआई) को ब्लॉक होने से रोका जा सके. यह ज़रूरी है, क्योंकि HID डेटा कभी भी पाया जा सकता है. इसलिए, इसे सुनने का तरीका होना चाहिए.
एचआईडी कनेक्शन खोलने के लिए, पहले HIDDevice
ऑब्जेक्ट को ऐक्सेस करें. इसके लिए, navigator.hid.requestDevice()
को कॉल करके उपयोगकर्ता को कोई डिवाइस चुनने के लिए कहा जा सकता है या navigator.hid.getDevices()
से कोई डिवाइस चुना जा सकता है. navigator.hid.getDevices()
से उन डिवाइसों की सूची मिलती है जिनका ऐक्सेस वेबसाइट को पहले दिया गया है.
navigator.hid.requestDevice()
फ़ंक्शन, फ़िल्टर तय करने के लिए एक ज़रूरी ऑब्जेक्ट लेता है. इनका इस्तेमाल, यूएसबी वेंडर आइडेंटिफ़ायर (vendorId
), यूएसबी प्रॉडक्ट आइडेंटिफ़ायर (productId
), इस्तेमाल की जानकारी वाले पेज की वैल्यू (usagePage
), और इस्तेमाल की वैल्यू (usage
) से कनेक्ट किए गए किसी भी डिवाइस से मैच करने के लिए किया जाता है. इन्हें यूएसबी आईडी रिपॉज़िटरी और एचआईडी के इस्तेमाल की जानकारी वाली टेबल के दस्तावेज़ से पाया जा सकता है.
इस फ़ंक्शन से मिले कई HIDDevice
ऑब्जेक्ट, एक ही फ़िज़िकल डिवाइस पर मौजूद कई HID इंटरफ़ेस दिखाते हैं.
// Filter on devices with the Nintendo Switch Joy-Con USB Vendor/Product IDs.
const filters = [
{
vendorId: 0x057e, // Nintendo Co., Ltd
productId: 0x2006 // Joy-Con Left
},
{
vendorId: 0x057e, // Nintendo Co., Ltd
productId: 0x2007 // Joy-Con Right
}
];
// Prompt user to select a Joy-Con device.
const [device] = await navigator.hid.requestDevice({ filters });
// Get all devices the user has previously granted the website access to.
const devices = await navigator.hid.getDevices();
navigator.hid.requestDevice()
में मौजूद वैकल्पिक exclusionFilters
बटन का इस्तेमाल करके भी, ब्राउज़र पिकर से कुछ डिवाइसों को हटाया जा सकता है. उदाहरण के लिए, ऐसे डिवाइस जिनमें ब्राउज़र ठीक से काम नहीं कर रहा है.
// Request access to a device with vendor ID 0xABCD. The device must also have
// a collection with usage page Consumer (0x000C) and usage ID Consumer
// Control (0x0001). The device with product ID 0x1234 is malfunctioning.
const [device] = await navigator.hid.requestDevice({
filters: [{ vendorId: 0xabcd, usagePage: 0x000c, usage: 0x0001 }],
exclusionFilters: [{ vendorId: 0xabcd, productId: 0x1234 }],
});
HIDDevice
ऑब्जेक्ट में, डिवाइस की पहचान के लिए यूएसबी वेंडर और प्रॉडक्ट आइडेंटिफ़ायर मौजूद हैं. इसके collections
एट्रिब्यूट की शुरुआत, डिवाइस के रिपोर्ट फ़ॉर्मैट की हैरारकी की जानकारी के साथ की जाती है.
for (let collection of device.collections) {
// An HID collection includes usage, usage page, reports, and subcollections.
console.log(`Usage: ${collection.usage}`);
console.log(`Usage page: ${collection.usagePage}`);
for (let inputReport of collection.inputReports) {
console.log(`Input report: ${inputReport.reportId}`);
// Loop through inputReport.items
}
for (let outputReport of collection.outputReports) {
console.log(`Output report: ${outputReport.reportId}`);
// Loop through outputReport.items
}
for (let featureReport of collection.featureReports) {
console.log(`Feature report: ${featureReport.reportId}`);
// Loop through featureReport.items
}
// Loop through subcollections with collection.children
}
HIDDevice
डिवाइसों को डिफ़ॉल्ट रूप से "बंद" स्थिति में लौटाया जाता है. डेटा भेजने या पाने से पहले, open()
को कॉल करके उन्हें खोलना ज़रूरी है.
// Wait for the HID connection to open before sending/receiving data.
await device.open();
इनपुट रिपोर्ट पाएं
एचआईडी कनेक्शन बन जाने के बाद, डिवाइस से "inputreport"
इवेंट सुनकर, इनकमिंग इनपुट
रिपोर्ट मैनेज की जा सकती हैं. उन इवेंट में, एचआईडी डेटा को DataView
ऑब्जेक्ट (data
) के तौर पर शामिल किया जाता है. साथ ही, उस एचआईडी डिवाइस (device
) और इनपुट रिपोर्ट (reportId
) से जुड़े 8-बिट रिपोर्ट आईडी की जानकारी भी शामिल होती है.
पिछले उदाहरण की तरह, नीचे दिए गए कोड में यह पता लगाने का तरीका बताया गया है कि उपयोगकर्ता ने जॉय-कॉन राइट डिवाइस पर किस बटन को दबाया है, ताकि आप उसे घर पर आज़मा सकें.
device.addEventListener("inputreport", event => {
const { data, device, reportId } = event;
// Handle only the Joy-Con Right device and a specific report ID.
if (device.productId !== 0x2007 && reportId !== 0x3f) return;
const value = data.getUint8(0);
if (value === 0) return;
const someButtons = { 1: "A", 2: "X", 4: "B", 8: "Y" };
console.log(`User pressed button ${someButtons[value]}.`);
});
आउटपुट रिपोर्ट भेजना
किसी एचआईडी डिवाइस पर आउटपुट रिपोर्ट भेजने के लिए, आउटपुट रिपोर्ट (reportId
) से जुड़ा 8-बिट रिपोर्ट आईडी और बाइट को BufferSource
(data
) के तौर पर device.sendReport()
पर पास करें. रिपोर्ट भेजे जाने के बाद, वापस किया गया प्रॉमिस रिज़ॉल्व हो जाता है. अगर एचआईडी डिवाइस, रिपोर्ट आईडी का इस्तेमाल नहीं करता है, तो reportId
को 0 पर सेट करें.
नीचे दिया गया उदाहरण जॉय-कॉन डिवाइस पर लागू होता है और इसमें आउटपुट रिपोर्ट की मदद से गड़बड़ी को ठीक करने का तरीका बताया गया है.
// First, send a command to enable vibration.
// Magical bytes come from https://github.com/mzyy94/joycon-toolweb
const enableVibrationData = [1, 0, 1, 64, 64, 0, 1, 64, 64, 0x48, 0x01];
await device.sendReport(0x01, new Uint8Array(enableVibrationData));
// Then, send a command to make the Joy-Con device rumble.
// Actual bytes are available in the sample below.
const rumbleData = [ /* ... */ ];
await device.sendReport(0x10, new Uint8Array(rumbleData));
सुविधा से जुड़ी रिपोर्ट भेजना और पाना
सुविधा रिपोर्ट ही एचआईडी डेटा रिपोर्ट का एक टाइप है, जो दोनों निर्देशों में ट्रांसफ़र की जा सकती है. इनकी मदद से, एचआईडी डिवाइसों और ऐप्लिकेशन के बीच, स्टैंडर्ड के मुताबिक न होने वाला एचआईडी डेटा शेयर किया जा सकता है. इनपुट और आउटपुट रिपोर्ट के उलट, ऐप्लिकेशन नियमित तौर पर सुविधा रिपोर्ट को न तो भेजता है और न ही पाता है.
किसी एचआईडी डिवाइस पर सुविधा रिपोर्ट भेजने के लिए, सुविधा रिपोर्ट (reportId
) से जुड़े 8-बिट रिपोर्ट आईडी को BufferSource
(data
) के तौर पर device.sendFeatureReport()
को पास करें. रिपोर्ट भेजे जाने के बाद, रिटर्न किया गया प्रॉमिस रिज़ॉल्व हो जाता है. अगर एचआईडी डिवाइस, रिपोर्ट आईडी का इस्तेमाल नहीं करता है, तो reportId
को 0 पर सेट करें.
नीचे दिए गए उदाहरण में, सुविधा रिपोर्ट के इस्तेमाल के बारे में बताया गया है. इसमें, Apple कीबोर्ड के बैकलाइट डिवाइस का अनुरोध करने, उसे खोलने, और उसे ब्लिंक करने का तरीका बताया गया है.
const waitFor = duration => new Promise(r => setTimeout(r, duration));
// Prompt user to select an Apple Keyboard Backlight device.
const [device] = await navigator.hid.requestDevice({
filters: [{ vendorId: 0x05ac, usage: 0x0f, usagePage: 0xff00 }]
});
// Wait for the HID connection to open.
await device.open();
// Blink!
const reportId = 1;
for (let i = 0; i < 10; i++) {
// Turn off
await device.sendFeatureReport(reportId, Uint32Array.from([0, 0]));
await waitFor(100);
// Turn on
await device.sendFeatureReport(reportId, Uint32Array.from([512, 0]));
await waitFor(100);
}
किसी एचआईडी डिवाइस से सुविधा की रिपोर्ट पाने के लिए, सुविधा की रिपोर्ट (reportId
) से जुड़ा 8-बिट रिपोर्ट आईडी, device.receiveFeatureReport()
को भेजें. रिटर्न किया गया प्रॉमिस, DataView
ऑब्जेक्ट के साथ रिज़ॉल्व होता है. इसमें, सुविधा की रिपोर्ट का कॉन्टेंट होता है. अगर एचआईडी डिवाइस, रिपोर्ट आईडी का इस्तेमाल नहीं करता है, तो reportId
को 0 पर सेट करें.
// Request feature report.
const dataView = await device.receiveFeatureReport(/* reportId= */ 1);
// Read feature report contents with dataView.getInt8(), getUint8(), etc...
कनेक्ट और डिसकनेक्ट होने की जानकारी सुनना
जब वेबसाइट को किसी एचआईडी डिवाइस को ऐक्सेस करने की अनुमति मिल जाती है, तो वह "connect"
और "disconnect"
इवेंट सुनकर, कनेक्शन और डिस्कनेक्शन इवेंट पा सकती है.
navigator.hid.addEventListener("connect", event => {
// Automatically open event.device or warn user a device is available.
});
navigator.hid.addEventListener("disconnect", event => {
// Remove |event.device| from the UI.
});
किसी एचआईडी डिवाइस का ऐक्सेस रद्द करना
वेबसाइट, HIDDevice
इंस्टेंस पर forget()
को कॉल करके, किसी ऐसे एचआईडी डिवाइस को ऐक्सेस करने की अनुमतियों को हटा सकती है जिसे अब उसे ऐक्सेस नहीं करना है. उदाहरण के लिए, कई डिवाइसों के साथ शेयर किए गए कंप्यूटर पर इस्तेमाल किए जाने वाले किसी शिक्षा से जुड़े वेब ऐप्लिकेशन के लिए, उपयोगकर्ता से मिली अनुमतियों की बड़ी संख्या से उपयोगकर्ता अनुभव खराब हो जाता है.
किसी एक HIDDevice
इंस्टेंस पर forget()
को कॉल करने से, उसी फ़िज़िकल डिवाइस पर मौजूद सभी एचआईडी इंटरफ़ेस का ऐक्सेस रद्द हो जाएगा.
// Voluntarily revoke access to this HID device.
await device.forget();
forget()
, Chrome 100 या उसके बाद के वर्शन में उपलब्ध है. इसलिए, देखें कि यह सुविधा इनके साथ काम करती है या नहीं:
if ("hid" in navigator && "forget" in HIDDevice.prototype) {
// forget() is supported.
}
डेवलपर के लिए सलाह
Chrome में एचआईडी को डीबग करना आसान है. इसके लिए, इंटरनल पेज about://device-log
का इस्तेमाल करें. यहां आपको एचआईडी और यूएसबी डिवाइस से जुड़े सभी इवेंट एक ही जगह पर दिखेंगे.
एचआईडी डिवाइस की जानकारी को, मनुष्य के पढ़ने लायक फ़ॉर्मैट में डंप करने के लिए, एचआईडी एक्सप्लोरर देखें. यह हर HID इस्तेमाल के लिए, इस्तेमाल की वैल्यू से नामों पर मैप करता है.
ज़्यादातर Linux सिस्टम पर, एचआईडी डिवाइसों को डिफ़ॉल्ट रूप से सिर्फ़ पढ़ने की अनुमतियों के साथ मैप किया जाता है. Chrome को किसी एचआईडी डिवाइस को खोलने की अनुमति देने के लिए, आपको एक नया udev
नियम जोड़ना होगा. /etc/udev/rules.d/50-yourdevicename.rules
पर, यहां दिए गए कॉन्टेंट वाली फ़ाइल बनाएं:
KERNEL=="hidraw*", ATTRS{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
ऊपर दी गई लाइन में, [yourdevicevendor]
057e
है. उदाहरण के लिए, अगर आपका डिवाइस Nintendo Switch
Joy-Con है. ज़्यादा खास नियम के लिए भी ATTRS{idProduct}
जोड़ा जा सकता है. पक्का करें कि आपका user
, plugdev
ग्रुप का सदस्य हो. इसके बाद, अपने डिवाइस को फिर से कनेक्ट करें.
ब्राउज़र समर्थन
WebHID API, Chrome 89 में सभी डेस्कटॉप प्लैटफ़ॉर्म (ChromeOS, Linux, macOS, और Windows) पर उपलब्ध है.
डेमो
WebHID के कुछ डेमो web.dev/hid-examples पर दिए गए हैं. आइए एक नज़र डालें!
सुरक्षा और निजता
स्पेसिफ़िकेशन के लेखकों ने वेब प्लैटफ़ॉर्म की बेहतर सुविधाओं के ऐक्सेस को कंट्रोल करना में बताए गए मुख्य सिद्धांतों का इस्तेमाल करके, WebHID API को डिज़ाइन और लागू किया है. इन सिद्धांतों में, उपयोगकर्ता कंट्रोल, पारदर्शिता, और काम करने के तरीके शामिल हैं. इस एपीआई का इस्तेमाल करने की अनुमति, मुख्य रूप से अनुमति मॉडल के हिसाब से दी जाती है. यह मॉडल, एक समय में सिर्फ़ एक एचआईडी डिवाइस का ऐक्सेस देता है. उपयोगकर्ता के प्रॉम्प्ट के जवाब में, उपयोगकर्ता को किसी खास एचआईडी डिवाइस को चुनने के लिए, सक्रिय कार्रवाई करनी होगी.
सुरक्षा से जुड़े समझौते को समझने के लिए, WebHID स्पेसिफ़िकेशन का सुरक्षा और निजता से जुड़ी बातें सेक्शन देखें.
इसके अलावा, Chrome हर टॉप-लेवल कलेक्शन के इस्तेमाल की जांच करता है. अगर किसी टॉप-लेवल कलेक्शन का इस्तेमाल सुरक्षित है, जैसे कि सामान्य कीबोर्ड, माउस वगैरह, तो कोई वेबसाइट उस कलेक्शन में बताई गई किसी भी रिपोर्ट को भेज और पा नहीं सकती. सुरक्षित इस्तेमाल की पूरी सूची सार्वजनिक तौर पर उपलब्ध है.
ध्यान दें कि Chrome में, सुरक्षा से जुड़े एचआईडी डिवाइस भी ब्लॉक किए जाते हैं. जैसे, पुष्टि करने के बेहतर तरीके के लिए इस्तेमाल किए जाने वाले एफ़आईडीओ एचआईडी डिवाइस. यूएसबी ब्लॉकलिस्ट और एचआईडी ब्लॉकलिस्ट फ़ाइलें देखें.
सुझाव/राय दें या शिकायत करें
Chrome की टीम को WebHID API के बारे में आपके विचार और अनुभव जानने में दिलचस्पी होगी.
हमें एपीआई के डिज़ाइन के बारे में बताएं
क्या एपीआई में कोई ऐसी चीज़ है जो उम्मीद के मुताबिक काम नहीं करती? इसके अलावा, क्या अपने आइडिया को लागू करने के लिए कोई तरीका या प्रॉपर्टी मौजूद नहीं है?
WebHID API के GitHub रिपॉज़िटरी पर, खास जानकारी से जुड़ी कोई समस्या दर्ज करें या किसी मौजूदा समस्या के बारे में अपनी राय दें.
लागू करने से जुड़ी समस्या की शिकायत करना
क्या आपको Chrome में इस सुविधा को लागू करने में कोई गड़बड़ी मिली? या क्या इसे लागू करने का तरीका, ज़रूरी निर्देशों से अलग है?
WebHID से जुड़ी गड़बड़ियों की शिकायत करने का तरीका जानें. ज़्यादा से ज़्यादा जानकारी ज़रूर शामिल करें. गड़बड़ी को दोहराने के लिए आसान निर्देश दें. साथ ही, कॉम्पोनेंट को Blink>HID
पर सेट करें. Glitch, समस्या की जानकारी तुरंत और आसानी से शेयर करने के लिए बहुत अच्छा है.
क्रिएटर के लिए अपना सपोर्ट दिखाना
क्या आपको WebHID API का इस्तेमाल करना है? सार्वजनिक तौर पर सहायता पाने से, Chrome टीम को सुविधाओं को प्राथमिकता देने में मदद मिलती है. साथ ही, इससे ब्राउज़र के अन्य वेंडर को यह पता चलता है कि इन सुविधाओं को उपलब्ध कराना कितना ज़रूरी है.
#WebHID
हैशटैग का इस्तेमाल करके, @ChromiumDev को ट्वीट करें और हमें बताएं कि इसका इस्तेमाल कहां और कैसे किया जा रहा है.
मदद के लिए लिंक
- खास जानकारी
- बग को ट्रैक करना
- ChromeStatus.com पर मौजूद जानकारी
- Blink कॉम्पोनेंट:
Blink>HID
स्वीकार की गई
इस लेख की समीक्षा करने के लिए, मैट रेनॉल्ड्स और जो मेडली का धन्यवाद. Unsplash पर Sara Kurfeß की ओर से ली गई, लाल और नीले रंग के Nintendo Switch की फ़ोटो. साथ ही, Athul Cyriac Ajay की ओर से ली गई, काले और सिल्वर रंग के लैपटॉप की फ़ोटो.