To solve this problem, we first need to define the decision variables and the objective function. Let's denote the number of A400 keyboards produced as \(x_A\) and the number of P500 keyboards produced as \(x_P\). The objective is to maximize profit, which can be calculated based on the profits per unit of each keyboard type.

Given:
- Profit per A400 keyboard: $35
- Profit per P500 keyboard: $80
- Labour hours required per A400 keyboard: 5 hours
- Labour hours required per P500 keyboard: 9 hours
- Maximum labour hours available per week: 45 hours
- Demand constraint: Produce at least three times as many A400 keyboards as P500 keyboards.

The objective function to maximize profit can be written as:
\[ \text{Maximize} \quad 35x_A + 80x_P \]

Subject to the constraints:
1. Labour hours constraint: \(5x_A + 9x_P \leq 45\)
2. Demand forecast constraint: \(x_A \geq 3x_P\)
3. Non-negativity constraints (since production cannot be negative): \(x_A \geq 0, x_P \geq 0\)

Now, let's translate this into Gurobi code in Python:

```python
from gurobipy import *

# Create a model
m = Model("Curious_Electronics")

# Define the decision variables
xA = m.addVar(vtype=GRB.CONTINUOUS, name="xA", lb=0)  # Number of A400 keyboards
xP = m.addVar(vtype=GRB.CONTINUOUS, name="xP", lb=0)  # Number of P500 keyboards

# Define the objective function: Maximize profit
m.setObjective(35*xA + 80*xP, GRB.MAXIMIZE)

# Add constraints
# Labour hours constraint
m.addConstr(5*xA + 9*xP <= 45, name="labour_hours")

# Demand forecast constraint
m.addConstr(xA >= 3*xP, name="demand_forecast")

# Solve the model
m.optimize()

# Print the results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found.")
    print(f"Produce {xA.x} A400 keyboards and {xP.x} P500 keyboards.")
    print(f"Maximum profit: ${35*xA.x + 80*xP.x:.2f}")
else:
    print("No optimal solution found. The model is infeasible or unbounded.")

```