The last version of the touch window and touch lists still needed improvements, notably on scrolling smoothness and clicking accuracy. In this post I'm presenting new versions of both classes where I tried to address these issues. The bottom line is that clicking feels much better but scrolling is still a bit jagged. I have to say that in order to get a game-like smooth screen scrolling one would have to choose something like DirectDraw because GDI was not made for this. Anyway, you will be the judge.
First I changed how the window scrolls by removing the timer. How do you force the window to scroll without a timer? Well, it's kind of easy: set up a scrolling mechanism that determines the next position based on the current time (I showed how to do that with the kinematic equations), set up a cutoff point (time and / or position) and just invalidate the whole window after painting. If you just invalidate the window, you allow all other messages to be processed and when the message queue is empty, the OS will send you a WM_PAINT message. If the window is still scrolling, you calculate the new position (based on the current time), paint the window and if the motion has not stopped, you invalidate the window again. This way you get a more natural way of scrolling the window and you know that you will get the best screen update frequency that GDI can muster. Note that in order to implement this in a generic way, I had to implement the OnPaint handler in CTouchWindow. This class delegates to its children through the "static virtual" Paint method.
In this process I had to update the way the kinematic equations are calculated due to some rounding errors I found on QVGA devices. To solve the issue, I changed the main equation back to the more classical form but reduced the timer precision from millisecond to hundredths of a second (divided by 10 in order to get smaller number from multiplication). The rounding error seems to be gone. I have also added a double criteria to test if the motion did end: now the code tests for both time limit and end point.
To help with both scrolling and clicking, I added a new class named CTouchGesture that essentially handles all the data coming from the stylus (mouse) messages and helps CTouchWindow determine if the last gesture was a click or a "flick". Note that for flicking, the class adds up all the partial moves (compensating for changes in direction) and reports an "average" flick speed (total displacement and time) instead of the last move.
Clicking the items is now a bit more reliable because the code tests for clicking eligibility. If the window is moving and you click it, there will not be an OnClick call: you will only get one if the window is still to begin with.
I hope that these modifications did improve the code and the user experience, but with my limited assortment of devices I cannot have a good judgment on that. So please tell me what you think!
Sample code: AppStart01.zip (161 KB)
Tuesday, August 25, 2009
Wednesday, August 19, 2009
A simple application launcher
As I promised on my last post, here is the code for a very simple application launcher. It essentially lists all the applications registered in the "Programs" folder of your Windows Mobile device and launches them when the user clicks the corresponding list item.
I have to confess that I went into a bit of an ordeal in order to implement this very simple application. Quite simply because I tried to outsmart the Windows Mobile shell and to collect all the required information from the .lnk files. If you are on this same path, please read these words carefully: all has been done for you already, so don't try to reinvent the wheel.
My first pain was to get the icons from the shortcuts. You can almost do this by using ExtractIconEx, but this function will not work for some of the system DLLs, such as ceshell.dll. Why? I really don't know why, but the "Search" application icon (the magnifying glass) is impossible to get to by using this function. After asking around a bit, I was steered to the right direction by Christopher Fairbairn: use SHGetFileInfo. The only caveat is that you must use this function against the .lnk file itself, not against the target. If you do so, your icons will show up just right as you can see from the image.
The item name is taken from the shortcut file name - just remove the extension and the path. To make this easier I creted a very simple class named CFilePath that, for the time being, contains only one function: GetFileNameWithoutExtension (now where have I seen a similar function name?).
Finally, in order to execute the application, you just send the full .lnk file name to the ShellExecuteEx function and you are done with it. No need to mess around with the .lnk file format and all of its quirks.
For your viewing pleasure, here is the sample code: AppStart00.zip
I have to confess that I went into a bit of an ordeal in order to implement this very simple application. Quite simply because I tried to outsmart the Windows Mobile shell and to collect all the required information from the .lnk files. If you are on this same path, please read these words carefully: all has been done for you already, so don't try to reinvent the wheel.
My first pain was to get the icons from the shortcuts. You can almost do this by using ExtractIconEx, but this function will not work for some of the system DLLs, such as ceshell.dll. Why? I really don't know why, but the "Search" application icon (the magnifying glass) is impossible to get to by using this function. After asking around a bit, I was steered to the right direction by Christopher Fairbairn: use SHGetFileInfo. The only caveat is that you must use this function against the .lnk file itself, not against the target. If you do so, your icons will show up just right as you can see from the image.
The item name is taken from the shortcut file name - just remove the extension and the path. To make this easier I creted a very simple class named CFilePath that, for the time being, contains only one function: GetFileNameWithoutExtension (now where have I seen a similar function name?).
Finally, in order to execute the application, you just send the full .lnk file name to the ShellExecuteEx function and you are done with it. No need to mess around with the .lnk file format and all of its quirks.
For your viewing pleasure, here is the sample code: AppStart00.zip
Monday, August 17, 2009
Shell Shortcuts
Windows Mobile shell shortcuts have a very simple file format, something like (taken from my HTC Touch Pro):
22#:MSPIMG?pimgres.dll,-101
The number 22 is supposed to tell us how many characters there are in the string, but this example seems to be wrong. Incidentally, I have seen examples where this value is zero so apparently you can forget about it.
After the # character, you can read the associated command. In this case, you get a "shell macro" that needs to be expanded using a technique that I explained on my previous post. After the ? character there is a module name where the display icon can be found. This section is optional as well as the final section after the comma: the display icon identifier. The negative value means that this is an icon ID and you should be able to feed it directly to the ExtractIconEx API to get the icon handle.
One of the interesting things I've found while doing some research on these files is that you can add a comment section to the beginning of the file, something like:
;Pictures & Videos
22#:MSPIMG?pimgres.dll,-101
Interesting, huh?
I'm putting together a very simple application launcher that uses this knowledge to read from the Program Files directory all the existing shell shortcuts and displays them on a touch list with the right icon and name. This will be published on my next post, so stay tuned.
22#:MSPIMG?pimgres.dll,-101
The number 22 is supposed to tell us how many characters there are in the string, but this example seems to be wrong. Incidentally, I have seen examples where this value is zero so apparently you can forget about it.
After the # character, you can read the associated command. In this case, you get a "shell macro" that needs to be expanded using a technique that I explained on my previous post. After the ? character there is a module name where the display icon can be found. This section is optional as well as the final section after the comma: the display icon identifier. The negative value means that this is an icon ID and you should be able to feed it directly to the ExtractIconEx API to get the icon handle.
One of the interesting things I've found while doing some research on these files is that you can add a comment section to the beginning of the file, something like:
;Pictures & Videos
22#:MSPIMG?pimgres.dll,-101
Interesting, huh?
I'm putting together a very simple application launcher that uses this knowledge to read from the Program Files directory all the existing shell shortcuts and displays them on a touch list with the right icon and name. This will be published on my next post, so stay tuned.
Wednesday, August 12, 2009
Default Windows Mobile Applications
How do you start the default Windows Mobile applications like Calendar, Contacts or Messaging from your application? I recently came across this question in the Visual Studio Smart Device Development - Native C++ Project (quite a long name, huh?) MSDN forum. The answer is quite simple and relies on a registry entry that has been around at least since Windows Mobile 2003:
HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\Rai
Here you find a list of varying size containing all the default applications in your machine (both a human-readable name and the required command line). For instance, on my HTC Touch Pro the calendar is stored in the following entry:
HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\Rai\:MSCALENDAR
The application's human-readable name is stored in the "0" (zero) key while the command line is stored in the "1" key. If you look up this in your device's registry you will probably find something like:
:MSPOUTLOOK calendar
Note that this requires further expansion by looking up the following entry:
HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\Rai\:MSPOUTLOOK
The value of the "1" key contains "poutlook.exe" so the final command line to start the Calendar application must be "poutlook.exe calendar". Easy huh?
HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\Rai
Here you find a list of varying size containing all the default applications in your machine (both a human-readable name and the required command line). For instance, on my HTC Touch Pro the calendar is stored in the following entry:
HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\Rai\:MSCALENDAR
The application's human-readable name is stored in the "0" (zero) key while the command line is stored in the "1" key. If you look up this in your device's registry you will probably find something like:
:MSPOUTLOOK calendar
Note that this requires further expansion by looking up the following entry:
HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\Rai\:MSPOUTLOOK
The value of the "1" key contains "poutlook.exe" so the final command line to start the Calendar application must be "poutlook.exe calendar". Easy huh?
Monday, August 10, 2009
Item Activation
I'm still not sure how this is going to end, but right now items can be focused, selected and activated. An item gets the focus when you use the arrow keys to navigate the list and that is meant to mean the "current" item in the list. When you select an item it gets added to a selection list (in case you need to use multiple-selection lists). Note that focus does not mean selection nor selection means focus. Finally, an activated item is the one you just "pressed" or clicked.
The code I'm publishing today shows how to set the focus on a particular item (just added a highlighter to the DrawItem method) by navigating the list with the arrow keys and how it can be activated by directly clicking it or by pressing the enter key on the focused item.
I had to make some changes to the CTouchWindow class template in order to make sure that scrolling (or flicking through) the list does not get confused with a click. If you hook the application with Remote Spy you will see an interesting pattern of messages when clicking an item: WM_LBUTTONDOWN, WM_MOUSEMOVE (may occur more than once) and WM_LBUTTONUP. What's interesting is that the "mouse move" message always shows up even if it reports the same screen position as the "button down" message. Is this a bug, Microsoft? Anyway, the code already handles null movements so...
When an item is selected, the CCrypSafeView::OnItemChangedState method is called by the base class and to handle the item activation you must handle the TLN_ITEMACTIVATED code. Just take a look at the sample code to see how it is done. Note that you test nmtl.dwState for nonzero meaning activation - it is zero when the item is "deactivated".
Sample code: CrypSafe04.zip (325 KB - now includes the OleDbClient lib)
The code I'm publishing today shows how to set the focus on a particular item (just added a highlighter to the DrawItem method) by navigating the list with the arrow keys and how it can be activated by directly clicking it or by pressing the enter key on the focused item.
I had to make some changes to the CTouchWindow class template in order to make sure that scrolling (or flicking through) the list does not get confused with a click. If you hook the application with Remote Spy you will see an interesting pattern of messages when clicking an item: WM_LBUTTONDOWN, WM_MOUSEMOVE (may occur more than once) and WM_LBUTTONUP. What's interesting is that the "mouse move" message always shows up even if it reports the same screen position as the "button down" message. Is this a bug, Microsoft? Anyway, the code already handles null movements so...
When an item is selected, the CCrypSafeView::OnItemChangedState method is called by the base class and to handle the item activation you must handle the TLN_ITEMACTIVATED code. Just take a look at the sample code to see how it is done. Note that you test nmtl.dwState for nonzero meaning activation - it is zero when the item is "deactivated".
Sample code: CrypSafe04.zip (325 KB - now includes the OleDbClient lib)
Monday, August 03, 2009
Compiling CrypSafe
Back from the sunny Algarve and ready for more work. I have to confess that during these last two weeks I barely touched my laptop, but I surely needed the rest.
Compiling the CrypSafe prototype has proven to be a bit of a challenge for some of the readers and I have received some complaints about this very subject. Here is a list of what you need to do, both with VS 2005 and VS 2008 to get the sample to compile. Please note that I'm distributing the VS 2008 solution files only but you should be able to recreate the project for VS 2005 without major issues.
Here's what you must do to compile the sample:
Compiling the CrypSafe prototype has proven to be a bit of a challenge for some of the readers and I have received some complaints about this very subject. Here is a list of what you need to do, both with VS 2005 and VS 2008 to get the sample to compile. Please note that I'm distributing the VS 2008 solution files only but you should be able to recreate the project for VS 2005 without major issues.
Here's what you must do to compile the sample:
- Download WTL 8.0 or 8.1. You can get the latest version of WTL from its sourceforge page.
- Unzip the WTL distribution file to a directory of your choice.
- Under the installation directory, you will find some directories named AppWiz, AppWizCE and AppWizMobile. Navigate to each of these in turn and run the setup90.js (for Visual Studio 2008) and/or setup80.js (for Visual Studio 2005) scripts in order to install the Visual Studio application wizards. Please note that under Vista (and probably also under Windows 7) you must open a command prompt with elevated privileges because these scripts write files to the Visual Studio install directories.
- Now you have to open Visual Studio and let it know where to find the WTL include files. To do this, open Visual Studio and go to the Tools / Options menu and select "Projects and Solutions" item in the tree. Select the "VC++ Directories" under that item and then select the "Include files" option of the "Show directories for:" combo box. Now, for each platform listed on the left combo box, you must enter your WTL include directory in the list below.
- Now you can open the CrypSafe solution in Visual Studio and try to compile it. If it still fails, please make sure you correct each project's "Additional Include Directories" property under the project's Configuration Properties / C++ / General option.
Subscribe to:
Posts (Atom)