Skip to content
This repository has been archived by the owner on Jul 16, 2020. It is now read-only.

Commit

Permalink
sample: screen control sample
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshSnider committed May 17, 2018
1 parent 5c48b0d commit 1876946
Show file tree
Hide file tree
Showing 9 changed files with 604 additions and 0 deletions.
167 changes: 167 additions & 0 deletions samples/InteractiveScreenControlSample/InteractiveSample.vcxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.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="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{C5D30411-CECD-48B1-9B9C-3C86A1ACD2FA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>InteractiveSample</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
<ProjectName>InteractiveScreenControlSample</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</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 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 Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<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|x64'">
<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>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\source\interactivity.cpp" />
<ClCompile Include="InteractiveScreenControlSample.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>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?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;hh;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>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\source\interactivity.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="InteractiveScreenControlSample.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#include "stdafx.h"
#include "../../source/interactivity.h"
#include "../../source/internal/rapidjson/Document.h"

#include <windows.h>
#include <shellapi.h>

// STL includes
#include <chrono>
#include <thread>
#include <iostream>
#include <map>
#include <string>

#define CLIENT_ID "f0d20e2d263b75894f5cdaabc8a344b99b1ea6f9ecb7fa4f"
#define INTERACTIVE_ID "247834"
#define SHARE_CODE "v8t3hlaa"

#define MIXER_DEBUG 0

std::map<std::string, std::string> controlsByTransaction;

// Display an OAuth consent page to the user.
int authorize(std::string& authorization);

// Handle interactive input.
void handle_interactive_input(void* context, interactive_session session, const interactive_input* input);

int main()
{
int err = 0;

#if MIXER_DEBUG
interactive_config_debug(interactive_debug_trace, [](const interactive_debug_level dbgMsgType, const char* dbgMsg, size_t dbgMsgSize)
{
std::cout << dbgMsg << std::endl;
});
#endif

// Get an authorization token for the user to pass to the connect function.
std::string authorization;
err = authorize(authorization);
if (err) return err;

// Connect to the user's interactive channel, using the interactive project specified by the version ID.
interactive_session session;
err = interactive_open_session(authorization.c_str(), INTERACTIVE_ID, SHARE_CODE, false, &session);
if (err) return err;

// Register a callback for button presses.
err = interactive_set_input_handler(session, handle_interactive_input);
if (err) return err;

// Now notify participants that interactive is ready.
err = interactive_set_ready(session, true);
if (err) return err;

// Simulate game update loop. All previously registered session callbacks will be called from this thread.
for (;;)
{
// This call processes any waiting messages from the interactive service. If there are no messages this returns immediately.
err = interactive_run(session, 1);
if (err) break;
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}

interactive_close_session(session);

return err;
}

int authorize(std::string& authorization)
{
int err = 0;
char shortCode[7];
size_t shortCodeLength = _countof(shortCode);
char shortCodeHandle[1024];
size_t shortCodeHandleLength = _countof(shortCodeHandle);

// Get an OAuth short code from the user. For more information about OAuth see: https://oauth.net/2/
err = interactive_auth_get_short_code(CLIENT_ID, nullptr, shortCode, &shortCodeLength, shortCodeHandle, &shortCodeHandleLength);
if (err) return err;

// Pop the browser for the user to approve access.
std::string authUrl = std::string("https://www.mixer.com/go?code=") + shortCode;
ShellExecuteA(0, 0, authUrl.c_str(), nullptr, nullptr, SW_SHOW);

// Wait for OAuth token response.
char refreshTokenBuffer[1024];
size_t refreshTokenLength = _countof(refreshTokenBuffer);
err = interactive_auth_wait_short_code(CLIENT_ID, nullptr, shortCodeHandle, refreshTokenBuffer, &refreshTokenLength);
if (err)
{
if (MIXER_ERROR_TIMED_OUT == err)
{
std::cout << "Authorization timed out, user did not approve access within the time limit." << std::endl;
}
else if (MIXER_ERROR_AUTH_DENIED == err)
{
std::cout << "User denied access." << std::endl;
}

return err;
}

/*
* TODO: This is where you would serialize the refresh token locally or on your own service for future use in a way that is associated with the current user.
* Future calls would then only need to check if the token is stale, refresh it if so, and then parse the new authorization header.
*/

// Extract the authorization header from the refresh token.
char authBuffer[1024];
size_t authBufferLength = _countof(authBuffer);
err = interactive_auth_parse_refresh_token(refreshTokenBuffer, authBuffer, &authBufferLength);
if (err) return err;

// Set the authorization out parameter.
authorization = std::string(authBuffer, authBufferLength);
return 0;
}

int get_participant_name(interactive_session session, const char* participantId, std::string& participantName)
{
// Get the participant's name.
size_t participantNameLength = 0;

// First call with a nullptr to get the required size for the user's name, MIXER_ERROR_BUFFER_SIZE is the expected return value.
int err = interactive_participant_get_user_name(session, participantId, nullptr, &participantNameLength);
if (MIXER_ERROR_BUFFER_SIZE != err)
{
return err;
}

// Resize the string to the correct size and call it again.
participantName.resize(participantNameLength);
err = interactive_participant_get_user_name(session, participantId, (char*)participantName.data(), &participantNameLength);
// STL strings don't need a trailing null character.
participantName = participantName.erase(participantNameLength - 1);

return 0;
}

void handle_interactive_input(void* context, interactive_session session, const interactive_input* input)
{
// Get the participant's Mixer name to give them attribution.
std::string participantName;
int err = get_participant_name(session, input->participantId, participantName);
if (err)
{
std::cerr << "Failed to get participant user name (" << std::to_string(err) << ")" << std::endl;
return;
}

// Now handle the input based on input type.
if ((input_type_key == input->type || input_type_click == input->type) && interactive_button_action_down == input->buttonData.action)
{
float x = input->coordinateData.x;
float y = input->coordinateData.y;
std::cout << participantName << " clicked x: " + std::to_string(x) << " y: " << std::to_string(y) << std::endl;
}
else if (input_type_move == input->type)
{
// Show which user moved the joystick.
float x = input->coordinateData.x;
float y = input->coordinateData.y;
std::cout << participantName << " moved pointer to x: " + std::to_string(x) << " y: " << std::to_string(y) << std::endl;
}
}
Loading

0 comments on commit 1876946

Please sign in to comment.