blob: 6acb2cbf852ca8e43b52ff7e0cfdf858af71cf1a [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/device/public/cpp/hid/hid_item_state_table.h"
#include <limits>
namespace device {
namespace {
bool IsGlobalItem(HidReportDescriptorItem::Tag tag) {
switch (tag) {
case HidReportDescriptorItem::kTagUsagePage:
case HidReportDescriptorItem::kTagLogicalMinimum:
case HidReportDescriptorItem::kTagLogicalMaximum:
case HidReportDescriptorItem::kTagPhysicalMinimum:
case HidReportDescriptorItem::kTagPhysicalMaximum:
case HidReportDescriptorItem::kTagUnitExponent:
case HidReportDescriptorItem::kTagUnit:
case HidReportDescriptorItem::kTagReportSize:
case HidReportDescriptorItem::kTagReportId:
case HidReportDescriptorItem::kTagReportCount:
return true;
default:
break;
}
return false;
}
uint32_t MaybeCombineUsageAndUsagePage(
uint32_t usage,
const std::vector<HidItemStateTable::HidGlobalItemState>& global_stack) {
// Check if the usage value already has a usage page in the upper bytes.
if (usage > std::numeric_limits<uint16_t>::max())
return usage;
// No global state, just return the usage value.
if (global_stack.empty())
return usage;
// Combine the global usage page with the usage value.
return (global_stack.back().usage_page << (sizeof(uint16_t) * 8)) | usage;
}
} // namespace
HidItemStateTable::HidItemStateTable() = default;
HidItemStateTable::~HidItemStateTable() = default;
void HidItemStateTable::SetItemValue(HidReportDescriptorItem::Tag tag,
uint32_t value) {
if (IsGlobalItem(tag)) {
if (global_stack.empty())
global_stack.emplace_back();
auto& global = global_stack.back();
switch (tag) {
case HidReportDescriptorItem::kTagUsagePage:
global.usage_page = value;
break;
case HidReportDescriptorItem::kTagLogicalMinimum:
global.logical_minimum = int32_t{value};
break;
case HidReportDescriptorItem::kTagLogicalMaximum:
global.logical_maximum = int32_t{value};
break;
case HidReportDescriptorItem::kTagPhysicalMinimum:
global.physical_minimum = int32_t{value};
break;
case HidReportDescriptorItem::kTagPhysicalMaximum:
global.physical_maximum = int32_t{value};
break;
case HidReportDescriptorItem::kTagUnitExponent:
global.unit_exponent = value;
break;
case HidReportDescriptorItem::kTagUnit:
global.unit = value;
break;
case HidReportDescriptorItem::kTagReportSize:
global.report_size = value;
break;
case HidReportDescriptorItem::kTagReportCount:
global.report_count = value;
break;
default:
NOTREACHED() << "Unexpected global item in HID report descriptor";
break;
}
} else {
switch (tag) {
case HidReportDescriptorItem::kTagUsage:
local.usages.push_back(
MaybeCombineUsageAndUsagePage(value, global_stack));
break;
case HidReportDescriptorItem::kTagUsageMinimum:
local.usage_minimum =
MaybeCombineUsageAndUsagePage(value, global_stack);
break;
case HidReportDescriptorItem::kTagUsageMaximum:
local.usage_maximum =
MaybeCombineUsageAndUsagePage(value, global_stack);
break;
case HidReportDescriptorItem::kTagDesignatorIndex:
local.designator_index = value;
break;
case HidReportDescriptorItem::kTagDesignatorMinimum:
local.designator_minimum = value;
break;
case HidReportDescriptorItem::kTagDesignatorMaximum:
local.designator_maximum = value;
break;
case HidReportDescriptorItem::kTagStringIndex:
local.string_index = value;
break;
case HidReportDescriptorItem::kTagStringMinimum:
local.string_minimum = value;
break;
case HidReportDescriptorItem::kTagStringMaximum:
local.string_maximum = value;
break;
case HidReportDescriptorItem::kTagDelimiter:
local.delimiter = value;
break;
default:
NOTREACHED() << "Unexpected local item in HID report descriptor";
break;
}
}
}
HidItemStateTable::HidGlobalItemState::HidGlobalItemState() = default;
HidItemStateTable::HidGlobalItemState::HidGlobalItemState(
const HidGlobalItemState&) = default;
HidItemStateTable::HidGlobalItemState::~HidGlobalItemState() = default;
HidItemStateTable::HidLocalItemState::HidLocalItemState() = default;
HidItemStateTable::HidLocalItemState::HidLocalItemState(
const HidLocalItemState&) = default;
HidItemStateTable::HidLocalItemState::~HidLocalItemState() = default;
void HidItemStateTable::HidLocalItemState::Reset() {
usages.clear();
usage_minimum = 0;
usage_maximum = 0;
designator_index = 0;
designator_minimum = 0;
designator_maximum = 0;
string_index = 0;
string_minimum = 0;
string_maximum = 0;
delimiter = 0;
}
} // namespace device