Commit e7447865 authored by sm's avatar sm

Remove XI2 (X11) related projects and functionality

Remove device-floater
Add groups to PluginsDeviceManager
Remove FloGtkDeviceManager
Make some useful classes available in libstmm-input-gtk
parent 6841f30c
/build
configure
/nbproject
.metadata
.project
.cproject
.settings
Program:
Stefano Marsili, <stemars@gmx.ch>
Artwork:
"buoy_32313.png", "keyboard_1420.png", "mouse_347.png"
made by Freepik (http://www.freepik.com) from www.flaticon.com is licensed by
Creative Commons BY 3.0 (http://creativecommons.org/licenses/by/3.0/)
# File: device-floater/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(device-floater CXX)
set(RUNTIME_OUTPUT_DIRECTORY "build")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../share/cmake)
include(CommonUtil)
CheckBinaryNotSourceTree()
CheckBuildType()
DefineCommonCompileOptions()
include(FindPkgConfig)
if (NOT PKG_CONFIG_FOUND)
message(FATAL_ERROR "Mandatory 'pkg-config' not found!")
endif()
#
set(DEVICE_FLOATER_MAJOR_VERSION 0)
set(DEVICE_FLOATER_MINOR_VERSION 1)
set(DEVICE_FLOATER_VERSION "${DEVICE_FLOATER_MAJOR_VERSION}.${DEVICE_FLOATER_MINOR_VERSION}.0")
set(GTKMM_VERSION_REQ "3.14.0")
set(XI_VERSION_REQ "1.7.4")
set(X11_VERSION_REQ "1.6.2")
pkg_check_modules(GTKMM REQUIRED gtkmm-3.0>=${GTKMM_VERSION_REQ})
pkg_check_modules(XI REQUIRED xi>=${XI_VERSION_REQ})
pkg_check_modules(X11 REQUIRED x11>=${X11_VERSION_REQ})
list(APPEND STMMI_DEVFLO_EXTRA_INCLUDE_DIRS ${GTKMM_INCLUDE_DIRS} ${XI_INCLUDE_DIRS} ${X11_INCLUDE_DIRS})
list(APPEND STMMI_DEVFLO_EXTRA_LIBS ${GTKMM_LIBRARIES} ${XI_LIBRARIES} ${X11_LIBRARIES})
string(STRIP "${STMMI_DEVFLO_EXTRA_LIBS}" STMMI_DEVFLO_EXTRA_LIBS)
string(STRIP "${STMMI_DEVFLO_EXTRA_INCLUDE_DIRS}" STMMI_DEVFLO_EXTRA_INCLUDE_DIRS)
# Source files (and headers only used for building)
set(STMMI_DEVFLO_SOURCES
${PROJECT_SOURCE_DIR}/src/config.h
${PROJECT_SOURCE_DIR}/src/devicefloater.h
${PROJECT_SOURCE_DIR}/src/devicefloater.cc
${PROJECT_SOURCE_DIR}/src/main.cc
${PROJECT_SOURCE_DIR}/src/xideviceswindow.h
${PROJECT_SOURCE_DIR}/src/xideviceswindow.cc
)
set(STMMI_DEVFLO_DATA_FILES
${PROJECT_SOURCE_DIR}/data/buoy_32313.png
${PROJECT_SOURCE_DIR}/data/keyboard_1420.png
${PROJECT_SOURCE_DIR}/data/mouse_347.png
)
add_executable(device-floater ${STMMI_DEVFLO_SOURCES} ${PROJECT_BINARY_DIR}/config.cc)
target_include_directories(device-floater PUBLIC ${STMMI_DEVFLO_EXTRA_INCLUDE_DIRS})
DefineTargetPublicCompileOptions(device-floater)
include(GNUInstallDirs)
set(STMMI_DEVFLO_PKG_DATA_DIR "${CMAKE_INSTALL_FULL_DATADIR}/device-floater")
set(STMMI_DEVFLO_PKG_REL_DATA_DIR "${CMAKE_INSTALL_DATADIR}/device-floater")
# Create config file for executable
configure_file("${PROJECT_SOURCE_DIR}/src/config.cc.in"
"${PROJECT_BINARY_DIR}/config.cc" @ONLY)
# This allows config.cc to find the config.h include
target_include_directories(device-floater PUBLIC ${PROJECT_SOURCE_DIR}/src)
if ($ENV{STMM_CMAKE_COMMENTS})
message(STATUS "")
message(STATUS "device-floater was configured with the following options:")
message(STATUS " STMMI_DEVFLO_SOURCES: ${STMMI_DEVFLO_SOURCES}")
#message(STATUS " STMMI_DEVFLO_EXTRA_INCLUDE_DIRS: ${STMMI_DEVFLO_EXTRA_INCLUDE_DIRS}")
message(STATUS " STMMI_DEVFLO_EXTRA_LIBS: ${STMMI_DEVFLO_EXTRA_LIBS}")
message(STATUS " STMMI_DEVFLO_DATA_FILES ${STMMI_DEVFLO_DATA_FILES}")
message(STATUS " CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
message(STATUS " CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS " CMAKE_CXX_COMPILER_VERSION: ${CMAKE_CXX_COMPILER_VERSION}")
#message(STATUS " CMAKE_CXX_FLAGS: $<TARGET_PROPERTY:device-floater,COMPILE_OPTIONS>")
message(STATUS " install prefix: ${CMAKE_INSTALL_PREFIX}")
endif()
target_link_libraries(device-floater ${STMMI_DEVFLO_EXTRA_LIBS}) # ${STMMI_DEVFLO_EXTRA_LDFLAGS}
install(TARGETS device-floater RUNTIME DESTINATION "bin")
install(FILES ${STMMI_DEVFLO_DATA_FILES} DESTINATION ${STMMI_DEVFLO_PKG_REL_DATA_DIR})
#================
# device-floater
#================
Requirements
------------
g++ compiler or compatible (>= C++14)
libgtkmm3.0-dev
libxi-dev
libx11-dev
Instructions
------------
From this directory execute the following commands:
$ mkdir build
$ cd build
$ cmake -D CMAKE_BUILD_TYPE=Release ..
Instead of 'Release' CMAKE_BUILD_TYPE can also be set to
'Debug', 'MinSizeRel' or 'RelWithDebInfo'.
To change the default installation directory add definition
'-D CMAKE_INSTALL_PREFIX=/home/adam/mybin' to the preceding command.
$ make
$ sudo make install
sudo might be omitted if installing to a directory owned by the current user.
Alternatively you can just execute the script
$ ./scripts/install_device-floater.py -b Release --destdir /home/adam/mylib
setting the parameter(s) to your preferred value (like above).
$ ./scripts/install_device-floater.py --help
for a description of all available options.
This diff is collapsed.
==============
device-floater
==============
device-floater is a simple gui application that let's you safely float
keyboard and pointer devices managed by X11 (XI2). It provides a subset of the
'xinput float' command.
Multiple floating keyboards, alongside with the master keyboard, can be used
independently by multiple players in games using the stmm-input-gtk-dm library.
To float a device plug it in while the device-floater is in acquiring mode.
To unfloat a device unplug and replug it while it is not in acquiring mode,
it will reappear as a slave device of either the master keyboard or pointer.
When the computer is turned off, the floating devices status is not saved.
The acquiring mode is time limited to prevent you from locking yourself out
of your computer. Type 'device-floater --help' on your terminal for more
information.
#!/usr/bin/env python3
# Copyright © 2016-2017 Stefano Marsili, <stemars@gmx.ch>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, see <http://www.gnu.org/licenses/>
# File: install_device-floater.py
# Compiles and installs the device-floater application.
import sys
import os
import subprocess
def main():
import argparse
oParser = argparse.ArgumentParser()
oParser.add_argument("-b", "--buildtype", help="build type (default=Release)"\
, choices=['Debug', 'Release', 'MinSizeRel', 'RelWithDebInfo']\
, default="Release", dest="sBuildType")
oParser.add_argument("--destdir", help="install dir (default=/usr/local)", metavar='DESTDIR'\
, default="/usr/local", dest="sDestDir")
oParser.add_argument("--no-sudo", help="don't use sudo to install", action="store_true"\
, default=False, dest="bDontSudo")
oArgs = oParser.parse_args()
sDestDir = os.path.abspath(oArgs.sDestDir)
sScriptDir = os.path.dirname(os.path.abspath(__file__))
#print("sScriptDir:" + sScriptDir)
os.chdir(sScriptDir)
os.chdir("..")
#
sDestDir = "-D CMAKE_INSTALL_PREFIX=" + sDestDir
#print("sDestDir:" + sDestDir)
#
sBuildType = "-D CMAKE_BUILD_TYPE=" + oArgs.sBuildType
#print("sBuildType:" + sBuildType)
if oArgs.bDontSudo:
sSudo = ""
else:
sSudo = "sudo"
if not os.path.isdir("build"):
os.mkdir("build")
os.chdir("build")
subprocess.check_call("cmake {} {} ..".format(sBuildType, sDestDir).split())
subprocess.check_call("make $STMM_MAKE_OPTIONS", shell=True)
subprocess.check_call("{} make install".format(sSudo).split())
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# Copyright © 2016-2017 Stefano Marsili, <stemars@gmx.ch>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, see <http://www.gnu.org/licenses/>
# File: uninstall_device-floater.py
# Removes all files installed by the install_device-floater.py script.
import sys
import os
import subprocess
def main():
import argparse
oParser = argparse.ArgumentParser("Removes all files created by install_device-floater.py")
oParser.add_argument("-r", "--remove-builds", help="Remove build folders", action="store_true"\
, default=False, dest="bRemoveBuilds")
oParser.add_argument("-y", "--no-prompt", help="No prompt comfirmation", action="store_true"\
, default=False, dest="bNoPrompt")
oParser.add_argument("--destdir", help="install dir (default=/usr/local)", metavar='DESTDIR'\
, default="/usr/local", dest="sDestDir")
oParser.add_argument("--no-sudo", help="don't use sudo to uninstall", action="store_true"\
, default=False, dest="bDontSudo")
oArgs = oParser.parse_args()
sDestDir = os.path.abspath(oArgs.sDestDir)
sScriptDir = os.path.dirname(os.path.abspath(__file__))
os.chdir(sScriptDir)
os.chdir("..")
if not oArgs.bNoPrompt:
print("Uninstall from dir: " + sDestDir + " Remove build folders: " + str(oArgs.bRemoveBuilds))
while not oArgs.bNoPrompt:
sAnswer = input("Are you sure? (yes/no) >").strip()
if sAnswer.casefold() == "yes":
break
elif sAnswer.casefold() == "no":
return #-----------------------------------------------------------
if oArgs.bDontSudo:
sSudo = ""
else:
sSudo = "sudo"
subprocess.check_call("{} rm -r -f {}/bin/device-floater".format(sSudo, sDestDir).split())
subprocess.check_call("{} rm -r -f {}/share/device-floater".format(sSudo, sDestDir).split())
if oArgs.bRemoveBuilds:
os.chdir("..")
subprocess.check_call("{} rm -r -f device-floater/build".format(sSudo).split())
if __name__ == "__main__":
main()
/*
* Copyright © 2016-2017 Stefano Marsili, <stemars@gmx.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
/*
* File: config.cc
*/
#include "config.h"
namespace stmi
{
namespace Config
{
const std::string& getVersionString()
{
static std::string s_sVersion = "@DEVICE_FLOATER_VERSION@";
return s_sVersion;
}
const std::string& getDataDir()
{
static std::string s_sDataDir = "@STMMI_DEVFLO_PKG_DATA_DIR@";
return s_sDataDir;
}
} // namespace Config
} // namespace stmi
/*
* Copyright © 2016-2017 Stefano Marsili, <stemars@gmx.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
/*
* File: config.h
*/
#ifndef STMI_CONFIG_H
#define STMI_CONFIG_H
#include <string>
namespace stmi
{
namespace Config
{
const std::string& getVersionString();
const std::string& getDataDir();
} // namespace Config
} // namespace stmi
#endif /* STMI_CONFIG_H */
/*
* Copyright © 2016-2017 Stefano Marsili, <stemars@gmx.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
/*
* File: devicefloater.cc
*/
#include "devicefloater.h"
#include <gdk/gdkx.h>
#include <X11/extensions/XI2.h>
#include <cassert>
#ifndef NDEBUG
#include <iostream>
#endif //NDEBUG
namespace stmi
{
DeviceFloater::DeviceFloater(const Glib::RefPtr<Gdk::Display>& refDisplay)
: m_p0XDisplay(nullptr)
, m_nConnectHandlerDeviceAdded(0)
, m_nConnectHandlerDeviceChanged(0)
, m_nConnectHandlerDeviceRemoved(0)
{
assert(refDisplay);
initXI(refDisplay);
initGdkDeviceManager(refDisplay);
refreshDevices();
}
DeviceFloater::~DeviceFloater()
{
deinitGdkDeviceManager();
}
void DeviceFloater::initXI(const Glib::RefPtr<Gdk::Display>& refDisplay)
{
GdkDisplay* p0GdkDisplay = refDisplay->gobj();
Display* p0XDisplay = gdk_x11_display_get_xdisplay(p0GdkDisplay);
int nXIOpcode;
int nEvent;
int nError;
if (!XQueryExtension( p0XDisplay, "XInputExtension", &nXIOpcode, &nEvent, &nError)) {
throw std::runtime_error("DeviceFloater: X Input extension not available.");
}
// We need XI 2.2
int nMajor = 2;
int nMinor = 2;
int nRes = XIQueryVersion( p0XDisplay, &nMajor, &nMinor );
if ( nRes == BadRequest ) {
throw std::runtime_error("DeviceFloater: No XI2 support. Server supports version " + std::to_string(nMajor) + "." + std::to_string(nMinor) + " only.");
} else if ( nRes != Success ) {
throw std::runtime_error("DeviceFloater: Internal Error! Probably a bug in Xlib.");
//} else {
// std::cout << "DeviceFloater: XI2 supported. Server provides version " << nMajor << "." << nMinor << std::endl;
}
m_p0XDisplay = p0XDisplay;
}
void gdkDeviceManagerCallbackCommon(GdkDeviceManager *p0DeviceManager, GdkDevice* p0Device, gpointer p0Data)
{
auto p0DeviceFloater = static_cast<DeviceFloater*>(p0Data);
p0DeviceFloater->onDeviceCommon(p0DeviceManager, p0Device);
}
void DeviceFloater::initGdkDeviceManager(const Glib::RefPtr<Gdk::Display>& refDisplay)
{
refGdkDeviceManager = refDisplay->get_device_manager();
assert(m_nConnectHandlerDeviceAdded == 0);
GdkDeviceManager* p0GdkDeviceManager = refGdkDeviceManager->gobj();
gpointer p0Data = this;
m_nConnectHandlerDeviceAdded = g_signal_connect(p0GdkDeviceManager, "device-added", G_CALLBACK(gdkDeviceManagerCallbackCommon), p0Data);
assert(m_nConnectHandlerDeviceAdded > 0);
m_nConnectHandlerDeviceChanged = g_signal_connect(p0GdkDeviceManager, "device-changed", G_CALLBACK(gdkDeviceManagerCallbackCommon), p0Data);
assert(m_nConnectHandlerDeviceChanged > 0);
m_nConnectHandlerDeviceRemoved = g_signal_connect(p0GdkDeviceManager, "device-removed", G_CALLBACK(gdkDeviceManagerCallbackCommon), p0Data);
assert(m_nConnectHandlerDeviceRemoved > 0);
}
void DeviceFloater::deinitGdkDeviceManager()
{
if (refGdkDeviceManager && (m_nConnectHandlerDeviceAdded > 0)) {
GdkDeviceManager* p0GdkDeviceManager = refGdkDeviceManager->gobj();
if (g_signal_handler_is_connected(p0GdkDeviceManager, m_nConnectHandlerDeviceAdded)) {
g_signal_handler_disconnect(p0GdkDeviceManager, m_nConnectHandlerDeviceAdded);
}
if (g_signal_handler_is_connected(p0GdkDeviceManager, m_nConnectHandlerDeviceChanged)) {
g_signal_handler_disconnect(p0GdkDeviceManager, m_nConnectHandlerDeviceChanged);
}
if (g_signal_handler_is_connected(p0GdkDeviceManager, m_nConnectHandlerDeviceRemoved)) {
g_signal_handler_disconnect(p0GdkDeviceManager, m_nConnectHandlerDeviceRemoved);
}
}
}
void DeviceFloater::onDeviceCommon(GdkDeviceManager*
#ifndef NDEBUG
p0DeviceManager
#endif //NDEBUG
, GdkDevice* p0Device)
{
assert(p0DeviceManager == refGdkDeviceManager->gobj());
GdkDeviceType eDeviceType = gdk_device_get_device_type(p0Device);
if (eDeviceType == GDK_DEVICE_TYPE_MASTER) {
// no masters, just slaves (floating or not)
return; //--------------------------------------------------------------
}
auto aSaveDevices = m_aDevices;
refreshDevices();
if (aSaveDevices == m_aDevices) {
return; //--------------------------------------------------------------
}
m_oDeviceChangedSignal.emit();
// for each slave not in saved devices call
decltype(aSaveDevices) aAddedSlaves;
for (auto& oData : m_aDevices) {
auto itSaved = std::find_if(aSaveDevices.begin(), aSaveDevices.end(),
[&oData](const SlaveDeviceData& oOldData)
{
return oData.m_nId == oOldData.m_nId;
}
);
if (itSaved == aSaveDevices.end()) {
aAddedSlaves.push_back(oData);
}
}
for (auto& oData : aAddedSlaves) {
m_oSlaveAddedSignal.emit(oData);
}
}
void DeviceFloater::addDevice(const XIDeviceInfo& oDev, DEVICE_TYPE eType)
{
SlaveDeviceData oData;
oData.m_nId = oDev.deviceid;
oData.m_nMasterId = ((eType == DEVICE_TYPE_FLOATING) ? -777 : oDev.attachment);
oData.m_eType = eType;
oData.m_sName = oDev.name;
oData.m_nTotKeys = 0;
XIAnyClassInfo** p0Classes = oDev.classes;
const int32_t nTotClasses = oDev.num_classes;
for (int32_t nCurClass = 0; nCurClass < nTotClasses; ++nCurClass) {
if (p0Classes[nCurClass]->type == XIKeyClass) {
XIKeyClassInfo *p0KeyClass = (XIKeyClassInfo*)p0Classes[nCurClass];
oData.m_nTotKeys = std::max(p0KeyClass->num_keycodes, oData.m_nTotKeys);
}
}
m_aDevices.emplace_back(oData);
}
void DeviceFloater::refreshDevices()
{
static_assert(sizeof(int) == sizeof(int32_t), "");
m_aDevices.clear();
assert(m_p0XDisplay != nullptr);
int32_t nTotDevices;
XIDeviceInfo* pInfo = XIQueryDevice(m_p0XDisplay, XIAllDevices, &nTotDevices);
//std::cout << "DeviceFloater::refreshDevices() nTotDevices=" << nTotDevices << std::endl;
// Add floating devices
for (int32_t nCurDevice = 0; nCurDevice < nTotDevices; ++nCurDevice) {
const XIDeviceInfo& oDev = pInfo[nCurDevice];
if (oDev.enabled == 0) {
continue; //for
}
DEVICE_TYPE eType = DEVICE_TYPE_FLOATING;
if (oDev.use == XISlaveKeyboard) {
eType = DEVICE_TYPE_KEYBOARD;
} else if (oDev.use == XISlavePointer) {
eType = DEVICE_TYPE_POINTER;
} else if (oDev.use == XIFloatingSlave) {
} else {
continue; //for
}
addDevice(oDev, eType);
}
XIFreeDeviceInfo(pInfo);
//
std::sort(m_aDevices.begin(), m_aDevices.end());
}
bool DeviceFloater::floatDevice(int32_t nDeviceId)
{
XIDetachSlaveInfo oDetach;
oDetach.type = XIDetachSlave;
oDetach.deviceid = nDeviceId;
const int32_t nRet = XIChangeHierarchy(m_p0XDisplay, (XIAnyHierarchyChangeInfo*)&oDetach, 1);
return (nRet == 0);
}
} // namespace stmi
/*
* Copyright © 2016-2017 Stefano Marsili, <stemars@gmx.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
/*
* File: devicefloater.h
*/
#ifndef STMI_DEVICE_FLOATER_H
#define STMI_DEVICE_FLOATER_H
#include <gtkmm.h>
#include <sigc++/signal.h>
#include <X11/extensions/XInput2.h>
namespace stmi
{
class DeviceFloater
{
public:
/* throws */
DeviceFloater(const Glib::RefPtr<Gdk::Display>& refDisplay);
virtual ~DeviceFloater();
enum DEVICE_TYPE {
DEVICE_TYPE_FLOATING = 0
, DEVICE_TYPE_KEYBOARD = 1
, DEVICE_TYPE_POINTER = 2
};
struct SlaveDeviceData
{
int32_t m_nId;
int32_t m_nMasterId;
std::string m_sName;
DEVICE_TYPE m_eType;
int32_t m_nTotKeys;
bool operator==(const SlaveDeviceData& oOther) const
{
return (m_nId == oOther.m_nId) && (m_sName == oOther.m_sName)
&& (m_eType == oOther.m_eType) && (m_nTotKeys == oOther.m_nTotKeys);
}
bool operator<(const SlaveDeviceData& oOther) const
{
if (m_eType < oOther.m_eType) {
return true;
} else if (m_eType > oOther.m_eType) {
return false;
}
if (m_nTotKeys > oOther.m_nTotKeys) { // descending order!
return true;
} else if (m_nTotKeys < oOther.m_nTotKeys) {
return false;
}
return (m_nId < oOther.m_nId);
}
};
/* Gets the devices. */
inline const std::vector<SlaveDeviceData>& getDevices() { return m_aDevices; }