Showing posts with label CodeGear. Show all posts
Showing posts with label CodeGear. Show all posts

Friday, June 25, 2010

Life before Interfaces

Way way back this is how IUnknown was defined before Delphi added the interface language feature:

IUnknown = class
public
{ IUnknown }
  function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; abstract;
  function _AddRef: Integer; virtual; stdcall; abstract;
  function _Release: Integer; virtual; stdcall; abstract;
end;


Here's IUnknown now:
IUnknown = interface
['{00000000-0000-0000-C000-000000000046}']
  function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  function _AddRef: Integer; stdcall;
  function _Release: Integer; stdcall;
end;

There are so many advantages it's hard to list them all and now we just take them for granted, but here are a few advantages:

  • implement multiple interfaces on the same object
  • compiler support for lifetime management
  • assign an interface to a GUID

Tuesday, June 22, 2010

Cleaning Touch Screens

It's really tough cleaning a touch screen monitor when the computer is on.

Thursday, June 17, 2010

More GetFinalPathNameByHandle

Yesterday I posted about how GetFinalPathNameByHandle is less than ideal. It doesn't work. Well it works in some situations, but it is unusable in a real world situation. The work around is to create a file map to get the file name but that only works if the handle is to a file that is not zero bytes and is not a directory. So for those cases one must use an undesirable function: NTQueryObject. So it works, for now.

Microsoft, please fix GetFinalPathNameByHandle.

Note: I did all my testing on Windows 7. Your milage on Vista may be different.

Wednesday, June 16, 2010

GetFinalPathNameByHandle

Too bad GetFinalPathNameByHandle only works if the handle is a file that has something in it. For a directory or file with zero bytes it fails in a bad way. So you can't get the name of a directory or a zero byte file. Kind of a bummer especially since this is a new to Vista API and would be really nice to have when used in conjunction with CreateSymbolicLink. There are ways of getting around the odd failure by creating a file map, but the directory and zero byte file is a bit more difficult requiring some rather serious hoop jumping.

Monday, March 29, 2010

The Move

This past weekend Embarcadero moved us out of the old Borland building to a new office space a very short distance away. Something about saving some money or something. To my surprise this is what my office cube looked like when I arrived.


Nothing but an Asus EE Touch Top to work with plugged in and ready to go with awesome touch goodness. It didn't take long to realize this was a practical joke. Over the next couple hours my equipment started showing up and here is what my cube should have looked like.

Thursday, February 4, 2010

Hacking the TTouchKeyboard Part IV

Hacking the TTouchKeyboard Part I
Hacking the TTouchKeyboard Part II
Hacking the TTouchKeyboard Part III
Hacking the TTouchKeyboard Part IV
Hacking the TTouchKeyboard Part V (not published yet)

Here is a quick off the top of my head documentation for the XML layout that is used by the keyboard compiler. If something doesn't behave as expected drop me a line with a comment or email so I can get it fixed.


This describes the schema and the attributes for the keyboard layout XML file.

<keyboard keyboardtype="Standard" keyboardname="Standard101" width=768" height="228" maxwidth="0" maxheight="0" minwidth="0" minheight="0">

keyboardtype - this allows multiple keyboard layouts to contribute to an overall keyboard type. For instance, for Standard we have the Standard101, Standard102 and Standard 106 keyboard layouts. Each one specifies a different layout for the Standard keyboard layout depending on the keyboard's language. This becomes the value of the TTouchKeyboard.KeyboardLayout property.

keyboardname - this is only used for humans to distinguish which keyboard layout is being used.

width - this is the default width of the keyboard layout.

height - is the default height of the keyboard layout.

maxwidth - is the maxwidth constraint of the keyboard layout.

minwidth - is the minwidth constraint of the keyboard layout.

maxheight - is the maxheight constraint of the keyboard layout.

minheight - is the minheight constraint of the keyboard layout.


<language languagename="en" />

languagename - specifies the two letter language code for the languages that this keyboard layout applies. When the system is searching for a keyboard layout for the current keyboard language it starts from the last keyboard layout registered, to allow developers to override the defaults, once a keyboardtype and language are found that keyboard layout is used.


<row topmargin="0" bottommargin="2">

topmargin - this is the padding between the key rows.

bottommargin - this is the padding between the key rows.


<key scancode="1" vk="200" caption="Esc" width="65" stretch="True" modifiername="fn" imageindex="3" toggle="True" mapscancode="42" mapvk="0" margin="5" doubletall="True" groupindex="1" combokeys="vk:12;vk:12;scancode:24;scancode:24">

scancode - this is the Scan Code that is sent to the active window. The default value is 0. A valid scan code is greater than zero. Any value greater than zero will be sent as a key. If the value is 0 then it is key that does not have a scan code. Any key that does not have a scan code and or a vk is not a real key. If the value is less than 0 then it is also a fake key. This is useful for modifier keys.

vk - Same as scancode above only for the vk. It is important to note that either one or both can be provided. If one isn't provided then the other will be determined by the OS.

caption - this is the key caption to display.

imageindex - this is a image that is displayed. -1 is the default which means the key caption is text. tab=0, shift=1, enter=2, backspace=3, up=4, down=5, left=6, right=7.

width - this is how wide the key is. Since the keyboard is flow layout from the upper left hand following to the right and down it just gets the next available location. The width and height of the key will be the hit test area. The button will be drawn inside this region offset by the margins.

height - Set the height of the key. The only valid value here is double the height of the row. Only one tall key is valid per row and only on the right hand side.

leftmargin - is the margin to the left of the key.

rightmargin - is the margin to the right of the key.

stretch - in flow layout when resizing setting the stretch to True will tell the resize function to allow this key to take up all available space. Keys that are not stretch keys must have their appropriate proportions no matter the size of the keyboard while keys that are stretch keys will take up the available space.

toggle - if a key is a toggle key then it can be pressed and stay's down. A second press will release the key and draw it normally.

groupindex - toggle keys can be in a group. If two ore more keys are in the same group only one of them can be toggled at a time. When pressing a toggle key all the other toggle keys in the same group will be drawn normally while the newly pressed key will be pressed.

combokeys - there are times when it is handy to generate a key sequence. The format is vk:# or scancode:# separated by a semicolon. The first time the vk or scancode is encountered it will trigger a down, the second occurrence it will be an up.

mapscancode, mapvk - keys like the left and right shift keys or left and right ctrl keys have different scan codes and vks, so to show the same state on these keys one can provide an alternate vk or scancode values.

modifiername - this tells the keyboard that this is a modifier key. When this key is toggled and a key has a modifier attribute then the key can change it's caption, scancode, vk and imageindex.

publishedname - this is the name of the key caption override that is displayed in the object inspector under the CaptionOverrides property. This caption will override any and all captions for this key. Note that the developer can provide keyboard locale specific overrides programatically.


<language languagename="fr" scancode="100" vk="2" imageindex="1" caption="AltGr" />

languagename - specifies a language override for the key. If the keyboard language is fr then the scancode, vk, imageindex and caption will overridden with the values provided.


<modifier scancode="44" vk="0" scancode="20" vk="20" imageindex="2" caption="foo" modifiername="caps">

modifiername - specifies an override for the key. If the modifier is toggled then the scancode, vk, imageindex and caption will overridden with the values provided.


<language languagename="fr" scancode="100" vk="2" imageindex="1" caption="AltGr" />
</modifier>
</key>
</row> </keyboard>

Tuesday, February 2, 2010

Hacking the TTouchKeyboard Part III

Hacking the TTouchKeyboard Part I
Hacking the TTouchKeyboard Part II
Hacking the TTouchKeyboard Part III
Hacking the TTouchKeyboard Part IV
Hacking the TTouchKeyboard Part V (not published yet)

This post is going to be short because it is just an example application to illustrate how to convert an XML touch keyboard layout the binary version that you can then add as a resource and use from your touch applications. You can download the source to the command line utility called kcc (stands for Keyboard Command line Compiler).

My next post will be the documentation for the XML layout and the final post on hacking the TTouchKeyboard will walk you through the steps to make this all work.

Monday, February 1, 2010

Haiti Relief

Many ExBorlanders have donated Borland memorabilia such as first ship and other interesting antiques to be auctioned off with all proceeds going to the Clinton Bush Haiti Fund. You can find the ebay auction here.

I gave just about every one of my first ship boxes to my Dad so he could play with them, but I did have one interesting box still sitting on my shelf: Turbo C++ 3.0! Check it out here. In the box are the original 3 1/2" floppies (opened because I used them to install it) and the unopened 5 1/4" floppies! The original receipt is also in the box along with all documentation. The box is virtually mint!



Update: We made slashdot with this auction. Read about it here

Tuesday, January 5, 2010

Hacking the TTouchKeyboard Part II

Hacking the TTouchKeyboard Part I
Hacking the TTouchKeyboard Part II
Hacking the TTouchKeyboard Part III
Hacking the TTouchKeyboard Part IV
Hacking the TTouchKeyboard Part V (not published yet)

This post is going to be short because it is just an example application that you can download source code to illustrate how to access and save a touch keyboard layout as an XML file.

My next post will be an example application illustrating generate a resource file from the XML file so you can make your own keyboard layouts.

Monday, December 21, 2009

Hacking the TTouchKeyboard Part I

Hacking the TTouchKeyboard Part I
Hacking the TTouchKeyboard Part II
Hacking the TTouchKeyboard Part III
Hacking the TTouchKeyboard Part IV
Hacking the TTouchKeyboard Part V (not published yet)

The TTouchKeyboard is a a fairly flexible on screen keyboard that supports multiple keyboard layouts but only shipped with the number pad and the standard keyboard layout for a whole lot of input languages. How to create these keyboard layouts has been a mystery, until now. Over the next few posts I'll provide some tools, documentation and sample code to build everything you need to hack the TTouchKeyboard.

The first bit of code I'm going to provide demonstrates listing all the keyboard layouts that are available. It's pretty simple really. A keyboard layout is just a resource with the string "KEYBOARD" in the name.

procedure GetKeyboardLayoutNames(ANames: TStrings);

function EnumResNames(Module: HMODULE; ResType, ResName: PChar;
Nothing: Pointer): Integer; stdcall;
const
sResourceName = 'KEYBOARD';
begin
if Pos(sResourceName, ResName) > 0 then
LayoutNames.Add(ResName);
Result := 1;
end;

begin
LayoutNames := TStringList.Create;
try
EnumResourceNames(HInstance, RT_RCDATA, @EnumResNames, 0);
ANames.Clear;
ANames.AddStrings(LayoutNames);
finally
FreeAndNil(LayoutNames);
end;
end;


Once you have a layout you can load it by calling this little function.

function LoadLayout(const LayoutName: string): TVirtualKeyLayout;
var
Stream: TResourceStream;
TempStream: TStream;
begin
Result := nil;
Stream := TResourceStream.Create(HInstance, LayoutName, RT_RCDATA);
try
Result := TVirtualKeyLayout.Create;
Result.LoadFromStream(Stream);
finally
Stream.Free;
end;
end;


Next I'll show how to iterate the data structures and save it to an XML file for easy text manipulation.

Tuesday, November 24, 2009

Debugging Direct2D

When debugging Direct2D the debugger can be really slow, and I've recently discovered the culprit of the poor performance; the Intel graphics driver. The same performance problems happen in Visual Studio so it isn't a C++Builder or Delphi bug. If you are debugging Direct2D just run without debugging or get a system with an NVIDIA or ATI graphics card.

Touch Demo

My Touch Move demo is now complete. Here is a quick list of the four parts:

Part I
Part II
Part III
Part IV

And you can download source code from CodeCentral for all four demos. The download wasn't working but has now been fixed.

After the Thanksgiving Holiday I'll start something new. I was thinking of how to hack the touch keyboard, but if anyone has suggestions regarding things you'd like to know about touch drop me a line either via comments or the contact me link on the right side of this blog and I'll try and make a post out of it.

Thursday, November 19, 2009

Touch Demo Part IV

Previously I posted Part I, Part II and Part III of the Touch Demo.

This is the final step of the touch demo where I will be adding the inertia processing and mouse support. Mouse support is easy but requires a minor refactoring of the touch message handler so the mouse can piggy back on it. For CodeRage I did add a touch keyboard but I will leave that as an exercise for the user.

And now you can download source code from CodeCentral for all four demos. Update: The download wasn't working but it has now been fixed.

Inertia processing requires the Manipulations unit. Then the object that is to be manipulated, in this case TGlowSpot, should implement the _IManipulationsEvents interface which is a COM event sync. Here is how that class changed:


TGlowSpot = class(TInterfacedObject, _IManipulationEvents)
private
FInertia: IInertiaProcessor;
FManipulator: IManipulationProcessor;
FInertiaCookie, FManipulatorCookie: LongInt;
FCompleted: BOOL;
public
X, Y, Radius: Integer;
Alpha: Extended;
FadeIn: Boolean;
Color: TColor;
ID: Integer;

protected
procedure DoTouch(const APoint: TPoint; AID: Integer; ATouchMessage: TTouchMessage);

{ _IManipulationEvents }
function ManipulationStarted(X: Single; Y: Single): HRESULT; stdcall;
function ManipulationDelta(X: Single; Y: Single; translationDeltaX: Single;
translationDeltaY: Single; scaleDelta: Single; expansionDelta: Single;
rotationDelta: Single; cumulativeTranslationX: Single;
cumulativeTranslationY: Single; cumulativeScale: Single;
cumulativeExpansion: Single; cumulativeRotation: Single): HRESULT;
stdcall;
function ManipulationCompleted(X: Single; Y: Single;
cumulativeTranslationX: Single; cumulativeTranslationY: Single;
cumulativeScale: Single; cumulativeExpansion: Single;
cumulativeRotation: Single): HRESULT; stdcall;
public
constructor Create(AParent: TWinControl);

procedure Paint(Canvas: TDirect2DCanvas);
procedure Disconnect;
procedure ProcessInertia;
end;
...


Each TGlowSpot needs to hold on to an instance of the inertia processor and the manipulation processor and then connect up to them with the event sync. That is done in the constructor:

constructor TGlowSpot.Create(AParent: TWinControl);
begin
inherited Create;
Alpha := 1;
Radius := 80;
FadeIn := False;
Randomize;
Color := RGB(Random(255), Random(256), Random(256));
ID := -1;
FCompleted := True;
ID := -1;
FCompleted := True;

FInertia := CreateComObject(CLSID_IInertiaProcessor) as IInertiaProcessor;
FManipulator := CreateComObject(CLSID_IManipulationProcessor) as IManipulationProcessor;
InterfaceConnect(FInertia, _IManipulationEvents, Self, FInertiaCookie);
InterfaceConnect(FManipulator, _IManipulationEvents, Self, FManipulatorCookie);

FInertia.put_DesiredDeceleration(0.001);

FInertia.put_BoundaryLeft(200);
FInertia.put_BoundaryTop(200);
FInertia.put_BoundaryRight(AParent.Width - 200);
FInertia.put_BoundaryBottom(AParent.Height - 200);

FInertia.put_ElasticMarginLeft(200);
FInertia.put_ElasticMarginTop(200);
FInertia.put_ElasticMarginRight(200);
FInertia.put_ElasticMarginBottom(200);
end;


And then of the disconnect is done like this:

procedure TGlowSpot.Disconnect;
begin
InterfaceDisconnect(FInertia, _IManipulationEvents, FInertiaCookie);
InterfaceDisconnect(FManipulator, _IManipulationEvents, FManipulatorCookie);
end;


The inertia processing is handled with each WM_TOUCH message that is fired. It's pretty simple really, if there is a move, call the manipulation COM object's ProcessMove, and do the same with down. Up is a bit different because of the inertia but all you need to do is set the velocity and the location.

procedure TGlowSpot.DoTouch(const APoint: TPoint; AID: Integer;
ATouchMessage: TTouchMessage);
var
Vx, Vy: Single;
begin
case ATouchMessage of
tmMove:
begin
X := APoint.X;
Y := APoint.Y;
FManipulator.ProcessMove(AID, APoint.X, APoint.Y);
end;

tmDown:
begin
X := APoint.X;
Y := APoint.Y;
FManipulator.ProcessDown(AID, APoint.X, APoint.Y);
end;

tmUp:
begin
ID := -1;

FManipulator.ProcessUp(AID, APoint.X, APoint.Y);

FManipulator.GetVelocityX(Vx);
FManipulator.GetVelocityY(Vy);

FInertia.put_InitialVelocityX(Vx);
FInertia.put_InitialVelocityY(Vy);

FInertia.put_InitialOriginX(X);
FInertia.put_InitialOriginY(Y);

FCompleted := False;
end;
end;
end;

function TGlowSpot.ManipulationCompleted(X, Y, cumulativeTranslationX,
cumulativeTranslationY, cumulativeScale, cumulativeExpansion,
cumulativeRotation: Single): HRESULT;
begin
Result := S_OK;
end;

function TGlowSpot.ManipulationDelta(X, Y, translationDeltaX, translationDeltaY,
scaleDelta, expansionDelta, rotationDelta, cumulativeTranslationX,
cumulativeTranslationY, cumulativeScale, cumulativeExpansion,
cumulativeRotation: Single): HRESULT;
begin
Inc(Self.X, Round(translationDeltaX));
Inc(Self.Y, Round(translationDeltaY));
Result := S_OK;
end;

function TGlowSpot.ManipulationStarted(X, Y: Single): HRESULT;
begin
Result := S_OK;
end;

procedure TGlowSpot.ProcessInertia;
begin
if not FCompleted then
FInertia.Process(FCompleted);
end;


The last bit of code I want to talk about is the mouse handling. I refactored the handling of the WM_TOUCH message into WMTouch and ProcessTouchMessages. ProcessTouchMessages is the common function that the mouse message can call to get the same inertia behavior.

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;
TouchMessage: TTouchMessage;
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);

if (TouchInput.dwFlags and TOUCHEVENTF_MOVE) <> 0 then
TouchMessage := tmMove
else if (TouchInput.dwFlags and TOUCHEVENTF_UP) <> 0 then
TouchMessage := tmUp
else if (TouchInput.dwFlags and TOUCHEVENTF_DOWN) <> 0 then
TouchMessage := tmDown;

ProcessTouchMessages(Point, TouchInput.dwID, TouchMessage);
end;

Handled := True;
finally
if Handled then
CloseTouchInputHandle(Message.LParam)
else
inherited;
end;
end;

function TTouchForm.ProcessTouchMessages(const APoint: TPoint; ID: Integer;
TouchMessage: TTouchMessage): TGlowSpot;
var
Spot: TGlowSpot;
begin
Result := nil;
Spot := FindSpot(ID);

if Spot = nil then
begin
Spot := FindSpot(APoint);

if Spot <> nil then
Spot.ID := ID;
end;

if Spot = nil then
begin
Spot := TGlowSpot.Create(Self);
Spot.ID := ID;
FSpots.Add(Spot);
end;

Spot.DoTouch(APoint, ID, TouchMessage);
Result := Spot;
end;


And last the mouse handling functions with the check for ssTouch in the Shift parameter. If that check wasn't there each message would happen effectively twice because the touch messages also send mouse messages for backwards compatibility with applications that don't support touch.

procedure TTouchForm.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if ssTouch in Shift then Exit;
FMouseDown := True;
ProcessTouchMessages(Point(X, Y), 0, tmDown);
end;

procedure TTouchForm.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if ssTouch in Shift then Exit;
if FMouseDown then
ProcessTouchMessages(Point(X, Y), 0, tmMove);
end;

procedure TTouchForm.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
Spot: TGlowSpot;
begin
if ssTouch in Shift then Exit;
Spot := ProcessTouchMessages(Point(X, Y), 0, tmUp);
Spot.ID := -1;
FMouseDown := False;
end;


I just realized that there is a bug in the program. It will run just fine but crash pretty bad if it runs too long. I guess I never demoed it very long before. So I'll leave debugging this crash as an exercise for the user.

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.

Monday, August 17, 2009

Touch Hardware

One of the first questions people ask about multi-touch is what hardware to get.

Everything is supported just at different levels. First you have touch screens that emulate the mouse such as most Point-of-Sale monitors. We have a Dell POS and a Planar PT 19. These are only good for big buttons. Any sort of dragging your finger across the screen is lost by the device/driver. The Planar doesn't loose the mouse as bad as the Dell.

Then you have the old school tablet laptops. These add pen and sometimes support touch with the finger as well. The pen resolution is equal to or better than the mouse. The finger with these older systems is an afterthought. Lenovo IBM X61 is an example of such a system.

Next you have all-in-one systems such as the Asus EeeTop which has better drivers/hardware than the Point-of-Sale monitors but they are still just a touch screen mouse. I.E. push the monitor with your finger and you get a left mouse click. The Asus has a pretty decent touch screen but still only supports one touch point and it is just emulating the mouse. The processor on the Asus is really slow.

Now enters multi-touch which only Windows 7 really supports. Some Vista systems support multi-touch but just go with Windows 7, you'll be much happier.

Building on the tablet there are currently two shipping multi-touch laptops. One by Dell and one by HP. These make touch a forethought and add multi-touch. The HP supports 2 touch points and with an updated driver 4. The Dell supports 10 touch points. They are the exact same display so it must be the driver or other components that allow the extra touch points on the Dell. A Dell is currently sitting on my desk and it is the nicest of the systems. It feels like a laptop that I would buy for myself. The Dell is priced a bit high but it is a nice slimline laptop. The HP feels a bit cheap and has some flowery patterns on it.

Lastly you have the all-in-one multi-touch systems such as the HP TouchSmart which features a large display and two touch points. We have purchased two batches of these. The first batch is pretty bad. I'm pretty sure these are the ones currently selling on Woot. The second batch is a lot better but the Dell and HP laptops I mentioned above are better. Update: If you buy one of these be sure to get the NVIDIA graphics card.

Thursday, August 6, 2009

RAD Studio 2010 - Actions

One very useful feature is an updated Action property editor. The little drop down hasn't changed in years and we wanted to get to our Actions quicker. So Seppy Bloom through some Object Inspector trickery, which you can find all about in his CodeRage 4 session Customizing the Object Inspector, updated the Action property editor.





What you are looking at is a new drop down that allows you to selection from one simple menu any standard action from the action list, choose any existing actions, or create a new action.



If you have more than one action list then just choose which one to use.

Just one more example of increased productivity.

Tuesday, August 4, 2009

Embarcadero RAD Studio 2010



Finally I can talk about Delphi 2010/C++Builder 2010/RAD Studio 2010! This should be a pretty awesome release with some cool stuff. For anyone that didn't attended my Delphi Live! talk, I've been working on something a bit different from COM and ActiveX this release, but that'll have to wait because first I want to talk about some of the IDE features we worked on.

For the official RAD Studio 2010 preview page click here where you can watch a video of David I getting the Delphi 2010 low down from Nick Hodges.



At the very end of the video you can see my office door.



I've talked about CTRL + F12 before here but this release it has gotten way better. In the video Nick showed off IDE Insight which is a totally awesome feature built by Mark Duncan using my search edit. Everyone one of us here use it every day. Features like this don't just spring out of nowhere. It went through various incarnations and refinements. Features like this are always fun because they build from collaboration of a few different features getting smashed together. One of the earliest versions of Find Units was embedded in the Project Manager.



The search edit is the same search edit seen throughout the IDE but with a few more bells and whistles because this one supports pattern matching with '*' and '?'. And it's fast! Which is why we didn't want to support regular expressions. All information gathered and searched is gathered on the fly, not indexed which is why a fast pattern search is needed.

The Gallery also has been augmented with a search feature. And as an extra productivity enhancement, all gallery items show up but the ones that used to be invisible are grayed out. This should really help those customers migrating from Delphi 7 where all COM wizards were visible but you had to know the order to create them. Now, you can run any wizard that is enabled and there won't be any question of where the COM wizards went.



Another place the search edit shows up is in the C++ class browser built by Bruneau Babet. Did I mention the search is fast? Well in a fraction of a second you can search with wild cards through all symbols in your C++ projects.



One last feature before I wrap this up. The Object Inspector got a small update from our newest VCL memeber Thom Gerdes. Boolean values now have check boxes. It might seem silly but it's really hard to use an older version of Delphi after getting used to the check boxes. We've also enhanced some of the property editors such as TDateTimePicker.Date.

Monday, May 11, 2009

Only a couple more days before Delphi Live!

Engineers from around the world are already flying in building up the excitement for Delphi Live! in the halls around here so this should be a fun week. It's also been quite a while since I've been able to meet our customers face to face so come by and say "hi" at beatmeet the team on Thursday at 7:30pm to 8:30pm. If I yawn it's not your fault, having a two year old at home I normally head to bed pretty early.

Friday will be another exciting day with my talk from 5.00pm to 6.15pm. I really wish I could say something more about this talk other than it's straight from the Embarcadero Labs so it's pretty raw! Raw is good.

I never thought I'd be doing this, but I've been using Google Docs to create my slides for Delphi Live!. I can't believe how well it's worked to give other team members direct access to the slides for feedback. My only complaint is the PDF conversion looses the Courier font.

Tuesday, March 10, 2009

Delphi Performance Tip

Here's a small little Delphi performance tip that I'm not sure many people are aware of. Putting the $EXTERNALSYM after the symbol has better compiler performance than placing it before the symbol. The reason for this is pretty simple. When the compiler encounters a $EXTERNALSYM it looks for the symbol. If the symbol isn't found then it must be stored and dealt with later. If the symbol is found it is used immediately.

Here's a small example:


const
MAPVK_VK_TO_VSC = 0;
{$EXTERNALSYM MAPVK_VK_TO_VSC}
MAPVK_VSC_TO_VK = 1;
{$EXTERNALSYM MAPVK_VSC_TO_VK}
MAPVK_VK_TO_CHAR = 2;
{$EXTERNALSYM MAPVK_VK_TO_CHAR}
MAPVK_VSC_TO_VK_EX = 3;
{$EXTERNALSYM MAPVK_VSC_TO_VK_EX}
MAPVK_VK_TO_VSC_EX = 4;
{$EXTERNALSYM MAPVK_VK_TO_VSC_EX}

Friday, February 20, 2009

Delphi Live!




I just opened up a poll (you can view it on the sidebar), to see how many readers of this blog will be attending Delphi Live! I'll be there at least one day giving talks and milling around.