1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#ifndef KEYMAP_HXX
19#define KEYMAP_HXX
20
21#include <unordered_map>
22#include "Event.hxx"
23#include "EventHandlerConstants.hxx"
24
25/**
26 This class handles keyboard mappings in Stella.
27
28 @author Thomas Jentzsch
29*/
30class KeyMap
31{
32 public:
33
34 struct Mapping
35 {
36 EventMode mode;
37 StellaKey key;
38 StellaMod mod;
39
40 Mapping() : mode(EventMode(0)), key(StellaKey(0)), mod(StellaMod(0)) { }
41 Mapping(const Mapping& m) : mode(m.mode), key(m.key), mod(m.mod) { }
42 explicit Mapping(EventMode c_mode, StellaKey c_key, StellaMod c_mod)
43 : mode(c_mode), key(c_key), mod(c_mod) { }
44 explicit Mapping(EventMode c_mode, int c_key, int c_mod)
45 : mode(c_mode), key(StellaKey(c_key)), mod(StellaMod(c_mod)) { }
46
47 bool operator==(const Mapping& other) const
48 {
49 return (key == other.key
50 && mode == other.mode
51 && (((mod | other.mod) & KBDM_SHIFT) ? (mod & other.mod & KBDM_SHIFT) : true)
52 && (((mod | other.mod) & KBDM_CTRL ) ? (mod & other.mod & KBDM_CTRL ) : true)
53 && (((mod | other.mod) & KBDM_ALT ) ? (mod & other.mod & KBDM_ALT ) : true)
54 && (((mod | other.mod) & KBDM_GUI ) ? (mod & other.mod & KBDM_GUI ) : true)
55 );
56 }
57 };
58 using MappingArray = std::vector<Mapping>;
59
60 KeyMap();
61 virtual ~KeyMap() = default;
62
63 /** Add new mapping for given event */
64 void add(const Event::Type event, const Mapping& mapping);
65 void add(const Event::Type event, const EventMode mode, const int key, const int mod);
66
67 /** Erase mapping */
68 void erase(const Mapping& mapping);
69 void erase(const EventMode mode, const int key, const int mod);
70
71 /** Get event for mapping */
72 Event::Type get(const Mapping& mapping) const;
73 Event::Type get(const EventMode mode, const int key, const int mod) const;
74
75 /** Check if a mapping exists */
76 bool check(const Mapping& mapping) const;
77 bool check(const EventMode mode, const int key, const int mod) const;
78
79 /** Get mapping description */
80 string getDesc(const Mapping& mapping) const;
81 string getDesc(const EventMode mode, const int key, const int mod) const;
82
83 /** Get the mapping description(s) for given event and mode */
84 string getEventMappingDesc(const Event::Type event, const EventMode mode) const;
85
86 MappingArray getEventMapping(const Event::Type event, const EventMode mode) const;
87
88 string saveMapping(const EventMode mode) const;
89 int loadMapping(string& list, const EventMode mode);
90
91 /** Erase all mappings for given mode */
92 void eraseMode(const EventMode mode);
93 /** Erase given event's mapping for given mode */
94 void eraseEvent(const Event::Type event, const EventMode mode);
95 /** clear all mappings for a modes */
96 // void clear() { myMap.clear(); }
97 size_t size() { return myMap.size(); }
98
99 bool& enableMod() { return myModEnabled; }
100
101 private:
102 //** Convert modifiers */
103 Mapping convertMod(const Mapping& mapping) const;
104
105 struct KeyHash {
106 size_t operator()(const Mapping& m) const {
107 return std::hash<uInt64>()((uInt64(m.mode)) // 3 bits
108 + ((uInt64(m.key)) * 7) // 8 bits
109 + (((uInt64((m.mod & KBDM_SHIFT) != 0) << 0)) // 1 bit
110 | ((uInt64((m.mod & KBDM_ALT ) != 0) << 1)) // 1 bit
111 | ((uInt64((m.mod & KBDM_GUI ) != 0) << 2)) // 1 bit
112 | ((uInt64((m.mod & KBDM_CTRL ) != 0) << 3)) // 1 bit
113 ) * 2047
114 );
115 }
116 };
117
118 std::unordered_map<Mapping, Event::Type, KeyHash> myMap;
119
120 // Indicates whether the key-combos tied to a modifier key are
121 // being used or not (e.g. Ctrl by default is the fire button,
122 // pressing it with a movement key could inadvertantly activate
123 // a Ctrl combo when it isn't wanted)
124 bool myModEnabled;
125};
126
127#endif
128