Capturer les événements de souris dans le concepteur PowerPoint via VSTO

Je développe un complément pour PowerPoint (2013) avec C # / VSTO. Le complément fonctionnera lorsque l’utilisateur est en mode Création et non en mode présentation .

Comment capturer des événements de souris concernant des formes / objects sur les diapositives, par exemple mouseOver, mouseDown, etc.? Je souhaite écouter ces événements afin de créer une interface utilisateur personnalisée située à proximité des objects / des formes. Existe-t-il des événements que je peux écouter ou faut-il utiliser des méthodes plus avancées, telles que la création d’un écouteur de souris global, la traduction des coordonnées en formes PowerPoint et la lecture en boucle des formes sur la diapositive pour voir si la souris est à l’intérieur les limites de l’une des formes? J’apprécierai également d’autres solutions créatives au problème.

J’ai essayé de chercher une réponse sans aucune chance. Cependant, je sais que c’est possible car d’autres compléments font ce que je veux. Think-Cell ( https://www.youtube.com/watch?v=qsnciEZi5X0 ) en est un exemple. Les objects que vous manipulez sont des objects PowerPoint “ordinaires” tels que TextFrames et Shapes.

Je travaille avec .Net 4.5 sur Windows 8.1 Pro.

PowerPoint n’expose pas directement ces événements, mais il est possible d’implémenter vos propres événements en combinant des points d’ancrage de souris globaux avec des parameters de forme exposés par PowerPoint.

Cette réponse couvre le cas le plus difficile avec MouseEnter et MouseLeave. Pour gérer d’autres événements tels que MouseDown et MouseUp, vous pouvez utiliser l’événement PowerPoint fourni Application_WindowSelectionChange tel que proposé par Steve Rindsberg.

Pour obtenir un crochet de souris global, vous pouvez utiliser les excellents crochets de souris et de clavier pour applications et globaux .Net Libary en C # disponibles à l’ adresse http://globalmousekeyhook.codeplex.com/

Vous devrez télécharger et référencer la bibliothèque, puis configurer le crochet de la souris en utilisant ce code

 // Initialize the global mouse hook _mouseHookManager = new MouseHookListener(new AppHooker()); _mouseHookManager.Enabled = true; // Listen to the mouse move event _mouseHookManager.MouseMove += MouseHookManager_MouseMove; 

L’événement MouseMove peut être configuré pour gérer les événements de souris comme ceci (exemple avec MouseEnter et MouseLeave uniquement)

 private List _shapesEntered = new List(); private List _shapesOnSlide = new List(); void MouseHookManager_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { // Temporary list holding active shapes (shapes with the mouse cursor within the shape) List activeShapes = new List(); // Loop through all shapes on the slide, and add active shapes to the list foreach (PPShapes in _shapesOnSlide) { if (MouseWithinShape(s, e)) { activeShapes.Add(s); } } // Handle shape MouseEnter events // Select elements that are active but not currently in the shapesEntered list foreach (PPShape s in activeShapes) { if (!_shapesEntered.Contains(s)) { // Raise your custom MouseEntered event s.OnMouseEntered(); // Add the shape to the shapesEntered list _shapesEntered.Add(s); } } // Handle shape MouseLeave events // Remove elements that are in the shapes entered list, but no longer active HashSet activeIds = new HashSet(activeShapes.Select(s => s.Id)); _shapesEntered.RemoveAll(s => { if (!activeIds.Contains(s.Id)) { // The mouse is no longer over the shape // Raise your custom MouseLeave event s.OnMouseLeave(); // Remove the shape return true; } else { return false; } }); } 

_shapesOnSlide est une liste contenant toutes les formes de la diapositive actuelle, _shapesEntered est une liste des formes entrées mais non encore laissées, et PPShape est un object wrapper pour les formes PowerPoint (voir ci-dessous).

La méthode MouseWithinShape teste si la souris est actuellement dans une forme sur la diapositive. Pour ce faire, il convertit les formes en coordonnées X et Y (que PowerPoint expose dans l’unité Points) en coordonnées d’écran et teste si la souris se trouve dans ce cadre de sélection.

 ///  /// Test whether the mouse is within a shape ///  /// The shape to test /// MouseEventArgs /// TRUE if the mouse is within the bounding box of the shape; FALSE otherwise private bool MouseWithinShape(PPShape shape, System.Windows.Forms.MouseEventArgs e) { // Fetch the bounding box of the shape RectangleF shapeRect = shape.Rectangle; // Transform to screen pixels Rectangle shapeRectInScreenPixels = PointsToScreenPixels(shapeRect); // Test whether the mouse is within the bounding box return shapeRectInScreenPixels.Contains(e.Location); } ///  /// Transforms a RectangleF with PowerPoint points to a Rectangle with screen pixels ///  /// The Rectangle in PowerPoint point-units /// A Rectangle in screen pixel units private Rectangle PointsToScreenPixels(RectangleF shapeRectangle) { // Transform the points to screen pixels int x1 = pointsToScreenPixelsX(shapeRectangle.X); int y1 = pointsToScreenPixelsY(shapeRectangle.Y); int x2 = pointsToScreenPixelsX(shapeRectangle.X + shapeRectangle.Width); int y2 = pointsToScreenPixelsY(shapeRectangle.Y + shapeRectangle.Height); // Expand the bounding box with a standard padding // NOTE: PowerPoint transforms the mouse cursor when entering shapes before it actually // enters the shape. To account for that, add this extra 'padding' // Testing reveals that the current value (in PowerPoint 2013) is 6px x1 -= 6; x2 += 6; y1 -= 6; y2 += 6; // Return the rectangle in screen pixel units return new Rectangle(x1, y1, x2-x1, y2-y1); } ///  /// Transforms a PowerPoint point to screen pixels (in X-direction) ///  /// The value of point to transform in PowerPoint point-units /// The screen position in screen pixel units private int pointsToScreenPixelsX(float point) { // TODO Handle multiple windows // NOTE: PresStatic is a reference to the PowerPoint presentation object return PresStatic.Windows[1].PointsToScreenPixelsX(point); } ///  /// Transforms a PowerPoint point to screen pixels (in Y-direction) ///  /// The value of point to transform in PowerPoint point-units /// The screen position in screen pixel units private int pointsToScreenPixelsY(float point) { // TODO Handle multiple windows // NOTE: PresStatic is a reference to the PowerPoint presentation object return PresStatic.Windows[1].PointsToScreenPixelsY(point); } 

Enfin, nous implémentons un object PPShape personnalisé qui expose les événements que nous voulons écouter.

 using System.Drawing; using Microsoft.Office.Interop.PowerPoint; using System; namespace PowerPointDynamicLink.PPObject { class PPShape { #region Fields protected Shape shape; ///  /// Get the PowerPoint Shape this object is based on ///  public Shape Shape { get { return shape; } } protected long id; ///  /// Get or set the Id of the Shape ///  public long Id { get { return id; } set { id = value; } } protected ssortingng name; ///  /// Get or set the name of the Shape ///  public ssortingng Name { get { return name; } set { name = value; } } ///  /// Gets the bounding box of the shape in PowerPoint Point-units ///  public RectangleF Rectangle { get { RectangleF rect = new RectangleF { X = shape.Left, Y = shape.Top, Width = shape.Width, Height = shape.Height }; return rect; } } #endregion #region Constructor ///  /// Creates a new PPShape object ///  /// The PowerPoint shape this object is based on public PPShape(Shape shape) { this.shape = shape; this.name = shape.Name; this.id = shape.Id; } #endregion #region Event handling #region MouseEntered ///  /// An event that notifies listeners when the mouse has entered this shape ///  public event EventHandler MouseEntered = delegate { }; ///  /// Raises an event telling listeners that the mouse has entered this shape ///  internal void OnMouseEntered() { // Raise the event MouseEntered(this, new EventArgs()); } #endregion #region MouseLeave ///  /// An event that notifies listeners when the mouse has left this shape ///  public event EventHandler MouseLeave = delegate { }; ///  /// Raises an event telling listeners that the mouse has left this shape ///  internal void OnMouseLeave() { // Raise the event MouseLeave(this, new EventArgs()); } #endregion #endregion } } 

Pour être complètement exhaustif, il y a de nombreux éléments supplémentaires à traiter qui ne sont pas traités ici. Cela inclut des choses telles que suspendre le crochet de la souris lorsque la fenêtre PowerPoint est désactivée, gérer plusieurs fenêtres PowerPoint et plusieurs écrans, etc.

J’ai rencontré le même problème il y a quelques semaines. Mais au lieu d’approfondir la programmation des API Windows pour écouter les événements de la souris, j’ai utilisé Excel.Chart . Contrairement à PowerPoint.Chart il permet à de nombreux événements de souris de fonctionner comme

Chart.MouseUp , Chart.MouseOver , Chart.WindowBeforeDoubleClick , Chart.WindowBeforeRightClick , Chart.DragOver etc.

Vous avez très probablement déjà approfondi la programmation des API Windows. Avez-vous réussi à écouter l’événement de la souris? Si oui, alors comment l’avez-vous fait?

Merci 🙂