Situation
You want to know how to use keyboard keys in combination with mouse clicks in controlling MultiCharts .NET.

Programming example

using System;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using System.Windows.Forms;             // Added

namespace PowerLanguage.Indicator
{
    [MouseEvents(true), SameAsSymbol(true)]
    public class Example_MouseClicksAndKeyboardKeys : IndicatorObject
    {
        private ChartPoint shiftClick, controlClick;

        public Example_MouseClicksAndKeyboardKeys(object _ctx) : base(_ctx) { }

        protected override void StartCalc()
        {
            Output.Clear();
        }
        
        protected override void CalcBar() { }

        protected override void OnMouseEvent(MouseClickArgs arg)
        {
            // Don't take action on right mouse clicks
            if (arg.buttons == MouseButtons.Right)
                return;

            switch (arg.keys)
            {
                // Left mouse button + control: store & output information about the first click
                case Keys.Control:
                    controlClick = arg.point;
                    OutputClickInfo(controlClick);
                    break;

                // Left mouse button + shift: store & output information about the second click
                case Keys.Shift:
                    shiftClick = arg.point;
                    OutputClickInfo(shiftClick);
                    break;

                // Left mouse button + control & shift: output the absolute differences between clicks
                case Keys.Control | Keys.Shift:
                    // .. but only when click data is available
                    if (shiftClick.Price != 0 && controlClick.Price != 0)
                    {
                        ClickDifference(controlClick, shiftClick);
                    }
                    break;
            }
        }

        // OutputClickInfo(): outputs information about mouse click location
        private void OutputClickInfo(ChartPoint locationOfClick)
        {
            Output.WriteLine("Click at time {0} and price {1}.",
                locationOfClick.Time.ToString("d-M HH:mm:ss"),
                locationOfClick.Price.ToString("F2")); 
        }

        // ClickDifference(): outputs absolute price and time difference between 2 click locations
        private void ClickDifference(ChartPoint clickOne, ChartPoint clickTwo)
        {
            double priceDifference  = Math.Abs(clickOne.Price - clickTwo.Price);
            double timeDifference   = Math.Abs((clickOne.Time - clickTwo.Time).TotalMinutes);

            Output.WriteLine("Price difference is {0} and time difference is {1} minutes.",
                priceDifference.ToString("F3"),
                timeDifference);
        }
    }
}

Output of the programming example

With a chart like:

Example of mouse clicks and keyboard keys in MultiCharts .NET

The indicator generates the following output in the Output Window after a couple of mouse clicks:

Click at time 21-3 05:30:00 and price 1859,73.
Click at time 21-3 12:30:00 and price 1865,70.
Price difference is 5,970 and time difference is 420 minutes.
Click at time 21-3 07:00:00 and price 1869,82.
Click at time 21-3 11:30:00 and price 1871,46.
Price difference is 1,647 and time difference is 270 minutes.
Click at time 21-3 06:00:00 and price 1860,76.
Click at time 21-3 21:00:00 and price 1881,35.
Price difference is 20,586 and time difference is 900 minutes.

Working with mouse clicks and keyboard keys in MultiCharts .NET

Programmatically determining if a mouse click was accompanied with a keyboard modifier key is quite useful. Because mouse clicks on a price chart also happen during normal usage, we probably only want to execute programming code when a mouse click is accompanied with a keyboard key.

See working with mouse clicks to learn more about mouse clicks. For more examples of mouse clicks combined with keyboard keys, see submit market orders with a mouse click and turn a script on or off with mouse clicks.

Working with mouse clicks in MultiCharts .NET requires two things:

  • The MouseEvents attribute needs to be enabled;
  • The OnMouseEvent() method, which provides the programmatic side of dealing with mouse clicks (see PowerLanguage .NET Help, n.d.), needs to be implemented. In this method the differentiation between keyboard keys is done.

In the programming example different actions are taken depending on the keyboard key that goes along the mouse click.

MultiCharts .NET programming example

The example begins with including a namespace:

using System.Windows.Forms;             // Added

This makes it easier to use the Keys and MouseButtons enumerations later on: otherwise, the fully qualified name (e.g., System.Windows.Forms.MouseButtons) needs to be used every time.

Next are the MultiCharts .NET class attributes:

[MouseEvents(true), SameAsSymbol(true)]

Setting MouseEvents to true enables mouse click processing, while SameAsSymbol set to true prevents the indicator from being plotted in a sub-chart.

Variable declaration and Output Window clearing

Then two ChartPoint struct variables are declared:

private ChartPoint shiftClick, controlClick;

By the way, structs are value types, but similar to classes in that they can include properties, methods, constructors, and fields (Liberty & MacDonald, 2009). Their typical use is to encapsulate a small group of related variables (in this case, mouse click coordinates).

The click coordinates of a mouse click with Shift will be stored in shiftClick, while controlClick saves the click location of a mouse click with the Control key.

Next is the StartCalc() override method:

protected override void StartCalc()
{
    Output.Clear();
}

This method, executed at the start of every calculation cycle (MultiCharts, 2013), clears the Output Window with Output.Clear() to prevent cluttering.

Processing mouse clicks and keyboards keys in MultiCharts .NET

The next part is the OnMouseEvent() method (lines 23-52), which starts with an if statement:

// Don't take action on right mouse clicks
if (arg.buttons == MouseButtons.Right)
    return;

PS: Only left (MouseButtons.Left) and right (MouseButtons.Right) mouse buttons are processed by MultiCharts .NET.

When the mouse click button on the price chart (arg.buttons) is the right button (MouseButtons.Right), the return statement is called. This statement tells the current method to exit immediately (Stellman & Greene, 2010); other statements in the OnMouseEvent() method will therefore not be processed when a right mouse click occurred.

Switching on the keyboard key enumeration

Next is a switch statement that “switches on” the arg.keys enum variable:

switch (arg.keys)
{
    // Left mouse button + control: store & output information about the first click
    case Keys.Control:
        controlClick = arg.point;
        OutputClickInfo(controlClick);
        break;
 
    // Left mouse button + shift: store & output information about the second click
    case Keys.Shift:
        shiftClick = arg.point;
        OutputClickInfo(shiftClick);
        break;
 
    // Left mouse button + control & shift: output the absolute differences between clicks
    case Keys.Control | Keys.Shift:
        // .. but only when click data is available
        if (shiftClick.Price != 0 && controlClick.Price != 0)
        {
            ClickDifference(controlClick, shiftClick);
        }
        break;
}

PS: Only the Shift (Keys.Shift) and Control (Keys.Control) keys are processed by MultiCharts .NET (MultiCharts Support, personal communication, March 19, 2014).

The switch statement contains three cases: the Control key (lines 31-35), the Shift key (lines 37-41), and the Control + Shift combination (lines 43-50).

The Control and Shift key are processed similarly: first the mouse click location (arg.point) is assigned to either the controlClick (line 33) or shiftClick (line 39) variable. Then the OutputClickInfo() method (discussed below) is called (lines 34 and 40).

The Keys enumeration contains both modifier and individual keys: Keys.Shift and Keys.Control refer to the modifier key, while Keys.ShiftKey and Keys.ControlKey refer to the individual, standalone keys (StackOverflow, 2011).

The bitwise OR logical operator (|) is used for the Control and Shift key combination (line 44). An if statement verifies if both ChartPoint struct variables have a non-zero price value (line 46). When that is the case, calculating the difference between both makes sense and the ClickDifference() method is called (discussed below).

Output mouse click information in MultiCharts .NET

The OuputClickInfo() method is implemented as follows:

// OutputClickInfo(): outputs information about mouse click location
private void OutputClickInfo(ChartPoint locationOfClick)
{
    Output.WriteLine("Click at time {0} and price {1}.",
        locationOfClick.Time.ToString("d-M HH:mm:ss"),
        locationOfClick.Price.ToString("F2"));
}

In the Output.WriteLine() method two substitution parameters are used to output information from the locationOfClick ChartPoint parameter.

The date and time of the click location (locationOfClick.Time) DateTime value is formatted to a string, followed by using the format specifier "F2" to output the price of the click location (locationOfClick.Price) with two decimals.

Calculating the difference between mouse clicks

The ClickDifference() method does the following:

// ClickDifference(): outputs absolute price and time difference between 2 click locations
private void ClickDifference(ChartPoint clickOne, ChartPoint clickTwo)
{
    double priceDifference  = Math.Abs(clickOne.Price - clickTwo.Price);
    double timeDifference   = Math.Abs((clickOne.Time - clickTwo.Time).TotalMinutes);
 
    Output.WriteLine("Price difference is {0} and time difference is {1} minutes.",
        priceDifference.ToString("F3"),
        timeDifference);
}

This method has two ChartPoint structs as parameters: clickOne and clickTwo.

The absolute price difference between mouse clicks is calculated by having the Math.Abs() method return the absolute value of subtracting the Price properties from both chart points (line 65).

The time difference is calculated by subtracting both Time properties (which return DateTime values). The number of minutes in this time interval is returned by the TotalMinutes property from the TimeSpan structure. With the Math.Abs() method the absolute amount is returned (line 66).

Lastly, both variables are outputted to the Output Window with two substitution parameters: priceDifference, formatted with three decimals with a format specifier ("F3"), and timeDifference (lines 68-70).

Key points

  • Working with mouse click events requires enabling the MouseEvents attribute and implementing the OnMouseEvent() method;
  • The MouseClickArgs struct variable in the OnMouseEvent() method provides access to mouse click information, such as keyboard key (keys) and mouse button (buttons);
  • Left (MouseButtons.Left) and right (MouseButtons.Right) mouse buttons are registered by MultiCharts .NET, as well as the Control (Keys.Control) and Shift (Keys.Shift) key.
References

Liberty, J. & MacDonald, B. (2009). Learning C# 3.0: Master the Fundamentals of C# 3.0. Sebastopol, CA: O’Reilly Media.

MultiCharts (2013). MultiCharts .NET Programming Guide (version 1.0). Retrieved from http://www.multicharts.com/downloads/MultiCharts.NET-ProgrammingGuide-v1.0.pdf

PowerLanguage .NET Help (n.d.). Retrieved on May 16, 2014, from http://www.multicharts.com/downloads/PowerLanguage.NET.chm

StackOverflow (June 2011). C# - Difference between Keys.Shift and Keys.ShiftKey. Retrieved on March 18, 2014, from https://stackoverflow.com/questions/6446927/c-sharp-difference-between-keys-shift-and-keys-shiftkey

Stellman, A. & Greene, J. (2010). Head First C#: A Brain-Friendly Guide (2nd edition). Sebastopol, CA: O’Reilly Media.