├── example_basic ├── addons.make ├── icon.rc ├── src │ ├── main.cpp │ ├── ofApp.h │ └── ofApp.cpp ├── example_basic.vcxproj.filters ├── example_basic.sln └── example_basic.vcxproj ├── src ├── ofxWin8Touch.h └── ofxWin8Touch.cpp ├── README.md └── .gitignore /example_basic/addons.make: -------------------------------------------------------------------------------- 1 | ofxWin8Touch 2 | -------------------------------------------------------------------------------- /src/ofxWin8Touch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ofxWin8Touch.h 3 | * Header file for Windows 8 touch event handling. 4 | * 5 | * Created by Robert Xiao on August 24, 2015. 6 | */ 7 | 8 | #pragma once 9 | 10 | void ofxWin8TouchSetup(); 11 | -------------------------------------------------------------------------------- /example_basic/icon.rc: -------------------------------------------------------------------------------- 1 | // Icon Resource Definition 2 | #define MAIN_ICON 102 3 | 4 | #if defined(_DEBUG) 5 | MAIN_ICON ICON "..\..\..\libs\openFrameworksCompiled\project\vs\icon_debug.ico" 6 | #else 7 | MAIN_ICON ICON "..\..\..\libs\openFrameworksCompiled\project\vs\icon.ico" 8 | #endif 9 | -------------------------------------------------------------------------------- /example_basic/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofMain.h" 2 | #include "ofApp.h" 3 | 4 | //======================================================================== 5 | int main( ){ 6 | ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context 7 | 8 | // this kicks off the running of my app 9 | // can be OF_WINDOW or OF_FULLSCREEN 10 | // pass in width and height too: 11 | ofRunApp(new ofApp()); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /example_basic/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | 5 | class ofApp : public ofBaseApp{ 6 | 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | void keyPressed(int key); 13 | void keyReleased(int key); 14 | void mouseMoved(int x, int y ); 15 | void mouseDragged(int x, int y, int button); 16 | void mousePressed(int x, int y, int button); 17 | void mouseReleased(int x, int y, int button); 18 | void windowResized(int w, int h); 19 | void dragEvent(ofDragInfo dragInfo); 20 | void gotMessage(ofMessage msg); 21 | 22 | /* Touches */ 23 | void touchDown(ofTouchEventArgs & touch); 24 | void touchMoved(ofTouchEventArgs & touch); 25 | void touchUp(ofTouchEventArgs & touch); 26 | void touchDoubleTap(ofTouchEventArgs & touch); 27 | void touchCancelled(ofTouchEventArgs & touch); 28 | map touchMap; 29 | 30 | }; 31 | -------------------------------------------------------------------------------- /example_basic/example_basic.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | src 6 | 7 | 8 | src 9 | 10 | 11 | addons\ofxWin8Touch\src 12 | 13 | 14 | 15 | 16 | {d8376475-7454-4a24-b08a-aac121d3ad6f} 17 | 18 | 19 | {71834F65-F3A9-211E-73B8-DC85} 20 | 21 | 22 | {7BD16398-29F9-7826-F113-2AB6} 23 | 24 | 25 | {77869FFA-D144-7587-3764-48C5} 26 | 27 | 28 | 29 | 30 | src 31 | 32 | 33 | addons\ofxWin8Touch\src 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /example_basic/example_basic.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2012 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_basic", "example_basic.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}" 4 | EndProject 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Win32 = Debug|Win32 10 | Release|Win32 = Release|Win32 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32 14 | {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32 15 | {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32 16 | {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32 17 | {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32 18 | {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32 19 | {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32 20 | {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ofxWin8Touch 2 | ============ 3 | 4 | This addon provides OpenFrameworks touch events on Windows 8 and above. It uses the new `WM_POINTER` events 5 | to obtain more detailed information about the touch, as well as providing improved touch event stability and precision (compared with `WM_TOUCH`). 6 | 7 | The development of this addon was inspired by `ofxWin7` and later `ofxWinTouch`. The big difference is that this addon 8 | uses `WM_POINTER` (available since Windows 8), not `WM_TOUCH` (available since Windows 7). For some devices, this makes a big 9 | difference: `WM_TOUCH` may sometimes drop or mangle touch events which are passed through fine by `WM_POINTER`. You should try 10 | this addon if `ofxWinTouch` is giving you weird results (such as missing touches or "stuck" touches). 11 | 12 | It is dead simple to use: add the five standard touch event handlers to your `ofApp` (with matching implementations in `ofApp.cpp`): 13 | 14 | void touchDown(ofTouchEventArgs & touch); 15 | void touchMoved(ofTouchEventArgs & touch); 16 | void touchUp(ofTouchEventArgs & touch); 17 | void touchDoubleTap(ofTouchEventArgs & touch); 18 | void touchCancelled(ofTouchEventArgs & touch); 19 | 20 | the following `#include`: 21 | 22 | #include "ofxWin8Touch.h" 23 | 24 | and the following to `setup`: 25 | 26 | ofxWin8TouchSetup(); 27 | ofRegisterTouchEvents(this); 28 | 29 | See `example_basic` for simple usage (tested with a Perceptive Pixel 55" touchscreen). 30 | 31 | HighDPI Awareness 32 | ================= 33 | 34 | Some devices (like the Windows Surface Pro) have a default "High DPI" setting to make text more readable on the screen. 35 | On the Surface Pro, the default settings is 150% DPI - which means a display resolution of 1920x1080 will report a screen size of 1280x720 to openFrameworks, but still report touches on a 1920x1080 grid. 36 | Thankfully, there's an easy fix: 37 | * Open Project Properties 38 | * Navigate to Configuration Properties > Manifest Tool > Input and Output 39 | * Set 'Enable DPI Awareness' to Yes 40 | -------------------------------------------------------------------------------- /example_basic/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | #include "ofxWin8Touch.h" 3 | 4 | //-------------------------------------------------------------- 5 | void ofApp::setup(){ 6 | /* Essential setup */ 7 | ofxWin8TouchSetup(); 8 | ofRegisterTouchEvents(this); 9 | } 10 | 11 | //-------------------------------------------------------------- 12 | void ofApp::update(){ 13 | 14 | } 15 | 16 | //-------------------------------------------------------------- 17 | void ofApp::draw(){ 18 | /* Draw touches */ 19 | ofBackground(0); 20 | ofNoFill(); 21 | ofSetColor(255); 22 | for(auto &i : touchMap) { 23 | auto &touch = i.second; 24 | ofPushMatrix(); 25 | ofTranslate(touch.x, touch.y); 26 | ofRotate(90-touch.angle); 27 | ofRect(-touch.width/2, -touch.height/2, touch.width, touch.height); 28 | ofEllipse(0, 0, touch.width * 5, touch.height * 5); 29 | ofDrawBitmapString(ofVAArgsToString("%d", touch.id), 0, 0); 30 | ofPopMatrix(); 31 | } 32 | } 33 | 34 | //-------------------------------------------------------------- 35 | void ofApp::keyPressed(int key){ 36 | 37 | } 38 | 39 | //-------------------------------------------------------------- 40 | void ofApp::keyReleased(int key){ 41 | 42 | } 43 | 44 | //-------------------------------------------------------------- 45 | void ofApp::mouseMoved(int x, int y ){ 46 | 47 | } 48 | 49 | //-------------------------------------------------------------- 50 | void ofApp::mouseDragged(int x, int y, int button){ 51 | 52 | } 53 | 54 | //-------------------------------------------------------------- 55 | void ofApp::mousePressed(int x, int y, int button){ 56 | 57 | } 58 | 59 | //-------------------------------------------------------------- 60 | void ofApp::mouseReleased(int x, int y, int button){ 61 | 62 | } 63 | 64 | //-------------------------------------------------------------- 65 | void ofApp::windowResized(int w, int h){ 66 | 67 | } 68 | 69 | //-------------------------------------------------------------- 70 | void ofApp::gotMessage(ofMessage msg){ 71 | 72 | } 73 | 74 | //-------------------------------------------------------------- 75 | void ofApp::dragEvent(ofDragInfo dragInfo){ 76 | 77 | } 78 | 79 | //-------------------------------------------------------------- 80 | void ofApp::touchDown(ofTouchEventArgs & touch){ 81 | touchMap[touch.id] = touch; 82 | } 83 | 84 | //-------------------------------------------------------------- 85 | void ofApp::touchMoved(ofTouchEventArgs & touch){ 86 | touchMap[touch.id] = touch; 87 | } 88 | 89 | //-------------------------------------------------------------- 90 | void ofApp::touchUp(ofTouchEventArgs & touch){ 91 | touchMap.erase(touch.id); 92 | } 93 | 94 | //-------------------------------------------------------------- 95 | void ofApp::touchDoubleTap(ofTouchEventArgs & touch){ 96 | 97 | } 98 | 99 | //-------------------------------------------------------------- 100 | void ofApp::touchCancelled(ofTouchEventArgs & touch){ 101 | touchMap.erase(touch.id); 102 | } 103 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .DS_Store 3 | 4 | ## Ignore Visual Studio temporary files, build results, and 5 | ## files generated by popular Visual Studio add-ons. 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | build/ 24 | bld/ 25 | [Bb]in/ 26 | [Oo]bj/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # DNX 47 | project.lock.json 48 | artifacts/ 49 | 50 | *_i.c 51 | *_p.c 52 | *_i.h 53 | *.ilk 54 | *.meta 55 | *.obj 56 | *.pch 57 | *.pdb 58 | *.pgc 59 | *.pgd 60 | *.rsp 61 | *.sbr 62 | *.tlb 63 | *.tli 64 | *.tlh 65 | *.tmp 66 | *.tmp_proj 67 | *.log 68 | *.vspscc 69 | *.vssscc 70 | .builds 71 | *.pidb 72 | *.svclog 73 | *.scc 74 | 75 | # Chutzpah Test files 76 | _Chutzpah* 77 | 78 | # Visual C++ cache files 79 | ipch/ 80 | *.aps 81 | *.ncb 82 | *.opensdf 83 | *.sdf 84 | *.cachefile 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # NuGet Packages 149 | *.nupkg 150 | # The packages folder can be ignored because of Package Restore 151 | **/packages/* 152 | # except build/, which is used as an MSBuild target. 153 | !**/packages/build/ 154 | # Uncomment if necessary however generally it will be regenerated when needed 155 | #!**/packages/repositories.config 156 | 157 | # Windows Azure Build Output 158 | csx/ 159 | *.build.csdef 160 | 161 | # Windows Store app package directory 162 | AppPackages/ 163 | 164 | # Visual Studio cache files 165 | # files ending in .cache can be ignored 166 | *.[Cc]ache 167 | # but keep track of directories ending in .cache 168 | !*.[Cc]ache/ 169 | 170 | # Others 171 | ClientBin/ 172 | [Ss]tyle[Cc]op.* 173 | ~$* 174 | *~ 175 | *.dbmdl 176 | *.dbproj.schemaview 177 | *.pfx 178 | *.publishsettings 179 | node_modules/ 180 | orleans.codegen.cs 181 | 182 | # RIA/Silverlight projects 183 | Generated_Code/ 184 | 185 | # Backup & report files from converting an old project file 186 | # to a newer Visual Studio version. Backup files are not needed, 187 | # because we have git ;-) 188 | _UpgradeReport_Files/ 189 | Backup*/ 190 | UpgradeLog*.XML 191 | UpgradeLog*.htm 192 | 193 | # SQL Server files 194 | *.mdf 195 | *.ldf 196 | 197 | # Business Intelligence projects 198 | *.rdl.data 199 | *.bim.layout 200 | *.bim_*.settings 201 | 202 | # Microsoft Fakes 203 | FakesAssemblies/ 204 | 205 | # Node.js Tools for Visual Studio 206 | .ntvs_analysis.dat 207 | 208 | # Visual Studio 6 build log 209 | *.plg 210 | 211 | # Visual Studio 6 workspace options file 212 | *.opt 213 | 214 | # Visual Studio LightSwitch build output 215 | **/*.HTMLClient/GeneratedArtifacts 216 | **/*.DesktopClient/GeneratedArtifacts 217 | **/*.DesktopClient/ModelManifest.xml 218 | **/*.Server/GeneratedArtifacts 219 | **/*.Server/ModelManifest.xml 220 | _Pvt_Extensions 221 | -------------------------------------------------------------------------------- /example_basic/example_basic.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {7FD42DF7-442E-479A-BA76-D0022F99702A} 15 | Win32Proj 16 | example_basic 17 | 18 | 19 | 20 | Application 21 | Unicode 22 | v110 23 | 24 | 25 | Application 26 | Unicode 27 | true 28 | v110 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | bin\ 42 | obj\$(Configuration)\ 43 | $(ProjectName)_debug 44 | true 45 | true 46 | 47 | 48 | bin\ 49 | obj\$(Configuration)\ 50 | false 51 | 52 | 53 | 54 | Disabled 55 | true 56 | EnableFastChecks 57 | %(PreprocessorDefinitions) 58 | MultiThreadedDebugDLL 59 | Level3 60 | EditAndContinue 61 | %(AdditionalIncludeDirectories);..\..\..\addons\ofxWin8Touch\libs;..\..\..\addons\ofxWin8Touch\src 62 | CompileAsCpp 63 | 64 | 65 | true 66 | Console 67 | false 68 | %(AdditionalDependencies) 69 | %(AdditionalLibraryDirectories) 70 | 71 | 72 | 73 | 74 | false 75 | %(PreprocessorDefinitions) 76 | MultiThreadedDLL 77 | Level3 78 | %(AdditionalIncludeDirectories);..\..\..\addons\ofxWin8Touch\libs;..\..\..\addons\ofxWin8Touch\src 79 | CompileAsCpp 80 | 81 | 82 | false 83 | false 84 | Console 85 | true 86 | true 87 | false 88 | %(AdditionalDependencies) 89 | %(AdditionalLibraryDirectories) 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | {5837595d-aca9-485c-8e76-729040ce4b0b} 104 | 105 | 106 | 107 | 108 | /D_DEBUG %(AdditionalOptions) 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /src/ofxWin8Touch.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ofxWin8Touch.cpp 3 | * Windows 8 touch event handling. 4 | * 5 | * Created by Robert Xiao on August 24, 2015. 6 | */ 7 | 8 | #pragma once 9 | #ifndef _WIN32_WINNT 10 | #define _WIN32_WINNT _WIN32_WINNT_WIN8 11 | #endif 12 | 13 | #include "ofMain.h" 14 | #include "ofEvents.h" 15 | 16 | #include "ofxWin8Touch.h" 17 | 18 | static WNDPROC prevWndProc; 19 | 20 | /* Get window pointer */ 21 | struct EnumWindowsCallbackArgs { 22 | EnumWindowsCallbackArgs( DWORD p ) : pid( p ) { } 23 | const DWORD pid; 24 | std::vector handles; 25 | }; 26 | 27 | static BOOL CALLBACK EnumWindowsCallback( HWND hnd, LPARAM lParam ) { 28 | EnumWindowsCallbackArgs *args = (EnumWindowsCallbackArgs *)lParam; 29 | 30 | DWORD windowPID; 31 | (void)::GetWindowThreadProcessId( hnd, &windowPID ); 32 | if ( windowPID == args->pid ) { 33 | args->handles.push_back( hnd ); 34 | } 35 | 36 | return TRUE; 37 | } 38 | 39 | static std::vector getToplevelWindows() { 40 | EnumWindowsCallbackArgs args( ::GetCurrentProcessId() ); 41 | if ( ::EnumWindows( &EnumWindowsCallback, (LPARAM) &args ) == FALSE ) { 42 | return std::vector(); 43 | } 44 | return args.handles; 45 | } 46 | 47 | static HWND getOfxWindow() { 48 | HWND hwnd = ofGetWin32Window(); 49 | if(!hwnd) { 50 | /* Glut or something */ 51 | vector windows = getToplevelWindows(); 52 | HWND consoleWindow = GetConsoleWindow(); 53 | for(HWND h : windows) { 54 | if(h != consoleWindow) { 55 | hwnd = h; 56 | break; 57 | } 58 | } 59 | } 60 | return hwnd; 61 | } 62 | 63 | /* Handle incoming pointer event */ 64 | static bool handlePointerEvent(UINT uMsg, WPARAM wParam, LPARAM lParam) { 65 | UINT32 pointerId = GET_POINTERID_WPARAM(wParam); 66 | POINTER_INPUT_TYPE pointerType = PT_POINTER; 67 | 68 | if (!GetPointerType(pointerId, &pointerType)) { 69 | ofLogError() << "GetPointerType failed: 0x" << hex << GetLastError(); 70 | pointerType = PT_POINTER; // default to PT_POINTER 71 | } 72 | 73 | ofTouchEventArgs touch; 74 | 75 | union { 76 | POINTER_INFO pointer; 77 | POINTER_TOUCH_INFO touch; 78 | POINTER_PEN_INFO pen; 79 | } info; 80 | POINTER_INFO *pointer = &info.pointer; 81 | 82 | switch (pointerType) { 83 | case PT_TOUCH: { 84 | if(!GetPointerTouchInfo(pointerId, &info.touch)) { 85 | ofLogError() << "GetPointerTouchInfo failed: 0x" << hex << GetLastError(); 86 | return false; 87 | } 88 | pointer = &info.touch.pointerInfo; 89 | 90 | touch.width = info.touch.rcContact.right - info.touch.rcContact.left; 91 | touch.height = info.touch.rcContact.bottom - info.touch.rcContact.top; 92 | touch.angle = info.touch.orientation; // degrees 0-359 93 | touch.pressure = info.touch.pressure; // 0-1024 94 | touch.majoraxis = max(touch.width, touch.height); 95 | touch.minoraxis = min(touch.width, touch.height); 96 | break; 97 | } 98 | case PT_PEN: { 99 | if (!GetPointerPenInfo(pointerId, &info.pen)) { 100 | ofLogError() << "GetPointerPenInfo failed: 0x" << hex << GetLastError(); 101 | return false; 102 | } 103 | pointer = &info.pen.pointerInfo; 104 | 105 | touch.width = touch.height = 0; 106 | touch.angle = info.pen.rotation; // degrees 0-359 107 | touch.pressure = info.pen.pressure; // 0-1024 108 | touch.majoraxis = touch.minoraxis = 0; 109 | 110 | break; 111 | } 112 | default: 113 | return false; /* unsupported pointer type */ 114 | } 115 | 116 | /* Use HIMETRIC positions for improved precision (subpixel) */ 117 | RECT himetricRect, displayRect; 118 | if(GetPointerDeviceRects(pointer->sourceDevice, &himetricRect, &displayRect) 119 | && himetricRect.right - himetricRect.left > 0 120 | && himetricRect.bottom - himetricRect.top > 0) { 121 | double x = ((double)pointer->ptHimetricLocation.x - himetricRect.left) / (himetricRect.right - himetricRect.left); 122 | double y = ((double)pointer->ptHimetricLocation.y - himetricRect.top) / (himetricRect.bottom - himetricRect.top); 123 | touch.x = displayRect.left + x * (displayRect.right - displayRect.left) - ofGetWindowPositionX(); 124 | touch.y = displayRect.top + y * (displayRect.bottom - displayRect.top) - ofGetWindowPositionY(); 125 | } else { 126 | touch.x = pointer->ptPixelLocation.x - ofGetWindowPositionX(); 127 | touch.y = pointer->ptPixelLocation.y - ofGetWindowPositionY(); 128 | } 129 | touch.id = pointer->pointerId; 130 | if(pointer->pointerFlags & (POINTER_FLAG_CANCELED | POINTER_FLAG_CAPTURECHANGED)) { 131 | /* Cancelled */ 132 | touch.type = ofTouchEventArgs::Type::cancel; 133 | ofNotifyEvent(ofEvents().touchCancelled, touch); 134 | return true; 135 | } 136 | 137 | /* 138 | if(!(pointer->pointerFlags & POINTER_FLAG_CONFIDENCE)) { 139 | ofLogError() << "pointer id " << touch.id << " not confident: flags 0x" << hex << pointer->pointerFlags; 140 | } 141 | */ 142 | 143 | if(pointer->pointerFlags & POINTER_FLAG_DOWN) { 144 | touch.type = ofTouchEventArgs::Type::down; 145 | ofNotifyEvent(ofEvents().touchDown, touch); 146 | } 147 | if(pointer->pointerFlags & POINTER_FLAG_UPDATE) { 148 | touch.type = ofTouchEventArgs::Type::move; 149 | ofNotifyEvent(ofEvents().touchMoved, touch); 150 | } 151 | if(pointer->pointerFlags & POINTER_FLAG_UP) { 152 | touch.type = ofTouchEventArgs::Type::up; 153 | ofNotifyEvent(ofEvents().touchUp, touch); 154 | } 155 | return true; 156 | } 157 | 158 | /* Window callback function */ 159 | LRESULT APIENTRY pointerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 160 | switch(uMsg) { 161 | case WM_POINTERUPDATE: 162 | if(!IS_POINTER_INCONTACT_WPARAM(wParam)) 163 | break; 164 | /* fall through */ 165 | case WM_POINTERDOWN: 166 | case WM_POINTERUP: 167 | case WM_POINTERCAPTURECHANGED: 168 | if(handlePointerEvent(uMsg, wParam, lParam)) 169 | return 0; 170 | break; // fail, call CallWindowProc 171 | } 172 | // Chain to the next wndproc 173 | return CallWindowProc(prevWndProc, hwnd, uMsg, wParam, lParam); 174 | } 175 | 176 | void ofxWin8TouchSetup() { 177 | HWND hwnd = getOfxWindow(); 178 | if(!hwnd) { 179 | ofLogError() << "Failed to get HWND for ofx window - try calling this later in update()."; 180 | return; 181 | } 182 | 183 | if(prevWndProc) { 184 | ofLogError() << "Already called ofxWin8TouchSetup!"; 185 | return; 186 | } 187 | 188 | prevWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)pointerWndProc); 189 | } 190 | --------------------------------------------------------------------------------