Dell just introduced the Latitude XT2 XFR; the rugged version of the XT2 multitouch tablet machine I've mentioned a few times before only with a name that is more of a mouth full. So for those of you waiting for a rugged machine before jumping into multitouch wait no longer. The short spec list is 12 inch multitouch display, 5lbs and 1.5 inches thick and mil spec badassness! It also comes with Vista. I guess Windows 7 isn't rugged certified? Just as well, first thing I do when I get a new machine is format it anyway. For all the awesomeness it'll set you back some serious coin. The base model is $3,600 but I loaded one up for just under $5k! I don't think I can justify one of these to Nick, but damn!
Tuesday, October 27, 2009
Dell Latitude XT2 XFR Rugged Tablet
Posted by
Chris Bensen
at
1:00 PM
1 comments
Labels: Touch
Monday, October 26, 2009
Dell SX2210T - Multitouch Monitors
The first standalone multi-touch monitor is the SX2210T. Looks pretty awesome for those that want to add a multi-touch monitor tho an existing computer.
Updated: Link goes to the product page (which is up now) rather than the shopping cart.
Posted by
Chris Bensen
at
3:00 PM
4
comments
Labels: Touch
Thursday, October 15, 2009
Delphi Tips and Tricks - Additional Files
One of the most useful features in the Delphi IDE is CTRL + F12, or the "Search for units" dialog. One of the problems we encounter is we often want to look at files that are not in any of the opened projects. So a hidden registry key was created to add a list of files to the "Search for units" dialog. You can specify the text file by creating a string value under HKEY_CURRENT_USER\Software\CodeGear\BDS\
The text file format is name value pairs like any other INI file where the name is the short name you want to see and the value is the full path to the file (and this will expand IDE environment variables as well). For example:
Foo.pas=$(TP)\somedirectory\Foo.pas
Posted by
Chris Bensen
at
7:00 AM
3
comments
Labels: C++Builder, Delphi, Tips
Monday, October 12, 2009
Sony Touchscreen Computer/TV
From the specs I think this Sony Vaio L beats pants off the HP Touchsmart. It's got glass, HDMI input, 1080p (I'm not sure if this is the computer resolution as well) Blue-ray, NVIDIA graphics and the monitor can be used as a TV without turning on the computer. I'm not sure what the other computer specs are, but the mouse does look horrible. It also appears that the DVD drive isn't a slot loading drive so that's a bit odd. Check out Sony website for more information.
Posted by
Chris Bensen
at
7:00 AM
2
comments
Labels: Touch
Wednesday, October 7, 2009
Touch Demo Part III
Previously I posted Part I and Part II of the Touch Demo.
This time around we will add the glowing spots and the basic handling of the WM_TOUCH message. Add Generics.Collections to your uses and copy the following code to your unit:
type
TGlowSpot = class
public
X, Y, Radius: Integer;
Alpha: Extended;
FadeIn: Boolean;
Color: TColor;
public
constructor Create(AParent: TWinControl);
procedure Paint(Canvas: TDirect2DCanvas);
end;
TGlowSpotList = class(TList<TGlowSpot>);
...
implementation
{$R *.dfm}
procedure PaintGlow(Canvas: TDirect2DCanvas; Alpha: Single;
X, Y, Radius: Integer; Color: TColor);
var
Stops: array[0 .. 1] of TD2D1GradientStop;
Gradient: ID2D1GradientStopCollection;
BrushProperties: TD2D1RadialGradientBrushProperties;
RadialBrush: ID2D1RadialGradientBrush;
Brush: TDirect2DBrush;
begin
Stops[0].position := 0;
Stops[0].Color := D2D1ColorF(Color, Alpha);
Stops[1].position := 1;
Stops[1].Color := D2D1ColorF(Color, 0);
Canvas.RenderTarget.CreateGradientStopCollection
(@Stops[0], Length(Stops), D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP,
Gradient);
BrushProperties.center := D2D1PointF(X, Y);
BrushProperties.gradientOriginOffset.X := 0;
BrushProperties.gradientOriginOffset.Y := 0;
BrushProperties.radiusX := Radius;
BrushProperties.radiusY := Radius;
Canvas.RenderTarget.CreateRadialGradientBrush
(BrushProperties, nil, Gradient, RadialBrush);
Brush := TDirect2DBrush.Create(Canvas);
Brush.Handle := RadialBrush;
Canvas.Pen.Color := clNone;
Canvas.Brush := Brush;
Canvas.Ellipse(X - Radius, Y - Radius,
X + Radius, Y + Radius);
end;
{ TGlowButton }
constructor TGlowSpot.Create(AParent: TWinControl);
begin
inherited Create;
Alpha := 1;
Radius := 80;
FadeIn := False;
Randomize;
Color := RGB(Random(255), Random(256), Random(256));
end;
procedure TGlowSpot.Paint(Canvas: TDirect2DCanvas);
begin
PaintGlow(Canvas, Alpha, X, Y, Radius, Color);
end;
Add a local to hold a lists of TGlowSpots to your form then create it and free it:
TTouchForm = class(TForm)
...
private
FSpots: TGlowSpotList;
...
constructor TTouchForm.Create(AOwner: TComponent);
begin
inherited;
FCanvas := TDirect2DCanvas.Create(Handle);
FSpots := TGlowSpotList.Create;
end;
destructor TTouchForm.Destroy;
begin
FCanvas.Free;
FSpots.Free;
inherited;
end;
Update the Paint routine to paint the spots:
procedure TTouchForm.Paint;
var
Spot: TGlowSpot;
begin
Canvas.BeginDraw;
try
// Clear Background
Canvas.RenderTarget.Clear(D2D1ColorF(clBlack));
for Spot in FSpots do
Spot.Paint(Canvas);
// FPS
Canvas.Font.Color := clWhite;
Canvas.Brush.Color := clNone;
Canvas.Font.Size := 14;
Canvas.TextOut(10, 10, FloatToStrF(FFPS, ffFixed, 2, 2) + ' FPS');
finally
Canvas.EndDraw;
end;
end;
Modify the Update method to fade the spots:
procedure TTouchForm.Update;
var
Spot: TGlowSpot;
begin
Inc(FFrames);
if GetTickCount - FStartTime >= 1000 then
begin
FFPS := FFrames;
FFrames := 0;
FStartTime := GetTickCount;
end;
for Spot in FSpots do
begin
if Spot.FadeIn then
Spot.Alpha := Spot.Alpha + 0.012
else
Spot.Alpha := Spot.Alpha - 0.012;
if Spot.Alpha < 0.3 then
begin
Spot.FadeIn := True;
Spot.Alpha := 0.4
end
else if Spot.Alpha > 1 then
Spot.FadeIn := False;
end;
end;
And last handle the WM_TOUCH message:
TTouchForm = class(TForm)
...
procedure WMTouch(var Message: TMessage); message WM_TOUCH;
...
procedure TTouchForm.WMTouch(var Message: TMessage);
function TouchPointToPoint(const TouchPoint: TTouchInput): TPoint;
begin
Result := Point(TouchPoint.X div 100, TouchPoint.Y div 100);
PhysicalToLogicalPoint(Handle, Result);
end;
var
TouchInputs: array of TTouchInput;
TouchInput: TTouchInput;
Handled: Boolean;
Point: TPoint;
Spot: TGlowSpot;
begin
Handled := False;
SetLength(TouchInputs, Message.WParam);
GetTouchInputInfo(Message.LParam, Message.WParam, @TouchInputs[0],
SizeOf(TTouchInput));
try
for TouchInput in TouchInputs do
begin
Point := TouchPointToPoint(TouchInput);
Spot := TGlowSpot.Create(Self);
Spot.X := Point.X;
Spot.Y := Point.Y;
FSpots.Add(Spot);
end;
Handled := True;
finally
if Handled then
CloseTouchInputHandle(Message.LParam)
else
inherited;
end;
end;
If you ran your app at this point you wouldn't get any touch messages. You need to call RegisterTouchWindow and UnregisterTouchWindow. I find it easiest to call UnregisterTouchWindow in the FormClose:
procedure TTouchForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnregisterTouchWindow(Handle);
end;
and to call RegisterTouchWindow in the CreateWnd:
procedure TTouchForm.CreateWnd;
begin
inherited;
RegisterTouchWindow(Handle, 0);
end;
Now when you run your app and press the screen you'll get glowing spots wherever you touch the screen. Depending on your hardware 1, 2 or more at a time.
UPDATE: There is a memory leak in this program because I didn't want to delete any code for the next step.
UPDATE: Fixed HTML to make TGlowSpotList = class(TList) actually read TGlowSpotList(TList<TGlowSpot>);
Posted by
Chris Bensen
at
9:00 AM
17
comments
Tuesday, October 6, 2009
How to Write Applications Useful for Color Blind Users
We Are Color Blind is an online repository of information for anyone involved with creating content for the web and making it accessible to the color blind. This is a great resource that I feel is useful for anyone creating content or building applications, not just for the web.
The Quick Tips is probably a good place to start.
UPDATE: Fixed links.
Posted by
Chris Bensen
at
1:00 PM
2
comments
Touch Demo Part II
Last week I posted Touch Demo Part I. This is the continuation to that series.
In Part I I demonstrated how to add the Direct2D Canvas to a form. This step is another foundation step that will add frames to your application by adding a timer.
At the moment the form looks like this:
type
TTouchForm = class(TForm)
private
FCanvas: TDirect2DCanvas;
protected
procedure Paint; override;
procedure Resize; override;
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Canvas: TDirect2DCanvas read FCanvas
write FCanvas;
end;
Add the following private fields to keep track of the frames:
FFPS: Integer;
FFrames: Integer;
FStartTime: Cardinal;
and initialize them in the FormShow:
procedure TTouchForm.FormShow(Sender: TObject);
begin
FFPS := 0;
FFrames := 0;
FStartTime := GetTickCount;
end;
Next update the Paint function:
procedure TTouchForm.Paint;
begin
Canvas.BeginDraw;
try
// Clear Background
Canvas.RenderTarget.Clear(D2D1ColorF(clBlack));
// FPS
Canvas.Font.Color := clWhite;
Canvas.Brush.Color := clNone;
Canvas.Font.Size := 14;
Canvas.TextOut(10, 10, FloatToStrF(FFPS, ffFixed, 2, 2) + ' FPS'); finally
Canvas.EndDraw;
end;
end;
And then add a protected Update method that updates the frames:
procedure TTouchForm.Update;
begin
Inc(FFrames);
if GetTickCount - FStartTime >= 1000 then
begin
FFPS := FFrames;
FFrames := 0;
FStartTime := GetTickCount;
end;
end;
Last, drop a TTimer on your form and set the interval to 10. Also set the form's Align to alClient and the BorderStyle to bsNone.
Next create the OnTimer event and simply call two functions, Update and Paint:
procedure TTouchForm.Timer1Timer(Sender: TObject);
begin
Update;
Paint;
end;
At this point your form should look like this:
type
TTouchForm = class(TForm)
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormShow(Sender: TObject);
private
FCanvas: TDirect2DCanvas;
FFPS: Integer;
FFrames: Integer;
FStartTime: Cardinal;
protected
procedure Update;
procedure Paint; override;
procedure Resize; override;
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Canvas: TDirect2DCanvas read FCanvas
write FCanvas;
end;
Posted by
Chris Bensen
at
8:00 AM
0
comments
Monday, October 5, 2009
HP Touchsmart
If you buy a Touchsmart be sure to spend the extra duckets to get the NVIDIA graphics card. It comes with an NVIDIA GeForce 9300M which is a pretty smokin' card and you'll be much happier.
Posted by
Chris Bensen
at
10:00 AM
2
comments
Thursday, September 24, 2009
Failure Doesn't Preclude Success
This is a brilliant video on how failure doesn't preclude future success:
Posted by
Chris Bensen
at
3:00 PM
1 comments
Tuesday, September 22, 2009
Touch Demo Part I
Over the next few posts I am going to walk you through building one of the touch demos I used in my CodeRage 4 Session. This demo demonstrates using Direct2D and the WM_TOUCH message. Before we get started here is a brief explanation of these two technologies.
Since Windows Vista GDI has become a legacy drawing API supported with software rendering on top of Direct3D. Direct3D is great but it is very raw. This is where Direct2D shines for applications. Direct2D has all the performance benefits of Direct3D and adds support for bitmaps and text and support for GDI Interop all with a much simpler API. And Delphi 2010 has made it even simpler by wrapping it up with a TDirect2DCanvas that is very similar to TCanvas. Direct2D supports remote rendering through Remote Desktop which is very cool.
WM_TOUCH is the raw multi-touch message that provides various states of contact with the input digitizer for hot sizzling touch applications.
Now that we got that out of the way, create yourself a VCL Application. We want to start painting with Direct2D so add Direct2D and D2D1 to the uses and a TDirect2DCanvas property to your form like this:
private
FCanvas: TDirect2DCanvas;
...
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Canvas: TDirect2DCanvas read FCanvas
write FCanvas;
end;
...
constructor TTouchForm.Create(AOwner: TComponent);
begin
inherited;
FCanvas := TDirect2DCanvas.Create(Handle);
end;
destructor TTouchForm.Destroy;
begin
FCanvas.Free;
inherited;
end;
This creates a Direct2D surface (TDirect2DCanvas) that we can draw to instead of the traditional GDI surface (TCanvas).
Depending on the type of application you build you may experience some flicker. To avoid this handle the message WM_ERASEBKGND and returns true.
procedure TTouchForm.WMEraseBkgnd(
var Message: TWMEraseBkgnd);
begin
Message.Result := 1;
end;
Next override Paint and just draw a line:
procedure TTouchForm.Paint;
begin
Canvas.BeginDraw;
try
Canvas.Pen.Color := clRed;
Canvas.MoveTo(10, 10);
Canvas.LineTo(40, 40);
finally
Canvas.EndDraw;
end;
end;
If you run your application at this point and resize the form you will noticed that the line changes size. This is because the view port is resizing to scale to the window and your line will do the same. To prevent this override the Resize method and add the following:
procedure TTouchForm.Resize;
var
HwndTarget: ID2D1HwndRenderTarget;
begin
inherited;
if Supports(Canvas.RenderTarget,
ID2D1HwndRenderTarget, HwndTarget) then
HwndTarget.Resize(D2D1SizeU(ClientWidth, ClientHeight));
Invalidate;
end;
Now you have a form that renders everything drawn to the Canvas through a Direct2D surface.
UPDATE: Added Invalidate to Resize because when resizing the window larger it will force a redraw but smaller will not because typically a redraw isn't required.
Posted by
Chris Bensen
at
10:00 AM
7
comments
Delphi 2010 - Touch and Pen added to TShiftState
While we were researching adding Touch and Gesturing to VCL we quickly realized it was important to detect what type of input produced the mouse messages. So we introduced some new elements to TShiftState: ssTouch and ssPen:
TShiftState = set of (ssShift, ssAlt, ssCtrl,
ssLeft, ssRight, ssMiddle, ssDouble, ssTouch, ssPen);
One of the key reasons this is so important is when handling WM_TOUCH messages the mouse messages are also fired. Chances are you only want to handle one of them. On a non-touch machine you want to handle the mouse. So this allows input to be filtered and handled independently.
Posted by
Chris Bensen
at
8:00 AM
1 comments
Labels: C++Builder, Delphi, Tips, Touch
Wednesday, September 16, 2009
September Photo of the Month

This is a photo of Cottonwood Lake in Inyo National Forest. This photo is a panorama stitched from 14 photos! And one of the most beautiful mornings I've ever had the pleasure to see.
Posted by
Chris Bensen
at
9:49 PM
1 comments
Labels: photo