summaryrefslogtreecommitdiffhomepage
path: root/Tobii-EyeX/samples/ActivatableBoardGame
diff options
context:
space:
mode:
Diffstat (limited to 'Tobii-EyeX/samples/ActivatableBoardGame')
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.cpp54
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.icobin0 -> 2998 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.rcbin0 -> 8056 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.vcxproj193
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.vcxproj.filters70
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Board.cpp220
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Board.h110
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/BoardWindow.cpp488
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/BoardWindow.h94
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/ActivatableBoardGame.lastbuildstate2
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.command.1.tlogbin0 -> 4002 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.read.1.tlogbin0 -> 97924 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.write.1.tlogbin0 -> 2792 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.command.1.tlogbin0 -> 2284 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.read.1.tlogbin0 -> 4972 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.write.1.tlogbin0 -> 1100 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.command.1.tlogbin0 -> 432 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.read.1.tlogbin0 -> 2714 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.write.1.tlogbin0 -> 286 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.log8
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.objbin0 -> 131239 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.pchbin0 -> 8323072 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.resbin0 -> 7312 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/Board.objbin0 -> 257029 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/BoardWindow.objbin0 -> 348456 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/EyeXHost.objbin0 -> 353721 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/stdafx.objbin0 -> 142759 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/vc140.idbbin0 -> 1330176 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Debug/vc140.pdbbin0 -> 1552384 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/EyeXHost.cpp377
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/EyeXHost.h111
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Observer.h13
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/Resource.hbin0 -> 2126 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/small.icobin0 -> 2998 bytes
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/stdafx.cpp3
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/stdafx.h17
-rwxr-xr-xTobii-EyeX/samples/ActivatableBoardGame/targetver.h8
37 files changed, 1768 insertions, 0 deletions
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.cpp b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.cpp
new file mode 100755
index 0000000..4fbe055
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.cpp
@@ -0,0 +1,54 @@
+/*
+ * ActivatableBoardGame sample:
+ * This is an example that demonstrates the use of Activatable interactors in the context of a board game.
+ *
+ * Copyright 2013 Tobii Technology AB. All rights reserved.
+ */
+
+#include "stdafx.h"
+#include <windows.h>
+#include <objidl.h>
+#include <gdiplus.h>
+#include "Resource.h"
+#include "Board.h"
+#include "BoardWindow.h"
+
+#pragma comment (lib, "Gdiplus.lib")
+
+// Application entry point.
+int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
+ _In_opt_ HINSTANCE hPrevInstance,
+ _In_ LPTSTR lpCmdLine,
+ _In_ int nCmdShow)
+{
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+
+ // initialize the GDI+ library.
+ ULONG_PTR gdiplusToken;
+ Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+ Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+
+ // initialize the Board and the BoardWindow.
+ // these will be un-initialized automatically when they fall out of scope.
+ Board board(8);
+ BoardWindow::RegisterWindowClass(hInstance);
+ BoardWindow window(board, hInstance, nCmdShow);
+
+ HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GOBANG));
+
+ // Main message loop
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ Gdiplus::GdiplusShutdown(gdiplusToken);
+
+ return (int) msg.wParam;
+}
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.ico b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.ico
new file mode 100755
index 0000000..449296f
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.ico
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.rc b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.rc
new file mode 100755
index 0000000..718dee1
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.rc
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.vcxproj b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.vcxproj
new file mode 100755
index 0000000..5b82b9c
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.vcxproj
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{2732E876-973B-4453-AA9F-D306EFB11922}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>ActivatableBoardGame</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v140</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>..\..\lib\x86</AdditionalLibraryDirectories>
+ </Link>
+ <Manifest>
+ <EnableDpiAwareness>true</EnableDpiAwareness>
+ </Manifest>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>..\..\lib\x64</AdditionalLibraryDirectories>
+ </Link>
+ <Manifest>
+ <EnableDpiAwareness>true</EnableDpiAwareness>
+ </Manifest>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalLibraryDirectories>..\..\lib\x86</AdditionalLibraryDirectories>
+ </Link>
+ <Manifest>
+ <EnableDpiAwareness>true</EnableDpiAwareness>
+ </Manifest>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalLibraryDirectories>..\..\lib\x64</AdditionalLibraryDirectories>
+ </Link>
+ <Manifest>
+ <EnableDpiAwareness>true</EnableDpiAwareness>
+ </Manifest>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="Board.h" />
+ <ClInclude Include="BoardWindow.h" />
+ <ClInclude Include="EyeXHost.h" />
+ <ClInclude Include="Observer.h" />
+ <ClInclude Include="Resource.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Board.cpp" />
+ <ClCompile Include="BoardWindow.cpp" />
+ <ClCompile Include="ActivatableBoardGame.cpp" />
+ <ClCompile Include="EyeXHost.cpp" />
+ <ClCompile Include="stdafx.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="ActivatableBoardGame.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="ActivatableBoardGame.ico" />
+ <Image Include="small.ico" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <Import Project="..\CopyEyeXDllToOutputDirectory.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.vcxproj.filters b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.vcxproj.filters
new file mode 100755
index 0000000..9baf12a
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/ActivatableBoardGame.vcxproj.filters
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="stdafx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="targetver.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Board.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BoardWindow.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Observer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="EyeXHost.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="stdafx.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ActivatableBoardGame.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Board.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BoardWindow.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="EyeXHost.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="ActivatableBoardGame.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="small.ico">
+ <Filter>Resource Files</Filter>
+ </Image>
+ <Image Include="ActivatableBoardGame.ico">
+ <Filter>Resource Files</Filter>
+ </Image>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Board.cpp b/Tobii-EyeX/samples/ActivatableBoardGame/Board.cpp
new file mode 100755
index 0000000..e59fc92
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Board.cpp
@@ -0,0 +1,220 @@
+/*
+ * ActivatableBoardGame sample:
+ * This is an example that demonstrates the use of Activatable interactors in the context of a board game.
+ *
+ * Copyright 2013 Tobii Technology AB. All rights reserved.
+ */
+
+#include "stdafx.h"
+#include "Board.h"
+#include <cassert>
+#include <vector>
+#include "Observer.h"
+
+// initialize the random number generator.
+auto const seed = std::random_device()();
+std::mt19937 Board::_randomNumberGenerator(seed);
+
+Board::Board(int size)
+ : _size(size), _board(nullptr), _boardChangedObserver(nullptr)
+{
+ _board = new Marker[_size * _size];
+ BeginNewGame();
+}
+
+Board::~Board()
+{
+ delete[] _board;
+}
+
+void Board::InitBoard()
+{
+ for (int i = 0; i < _size; ++i)
+ {
+ for (int j = 0; j < _size; ++j)
+ {
+ SetMarkerAt(Position(i, j), Marker::None);
+ }
+ }
+
+ SetMarkerAt(Position((_size - 1) / 2, (_size - 1) / 2), Marker::X);
+ SetMarkerAt(Position((_size - 1) / 2, (_size - 1) / 2 + 1), Marker::O);
+ SetMarkerAt(Position((_size - 1) / 2 + 1, (_size - 1) / 2), Marker::O);
+ SetMarkerAt(Position((_size - 1) / 2 + 1, (_size - 1) / 2 + 1), Marker::X);
+}
+
+Board::Marker Board::GetMarkerAt(Position position) const
+{
+ assert(IsValidPosition(position));
+
+ return _board[position.column + position.row * _size];
+}
+
+void Board::SetMarkerAt(Position position, Marker marker)
+{
+ assert(IsValidPosition(position));
+
+ _board[position.column + position.row * _size] = marker;
+
+ NotifyObserver();
+}
+
+void Board::MakeHumanPlayerMove(Position position)
+{
+ if (_playerInTurn == Marker::X &&
+ !IsGameOver() &&
+ GetMarkerAt(position) == Marker::None)
+ {
+ MakeMove(position);
+
+ if (!IsGameOver())
+ {
+ MakeAIPlayerMove();
+ }
+ }
+}
+
+bool Board::CanMakeMoveAt(Position position) const
+{
+ return IsValidPosition(position) &&
+ GetMarkerAt(position) == Marker::None;
+}
+
+void Board::BeginNewGame()
+{
+ InitBoard();
+ _playerInTurn = Marker::X;
+ _winner = Marker::None;
+}
+
+bool Board::IsValidPosition(Position position) const
+{
+ return 0 <= position.row && position.row < _size &&
+ 0 <= position.column && position.column < _size;
+}
+
+void Board::MakeAIPlayerMove()
+{
+ // generate the list of all possible moves. not that they are good or anything, just possible.
+ std::vector<Position> possibleMoves;
+ for (int i = 0; i < _size; i++)
+ {
+ for (int j = 0; j < _size; j++)
+ {
+ Position position(i, j);
+ if (GetMarkerAt(position) == Marker::None)
+ {
+ possibleMoves.push_back(position);
+ }
+ }
+ }
+
+ // since we check whether the game is a draw before calling this method, there should always be at least one possible move.
+ assert(possibleMoves.size() > 0);
+
+ // pick a move at random.
+ std::uniform_int_distribution<int> idist(0, (int)possibleMoves.size() - 1);
+ int randomMoveIndex = idist(_randomNumberGenerator);
+ MakeMove(possibleMoves[randomMoveIndex]);
+}
+
+void Board::MakeMove(Position position)
+{
+ SetMarkerAt(position, _playerInTurn);
+ _playerInTurn = (_playerInTurn == Marker::O) ? Marker::X : Marker::O;
+
+ DetectWinner(position);
+ DetectDrawGame();
+}
+
+void Board::DetectWinner(Position position)
+{
+ auto marker = GetMarkerAt(position);
+
+ for (int i = 0; i < OrientationMaxValue; ++i)
+ {
+ Orientation orientation = (Orientation)i;
+ int sequenceLength(1);
+
+ bool directions[] = { true, false };
+
+ for each (auto forward in directions)
+ {
+ auto neighbor = GetAdjacentPosition(position, orientation, forward);
+ while (IsValidPosition(neighbor) && GetMarkerAt(neighbor) == marker)
+ {
+ sequenceLength++;
+ neighbor = GetAdjacentPosition(neighbor, orientation, forward);
+ }
+ }
+
+ if (sequenceLength >= WinningSequenceLength)
+ {
+ _winner = marker;
+ _playerInTurn = Marker::None;
+ NotifyObserver();
+ }
+ }
+}
+
+void Board::DetectDrawGame()
+{
+ // if there is an empty position, the game isn't a draw (yet).
+ for (int i = 0; i < _size; ++i)
+ {
+ for (int j = 0; j < _size; ++j)
+ {
+ if (GetMarkerAt(Position(i, j)) == Marker::None)
+ {
+ return;
+ }
+ }
+ }
+
+ // no empty positions found: it's a draw.
+ _playerInTurn = Marker::None;
+ NotifyObserver();
+}
+
+Board::Position Board::GetAdjacentPosition(Position position, Orientation orientation, bool forward) const
+{
+ Position delta(-1, -1);
+ switch (orientation)
+ {
+ case Orientation::North:
+ delta = Position(+1, 0);
+ break;
+ case Orientation::East:
+ delta = Position(0, +1);
+ break;
+ case Orientation::Northeast:
+ delta = Position(+1, +1);
+ break;
+ case Orientation::Southeast:
+ delta = Position(-1, +1);
+ break;
+ default:
+ assert(false);
+ }
+
+ if (!forward)
+ {
+ delta.row = -delta.row;
+ delta.column = -delta.column;
+ }
+
+ return Position(position.row + delta.row, position.column + delta.column);
+}
+
+void Board::RegisterBoardChangedObserver(Observer* boardChangedObserver)
+{
+ _boardChangedObserver = boardChangedObserver;
+}
+
+void Board::NotifyObserver()
+{
+ if (_boardChangedObserver)
+ {
+ _boardChangedObserver->SubjectChanged();
+ }
+}
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Board.h b/Tobii-EyeX/samples/ActivatableBoardGame/Board.h
new file mode 100755
index 0000000..d6abbe3
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Board.h
@@ -0,0 +1,110 @@
+/*
+ * Board class: Implements the game logic and the not-so-clever AI player for the exciting Gobang game.
+ *
+ * Copyright 2013 Tobii Technology AB. All rights reserved.
+ */
+
+#pragma once
+
+#include <random>
+
+class Observer;
+
+class Board
+{
+public:
+ // Represents a position on the board.
+ struct Position
+ {
+ int row;
+ int column;
+
+ Position(int paramRow, int paramColumn) : row(paramRow), column(paramColumn) { }
+ };
+
+ // Possible contents of a board position.
+ enum Marker
+ {
+ None,
+ X,
+ O
+ };
+
+ Board(int size);
+ virtual ~Board();
+
+ // gets the size of the board, which is assumed to be square: the number of positions on each side.
+ int Size() const { return _size; }
+
+ // indicates whether the game is over.
+ bool IsGameOver() const { return _playerInTurn == Marker::None; }
+
+ // gets the "name" of the lucky winner.
+ Marker GetWinner() const { return _winner; }
+
+ // gets what's on the board at a given position.
+ Marker GetMarkerAt(Position position) const;
+
+ // indicates whether it is possible to place a marker at a given position.
+ bool CanMakeMoveAt(Position position) const;
+
+ // makes a move for the human player (which will also trigger an AI move).
+ void MakeHumanPlayerMove(Position position);
+
+ // restarts the game.
+ void BeginNewGame();
+
+ // registers an observer that is notified when the board has changed.
+ void RegisterBoardChangedObserver(Observer* boardChangedObserver);
+
+private:
+ enum Orientation
+ {
+ North,
+ East,
+ Northeast,
+ Southeast,
+ OrientationMaxValue
+ };
+
+ // tests whether a position is on the board.
+ bool IsValidPosition(Position position) const;
+
+ // gets a position adjacent to the given one, in a particular direction.
+ Position GetAdjacentPosition(Position position, Orientation orientation, bool forward) const;
+
+ // prepares the board for a new, exciting game.
+ void InitBoard();
+
+ // lets the miserable AI player make a move.
+ void MakeAIPlayerMove();
+
+ // makes a move: places a marker and checks whether anyone has won or if it's a draw game.
+ void MakeMove(Position position);
+
+ // places a marker at the given position.
+ void SetMarkerAt(Position position, Marker marker);
+
+ // checks if the given position is part of a winning sequence.
+ void DetectWinner(Position position);
+
+ // checks if the game is a draw.
+ void DetectDrawGame();
+
+ // notifies the observer, if any, that the board has changed.
+ void NotifyObserver();
+
+ static const int WinningSequenceLength = 5;
+
+ static std::mt19937 _randomNumberGenerator;
+
+ int _size;
+ Marker* _board;
+ Marker _playerInTurn;
+ Marker _winner;
+ Observer* _boardChangedObserver;
+
+ // private copy constructor and operator making the class non-copyable (declared but not implemented).
+ Board(const Board&);
+ Board& operator = (const Board&);
+};
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/BoardWindow.cpp b/Tobii-EyeX/samples/ActivatableBoardGame/BoardWindow.cpp
new file mode 100755
index 0000000..7f8b9a7
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/BoardWindow.cpp
@@ -0,0 +1,488 @@
+/*
+ * ActivatableBoardGame sample:
+ * This is an example that demonstrates the use of Activatable interactors in the context of a board game.
+ *
+ * Copyright 2013 Tobii Technology AB. All rights reserved.
+ */
+
+#include "stdafx.h"
+#include "BoardWindow.h"
+#include "Board.h"
+#include "resource.h"
+
+// window messages used for notifications from the EyeXHost.
+#define WM_EYEX_HOST_STATUS_CHANGED WM_USER + 0
+#define WM_FOCUSED_REGION_CHANGED WM_USER + 1
+#define WM_REGION_ACTIVATED WM_USER + 2
+
+// color scheme.
+const Gdiplus::Color BoardWindow::BackgroundGazeInteractionFunctionalColor = Gdiplus::Color(134, 152, 172); // blue
+const Gdiplus::Color BoardWindow::BackgroundMouseOnlyColor = Gdiplus::Color(164, 156, 153); // grey
+const Gdiplus::Color BoardWindow::GridColor = Gdiplus::Color(110, 57, 88, 109); // dark blue
+const Gdiplus::Color BoardWindow::MarkerColor = Gdiplus::Color(242, 233, 216); // off white
+const Gdiplus::Color BoardWindow::HighlightColor = Gdiplus::Color(20, 242, 233, 216); // transparent off white
+const Gdiplus::Color BoardWindow::WonMessageColor = Gdiplus::Color(200, 64, 82, 60); // transparent dark green
+const Gdiplus::Color BoardWindow::LostMessageColor = Gdiplus::Color(200, 155, 109, 135); // transparent grape
+
+// constants.
+const int BoardWindow::SquareSize = 100;
+const int BoardWindow::MarkerMargin = 14;
+const int BoardWindow::MarkerDiameter = SquareSize - MarkerMargin * 2;
+const TCHAR* BoardWindow::WindowClassName = _T("GobangBoard");
+
+BoardWindow::BoardWindow(Board& board, HINSTANCE hInstance, int nCmdShow)
+ : _board(board), _hInstance(hInstance), _hWnd(0), _hMenu(0), _leftMargin(0), _upperMargin(0)
+{
+ // create the window instance.
+ _hWnd = CreateWindow(
+ WindowClassName,
+ _T("Gobang!"),
+ WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ (_board.Size() + 1) * SquareSize,
+ (_board.Size() + 1) * SquareSize + 40,
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ if (!_hWnd)
+ {
+ throw new std::runtime_error("Could not create main window.");
+ }
+
+ _hMenu = GetMenu(_hWnd);
+
+ // write the "this" pointer to the extra window memory so that we can reference back to this
+ // object from the window function.
+ SetWindowLongPtr(_hWnd, 0, (LONG_PTR)this);
+
+ ShowWindow(_hWnd, nCmdShow);
+ UpdateWindow(_hWnd);
+
+ _board.RegisterBoardChangedObserver(this);
+
+ // initialize the EyeX host and the activatable regions.
+ _eyeXHost.Init(_hWnd, WM_EYEX_HOST_STATUS_CHANGED, WM_FOCUSED_REGION_CHANGED, WM_REGION_ACTIVATED);
+ UpdateActivatableRegions();
+}
+
+BoardWindow::~BoardWindow()
+{
+}
+
+void BoardWindow::RegisterWindowClass(HINSTANCE hInstance)
+{
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = sizeof(void*); // make room for the "this" pointer.
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GOBANG));
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = 0;
+ wcex.lpszMenuName = MAKEINTRESOURCE(IDC_GOBANG);
+ wcex.lpszClassName = WindowClassName;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
+
+ RegisterClassEx(&wcex);
+}
+
+// Callback function invoked when the Board has changed.
+void BoardWindow::SubjectChanged()
+{
+ InvalidateRect(_hWnd, NULL, FALSE);
+ UpdateActivatableRegions();
+}
+
+// Callback function invoked from the message loop to process a Windows message.
+LRESULT CALLBACK BoardWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int wmId, wmEvent;
+ PAINTSTRUCT ps;
+ HDC hdc;
+
+ // read the "this" pointer from extra window memory.
+ BoardWindow* instance = reinterpret_cast<BoardWindow*>(GetWindowLongPtr(hWnd, 0));
+
+ switch (message)
+ {
+ case WM_COMMAND:
+ wmId = LOWORD(wParam);
+ wmEvent = HIWORD(wParam);
+
+ // Parse the menu selections:
+ switch (wmId)
+ {
+ case IDM_NEWGAME:
+ instance->OnNewGameClicked();
+ break;
+
+ case IDM_ABOUT:
+ DialogBox(instance->_hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
+ break;
+
+ case IDM_EXIT:
+ DestroyWindow(hWnd);
+ break;
+
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ {
+ // mouse button pressed; possibly on a board square.
+ auto point = MAKEPOINTS(lParam);
+ instance->OnSquareClicked(point);
+ }
+ break;
+
+ case WM_PAINT:
+ instance->UpdateMargins();
+ hdc = BeginPaint(hWnd, &ps);
+ instance->OnDraw(hdc);
+ EndPaint(hWnd, &ps);
+ break;
+
+ case WM_ERASEBKGND:
+ // no background erasing needed since our OnDraw method draws the entire window.
+ return TRUE;
+
+ case WM_EYEX_HOST_STATUS_CHANGED:
+ // the background color of the board indicates whether we have a working connection to the engine or not.
+ // so, when the status changes, we force a redraw of the window.
+ InvalidateRect(hWnd, 0, FALSE);
+ break;
+
+ case WM_FOCUSED_REGION_CHANGED:
+ // redraw to display the new focus state.
+ InvalidateRect(hWnd, 0, FALSE);
+ break;
+
+ case WM_REGION_ACTIVATED:
+ instance->OnSquareActivated((UINT)wParam);
+ break;
+
+ case WM_WINDOWPOSCHANGED:
+ // the window was moved, so we need to refresh the screen bounds of our activatable regions.
+ instance->UpdateActivatableRegions();
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ case WM_KEYUP:
+ // trigger an activation command when space is released.
+ if (VK_SPACE == wParam)
+ {
+ instance->_eyeXHost.TriggerActivation();
+ }
+ break;
+
+ case WM_KEYDOWN:
+ // trigger activation mode on when space is pressed down (so activation focus changed events are received, and a highlight can be drawn).
+ if (VK_SPACE == wParam)
+ {
+ instance->_eyeXHost.TriggerActivationModeOn();
+ }
+ break;
+
+
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+
+ return 0;
+}
+
+void BoardWindow::OnDraw(HDC hdc)
+{
+ // use double-buffer drawing to speed up the drawing and reduce flicker.
+ // (the drawing is performed on a bitmap, which is then blitted to the screen in one fell swoop.)
+
+ RECT rect;
+ GetClientRect(_hWnd, &rect);
+ Gdiplus::Bitmap bitmap(rect.right - rect.left, rect.bottom - rect.top);
+ Gdiplus::Graphics graphics(&bitmap);
+
+ // draw the background in a color which depends on the state of the connection to the engine.
+ // blue if the connection is functional, gray otherwise.
+ Gdiplus::Color backgroundColor(BackgroundGazeInteractionFunctionalColor);
+ if (!_eyeXHost.IsFunctional())
+ {
+ backgroundColor = BackgroundMouseOnlyColor;
+ }
+ Gdiplus::SolidBrush backgroundBrush(backgroundColor);
+ graphics.FillRectangle(&backgroundBrush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+
+ // draw the grid
+ DrawGrid(&graphics);
+
+ // draw the markers
+ Gdiplus::Pen markerPen(MarkerColor, 5.0F);
+ for (int row = 0; row < _board.Size(); row++)
+ {
+ for (int col = 0; col < _board.Size(); col++)
+ {
+ switch (_board.GetMarkerAt(Board::Position(row, col)))
+ {
+ case Board::Marker::X:
+ DrawXMarker(&graphics, &markerPen, row, col);
+ break;
+
+ case Board::Marker::O:
+ DrawOMarker(&graphics, &markerPen, row, col);
+ break;
+ }
+ }
+ }
+
+ // draw the focus highlight
+ int focusedRegionId = _eyeXHost.GetFocusedRegionId();
+ if (focusedRegionId >= 0)
+ {
+ DrawHighlight(&graphics, RegionIdToBoardRow(focusedRegionId), RegionIdToBoardColumn(focusedRegionId));
+ }
+
+ // draw the game over message
+ if (_board.IsGameOver())
+ {
+ WCHAR* message;
+ Gdiplus::Color messageColor(0,0,0);
+ switch (_board.GetWinner())
+ {
+ case Board::Marker::X:
+ message = L"YOU WON :)";
+ messageColor = WonMessageColor;
+ break;
+
+ case Board::Marker::O:
+ message = L"YOU LOST :(";
+ messageColor = LostMessageColor;
+ break;
+
+ default:
+ message = L"DRAW";
+ messageColor = LostMessageColor;
+ break;
+ }
+
+ DrawGameOver(&graphics, message, messageColor);
+ }
+
+ Gdiplus::Graphics screen(hdc);
+ screen.DrawImage(&bitmap, 0, 0);
+}
+
+void BoardWindow::DrawGrid(Gdiplus::Graphics *graphics)
+{
+ const int lineMargin = 14;
+
+ Gdiplus::Pen gridPen(GridColor);
+ gridPen.SetDashStyle(Gdiplus::DashStyleDash);
+
+ // horizontal lines
+ auto x0 = _leftMargin - lineMargin;
+ auto x1 = _leftMargin + _board.Size() * SquareSize + lineMargin;
+ for (int i = 0; i <= _board.Size(); i++)
+ {
+ auto y = _upperMargin + i * SquareSize;
+ graphics->DrawLine(&gridPen, x0, y, x1, y);
+ }
+
+ // vertical lines
+ auto y0 = _upperMargin - lineMargin;
+ auto y1 = _upperMargin + _board.Size() * SquareSize + lineMargin;
+ for (int j = 0; j <= _board.Size(); j++)
+ {
+ auto x = _leftMargin + j * SquareSize;
+ graphics->DrawLine(&gridPen, x, y0, x, y1);
+ }
+
+ // dots that guide the eye to the center of the square
+ Gdiplus::SolidBrush gridBrush(GridColor);
+ for (int i = 0; i <= _board.Size(); i++)
+ {
+ for (int j = 0; j <= _board.Size(); j++)
+ {
+ auto x = _leftMargin + (j + 0.5) * SquareSize;
+ auto y = _upperMargin + (i + 0.5) * SquareSize;
+ graphics->FillEllipse(&gridBrush, (Gdiplus::REAL)(x - 1), (Gdiplus::REAL)(y - 1), (Gdiplus::REAL)3, (Gdiplus::REAL)3);
+ }
+ }
+}
+
+void BoardWindow::DrawHighlight(Gdiplus::Graphics *graphics, INT row, INT column)
+{
+ Gdiplus::SolidBrush highlightBrush(HighlightColor);
+
+ int x = BoardToClientAreaX(column) + 1;
+ int y = BoardToClientAreaY(row) + 1;
+
+ graphics->FillRectangle(&highlightBrush, x, y, SquareSize - 1, SquareSize - 1);
+}
+
+void BoardWindow::DrawOMarker(Gdiplus::Graphics *graphics, Gdiplus::Pen *markerPen, INT row, INT column)
+{
+ int x = BoardToClientAreaX(column) + MarkerMargin;
+ int y = BoardToClientAreaY(row) + MarkerMargin;
+
+ graphics->DrawEllipse(markerPen, x, y, MarkerDiameter, MarkerDiameter);
+}
+
+void BoardWindow::DrawXMarker(Gdiplus::Graphics *graphics, Gdiplus::Pen *markerPen, INT row, INT column)
+{
+ int x = BoardToClientAreaX(column) + MarkerMargin;
+ int y = BoardToClientAreaY(row) + MarkerMargin;
+
+ graphics->DrawLine(markerPen, x, y + MarkerDiameter, x + MarkerDiameter, y);
+ graphics->DrawLine(markerPen, x, y, x + MarkerDiameter, y + MarkerDiameter);
+}
+
+void BoardWindow::DrawGameOver(Gdiplus::Graphics *graphics, WCHAR* message, const Gdiplus::Color& messageColor)
+{
+ Gdiplus::Font myFont(L"Arial", 72);
+
+ RECT rect;
+ GetClientRect(_hWnd, &rect);
+ Gdiplus::RectF layoutRect((float)rect.left, (float)rect.top, (float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
+
+ Gdiplus::StringFormat format;
+ format.SetAlignment(Gdiplus::StringAlignmentCenter);
+ format.SetLineAlignment(Gdiplus::StringAlignmentCenter);
+
+ Gdiplus::SolidBrush messageBrush(messageColor);
+
+ graphics->DrawString(
+ message,
+ (INT)wcslen(message),
+ &myFont,
+ layoutRect,
+ &format,
+ &messageBrush);
+}
+
+INT BoardWindow::BoardToClientAreaX(INT column)
+{
+ return column * SquareSize + _leftMargin;
+}
+
+INT BoardWindow::BoardToClientAreaY(INT row)
+{
+ return row * SquareSize + _upperMargin;
+}
+
+INT BoardWindow::ClientAreaToBoardColumn(INT x)
+{
+ return (x - _upperMargin) / SquareSize;
+}
+
+INT BoardWindow::ClientAreaToBoardRow(INT y)
+{
+ return (y - _leftMargin) / SquareSize;
+}
+
+int BoardWindow::BoardPositionToRegionId(int row, int column)
+{
+ return column + row * _board.Size();
+}
+
+int BoardWindow::RegionIdToBoardRow(int regionId)
+{
+ return regionId / _board.Size();
+}
+
+int BoardWindow::RegionIdToBoardColumn(int regionId)
+{
+ return regionId % _board.Size();
+}
+
+void BoardWindow::UpdateMargins()
+{
+ RECT rect;
+ GetClientRect(_hWnd, &rect);
+ _upperMargin = ((rect.bottom - rect.top) - _board.Size() * SquareSize) / 2;
+ _leftMargin = ((rect.right - rect.left) - _board.Size() * SquareSize) / 2;
+}
+
+void BoardWindow::OnSquareClicked(POINTS point)
+{
+ MakeHumanPlayerMove(ClientAreaToBoardRow(point.y), ClientAreaToBoardColumn(point.x));
+}
+
+void BoardWindow::OnSquareActivated(UINT regionId)
+{
+ MakeHumanPlayerMove(RegionIdToBoardRow(regionId), RegionIdToBoardColumn(regionId));
+}
+
+void BoardWindow::MakeHumanPlayerMove(int row, int column)
+{
+ Board::Position position(row, column);
+ if (_board.CanMakeMoveAt(position))
+ {
+ _board.MakeHumanPlayerMove(position);
+ }
+}
+
+void BoardWindow::UpdateActivatableRegions()
+{
+ std::vector<EyeXHost::ActivatableRegion> regions;
+
+ if (!_board.IsGameOver())
+ {
+ for (int row = 0; row < _board.Size(); row++)
+ {
+ for (int column = 0; column < _board.Size(); column++)
+ {
+ POINT point;
+ point.x = BoardToClientAreaX(column);
+ point.y = BoardToClientAreaY(row);
+ ClientToScreen(_hWnd, &point);
+
+ RECT bounds;
+ bounds.left = point.x;
+ bounds.top = point.y;
+ bounds.right = point.x + SquareSize;
+ bounds.bottom = point.y + SquareSize;
+
+ regions.push_back(EyeXHost::ActivatableRegion(BoardPositionToRegionId(row, column), bounds));
+ }
+ }
+ }
+
+ _eyeXHost.SetActivatableRegions(regions);
+}
+
+void BoardWindow::OnNewGameClicked()
+{
+ _board.BeginNewGame();
+ UpdateActivatableRegions();
+}
+
+// Message handler for about box.
+INT_PTR CALLBACK BoardWindow::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(lParam);
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ return (INT_PTR)TRUE;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+ {
+ EndDialog(hDlg, LOWORD(wParam));
+ return (INT_PTR)TRUE;
+ }
+ break;
+ }
+
+ return (INT_PTR)FALSE;
+}
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/BoardWindow.h b/Tobii-EyeX/samples/ActivatableBoardGame/BoardWindow.h
new file mode 100755
index 0000000..50dc346
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/BoardWindow.h
@@ -0,0 +1,94 @@
+/*
+ * BoardWindow class: Responsible for the game window and the GDI+ drawing.
+ * Listens to notifications from the Board.
+ * Owns the EyeX host.
+ *
+ * Copyright 2013 Tobii Technology AB. All rights reserved.
+ */
+
+#pragma once
+
+#include <Windows.h>
+#include <objidl.h>
+#include <gdiplus.h>
+#include "Observer.h"
+#include "EyeXHost.h"
+
+class Board;
+
+class BoardWindow : Observer
+{
+public:
+ BoardWindow(Board& board, HINSTANCE hInstance, int nCmdShow);
+ virtual ~BoardWindow();
+
+ // registers the window class; must be called once at application initialization.
+ static void RegisterWindowClass(HINSTANCE hInstance);
+
+ // From Observer
+ void SubjectChanged();
+
+private:
+ // window procedure for the main window.
+ static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+
+ // window procedure for the About dialog.
+ static INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
+
+ // GDI+ drawing methods.
+ void OnDraw(HDC hdc);
+ void DrawGrid(Gdiplus::Graphics *graphics);
+ void DrawHighlight(Gdiplus::Graphics* graphics, int row, int column);
+ void DrawXMarker(Gdiplus::Graphics* graphics, Gdiplus::Pen* pen, int row, int column);
+ void DrawOMarker(Gdiplus::Graphics* graphics, Gdiplus::Pen* pen, int row, int column);
+ void DrawGameOver(Gdiplus::Graphics* graphics, WCHAR* message, const Gdiplus::Color& messageColor);
+
+ // coordinate/board position mapping methods.
+ int BoardToClientAreaX(int column);
+ int BoardToClientAreaY(int row);
+ int ClientAreaToBoardColumn(int x);
+ int ClientAreaToBoardRow(int y);
+
+ // region id/board position mapping methods.
+ int BoardPositionToRegionId(int row, int column);
+ int RegionIdToBoardRow(int regionId);
+ int RegionIdToBoardColumn(int regionId);
+
+ // re-calculates the margins based on the size of the window.
+ void UpdateMargins();
+
+ // reports all vacant board positions as activatable regions to the EyeX host.
+ void UpdateActivatableRegions();
+
+ // makes a move at the given position.
+ void MakeHumanPlayerMove(int row, int column);
+
+ // event handlers.
+ void OnSquareClicked(POINTS point);
+ void OnSquareActivated(UINT regionId);
+ void OnNewGameClicked();
+
+ static const Gdiplus::Color BackgroundGazeInteractionFunctionalColor;
+ static const Gdiplus::Color BackgroundMouseOnlyColor;
+ static const Gdiplus::Color GridColor;
+ static const Gdiplus::Color MarkerColor;
+ static const Gdiplus::Color HighlightColor;
+ static const Gdiplus::Color WonMessageColor;
+ static const Gdiplus::Color LostMessageColor;
+ static const int SquareSize;
+ static const int MarkerMargin;
+ static const int MarkerDiameter;
+ static const TCHAR* WindowClassName;
+
+ Board& _board;
+ EyeXHost _eyeXHost;
+ HINSTANCE _hInstance;
+ HWND _hWnd;
+ HMENU _hMenu;
+ int _leftMargin;
+ int _upperMargin;
+
+ // private copy constructor and operator making the class non-copyable (declared but not implemented).
+ BoardWindow(const BoardWindow&);
+ BoardWindow& operator = (const BoardWindow&);
+};
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/ActivatableBoardGame.lastbuildstate b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/ActivatableBoardGame.lastbuildstate
new file mode 100755
index 0000000..5cd4c3b
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/ActivatableBoardGame.lastbuildstate
@@ -0,0 +1,2 @@
+#TargetFrameworkVersion=v4.0:PlatformToolSet=v140:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit:WindowsTargetPlatformVersion=8.1
+Debug|Win32|D:\dev\tobii\samples\|
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.command.1.tlog b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.command.1.tlog
new file mode 100755
index 0000000..001d8ba
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.command.1.tlog
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.read.1.tlog b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.read.1.tlog
new file mode 100755
index 0000000..ff00e89
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.read.1.tlog
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.write.1.tlog b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.write.1.tlog
new file mode 100755
index 0000000..f3a1acb
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/CL.write.1.tlog
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.command.1.tlog b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.command.1.tlog
new file mode 100755
index 0000000..5f8e2da
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.command.1.tlog
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.read.1.tlog b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.read.1.tlog
new file mode 100755
index 0000000..de1b91d
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.read.1.tlog
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.write.1.tlog b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.write.1.tlog
new file mode 100755
index 0000000..97ed8cf
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/link.write.1.tlog
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.command.1.tlog b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.command.1.tlog
new file mode 100755
index 0000000..57e38ff
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.command.1.tlog
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.read.1.tlog b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.read.1.tlog
new file mode 100755
index 0000000..7e1acc5
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.read.1.tlog
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.write.1.tlog b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.write.1.tlog
new file mode 100755
index 0000000..6c4a07a
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Activata.2732E876.tlog/rc.write.1.tlog
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.log b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.log
new file mode 100755
index 0000000..8d71d0b
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.log
@@ -0,0 +1,8 @@
+ stdafx.cpp
+ EyeXHost.cpp
+d:\dev\tobii\samples\activatableboardgame\eyexhost.cpp(243): warning C4477: 'sprintf_s' : format string '%d' requires an argument of type 'int', but variadic argument 1 has type 'HWND'
+ ActivatableBoardGame.cpp
+ BoardWindow.cpp
+ Board.cpp
+ Generating Code...
+ ActivatableBoardGame.vcxproj -> D:\dev\tobii\samples\Debug\ActivatableBoardGame.exe
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.obj b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.obj
new file mode 100755
index 0000000..cdf81f4
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.obj
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.pch b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.pch
new file mode 100755
index 0000000..d560dcc
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.pch
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.res b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.res
new file mode 100755
index 0000000..6aae112
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/ActivatableBoardGame.res
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Board.obj b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Board.obj
new file mode 100755
index 0000000..32b7253
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/Board.obj
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/BoardWindow.obj b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/BoardWindow.obj
new file mode 100755
index 0000000..15d39e6
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/BoardWindow.obj
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/EyeXHost.obj b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/EyeXHost.obj
new file mode 100755
index 0000000..69a81a1
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/EyeXHost.obj
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/stdafx.obj b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/stdafx.obj
new file mode 100755
index 0000000..cb850a6
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/stdafx.obj
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/vc140.idb b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/vc140.idb
new file mode 100755
index 0000000..46ca7f9
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/vc140.idb
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Debug/vc140.pdb b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/vc140.pdb
new file mode 100755
index 0000000..8d46bc5
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Debug/vc140.pdb
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/EyeXHost.cpp b/Tobii-EyeX/samples/ActivatableBoardGame/EyeXHost.cpp
new file mode 100755
index 0000000..410a6cf
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/EyeXHost.cpp
@@ -0,0 +1,377 @@
+/*
+ * ActivatableBoardGame sample:
+ * This is an example that demonstrates the use of Activatable interactors in the context of a board game.
+ *
+ * Copyright 2013-2014 Tobii Technology AB. All rights reserved.
+ */
+
+#include "stdafx.h"
+#include "EyeXHost.h"
+#include <objidl.h>
+#include <gdiplus.h>
+#include <cassert>
+#include <cstdint>
+
+#pragma comment (lib, "Tobii.EyeX.Client.lib")
+
+#if INTPTR_MAX == INT64_MAX
+#define WINDOW_HANDLE_FORMAT "%lld"
+#else
+#define WINDOW_HANDLE_FORMAT "%d"
+#endif
+
+EyeXHost::EyeXHost()
+ : _state(Initializing),
+ _hWnd(nullptr),
+ _statusChangedMessage(0), _focusedRegionChangedMessage(0), _regionActivatedMessage(0),
+ _focusedRegionId(-1),
+ _context(TX_EMPTY_HANDLE),
+ _connectionStateChangedTicket(0), _queryHandlerTicket(0), _eventHandlerTicket(0)
+{
+ // initialize the EyeX Engine client library.
+ txInitializeEyeX(TX_EYEXCOMPONENTOVERRIDEFLAG_NONE, nullptr, nullptr, nullptr, nullptr);
+
+ // create a context and register event handlers, but don't enable the connection to the engine just yet.
+ // we'll enable the connection in the Init method, when we're ready to handle the
+ // connection-status-changed notifications.
+ bool success = txCreateContext(&_context, TX_FALSE) == TX_RESULT_OK;
+ success &= RegisterConnectionStateChangedHandler();
+ success &= RegisterQueryHandler();
+ success &= RegisterEventHandler();
+
+ if (!success)
+ {
+ SetState(Failed);
+ }
+}
+
+EyeXHost::~EyeXHost()
+{
+ if (_context != TX_EMPTY_HANDLE)
+ {
+ // shut down, then release the context.
+ txShutdownContext(_context, TX_CLEANUPTIMEOUT_DEFAULT, TX_FALSE);
+ txReleaseContext(&_context);
+ }
+}
+
+void EyeXHost::Init(HWND hWnd, UINT statusChangedMessage, UINT focusedRegionChangedMessage, UINT regionActivatedMessage)
+{
+ _hWnd = hWnd;
+ _statusChangedMessage = statusChangedMessage;
+ _focusedRegionChangedMessage = focusedRegionChangedMessage;
+ _regionActivatedMessage = regionActivatedMessage;
+
+ // connect to the engine.
+ if (txEnableConnection(_context) != TX_RESULT_OK)
+ {
+ SetState(Failed);
+ }
+}
+
+void EyeXHost::SetActivatableRegions(const std::vector<ActivatableRegion>& regions)
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ _regions.assign(regions.begin(), regions.end());
+ ResetFocusedRegionIdIfNonExistent();
+}
+
+int EyeXHost::GetFocusedRegionId() const
+{
+ std::lock_guard<std::mutex> lock(const_cast<std::mutex&>(_mutex));
+
+ return _focusedRegionId;
+}
+
+void EyeXHost::TriggerActivation()
+{
+ TX_HANDLE command(TX_EMPTY_HANDLE);
+ txCreateActionCommand(_context, &command, TX_ACTIONTYPE_ACTIVATE);
+ txExecuteCommandAsync(command, NULL, NULL);
+ txReleaseObject(&command);
+}
+
+void EyeXHost::TriggerActivationModeOn()
+{
+ TX_HANDLE command(TX_EMPTY_HANDLE);
+ txCreateActionCommand(_context, &command, TX_ACTIONTYPE_ACTIVATIONMODEON);
+ txExecuteCommandAsync(command, NULL, NULL);
+ txReleaseObject(&command);
+}
+
+void EyeXHost::SetFocusedRegionId(int regionId)
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ _focusedRegionId = regionId;
+ ResetFocusedRegionIdIfNonExistent();
+ PostMessage(_hWnd, _focusedRegionChangedMessage, 0, 0);
+}
+
+// this method assumes that the mutex is held during the call.
+void EyeXHost::ResetFocusedRegionIdIfNonExistent()
+{
+ for (auto region : _regions)
+ {
+ if (region.id == _focusedRegionId)
+ {
+ return;
+ }
+ }
+
+ _focusedRegionId = -1;
+}
+
+bool EyeXHost::IsFunctional() const
+{
+ return _state == Initializing ||
+ _state == Connected;
+}
+
+void EyeXHost::SetState(State state)
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ if (_state != state)
+ {
+ _state = state;
+
+ // note the use of the asynchronous PostMessage function to marshal the event to the main thread.
+ // (this method is called from OnEngineConnectionStateChanged, which is typically invoked on a worker thread.)
+ PostMessage(_hWnd, _statusChangedMessage, 0, 0);
+ }
+}
+
+bool EyeXHost::RegisterConnectionStateChangedHandler()
+{
+ // we pass the "this" pointer as the user parameter when registering the event handler,
+ // so that we can access it in the callback function.
+
+ auto connectionStateChangedTrampoline = [](TX_CONNECTIONSTATE connectionState, TX_USERPARAM userParam)
+ {
+ static_cast<EyeXHost*>(userParam)->OnEngineConnectionStateChanged(connectionState);
+ };
+
+ bool success = txRegisterConnectionStateChangedHandler(
+ _context,
+ &_connectionStateChangedTicket,
+ connectionStateChangedTrampoline,
+ this) == TX_RESULT_OK;
+
+ return success;
+}
+
+bool EyeXHost::RegisterQueryHandler()
+{
+ auto queryHandlerTrampoline = [](TX_CONSTHANDLE hObject, TX_USERPARAM userParam)
+ {
+ static_cast<EyeXHost*>(userParam)->HandleQuery(hObject);
+ };
+
+ bool success = txRegisterQueryHandler(
+ _context,
+ &_queryHandlerTicket,
+ queryHandlerTrampoline,
+ this) == TX_RESULT_OK;
+
+ return success;
+}
+
+bool EyeXHost::RegisterEventHandler()
+{
+ auto eventHandlerTrampoline = [](TX_CONSTHANDLE hObject, TX_USERPARAM userParam)
+ {
+ static_cast<EyeXHost*>(userParam)->HandleEvent(hObject);
+ };
+
+ bool success = txRegisterEventHandler(_context,
+ &_eventHandlerTicket,
+ eventHandlerTrampoline,
+ this) == TX_RESULT_OK;
+
+ return success;
+}
+
+void EyeXHost::OnEngineConnectionStateChanged(TX_CONNECTIONSTATE connectionState)
+{
+ switch (connectionState)
+ {
+ case TX_CONNECTIONSTATE::TX_CONNECTIONSTATE_CONNECTED:
+ SetState(Connected);
+ break;
+
+ case TX_CONNECTIONSTATE::TX_CONNECTIONSTATE_DISCONNECTED:
+ case TX_CONNECTIONSTATE::TX_CONNECTIONSTATE_TRYINGTOCONNECT:
+ case TX_CONNECTIONSTATE::TX_CONNECTIONSTATE_SERVERVERSIONTOOLOW:
+ case TX_CONNECTIONSTATE::TX_CONNECTIONSTATE_SERVERVERSIONTOOHIGH:
+ SetState(Disconnected);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void EyeXHost::HandleQuery(TX_CONSTHANDLE hAsyncData)
+{
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ // NOTE. This method will fail silently if, for example, the connection is lost before the snapshot has been committed,
+ // or if we run out of memory. This is by design, because there is nothing we can do to recover from these errors anyway.
+
+ TX_HANDLE hQuery(TX_EMPTY_HANDLE);
+ txGetAsyncDataContent(hAsyncData, &hQuery);
+
+ const int bufferSize = 20;
+ TX_CHAR stringBuffer[bufferSize];
+
+ // read the query bounds from the query, that is, the area on the screen that the query concerns.
+ // the query region is always rectangular.
+ TX_HANDLE hBounds(TX_EMPTY_HANDLE);
+ txGetQueryBounds(hQuery, &hBounds);
+ TX_REAL pX, pY, pWidth, pHeight;
+ txGetRectangularBoundsData(hBounds, &pX, &pY, &pWidth, &pHeight);
+ txReleaseObject(&hBounds);
+ Gdiplus::Rect queryBounds((INT)pX, (INT)pY, (INT)pWidth, (INT)pHeight);
+
+ // create a new snapshot with the same window id and bounds as the query.
+ TX_HANDLE hSnapshot(TX_EMPTY_HANDLE);
+ txCreateSnapshotForQuery(hQuery, &hSnapshot);
+
+ TX_CHAR windowIdString[bufferSize];
+ sprintf_s(windowIdString, bufferSize, WINDOW_HANDLE_FORMAT, _hWnd);
+
+ if (QueryIsForWindowId(hQuery, windowIdString))
+ {
+ // define options for our activatable regions: no, we don't want tentative focus events.
+ TX_ACTIVATABLEPARAMS params = { TX_FALSE };
+
+ // iterate through all regions and create interactors for those that overlap with the query bounds.
+ for (auto region : _regions)
+ {
+ Gdiplus::Rect regionBounds((INT)region.bounds.left, (INT)region.bounds.top,
+ (INT)(region.bounds.right - region.bounds.left), (INT)(region.bounds.bottom - region.bounds.top));
+
+ if (queryBounds.IntersectsWith(regionBounds))
+ {
+ TX_HANDLE hInteractor(TX_EMPTY_HANDLE);
+ sprintf_s(stringBuffer, bufferSize, "%d", region.id);
+
+ TX_RECT bounds;
+ bounds.X = region.bounds.left;
+ bounds.Y = region.bounds.top;
+ bounds.Width = region.bounds.right - region.bounds.left;
+ bounds.Height = region.bounds.bottom - region.bounds.top;
+
+ txCreateRectangularInteractor(hSnapshot, &hInteractor, stringBuffer, &bounds, TX_LITERAL_ROOTID, windowIdString);
+ txCreateActivatableBehavior(hInteractor, &params);
+
+ txReleaseObject(&hInteractor);
+ }
+ }
+ }
+
+ txCommitSnapshotAsync(hSnapshot, OnSnapshotCommitted, nullptr);
+ txReleaseObject(&hSnapshot);
+ txReleaseObject(&hQuery);
+}
+
+void EyeXHost::HandleEvent(TX_CONSTHANDLE hAsyncData)
+{
+ TX_HANDLE hEvent(TX_EMPTY_HANDLE);
+ txGetAsyncDataContent(hAsyncData, &hEvent);
+
+ // NOTE. Uncomment the following line of code to view the event object. The same function can be used with any interaction object.
+ //OutputDebugStringA(txDebugObject(hEvent));
+
+ // read the interactor ID from the event.
+ const int bufferSize = 20;
+ TX_CHAR stringBuffer[bufferSize];
+ TX_SIZE idLength(bufferSize);
+ if (txGetEventInteractorId(hEvent, stringBuffer, &idLength) == TX_RESULT_OK)
+ {
+ int interactorId = atoi(stringBuffer);
+
+ HandleActivatableEvent(hEvent, interactorId);
+ }
+
+ txReleaseObject(&hEvent);
+}
+
+void EyeXHost::HandleActivatableEvent(TX_HANDLE hEvent, int interactorId)
+{
+ TX_HANDLE hActivatable(TX_EMPTY_HANDLE);
+ if (txGetEventBehavior(hEvent, &hActivatable, TX_BEHAVIORTYPE_ACTIVATABLE) == TX_RESULT_OK)
+ {
+ TX_ACTIVATABLEEVENTTYPE eventType;
+ if (txGetActivatableEventType(hActivatable, &eventType) == TX_RESULT_OK)
+ {
+ if (eventType == TX_ACTIVATABLEEVENTTYPE_ACTIVATED)
+ {
+ OnActivated(hActivatable, interactorId);
+ }
+ else if (eventType == TX_ACTIVATABLEEVENTTYPE_ACTIVATIONFOCUSCHANGED)
+ {
+ OnActivationFocusChanged(hActivatable, interactorId);
+ }
+ }
+
+ txReleaseObject(&hActivatable);
+ }
+}
+
+void EyeXHost::OnActivationFocusChanged(TX_HANDLE hBehavior, int interactorId)
+{
+ TX_ACTIVATIONFOCUSCHANGEDEVENTPARAMS eventData;
+ if (txGetActivationFocusChangedEventParams(hBehavior, &eventData) == TX_RESULT_OK)
+ {
+ if (eventData.HasActivationFocus)
+ {
+ SetFocusedRegionId(interactorId);
+ }
+ else
+ {
+ SetFocusedRegionId(-1);
+ }
+ }
+}
+
+void EyeXHost::OnActivated(TX_HANDLE hBehavior, int interactorId)
+{
+ PostMessage(_hWnd, _regionActivatedMessage, interactorId, 0);
+}
+
+void TX_CALLCONVENTION EyeXHost::OnSnapshotCommitted(TX_CONSTHANDLE hAsyncData, TX_USERPARAM param)
+{
+ // check the result code using an assertion.
+ // this will catch validation errors and runtime errors in debug builds. in release builds it won't do anything.
+
+ TX_RESULT result = TX_RESULT_UNKNOWN;
+ txGetAsyncDataResultCode(hAsyncData, &result);
+ assert(result == TX_RESULT_OK || result == TX_RESULT_CANCELLED);
+}
+
+bool EyeXHost::QueryIsForWindowId(TX_HANDLE hQuery, const TX_CHAR* windowId)
+{
+ const int bufferSize = 20;
+ TX_CHAR buffer[bufferSize];
+
+ TX_SIZE count;
+ if (TX_RESULT_OK == txGetQueryWindowIdCount(hQuery, &count))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ TX_SIZE size = bufferSize;
+ if (TX_RESULT_OK == txGetQueryWindowId(hQuery, i, buffer, &size))
+ {
+ if (0 == strcmp(windowId, buffer))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/EyeXHost.h b/Tobii-EyeX/samples/ActivatableBoardGame/EyeXHost.h
new file mode 100755
index 0000000..98aa84d
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/EyeXHost.h
@@ -0,0 +1,111 @@
+/*
+ * EyeXHost class: Responsible for the gaze interaction within a window.
+ * Holds the current set of activatable regions and acts as a simple interactor repository.
+ * Sends notifications as Windows messages so that they are received on the main thread and can be handled there.
+ *
+ * Copyright 2013 Tobii Technology AB. All rights reserved.
+ */
+
+#pragma once
+
+#include <windows.h>
+#include <vector>
+#include <mutex>
+#include "eyex/EyeX.h"
+
+class EyeXHost
+{
+public:
+ // Represents an activatable region, that is, one particular kind of interactor.
+ struct ActivatableRegion
+ {
+ int id;
+ RECT bounds;
+
+ ActivatableRegion(int paramId, RECT paramBounds) : id(paramId), bounds(paramBounds) { }
+ };
+
+ EyeXHost();
+ virtual ~EyeXHost();
+
+ // attaches to the window with the given handle.
+ // the message parameters are custom windows messages sent to the window when an event has occurred.
+ void Init(HWND hWnd, UINT statusChangedMessage, UINT focusedRegionChangedMessage, UINT regionActivatedMessage);
+
+ // updates the collection (repository) of activatable regions.
+ void SetActivatableRegions(const std::vector<ActivatableRegion>& regions);
+
+ // gets the ID of the region that currently has the activation focus.
+ int GetFocusedRegionId() const;
+
+ // triggers an activation ("direct click").
+ void TriggerActivation();
+
+ // trigger a request to the EyeX Engine to switch activation mode on.
+ // this will trigger Activation Focus Changed events to be raised for the
+ // interactor the user is looking at/no longer looking at.
+ // in this sample, the focus is used to draw a highlight on in the square
+ // that is about to be "clicked" - where the "X" will be placed.
+ void TriggerActivationModeOn();
+
+ // indicates whether the connection to the EyeX Engine is working.
+ bool IsFunctional() const;
+
+private:
+ enum State
+ {
+ Initializing,
+ Connected,
+ Disconnected,
+ Failed
+ };
+
+ // registers handlers for notifications from the engine.
+ bool RegisterConnectionStateChangedHandler();
+ bool RegisterQueryHandler();
+ bool RegisterEventHandler();
+
+ // event handlers.
+ void OnEngineConnectionStateChanged(TX_CONNECTIONSTATE connectionState);
+ void HandleQuery(TX_CONSTHANDLE hAsyncData);
+ void HandleEvent(TX_CONSTHANDLE hAsyncData);
+ void HandleActivatableEvent(TX_HANDLE hEvent, int interactorId);
+ void OnActivationFocusChanged(TX_HANDLE hBehavior, int interactorId);
+ void OnActivated(TX_HANDLE hBehavior, int interactorId);
+
+ // callback function invoked when a snapshot has been committed.
+ static void TX_CALLCONVENTION OnSnapshotCommitted(TX_CONSTHANDLE hAsyncData, TX_USERPARAM param);
+
+ // sets the internal state.
+ void SetState(State state);
+
+ // sets the ID of the region that currently has the activation focus.
+ void SetFocusedRegionId(int regionId);
+
+ // clears the focused region ID if there is no matching region in the repository.
+ void ResetFocusedRegionIdIfNonExistent();
+
+ static bool QueryIsForWindowId(TX_HANDLE hQuery, const TX_CHAR* windowId);
+
+ // mutex protecting the state of the object from race conditions caused by multiple threads.
+ // (for example, a call to SetActivatableRegions from the main thread while the HandleQuery
+ // method is iterating through the regions on a worker thread.)
+ std::mutex _mutex;
+ State _state;
+ std::vector<ActivatableRegion> _regions;
+ int _focusedRegionId;
+ TX_CONTEXTHANDLE _context;
+ TX_TICKET _connectionStateChangedTicket;
+ TX_TICKET _queryHandlerTicket;
+ TX_TICKET _eventHandlerTicket;
+
+ // attached window and custom messages.
+ HWND _hWnd;
+ UINT _statusChangedMessage;
+ UINT _focusedRegionChangedMessage;
+ UINT _regionActivatedMessage;
+
+ // private copy constructor and operator making the class non-copyable (declared but not implemented).
+ EyeXHost(const EyeXHost&);
+ EyeXHost& operator = (const EyeXHost&);
+};
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Observer.h b/Tobii-EyeX/samples/ActivatableBoardGame/Observer.h
new file mode 100755
index 0000000..8aa98c1
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Observer.h
@@ -0,0 +1,13 @@
+/*
+ * Observer interface: Standard Observer interface used for notifying an object of a change in another object.
+ *
+ * Copyright 2013 Tobii Technology AB. All rights reserved.
+ */
+
+#pragma once
+
+class Observer
+{
+public:
+ virtual void SubjectChanged() = 0;
+};
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/Resource.h b/Tobii-EyeX/samples/ActivatableBoardGame/Resource.h
new file mode 100755
index 0000000..6a23727
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/Resource.h
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/small.ico b/Tobii-EyeX/samples/ActivatableBoardGame/small.ico
new file mode 100755
index 0000000..449296f
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/small.ico
Binary files differ
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/stdafx.cpp b/Tobii-EyeX/samples/ActivatableBoardGame/stdafx.cpp
new file mode 100755
index 0000000..92e931f
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/stdafx.cpp
@@ -0,0 +1,3 @@
+// stdafx.cpp : source file that includes just the standard includes
+
+#include "stdafx.h"
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/stdafx.h b/Tobii-EyeX/samples/ActivatableBoardGame/stdafx.h
new file mode 100755
index 0000000..705c92c
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/stdafx.h
@@ -0,0 +1,17 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+
+#pragma once
+
+#include "targetver.h"
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include <windows.h>
+
+// C RunTime Header Files
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <tchar.h>
diff --git a/Tobii-EyeX/samples/ActivatableBoardGame/targetver.h b/Tobii-EyeX/samples/ActivatableBoardGame/targetver.h
new file mode 100755
index 0000000..90e767b
--- /dev/null
+++ b/Tobii-EyeX/samples/ActivatableBoardGame/targetver.h
@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>