I. Présentation de Microsoft Surface▲
I-A. Qu'est-ce que Microsoft Surface ?▲
Avant de se lancer dans le développement à proprement parler, il est utile de rappeler ce qu'est Microsoft Surface.
Il s'agit d'un produit multitouche, développé par Microsoft, qui se trouve être composé de deux parties :
- une partie matérielle (généralement sous forme de table) ;
- une partie logicielle, qui permet l'interaction avec un (ou plusieurs) utilisateur(s).
Les utilisateurs qui manipulent la table Surface se trouvent en présence d'un écran permettant leur permettant de manipuler toute sorte de contenu digital tel que des photos, des vidéos, etc. Cependant, grâce à ces fonctionnalités techniques, cette table est bien plus qu'un simple lecteur de photos et de vidéos. Ainsi, l'utilisateur à la possibilité d'interagir avec le contenu, via un ou plusieurs doigts, pour le déplacer, l'étirer, l'agrandir, le rétrécir, etc.
Si vous voulez en savoir plus ou si vous ne connaissez pas le produit, jetez donc un coup d'œil au site officiel : http://www.microsoft.com/surface/ avant de passer à la suite de cet article qui vous expliquera comment vous pourrez développer vos propres applications pour Microsoft Surface.
I-B. Comment ça marche ?▲
Afin de comprendre comment une telle technologie est possible, observez l'image suivante, qui représente l'architecture de Microsoft Surface :
Comme vous pouvez le constater, plusieurs composants constituent cette plateforme :
- Windows Vista, qui est le système d'exploitation sur lequel Surface fonctionne et qui permet de disposer d'un ensemble de fonctionnalités telles que la sécurité, la gestion des droits, etc. ;
- une couche matériel, qui contient l'ordinateur, les caméras, la surface de projection, etc. qui fonctionne sous Vista ;
- un système de vision, qui est en charge de capturer les données envoyées par le matériel, afin que vous puissiez les utiliser dans le code de votre application ;
-
deux jeux d'API :
- la couche WPF, qui permet l'utilisation de cette technologie et d'un ensemble de contrôle,
- la couche principale, qui permet des manipulations de l'interface graphique plus complexes que celles réalisables avec l'API WPF : animations 3D complexes, affichage via des « custom pixel shaders », etc. ;
- enfin, l'intégration entre Surface et le système d'exploitation est gérée par un shell.
Techniquement, vous pouvez donc constater qu'une table Surface n'est « rien d'autre » qu'un ordinateur équipé de Windows Vista, de matériel permettant, entre autres, la reconnaissance d'objets et d'un shell qui permet de faire la liaison entre les 2. Cependant, la partie logicielle de Surface supprime tous les éléments de l'interface, les notifications et les messages de Windows Vista.
II. Créer une première application▲
Pour pouvoir créer vos applications pour Microsoft Surface, il est nécessaire de disposer du SDK (Software Developement Kit) qui permet de disposer d'un émulateur, des templates de projets pour Visual Studio, etc.
Une fois le SDK installé, il est possible de lancer la création d'un nouveau projet, dans Visual Studio, via la commande « File » => « New Project » :
Une fois le projet créé, observons le contenu de la solution :
Première chose à remarquer : nous retrouvons un projet contenant des fichiers XAML (Extensible Application Markup Langage). En effet, les applications Surface sont des applications WPF (Windows Presentation Foundation), comme nous allons le voir par la suite. Le projet contient différents fichiers et un répertoire :
- App.xaml et SurfaceWindow1.xaml : Ce sont les fichiers XAML qui servent, respectivement, à définir la page de démarrage et à représenter l'interface graphique ;
- DemoAppSurface.xml : Ce fichier XML (dont le nom n'est rien d'autre que le nom du projet) contient différentes informations nécessaires pour installer l'application sur Microsoft Surface. Parmi les informations disponibles, on retrouve le nom de l'application, sa description, le nom du fichier exécutable, le nom des icônes/images de l'application, etc.
<
ss
:
ApplicationInfo
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns
:
ss
=
"http://schemas.microsoft.com/Surface/2007/ApplicationMetadata"
>
<Application>
<Title>
DemoAppSurface</Title>
<Description>
DemoAppSurface</Description>
<ExecutableFile>
DemoAppSurface.exe</ExecutableFile>
<Arguments></Arguments>
<IconImageFile>
Resources\icon.png</IconImageFile>
<Preview>
<PreviewImageFile>
Resources\iconPreview.png</PreviewImageFile>
</Preview>
</Application>
</
ss
:
ApplicationInfo>
- Le répertoire Resource : qui contient les différents fichiers images qui seront utilisées par l'application pour diverses raisons (image d'arrière-plan, icône de l'application, etc.).
Au niveau du code XAML de l'interface utilisateur, un squelette est déjà généré par le modèle de projet de Visual Studio :
<
s
:
SurfaceWindow
x
:
Class
=
"DemoAppSurface.SurfaceWindow1"
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns
:
x
=
"http://schemas.microsoft.com/winfx/2006/xaml"
xmlns
:
s
=
"http://schemas.microsoft.com/surface/2008"
Title
=
"DemoAppSurface"
>
<
s
:
SurfaceWindow.Resources>
<ImageBrush
x
:
Key
=
"WindowBackground"
Stretch
=
"None"
Opacity
=
"0.6"
ImageSource
=
"pack://application:,,,/Resources/WindowBackground.jpg"
/>
</
s
:
SurfaceWindow.Resources>
<Grid
Background
=
"{StaticResource WindowBackground}"
>
</Grid>
</
s
:
SurfaceWindow>
Comme vous pouvez le constater, cette interface n'a rien de bien compliquée : elle définit un objet principal de type SurfaceWindow qui contient une grille dont l'arrière-plan est rempli avec une image issue des ressources de l'application. Noter cependant qu'elle définit un nouvel espace de nom, spécifique à Surface : xmlns:s="http://schemas.microsoft.com/surface/2008"
Nous allons rajouter quelques contrôles, pour commencer à prendre en main le développement. On remarque qu'il existe déjà un grand nombre de contrôles utilisables :
Mais, si vous ne trouvez pas votre bonheur, n'oubliez pas une chose : la technologie utilisée pour Microsoft Surface, c'est du WPF donc du .NET. Cela signifie que vous avez tout à fait la possibilité de créer votre propre contrôle en utilisant l'héritage !
Commençons par rajouter un bouton et une zone de texte :
<Grid
Background
=
"{StaticResource WindowBackground}"
>
<
s
:
SurfaceButton
x
:
Name
=
"sBtn"
Content
=
"Click Me !"
HorizontalAlignment
=
"Center"
VerticalAlignment
=
"Top"
Click
=
"sBtn_Click"
/>
<
s
:
SurfaceTextBox
x
:
Name
=
"sTb"
HorizontalAlignment
=
"Center"
VerticalAlignment
=
"Center"
Height
=
"25"
Width
=
"100"
/>
</Grid>
Comme vous pouvez le constater, rien de bien compliqué. Certes, nous utilisons des contrôles propres à Surface, mais leurs propriétés sont les mêmes que pour des contrôles WPF classiques.
Au niveau du gestionnaire d'évènements défini pour l'évènement Click, il est tout ce qu'il y a de plus simple :
private
void
sBtn_Click
(
object
sender,
RoutedEventArgs e)
{
this
.
sTb.
Text =
this
.
sBtn.
Content.
ToString
(
);
}
Il ne reste plus qu'à exécuter l'application. Étant donné le prix d'une table Surface (environ 15 000 $), il est sûr que tout le monde ne pourra pas en acquérir une facilement. Fort heureusement, lorsque vous installez le SDK de Surface, un émulateur est également installé ce qui vous permet de tester votre application pour vous assurer qu'elle fonctionne :
Pour essayer votre application, il suffit de lancer l'émulateur et de faire un F5 dans Visual Studio : l'application est automatiquement déployée et lancée sur l'émulateur (de la même manière que pour les applications utilisant le Compact Framework et les émulateurs de Pocket PC/SmartPhone) :
On constate que l'application se lance correctement et qu'il est possible de déboguer avec Visual Studio :
On pourrait trouver bizarre qu'une zone de texte soit utilisable dans une application accessible uniquement au doigt. Fort heureusement, vous avez la possibilité d'utiliser un clavier virtuel qui apparait dès que la TextBox a le focus :
Pour ceux qui se poserait la question, sachez que les 4 arrondis que l'on voit dans les coins sont tout simplement les touches permettant d'accéder au menu, depuis lequel il est possible de choisir l'application à lancer/afficher.
Comme nous l'avons vu, le développement est plutôt simple à mettre en ouvre. Voyons maintenant comment utiliser un contrôle spécifique à Microsoft Surface : le contrôle ScatterView. Comme je vous l'ai indiqué précédemment, la technologie Surface permet de manipuler les contrôles insérés. Cependant, pour que cela fonctionne, il est nécessaire que les contrôles soient imbriqués dans un contrôle spécifique : le ScatterView. Nous allons légèrement modifier notre interface graphique pour y insérer ce contrôle :
<
s
:
SurfaceWindow
x
:
Class
=
"DemoAppSurface.SurfaceWindow1"
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns
:
x
=
"http://schemas.microsoft.com/winfx/2006/xaml"
xmlns
:
s
=
"http://schemas.microsoft.com/surface/2008"
Title
=
"DemoAppSurface"
>
<
s
:
SurfaceWindow.Resources>
<ImageBrush
x
:
Key
=
"WindowBackground"
Stretch
=
"None"
Opacity
=
"0.6"
ImageSource
=
"pack://application:,,,/Resources/WindowBackground.jpg"
/>
<DataTemplate
x
:
Key
=
"svItemTemplate"
>
<Image
Source
=
"{Binding}"
/>
</DataTemplate>
</
s
:
SurfaceWindow.Resources>
<
s
:
ScatterView
x
:
Name
=
"sv"
Background
=
"{StaticResource WindowBackground}"
ItemsSource
=
"{Binding}"
ItemTemplate
=
"{StaticResource svItemTemplate}"
Loaded
=
"sv_Loaded"
/>
</
s
:
SurfaceWindow>
Modifions à présent le code C# associé pour faire en sorte de charger une liste de photos, au démarrage de l'application :
private
void
sv_Loaded
(
object
sender,
RoutedEventArgs e)
{
this
.
sv.
DataContext =
from
file in
Directory.
GetFiles
(
@"C:\Users\Public\Pictures\Sample Pictures"
)
where
file.
ToLower
(
CultureInfo.
CurrentCulture).
EndsWith
(
"jpg"
)
select
file;
}
À l'exécution, la propriété DataContext est correctement affectée et chaque élément du contrôle ScatterView se voit appliquer le template défini soit, une image pointant vers l'élément indiqué :
Grâce à ce contrôle, il est donc possible de déplacer les images, mais également de les agrandir/diminuer, de les faire pivoter, etc. De plus, le simulateur permettant d'utiliser deux souris simultanément, il est possible de simuler l'appui de deux doigts ou plus :
Bien sûr, vous avez également la possibilité d'indiquer que vous ne souhaitez pas permettre à l'utilisateur de faire pivoter ou de manipuler les éléments du ScatterView. Pour cela, vous pouvez modifier les propriétés CanRotate et CanScale :
foreach
(
ScatterViewItem item in
sv.
Items)
{
item.
CanRotate =
item.
CanScale =
false
;
}
Comme vous pouvez le constater, le développement est relativement simple et très similaire à celui d'une application WPF. Cependant, voyons à présent comment aller un peu plus loin.
III. Allez plus loin dans le développement▲
III-A. Les notifications▲
Il est possible d'utiliser les notifications, disponibles dans Surface, pour afficher des informations qui seront présentées à l'utilisateur, éventuellement pendant une durée bien précise. Cette opération s'effectue au moyen de la méthode RequestNotification de la classe UserNotifications :
UserNotifications.
RequestNotification
(
"Notification"
,
"Ce message disparaitra dans 5 secondes..."
,
new
TimeSpan
(
0
,
0
,
5
));
à l'exécution, le message apparait et disparait au bout du nombre de secondes indiquées ou bien lorsque l'utilisateur clique sur la croix située au-dessus du bandeau :
III-B. Dessiner sur Microsoft Surface▲
Tout comme en WPF, il existe un composant particulier, avec Surface, permettant de dessiner. Dans le cas présent, il s'agit du contrôle SurfaceInkCanvas :
<
s
:
SurfaceInkCanvas
x
:
Name
=
"inkCanvas"
Grid.
Row
=
"1"
EditingMode
=
"Ink"
/>
Par défaut, la couleur utilisée est le noir cependant, en accédant à la propriété DefaultDrawingAttributes, vous accédez à l'ensemble des propriétés utilisées pour afficher les différentes Strokes représentant le dessin. Vous pouvez ainsi modifier la couleur des Strokes :
private
void
ChangeInkColor
(
object
sender,
RoutedEventArgs e)
{
var
btnColor =
sender as
SurfaceButton;
if
(
btnColor !=
null
)
{
var
color =
btnColor.
Content.
ToString
(
);
this
.
inkCanvas.
DefaultDrawingAttributes.
Color =
GetColorFromString
(
color);
}
}
// Method found here: http://geekswithblogs.net/ftom/archive/2008/08/21/silverlight-2-how-to-get-a-color-or-a.aspx
private
Color GetColorFromString
(
string
colorString)
{
Type colorType =
(
typeof
(
System.
Windows.
Media.
Colors));
if
(
colorType.
GetProperty
(
colorString) !=
null
)
{
var
color =
colorType.
InvokeMember
(
colorString,
BindingFlags.
GetProperty,
null
,
null
,
null
);
if
(
color !=
null
)
{
return
(
Color)color;
}
throw
new
InvalidCastException
(
"Color not defined"
);
}
throw
new
NotSupportedException
(
);
}
III-C. La gestion des « Byte Tag »▲
Microsoft Surface possède la particularité de pouvoir reconnaitre les objets dès lors qu'ils sont posés sur la table. Pour cela, il est nécessaire d'utiliser un objet de type TagVisualizer, qui réagit à un ou plusieurs contrôles tagués qui sont posés sur la table. Le résultat du contact entre cet objet et le matériel est affiché au moyen d'un objet de type TagVisualization.
Pour définir quels sont les objets tagués qui doivent déclencher la création d'objets de type TagVisualization, il est nécessaire de passer par la propriété Definitions (qui contient un ensemble d'objets de type TagVisualizationDefinition).
Pour créer un objet de type TagVisualization, avec Visual Studio, il suffit de faire un clic droit sur votre projet puis de choisir « Add New Item » => « Surface v1.0 » => « Tag Visualization (WPF) » :
Nous allons créer un TagVisualization qui affichera un rectangle rouge lorsqu'un objet marqué sera « déposé » sur la table :
<
s
:
TagVisualization
x
:
Class
=
"DemoAppSurface.CustomTagVisualization"
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns
:
x
=
"http://schemas.microsoft.com/winfx/2006/xaml"
xmlns
:
s
=
"http://schemas.microsoft.com/surface/2008"
Loaded
=
"CustomTagVisualization_Loaded"
>
<Rectangle
Fill
=
"Red"
Width
=
"50"
Height
=
"50"
/>
</
s
:
TagVisualization>
À présent, nous allons déposer notre objet TagVisualizer, qui représentera la zone sur laquelle il sera possible de déposer des objets qui seront identifiés :
<
s
:
TagVisualizer
Name
=
"visualizer"
Grid.
Row
=
"1"
HorizontalAlignment
=
"Stretch"
VerticalAlignment
=
"Stretch"
>
<
s
:
TagVisualizer.Definitions>
<
s
:
ByteTagVisualizationDefinition
Value
=
"200"
TagRemovedBehavior
=
"Fade"
Source
=
"CustomTagVisualization.xaml"
/>
</
s
:
TagVisualizer.Definitions>
</
s
:
TagVisualizer>
Comme vous pouvez le constater, on place un TagVisualizer et on définit sa propriété Definitions : on y ajoute ainsi un objet de type ByteTagVisualizationDefinition qui servira à reconnaitre les objets dont le tag vaut 200 (0xc8). En effet, chaque objet associé à Microsoft Surface dispose d'un Tag, sorte d'identifiant unique, qu'il est possible de reconnaitre lorsque l'objet est déposé sur la table. Dans le cas présent, dès qu'un objet portant l'identifiant 200 est déposé sur la table, une instance du TagVisualization de type CustomTagVisualization est affichée à la place de l'objet. En ce qui concerne la propriété TagRemoveBehavior, elle sert à indiquer comment doit disparaitre le TagVisualization lorsque l'objet est enlevé de la table : sur un fondu ou directement.
À l'exécution, l'application se lance correctement et il est possible de simuler le fait qu'un objet, portant un Tag particulier, soit déposé au moyen du menu du simulateur :
Par défaut, le simulateur émule un objet possédant le Tag 192 (0xc0). Dès lors, si un objet portant ce Tag est déposé, rien ne se produit sur la table :
Cependant, si l'utilisateur dépose un objet possédant le Tag 200 (0xc8) :
Alors une instance du TagVisualization, spécifié dans la propriété Definitions, est correctement insérée dans l'application, là où l'utilisateur l'a indiqué :
De plus, si vous « enlevez » l'objet qui est déposé sur la table, vous pouvez constater que l'effet de fondu (ou non) est appliqué :
Chaque objet de type TagVizualisationDefinition possède deux propriétés utilisées pour modifier le centre du TagVisualization affiché :
- OrientationOffsetFromTag : qui permet de spécifier, en degré, l'inclinaison du TagVisualization
- PhysicalCenterOffsetFromTag : qui permet de déplacer le centre du TagVisualization, en fonction d'un objet de type Vector.
Ainsi, le code suivant :
<
s
:
TagVisualizer
Name
=
"visualizer"
Grid.
Row
=
"1"
HorizontalAlignment
=
"Stretch"
VerticalAlignment
=
"Stretch"
>
<
s
:
TagVisualizer.Definitions>
<
s
:
ByteTagVisualizationDefinition
Value
=
"200"
OrientationOffsetFromTag
=
"45"
PhysicalCenterOffsetFromTag
=
"2.0,1.0"
TagRemovedBehavior
=
"Fade"
Source
=
"CustomTagVisualization.xaml"
/>
</
s
:
TagVisualizer.Definitions>
</
s
:
TagVisualizer>
Produit le résultat que vous pouvez constater sur cette image, où le TagVisualization est incliné de 45 degrés et déplacé de 2 sur l'axe des X et de 1 sur l'axe des Y :
IV. Conclusion▲
Comme vous pouvez le constater, le développement pour Microsoft Surface est relativement simple, surtout si vous connaissez déjà le développement d'applications WPF. Certes, le prix d'une table Surface est relativement élevé, mais les possibilités offertes par cette technologie sont indiscutables, dans bien des domaines : médecine, bâtiments, militaire, etc.
De plus, la mise à disposition d'un émulateur permet de tester ses applications avant de les déployer en production!
V. Liens▲
- La session sur le développement pour Microsoft Surface, présentée à la PDC 2008 : http://channel9.msdn.com/pdc2008/PC17/