/*
  Keyboard.h

  Copyright (c) 2015, Arduino LLC
  Original code (pre-library): Copyright (c) 2011, Peter Barrett

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#pragma once

#include "soc/soc_caps.h"
#if SOC_USB_OTG_SUPPORTED

#include "Print.h"
#include "USBHID.h"
#if CONFIG_TINYUSB_HID_ENABLED

#include "esp_event.h"

ESP_EVENT_DECLARE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS);

typedef enum {
  ARDUINO_USB_HID_KEYBOARD_ANY_EVENT = ESP_EVENT_ANY_ID,
  ARDUINO_USB_HID_KEYBOARD_LED_EVENT = 0,
  ARDUINO_USB_HID_KEYBOARD_MAX_EVENT,
} arduino_usb_hid_keyboard_event_t;

typedef union {
  struct {
    uint8_t numlock    : 1;
    uint8_t capslock   : 1;
    uint8_t scrolllock : 1;
    uint8_t compose    : 1;
    uint8_t kana       : 1;
    uint8_t reserved   : 3;
  };
  uint8_t leds;
} arduino_usb_hid_keyboard_event_data_t;

// Supported keyboard layouts
extern const uint8_t KeyboardLayout_de_DE[];
extern const uint8_t KeyboardLayout_en_US[];
extern const uint8_t KeyboardLayout_es_ES[];
extern const uint8_t KeyboardLayout_fr_CH[];
extern const uint8_t KeyboardLayout_fr_FR[];
extern const uint8_t KeyboardLayout_it_IT[];
extern const uint8_t KeyboardLayout_pt_PT[];
extern const uint8_t KeyboardLayout_sv_SE[];
extern const uint8_t KeyboardLayout_da_DK[];
extern const uint8_t KeyboardLayout_hu_HU[];
extern const uint8_t KeyboardLayout_pt_BR[];

#define KEY_LEFT_CTRL   0x80
#define KEY_LEFT_SHIFT  0x81
#define KEY_LEFT_ALT    0x82
#define KEY_LEFT_GUI    0x83
#define KEY_RIGHT_CTRL  0x84
#define KEY_RIGHT_SHIFT 0x85
#define KEY_RIGHT_ALT   0x86  // AltGr (Right Alt) Key
#define KEY_RIGHT_GUI   0x87

#define KEY_UP_ARROW     0xDA
#define KEY_DOWN_ARROW   0xD9
#define KEY_LEFT_ARROW   0xD8
#define KEY_RIGHT_ARROW  0xD7
#define KEY_MENU         0xED  //  "Keyboard Application" in USB standard
#define KEY_SPACE        0x20
#define KEY_BACKSPACE    0xB2
#define KEY_TAB          0xB3
#define KEY_RETURN       0xB0
#define KEY_ESC          0xB1
#define KEY_INSERT       0xD1
#define KEY_DELETE       0xD4
#define KEY_PAGE_UP      0xD3
#define KEY_PAGE_DOWN    0xD6
#define KEY_HOME         0xD2
#define KEY_END          0xD5
#define KEY_NUM_LOCK     0xDB
#define KEY_CAPS_LOCK    0xC1
#define KEY_F1           0xC2
#define KEY_F2           0xC3
#define KEY_F3           0xC4
#define KEY_F4           0xC5
#define KEY_F5           0xC6
#define KEY_F6           0xC7
#define KEY_F7           0xC8
#define KEY_F8           0xC9
#define KEY_F9           0xCA
#define KEY_F10          0xCB
#define KEY_F11          0xCC
#define KEY_F12          0xCD
#define KEY_F13          0xF0
#define KEY_F14          0xF1
#define KEY_F15          0xF2
#define KEY_F16          0xF3
#define KEY_F17          0xF4
#define KEY_F18          0xF5
#define KEY_F19          0xF6
#define KEY_F20          0xF7
#define KEY_F21          0xF8
#define KEY_F22          0xF9
#define KEY_F23          0xFA
#define KEY_F24          0xFB
#define KEY_PRINT_SCREEN 0xCE
#define KEY_SCROLL_LOCK  0xCF
#define KEY_PAUSE        0xD0

#define LED_NUMLOCK    0x01
#define LED_CAPSLOCK   0x02
#define LED_SCROLLLOCK 0x04
#define LED_COMPOSE    0x08
#define LED_KANA       0x10

// Numeric keypad
#define KEY_KP_SLASH    0xDC
#define KEY_KP_ASTERISK 0xDD
#define KEY_KP_MINUS    0xDE
#define KEY_KP_PLUS     0xDF
#define KEY_KP_ENTER    0xE0
#define KEY_KP_1        0xE1
#define KEY_KP_2        0xE2
#define KEY_KP_3        0xE3
#define KEY_KP_4        0xE4
#define KEY_KP_5        0xE5
#define KEY_KP_6        0xE6
#define KEY_KP_7        0xE7
#define KEY_KP_8        0xE8
#define KEY_KP_9        0xE9
#define KEY_KP_0        0xEA
#define KEY_KP_DOT      0xEB

//  Low level key report: up to 6 keys and shift, ctrl etc at once
typedef struct {
  uint8_t modifiers;
  uint8_t reserved;
  uint8_t keys[6];
} KeyReport;

class USBHIDKeyboard : public USBHIDDevice, public Print {
private:
  USBHID hid;
  KeyReport _keyReport;
  const uint8_t *_asciimap;
  bool shiftKeyReports;

public:
  USBHIDKeyboard(void);
  void begin(const uint8_t *layout = KeyboardLayout_en_US);
  void end(void);
  size_t write(uint8_t k);
  size_t write(const uint8_t *buffer, size_t size);
  size_t press(uint8_t k);
  size_t release(uint8_t k);
  void releaseAll(void);
  void sendReport(KeyReport *keys);
  void setShiftKeyReports(bool set);

  //raw functions work with TinyUSB's HID_KEY_* macros
  size_t pressRaw(uint8_t k);
  size_t releaseRaw(uint8_t k);

  void onEvent(esp_event_handler_t callback);
  void onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_handler_t callback);

  // internal use
  uint16_t _onGetDescriptor(uint8_t *buffer);
  void _onOutput(uint8_t report_id, const uint8_t *buffer, uint16_t len);
};

#endif /* CONFIG_TINYUSB_HID_ENABLED */
#endif /* SOC_USB_OTG_SUPPORTED */
