Extract text location by hooking ExtTextOutW - c++

I have question regarding the Windows APIs RedrawWindow , ExtTextOut and BitBlt .
I am hooking the ExtTextOut to extract the text location on screen, if I call RedrawWindow with parameter lprcUpdate = NULL and hrgnUpdate = NULL:
WindowWrapper.RedrawWindow(topWnd, IntPtr.Zero, IntPtr.Zero, RedrawWindowFlags.UpdateNow | RedrawWindowFlags.Frame | RedrawWindowFlags.Invalidate | RedrawWindowFlags.AllChildren | RedrawWindowFlags.Erase);
In hooked function ExtTextOut, I call LPToDP API to translate the location to device context location. Then it works fine. The text location is correct.
WindowWrapper.LPtoDP(hdc, arrPoint, 2);
But, if I call
WindowWrapper.RedrawWindow(topWnd, ref location, IntPtr.Zero, RedrawWindowFlags.UpdateNow | RedrawWindowFlags.Frame | RedrawWindowFlags.Invalidate | RedrawWindowFlags.AllChildren | RedrawWindowFlags.Erase);
Then it fails. The location is incorrect. I see that it translated by using LPToDP into incorrect location.
Any one know about this problem? How can we fix it?
public static bool ExtTextOutW_Hook(IntPtr hdc, int X, int Y, uint fuOptions,
IntPtr lprc, [MarshalAs(UnmanagedType.LPWStr)] string lpString,
uint cbCount, IntPtr lpDx)
{
try
{
lock (IsRetrievingSynch)
{
if (IsRetrieving && !string.IsNullOrEmpty(lpString) && cbCount > 0)
{
TextData textData = new TextData();
textData.FuncName = "ExtTextOutW";
char[] text = new char[cbCount];
bool isGlyphIndex = ((fuOptions & 0x0010) == 0x0010);
//ETO_GLYPH_INDEX
if (isGlyphIndex)
{
FontMap fontMap = GlyphCharMap.LoadGlyphCharMap(hdc);
if (fontMap != null && fontMap.GlyphCharMap != null)
{
for (int i = 0; i < cbCount; i++)
{
ushort glyph = lpString[i];
if (glyph < fontMap.GlyphCharMap.Length)
{
if (fontMap.GlyphCharMap[glyph] != 0)
{
text[i] = (char)(fontMap.GlyphCharMap[glyph]);
}
else
{
text[i] = (char)32;
}
}
else
{
text[i] = (char)glyph;
}
}
}
}
else
{
for (int i = 0; i < cbCount; i++)
{
text[i] = lpString[i];
}
}
textData.Text = new string(text);
textData.Text = textData.Text.Normalize(NormalizationForm.FormKC);
//textData.Text = textData.Text.Trim();
if (!string.IsNullOrEmpty(textData.Text))
{
int realCount = textData.Text.Length;
TEXTMETRICW tm = new TEXTMETRICW();
WindowWrapper.GetTextMetricsW(hdc, out tm);
int[] nWidth = new int[1];
WindowWrapper.GetCharWidth32W(hdc, ' ', ' ', nWidth);
textData.CharHeight = tm.tmHeight;
textData.CharWidth = nWidth[0];
textData.CharWidths = new int[realCount];
for (int i = 0; i < realCount; i++)
{
nWidth = new int[1];
WindowWrapper.GetCharWidth32W(hdc, textData.Text[i], textData.Text[i], nWidth);
textData.CharWidths[i] = nWidth[0];
}
uint textAlign = WindowWrapper.GetTextAlign(hdc);
POINT ptStartPos = new POINT();
if ((textAlign & WindowWrapper.TA_UPDATECP) > 0)
{
WindowWrapper.GetCurrentPositionEx(hdc, out ptStartPos);
}
else
{
ptStartPos.X = X;
ptStartPos.Y = Y;
}
switch (textAlign & (WindowWrapper.TA_BASELINE | WindowWrapper.TA_BOTTOM | WindowWrapper.TA_TOP))
{
case WindowWrapper.TA_BOTTOM:
textData.Location.Top = Y - tm.tmHeight;
textData.Location.Bottom = Y;
break;
case WindowWrapper.TA_BASELINE:
textData.Location.Top = Y - tm.tmAscent;
textData.Location.Bottom = Y + tm.tmDescent;
break;
case WindowWrapper.TA_TOP:
default:
textData.Location.Top = Y;
textData.Location.Bottom = Y + tm.tmHeight;
break;
}
int nLAlign = 0, nRAlign = 0;
switch (textAlign & (WindowWrapper.TA_LEFT | WindowWrapper.TA_RIGHT | WindowWrapper.TA_CENTER))
{
case WindowWrapper.TA_LEFT:
nLAlign = 0;
nRAlign = 2;
break;
case WindowWrapper.TA_CENTER:
nLAlign = -1;
nRAlign = 1;
break;
case WindowWrapper.TA_RIGHT:
nLAlign = -2;
nRAlign = 0;
break;
}
SIZE size = new SIZE();
if (WindowWrapper.GetTextExtentPoint32W(hdc, lpString, (int)cbCount, ref size))
{
textData.Location.Left = X + nLAlign * (size.CX / 2);
textData.Location.Right = X + nRAlign * (size.CX / 2);
}
else
{
textData.Location.Left = X - 20;
textData.Location.Right = X + 20;
}
LogFactory.RemoteLog.TraceDebug(string.Format("1.ExtTextOutW {0} {1} {2} {3} {4}",
textData.Text, textData.Location.Left, textData.Location.Top,
textData.Location.Right - textData.Location.Left,
textData.Location.Bottom - textData.Location.Top));
//Utility.ClipViewPort(hdc, ref textData.Location);
POINT[] arrPoint = new POINT[2];
arrPoint[0] = new POINT()
{
X = textData.Location.Left,
Y = textData.Location.Top
};
arrPoint[1] = new POINT()
{
X = textData.Location.Right,
Y = textData.Location.Bottom
};
POINT ptDCOrg = new POINT();
WindowWrapper.LPtoDP(hdc, arrPoint, 2);
textData.Location.Left = arrPoint[0].X;
textData.Location.Top = arrPoint[0].Y;
textData.Location.Right = arrPoint[1].X;
textData.Location.Bottom = arrPoint[1].Y;
WindowWrapper.GetDCOrgEx(hdc, out ptDCOrg);
textData.Location.Left += ptDCOrg.X;
textData.Location.Top += ptDCOrg.Y;
textData.Location.Right += ptDCOrg.X;
textData.Location.Bottom += ptDCOrg.Y;
LogFactory.RemoteLog.TraceDebug(string.Format("2.ExtTextOutW {0} {1} {2} {3} {4}",
textData.Text, textData.Location.Left, textData.Location.Top,
textData.Location.Right - textData.Location.Left,
textData.Location.Bottom - textData.Location.Top));
StringBuilder fontName = new StringBuilder();
fontName.Capacity = 260;
WindowWrapper.GetTextFace(hdc, 260, fontName);
textData.Font = fontName.ToString();
IntPtr hWnd = WindowWrapper.WindowFromDC(hdc);
if (WindowWrapper.IsWindowVisible(hWnd))
{
textData.Hdc = hdc;
textData.Hwnd = hWnd;
textData.ZOrder = WindowWrapper.GetZOrder(hWnd);
if (Utility.IsIntersect(_location, textData.Location) && WindowWrapper.IsChildWindow(_topWindow, hWnd))
{
LogFactory.RemoteLog.TraceVerbose(string.Format("3.ExtTextOutW {0} {1} {2} {3} {4} Z-Order: {5}",
textData.Text,
textData.Location.Left,
textData.Location.Top,
textData.Location.Right - textData.Location.Left,
textData.Location.Bottom - textData.Location.Top,
textData.ZOrder));
if (TextDataChannel != null)
TextDataChannel.SendTextData(textData);
}
}
else
{
textData.Hdc = hdc;
//if (lpDx != IntPtr.Zero)
// Utility.ClipViewPort(hdc, ref textData.Location);
_tempDataList.Add(textData);
}
}
}
}
}
catch (Exception ex)
{
LogFactory.RemoteLog.TraceError("ExtTextOutW " + ex.Message);
}
return ExtTextOutW(hdc, X, Y, fuOptions, lprc, lpString, cbCount, lpDx);
}
Thanks.

Related

How I change the resolution one monitor only

For example, my computer has two monitors, the primary monitor's resolution is 800*600, the other monitor's resolution is 1600*900.
I would like define the resolution on one monitor only ?
The function 'SetDisplayConfig' change the resolution screen on the two minotors...
https://learn.microsoft.com/fr-fr/windows-hardware/drivers/display/ccd-apis
https://learn.microsoft.com/fr-fr/windows/win32/api/winuser/nf-winuser-setdisplayconfig
[DllImport("User32.dll")]
public static extern int SetDisplayConfig(
uint numPathArrayElements,
[In] DisplayConfigPathInfo[] pathArray,
uint numModeInfoArrayElements,
[In] DisplayConfigModeInfo[] modeInfoArray,
SdcFlags flags
);
private static Boolean SetDisplaySettings(int Id_Monitor, uint Width, uint Height, uint Scaling)
{
try
{
CCDWrapper.DisplayConfigPathInfo[] pathInfoArray = new CCDWrapper.DisplayConfigPathInfo[0] { };
CCDWrapper.DisplayConfigModeInfo[] modeInfoArray = new CCDWrapper.DisplayConfigModeInfo[0] { };
CCDWrapper.MonitorAdditionalInfo[] additionalInfo = new CCDWrapper.MonitorAdditionalInfo[0] { };
bool Status = GetDisplaySettings(ref pathInfoArray, ref modeInfoArray, ref additionalInfo, true);
CCDWrapper.DisplayConfigPathInfo[] pathInfoArrayCurrent = new CCDWrapper.DisplayConfigPathInfo[0] { };
CCDWrapper.DisplayConfigModeInfo[] modeInfoArrayCurrent = new CCDWrapper.DisplayConfigModeInfo[0] { };
CCDWrapper.MonitorAdditionalInfo[] additionalInfoCurrent = new CCDWrapper.MonitorAdditionalInfo[0] { };
bool StatusCurrent = GetDisplaySettings(ref pathInfoArrayCurrent, ref modeInfoArrayCurrent, ref additionalInfoCurrent, false);
if (StatusCurrent)
{
for (int iPathInfo = 0; iPathInfo <= pathInfoArray.Length-1; iPathInfo++)
//for (int iPathInfo = 0; iPathInfo <= pathInfoArray.Length - 1; iPathInfo++)
{
for (int iPathInfoCurrent = 0; iPathInfoCurrent <= pathInfoArrayCurrent.Length - 1; iPathInfoCurrent++)
{
if ((pathInfoArray[iPathInfo].sourceInfo.id == pathInfoArrayCurrent[iPathInfoCurrent].sourceInfo.id) && (pathInfoArray[iPathInfo].targetInfo.id == pathInfoArrayCurrent[iPathInfoCurrent].targetInfo.id))
{
pathInfoArray[iPathInfo].sourceInfo.adapterId.LowPart = pathInfoArrayCurrent[iPathInfoCurrent].sourceInfo.adapterId.LowPart;
pathInfoArray[iPathInfo].targetInfo.adapterId.LowPart = pathInfoArrayCurrent[iPathInfoCurrent].targetInfo.adapterId.LowPart;
pathInfoArray[iPathInfo].targetInfo.scaling = (CCDWrapper.DisplayConfigScaling)Scaling;
break;
}
}
}
for (int iModeInfo = 0; iModeInfo <= modeInfoArray.Length - 1; iModeInfo++)
{
for (int iPathInfo = 0; iPathInfo <= pathInfoArray.Length - 1; iPathInfo++)
{
if ((modeInfoArray[iModeInfo].id == pathInfoArray[iPathInfo].targetInfo.id) && (modeInfoArray[iModeInfo].infoType == CCDWrapper.DisplayConfigModeInfoType.Target))
{
for (int iModeInfoSource = 0; iModeInfoSource <= modeInfoArray.Length - 1; iModeInfoSource++)
{
if ((modeInfoArray[iModeInfoSource].id == pathInfoArray[iPathInfo].sourceInfo.id) && (modeInfoArray[iModeInfoSource].adapterId.LowPart == modeInfoArray[iModeInfo].adapterId.LowPart) && (modeInfoArray[iModeInfoSource].infoType == CCDWrapper.DisplayConfigModeInfoType.Source))
{
modeInfoArray[iModeInfoSource].adapterId.LowPart = pathInfoArray[iPathInfo].sourceInfo.adapterId.LowPart;
modeInfoArray[iModeInfoSource].sourceMode.height = Height;
modeInfoArray[iModeInfoSource].sourceMode.width = Width;
break;
}
}
modeInfoArray[iModeInfo].adapterId.LowPart = pathInfoArray[iPathInfo].targetInfo.adapterId.LowPart;
break;
}
}
}
uint numPathArrayElements = System.Convert.ToUInt32(pathInfoArray.Length);
uint numModeInfoArrayElements = System.Convert.ToUInt32(modeInfoArray.Length);
long Result = CCDWrapper.SetDisplayConfig(numPathArrayElements, pathInfoArray, numModeInfoArrayElements, modeInfoArray, CCDWrapper.SdcFlags.Apply | CCDWrapper.SdcFlags.UseSuppliedDisplayConfig | CCDWrapper.SdcFlags.SaveToDatabase | CCDWrapper.SdcFlags.NoOptimization | CCDWrapper.SdcFlags.AllowChanges);
if (Result == 0)
return true;
else
return false;
}
else
return false;
}
catch (Exception ex)
{
EventLog.WriteEntry("ResolutionEcran", "Erreur SetDisplaySettings : " + ex.Message, EventLogEntryType.Error);
return false;
}
}
private static Boolean GetDisplaySettings(ref CCDWrapper.DisplayConfigPathInfo[] pathInfoArray, ref CCDWrapper.DisplayConfigModeInfo[] modeInfoArray, ref CCDWrapper.MonitorAdditionalInfo[] additionalInfo, Boolean ActiveOnly, [System.Runtime.InteropServices.Optional] int ID_Monitor)
{
uint numPathArrayElements;
uint numModeInfoArrayElements;
CCDWrapper.QueryDisplayFlags queryFlags = CCDWrapper.QueryDisplayFlags.AllPaths;
if (ActiveOnly)
{
//queryFlags = CCDWrapper.QueryDisplayFlags.OnlyActivePaths;
queryFlags = CCDWrapper.QueryDisplayFlags.OnlyActivePaths;
}
var status = CCDWrapper.GetDisplayConfigBufferSizes(queryFlags, out numPathArrayElements, out numModeInfoArrayElements);
if (status == 0)
{
pathInfoArray = new CCDWrapper.DisplayConfigPathInfo[numPathArrayElements];
modeInfoArray = new CCDWrapper.DisplayConfigModeInfo[numModeInfoArrayElements];
additionalInfo = new CCDWrapper.MonitorAdditionalInfo[numModeInfoArrayElements];
status = CCDWrapper.QueryDisplayConfig(queryFlags, ref numPathArrayElements, pathInfoArray, ref numModeInfoArrayElements, modeInfoArray, IntPtr.Zero);
if (status == 0)
{
for (var iMode = 0; iMode < numModeInfoArrayElements; iMode++)
{
if (modeInfoArray[iMode].infoType == CCDWrapper.DisplayConfigModeInfoType.Target)
{
try
{
additionalInfo[iMode] = CCDWrapper.GetMonitorAdditionalInfo(modeInfoArray[iMode].adapterId, modeInfoArray[iMode].id);
}
catch (Exception)
{
additionalInfo[iMode].valid = false;
}
}
}
return true;
}
else
{
//Erreur : Querying display;
}
}
else
{
//Erreur : Taille Buffer;
}
return false;
}
Use ChangeDisplaySettingsEx function to change the settings of the specified display device to the specified graphics mode. The following is an example you can refer to.
#include <windows.h>
int main()
{
for (DWORD devNum = 0; ; devNum++)
{
DISPLAY_DEVICE dev = {0};
dev.cb = sizeof(DISPLAY_DEVICE);
if (!EnumDisplayDevices(NULL, devNum, &dev, EDD_GET_DEVICE_INTERFACE_NAME))
break;
wprintf(L"Display name: %s \n", dev.DeviceName);
DEVMODE dMode = { 0 };
dMode.dmSize = sizeof(dMode);
if (!EnumDisplaySettings(dev.DeviceName, ENUM_CURRENT_SETTINGS, &dMode))
{
wprintf(L"EnumDisplaySettings error: %d \n", GetLastError());
continue;
}
wprintf(L"Display old settings: \n");
wprintf(L"dmBitsPerPel: %d \n", dMode.dmBitsPerPel);
wprintf(L"dmPelsWidth: %d \n", dMode.dmPelsWidth);
wprintf(L"dmPelsHeight: %d \n", dMode.dmPelsHeight);
wprintf(L"dmDisplayFlags: %x \n", dMode.dmDisplayFlags);
wprintf(L"dmDisplayFrequency: %d \n", dMode.dmDisplayFrequency);
dMode.dmPelsWidth = 800;
dMode.dmPelsHeight = 600;
ChangeDisplaySettingsEx(dev.DeviceName, &dMode, NULL, 0, NULL);
DEVMODE dModeNew = { 0 };
dModeNew.dmSize = sizeof(DEVMODE);
if (!EnumDisplaySettings(dev.DeviceName, ENUM_CURRENT_SETTINGS, &dModeNew))
{
wprintf(L"EnumDisplaySettings error: %d \n", GetLastError());
continue;
}
wprintf(L"Display new settings: \n");
wprintf(L"dmBitsPerPel: %d \n", dModeNew.dmBitsPerPel);
wprintf(L"dmPelsWidth: %d \n", dModeNew.dmPelsWidth);
wprintf(L"dmPelsHeight: %d \n", dModeNew.dmPelsHeight);
wprintf(L"dmDisplayFlags: %x \n", dModeNew.dmDisplayFlags);
wprintf(L"dmDisplayFrequency: %d \n", dModeNew.dmDisplayFrequency);
}
getchar();
}
I set dwflags to 0 let the graphics mode for the current screen change dynamically. Refer to dwflags parameter part of ChangeDisplaySettingsEx's document for deciding how you would like the graphics mode should be changed.
Sorry for my late response...I was absent.
I also need to change the scaling of monitor (Black bars removed on certain resolutions).
[Flags]
public enum DisplayConfigScaling : uint
{
Zero = 0x0,
Identity = 1,
Centered = 2,
Stretched = 3,
Aspectratiocenteredmax = 4,
Custom = 5,
Preferred = 128,
ForceUint32 = 0xFFFFFFFF
}
The function 'ChangeDisplaySettingsEx' may change the scale of monitor ?
Thank you very for your help.

create video from images with animation

I have ten images to create a video with animation , like that
https://youtu.be/iu9uazolcC8
it use freeImage and FFmpeg.
MovieWriter writer(fileName, IMG_WIDTH, IMG_HEIGHT);
vector<char*> ls = {
"D:/createVideo/src/c/1.jpg",
"D:/createVideo/src/c/2.jpg",
"D:/createVideo/src/c/3.jpg",
"D:/createVideo/src/c/4.jpg",
"D:/createVideo/src/c/5.jpg",
"D:/createVideo/src/c/6.jpg",
"D:/createVideo/src/c/7.jpg",
"D:/createVideo/src/c/8.jpg",
"D:/createVideo/src/c/9.jpg",
"D:/createVideo/src/c/10.jpg",
};
FREE_IMAGE_FORMAT pic_type = FIF_JPEG;
FIBITMAP *fiCopy = NULL;
FIBITMAP *corpImg = NULL;
uint8_t *ut = NULL;
for (int i=0;i<10;i++)
{
char *src_pic_path = ls[i];
FIBITMAP *fi = FreeImage_Load(pic_type, src_pic_path);
if(fi==NULL){
continue;
}
int w = IMG_WIDTH;
int h = IMG_HEIGHT;
unsigned int index = 0;
while (w > IMG_MIN_W_SCALE || h > IMG_MIN_H_SCALE)
{
fiCopy = FreeImage_RescaleRect(fi, IMG_WIDTH, IMG_HEIGHT,0, 0, w * 2, h * 2);
if(fiCopy == NULL){
break;
}
corpImg = FreeImage_Rescale(fiCopy, IMG_WIDTH, IMG_HEIGHT);
if(corpImg == NULL){
break;
}
ut = FreeImage_GetBits(corpImg);
if(ut == NULL){
break;
}
w -= ONE_W_PIECE;
h -= ONE_H_PIECE;
writer.addFrame(ut);
FreeImage_Unload(corpImg);
FreeImage_Unload(fiCopy);
index++;
}
}
but it so slowly, how to optimization that code? or how to faster to create that video?
would you know about an option to do that?

SDL text box highlighting text

I am making a program in C++ that uses SDL to display text boxes. I've made the basic functions of my text boxes like typing text, limitations, copy/paste, etc. but I am stuck at make it able to highlight text.
Here's how I draw textboxes:
void draw_text_box(SDL_Surface *screan, char *message, struct textbox *text_box, int r, int g, int b)
{
int temp_width;
int temp_frame;
SDL_Surface *text;
SDL_Color textcolor = {0,0,0,0};
SDL_Rect temp_location, clr_box;
temp_width = text_box->location.w; //preserve the correct width
temp_location = text_box->location;
temp_location.y += 4;
temp_location.h = 12;
clr_box = text_box->location;
//colors!
textcolor.r = r;
textcolor.g = g;
textcolor.b = b;
//text = TTF_RenderText_Solid(ttf_font, text_box->prev_message, textcolor);
//SDL_BlitSurface( text, NULL, screan, &text_box->location);//<-changes "location" width to width of text
//clear
SDL_FillRect(screan, &clr_box, SDL_MapRGB(screen->format, 0, 0, 0));
//strcpy(text_box->prev_message, message);
//set the text
text = TTF_RenderText_Solid(ttf_font, message, textcolor);
if(!text) return;
//set the offset
temp_location.x = text_box->last_shift;
temp_location.y = 0;
temp_location.h = text->h;
if(text_box->cursor_loc - text_box->last_shift > temp_location.w)
temp_location.x = text_box->cursor_loc - temp_location.w;
if(text_box->cursor_loc - 3 < text_box->last_shift)
temp_location.x = text_box->cursor_loc - 3;
if(temp_location.x < 0) temp_location.x = 0;
text_box->last_shift = temp_location.x;
//draw
SDL_BlitSurface( text, &temp_location, screan, &text_box->location);//<-changes "location" width to width of text
text_box->location.w = temp_width;
}
Setting the text:
void set_text_box_text(SDL_Surface *screan, struct textbox *text_box, char *message)
{
if(text_box->message != message)
strcpy(text_box->message, message);
text_box->char_amt = strlen(message);
text_box->cursor = text_box->char_amt;
text_box->last_shift = 0;
if (screan) //if not NULL
{
if (text_box->selected)
select_text_box(screan,text_box);
else
unselect_text_box(screan,text_box);
}
else
{
;//text_box->prev_message[0] = '\0';
}
}
Select and deselect the textbox:
void select_text_box(SDL_Surface *screan, struct textbox *text_box)
{
char temp_message[405] = "";
char temp_left[405];
int i;
text_box->selected = 1;
if (text_box->pass_char == '\0')
{
if (text_box->cursor != 0)
{
left(temp_left, text_box->message, text_box->cursor);
strcat(temp_message, temp_left);
}
temp_message[text_box->cursor] = '|';
temp_message[text_box->cursor + 1] = '\0';
right(temp_left, text_box->message, text_box->cursor);
strcat(temp_message, temp_left);
}
else
{
for(i=0;i<text_box->cursor;i++)
temp_message[i] = text_box->pass_char;
temp_message[i] = '|';
for(i++;i<text_box->char_amt + 1;i++)
temp_message[i] = text_box->pass_char;
temp_message[i] = '\0';
}
draw_text_box(screan, temp_message, text_box, 250, 250, 250);
}
void unselect_text_box(SDL_Surface *screan, struct textbox *text_box)
{
char temp_message[405];
int i;
text_box->selected = 0;
if (text_box->pass_char == '\0')
draw_text_box(screan, text_box->message, text_box, 250, 250, 250);
else
{
for(i=0;i<text_box->char_amt;i++)
temp_message[i] = text_box->pass_char;
temp_message[i] = '\0';
draw_text_box(screan, temp_message, text_box, 250, 250, 250);
}
}

How to inject individual touches on Windows 8.1 C++

I have been trying to inject individual contacts (Touch events) on Windows 8. I'm using the InjectTouchInput described here, so I'm able to inject two contacts with the next code:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
#include <windows.h>
using namespace std;
class calculate
{
POINTER_TOUCH_INFO contact[2];
public:
calculate(int m);
void setDots(long x, long y, long x2, long y2, int opt, string num_dots);
};
calculate::calculate(int m)
{
}
void calculate::setDots(long x, long y, long x2, long y2, int opt, string num_dots)
{
switch (opt)
{
case 0:
InitializeTouchInjection(2, TOUCH_FEEDBACK_INDIRECT);
memset(&contact[0], 0, sizeof(POINTER_TOUCH_INFO));
memset(&contact[1], 0, sizeof(POINTER_TOUCH_INFO));
contact[0].pointerInfo.pointerType = PT_TOUCH;
contact[0].pointerInfo.pointerId = 0; //Id 0 for contact 0
contact[0].pointerInfo.ptPixelLocation.y = y;
contact[0].pointerInfo.ptPixelLocation.x = x;
contact[0].touchFlags = TOUCH_FLAG_NONE;
contact[0].touchMask = TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE;
contact[0].orientation = 90;
contact[0].pressure = 32000;
contact[0].rcContact.top = contact[0].pointerInfo.ptPixelLocation.y - 2;
contact[0].rcContact.bottom = contact[0].pointerInfo.ptPixelLocation.y + 2;
contact[0].rcContact.left = contact[0].pointerInfo.ptPixelLocation.x - 2;
contact[0].rcContact.right = contact[0].pointerInfo.ptPixelLocation.x + 2;
contact[1].pointerInfo.pointerType = PT_TOUCH;
contact[1].pointerInfo.pointerId = 1; //Id 0 for contact 1
contact[1].pointerInfo.ptPixelLocation.y = y2;
contact[1].pointerInfo.ptPixelLocation.x = x2;
contact[1].touchFlags = TOUCH_FLAG_NONE;
contact[1].touchMask = TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE;
contact[1].orientation = 90;
contact[1].pressure = 32000;
contact[1].rcContact.top = contact[1].pointerInfo.ptPixelLocation.y - 2;
contact[1].rcContact.bottom = contact[1].pointerInfo.ptPixelLocation.y + 2;
contact[1].rcContact.left = contact[1].pointerInfo.ptPixelLocation.x - 2;
contact[1].rcContact.right = contact[1].pointerInfo.ptPixelLocation.x + 2;
break;
case 1:
contact[0].pointerInfo.ptPixelLocation.y = y;
contact[0].pointerInfo.ptPixelLocation.x = x;
contact[1].pointerInfo.ptPixelLocation.y = y2;
contact[1].pointerInfo.ptPixelLocation.x = x2;
contact[0].pointerInfo.pointerFlags = POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
contact[1].pointerInfo.pointerFlags = POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
break;
case 2:
/*if I inject this flag to first contact [0], both points stopped, but I'm able to inject this flag to the second contact [1] and all is OK*/
//contact[0].pointerInfo.pointerFlags = POINTER_FLAG_UP;
contact[0].pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
contact[1].pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
//contact[1].pointerInfo.pointerId = 0;
//contact[0].pointerInfo.pointerId = 1;
contact[0].pointerInfo.ptPixelLocation.x =x;
contact[0].pointerInfo.ptPixelLocation.y =y;
contact[1].pointerInfo.ptPixelLocation.x =x2;
contact[1].pointerInfo.ptPixelLocation.y =y2;
//num_dots = "single";
break;
case 3:
contact[0].pointerInfo.pointerFlags = POINTER_FLAG_UP;
contact[1].pointerInfo.pointerFlags = POINTER_FLAG_UP;
break;
}
bool s;
//check how many points to inject
if(num_dots == "single")
s = InjectTouchInput(1, contact);
else
s = InjectTouchInput(2, contact);
if(!s)
{
LPWSTR str = new wchar_t[255];
auto t = GetLastError();
wsprintf(str, L"error: %d\n", t);
OutputDebugString(str);
wsprintf(str, L" action: %d\n", opt);
OutputDebugString(str);
}
else
{
LPWSTR str = new wchar_t[255];
auto t = GetLastError();
wsprintf(str, L"action %d\n", opt);
OutputDebugString(str);
}
if(opt == 2)
Sleep(20);
}
int c =0;
int
WINAPI WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nShowCmd)
{
bool g = true;
POINT ipoint;
POINT point;
calculate set(0);
if (GetCursorPos(&ipoint))
set.setDots(ipoint.x, ipoint.y, 0,0,0, "single");//initialize both points
do
{
if (GetCursorPos(&point)) {
//stop the loop pressing right click
if((GetKeyState(VK_RBUTTON) & 0x100) != 0)
g = false;
if((GetKeyState(VK_LBUTTON) & 0x100) != 0)
{
if(c<1)
{
if((GetKeyState(VK_LSHIFT) & 0x100) != 0)//injecting DOWN event
set.setDots(point.x, point.y, point.x - 50, point.y + 50, 1, "two");
else
set.setDots(point.x, point.y, 0, 0, 1, "single");
}
else
{
if((GetKeyState(VK_LSHIFT) & 0x100) != 0)//injecting UPDATE event (on move)
set.setDots(point.x, point.y, point.x - 50, point.y + 50, 2, "two");
else
set.setDots(point.x, point.y, 0,0,2, "single");
}
c++;
}
else
{
/*if((GetKeyState(VK_LSHIFT) & 0x100) != 0)
set.setDots(0,0,0,0,3, "two");
else
set.setDots(0,0,0,0,3, "single");*/
c = 0;
}
}
} while (g);
}
So, with this code, I'm able to inject one or two touches (if shift key is pressed), and draw on paint using paint brushes. But when I try to inject individual events for each contact, for example contact[0].pointerInfo.pointerFlags = POINTER_FLAG_UP;
contact[1].pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT; both contacts stop, even when I try changing their ids, or changing the number of points to inject.
The above code is just an example, but I have tried using different flags for each contact without success :(
My goal is be able to inject two points, with individual events each one, and if first contact[0] has an UP event, the second contact should still running without stop the process...So, how can I inject individual contacts (touches) with different events each one?
Thank you!

Some new version of opencv_performance for opencv_traincascade?

I have noted that the cascades trained with the program opencv_traincascade does not run with the current version of opencv_performance. I've tried to convert the old performance cpp file to load the new types of cascades, but without success. The code is here:
#include "cv.h"
#include "highgui.h"
#include <cstdio>
#include <cmath>
#include <ctime>
#include <math.h>
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#ifndef PATH_MAX
#define PATH_MAX 512
#endif /* PATH_MAX */
/*typedef struct HidCascade {
int size;
int count;
} HidCascade;
*/
typedef struct ObjectPos {
float x;
float y;
float width;
int found; /* for reference */
int neghbors;
} ObjectPos;
using namespace std;
using namespace cv;
int main(int argc, char* argv[]) {
int i, j;
char* classifierdir = NULL;
//char* samplesdir = NULL;
int saveDetected = 1;
double scale_factor = 1.1;
float maxSizeDiff = 1.5F;
float maxPosDiff = 1.1F;
/* number of stages. if <=0 all stages are used */
//int nos = -1, nos0;
int width = 25;
int height = 15;
int rocsize;
FILE* info;
FILE* resultados;
char* infoname;
char fullname[PATH_MAX];
//char detfilename[PATH_MAX];
char* filename;
//char detname[] = "det-";
CascadeClassifier cascade;
double totaltime;
if (!(resultados = fopen("resultados.txt", "w"))) {
printf("Cannot create results file.\n");
exit(-1);
}
infoname = (char*) "";
rocsize = 20;
if (argc == 1) {
printf("Usage: %s\n -data <classifier_directory_name>\n"
" -info <collection_file_name>\n"
" [-maxSizeDiff <max_size_difference = %f>]\n"
" [-maxPosDiff <max_position_difference = %f>]\n"
" [-sf <scale_factor = %f>]\n"
" [-ni]\n"
" [-rs <roc_size = %d>]\n"
" [-w <sample_width = %d>]\n"
" [-h <sample_height = %d>]\n", argv[0], maxSizeDiff,
maxPosDiff, scale_factor, rocsize, width, height);
return 0;
}
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-data")) {
classifierdir = argv[++i];
} else if (!strcmp(argv[i], "-info")) {
infoname = argv[++i];
} else if (!strcmp(argv[i], "-maxSizeDiff")) {
maxSizeDiff = (float) atof(argv[++i]);
} else if (!strcmp(argv[i], "-maxPosDiff")) {
maxPosDiff = (float) atof(argv[++i]);
} else if (!strcmp(argv[i], "-sf")) {
scale_factor = atof(argv[++i]);
} else if (!strcmp(argv[i], "-ni")) {
saveDetected = 0;
} else if (!strcmp(argv[i], "-rs")) {
rocsize = atoi(argv[++i]);
} else if (!strcmp(argv[i], "-w")) {
width = atoi(argv[++i]);
} else if (!strcmp(argv[i], "-h")) {
height = atoi(argv[++i]);
}
}
if (!cascade.load(classifierdir)) {
printf("Unable to load classifier from %s\n", classifierdir);
return 1;
}
strcpy(fullname, infoname);
filename = strrchr(fullname, '\\');
if (filename == NULL) {
filename = strrchr(fullname, '/');
}
if (filename == NULL) {
filename = fullname;
} else {
filename++;
}
info = fopen(infoname, "r");
totaltime = 0.0;
if (info != NULL) {
int x, y, width, height;
Mat img;
int hits, missed, falseAlarms;
int totalHits, totalMissed, totalFalseAlarms;
int found;
float distance;
int refcount;
ObjectPos* ref;
int detcount;
ObjectPos* det;
int error = 0;
int* pos;
int* neg;
pos = (int*) cvAlloc(rocsize * sizeof(*pos));
neg = (int*) cvAlloc(rocsize * sizeof(*neg));
for (i = 0; i < rocsize; i++) {
pos[i] = neg[i] = 0;
}
printf("+================================+======+======+======+\n");
printf("| File Name | Hits |Missed| False|\n");
printf("+================================+======+======+======+\n");
fprintf(resultados,
"+================================+======+======+======+\n");
fprintf(resultados,
"| File Name | Hits |Missed| False|\n");
fprintf(resultados,
"+================================+======+======+======+\n");
//fprintf (resultados, "%d\n",framesCnt);
totalHits = totalMissed = totalFalseAlarms = 0;
while (!feof(info)) {
fscanf(info, "%s %d", filename, &refcount);
img = imread(fullname);
if (!img.data) {
cout << "ow" << endl;
return -1;
}
ref = (ObjectPos*) cvAlloc(refcount * sizeof(*ref));
for (i = 0; i < refcount; i++) {
error = (fscanf(info, "%d %d %d %d", &x, &y, &width, &height)
!= 4);
if (error)
break;
ref[i].x = 0.5F * width + x;
ref[i].y = 0.5F * height + y;
ref[i].width = sqrt(0.5F * (width * width + height * height));
ref[i].found = 0;
ref[i].neghbors = 0; //in the new cascade, where to get the neighbors?
}
vector<Rect> obj_detectados;
Rect retang;
if (!error) {
totaltime -= time(0);
cascade.detectMultiScale(img, obj_detectados, scale_factor, 4, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
// |CV_HAAR_DO_ROUGH_SEARCH
| CV_HAAR_SCALE_IMAGE, Size(25, 15));
totaltime += time(0);
if (obj_detectados.size() == 0) {
detcount = 0;
} else {
detcount = obj_detectados.size();
}
det = (detcount > 0) ?
((ObjectPos*) cvAlloc(detcount * sizeof(*det))) : NULL;
hits = missed = falseAlarms = 0;
for (vector<Rect>::const_iterator r = obj_detectados.begin();
r != obj_detectados.end(); r++, i++) {
Point r1, r2;
r1.x = (r->x);
r1.y = (r->y);
r2.x = (r->x + r->width);
r2.y = (r->y + r->height);
retang.x = r1.x;
retang.y = r1.y;
retang.width = abs(r2.x - r1.x);
retang.height = abs(r2.y - r1.y);
if (saveDetected) {
rectangle(img, retang, Scalar(0, 0, 255), 3, CV_AA);
}
det[i].x = 0.5F*r->width + r->x;
det[i].y = 0.5F*r->height + r->y;
det[i].width = sqrt(0.5F * (r->width * r->width
+ r->height * r->height));
det[i].neghbors = 1; // i don't know if it will work...
// det[i].neghbors = r.neighbors; --- how to do it in the new version??
found = 0;
for (j = 0; j < refcount; j++) {
distance = sqrtf( (det[i].x - ref[j].x) * (det[i].x - ref[j].x) +
(det[i].y - ref[j].y) * (det[i].y - ref[j].y) );
//cout << distance << endl;
if( (distance < ref[j].width * maxPosDiff) &&
(det[i].width > ref[j].width / maxSizeDiff) &&
(det[i].width < ref[j].width * maxSizeDiff) )
{
ref[j].found = 1;
ref[j].neghbors = MAX( ref[j].neghbors, det[i].neghbors );
found = 1;
}
}
if (!found) {
falseAlarms++;
neg[MIN(det[i].neghbors, rocsize - 1)]++;
//neg[MIN(0, rocsize - 1)]++;
}
}
//imshow("teste", img);
if (saveDetected) {
//strcpy(detfilename, detname);
//strcat(detfilename, filename);
//strcpy(filename, detfilename);
imwrite(fullname, img);
//cvvSaveImage(fullname, img);
}
for (j = 0; j < refcount; j++) {
if (ref[j].found) {
hits++;
//pos[MIN(0, rocsize - 1)]++;
pos[MIN(ref[j].neghbors, rocsize - 1)]++;
} else {
missed++;
}
}
totalHits += hits;
totalMissed += missed;
totalFalseAlarms += falseAlarms;
printf("|%32.64s|%6d|%6d|%6d|\n", filename, hits, missed,
falseAlarms);
//printf("+--------------------------------+------+------+------+\n");
fprintf(resultados, "|%32.64s|%6d|%6d|%6d|\n", filename, hits,
missed, falseAlarms);
//fprintf(resultados,
// "+--------------------------------+------+------+------+\n");
fflush(stdout);
if (det) {
cvFree( &det);
det = NULL;
}
} /* if( !error ) */
//char c = (char) waitKey(10);
// if (c == 27)
// exit(0);
cvFree( &ref);
}
fclose(info);
printf("|%32.32s|%6d|%6d|%6d|\n", "Total", totalHits, totalMissed,
totalFalseAlarms);
fprintf(resultados, "|%32.32s|%6d|%6d|%6d|\n", "Total", totalHits,
totalMissed, totalFalseAlarms);
printf("+================================+======+======+======+\n");
fprintf(resultados,
"+================================+======+======+======+\n");
//printf("Number of stages: %d\n", nos);
//printf("Number of weak classifiers: %d\n", numclassifiers[nos - 1]);
printf("Total time: %f\n", totaltime);
fprintf(resultados, "Total time: %f\n", totaltime);
/* print ROC to stdout */
for (i = rocsize - 1; i > 0; i--) {
pos[i - 1] += pos[i];
neg[i - 1] += neg[i];
}
//fprintf(stderr, "%d\n", nos);
for (i = 0; i < rocsize; i++) {
fprintf(stderr, "\t%d\t%d\t%f\t%f\n", pos[i], neg[i],
((float) pos[i]) / (totalHits + totalMissed),
((float) neg[i]) / (totalHits + totalMissed));
}
cvFree( &pos);
cvFree( &neg);
}
return 0;
}
My doubt is about the det[i].neghbors = r.neighbors; in the old performance.cpp. How I retrieve the neighbors in this new version?
Anyone could help me to convert opencv_performance to run the new cascades from opencv_traincascade?
Many thanks!