Merge branch 'master' of git.mutabah.net:acess2
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / wm_hotkeys.c
1 /*
2  * Acess2 Window Manager v3
3  * - By John Hodge (thePowersGang)
4  * 
5  * wm_hotkeys.c
6  * - Hotkey and key shortcut code
7  */
8 #include <common.h>
9 #include <wm_internals.h>
10 #include <wm_messages.h>
11 #include <wm_hotkeys.h>
12 #include <string.h>
13
14 #define true    1
15 #define false   0
16
17 #define MAX_STATE_SCANCODE      256
18
19 // === GOBALS ===
20 char    gbWM_HasBeenKeyDown = true;
21 uint8_t gWM_KeyStates[MAX_STATE_SCANCODE/8];
22 tHotkey *gpWM_Hotkeys;
23 tHotkeyTarget   *gpWM_HotkeyTargets;
24 tHotkeyTarget   *gpWM_HotkeyTargets_Last;
25
26 // === PROTOTYPES ===
27 static void     _SetKey(uint32_t sc);
28 static void     _UnsetKey(uint32_t sc);
29 static int      _IsKeySet(uint32_t sc);
30 void    WM_Hotkey_FireEvent(const char *Target);
31
32 // === CODE ===
33 void WM_Hotkey_Register(int nKeys, uint32_t *Keys, const char *ActionName)
34 {
35         // TODO: Duplicate detection
36         
37         // Create new structure
38         tHotkey *h = malloc(sizeof(tHotkey) + nKeys * sizeof(uint32_t) + strlen(ActionName) + 1);
39         h->nKeys = nKeys;
40         h->Target = (void*)( h->Keys + nKeys );
41         strcpy((char*)h->Target, ActionName);
42         memcpy(h->Keys, Keys, nKeys * sizeof(uint32_t));
43         
44         h->Next = NULL;
45         if( gpWM_Hotkeys )
46                 gpWM_Hotkeys->Next = h;
47         gpWM_Hotkeys = h;
48 }
49
50 void WM_Hotkey_RegisterAction(const char *ActionName, tWindow *Target, uint16_t Index)
51 {
52         // Check for a duplicate registration
53         for( tHotkeyTarget *t = gpWM_HotkeyTargets; t; t = t->Next )
54         {
55                 if( strcmp(t->Name, ActionName) != 0 )
56                         continue ;
57                 // Duplicate!
58                 return ;
59         }
60
61         // Create new structure
62         tHotkeyTarget   *t = malloc(sizeof(tHotkeyTarget) + strlen(ActionName) + 1);
63         t->Name = (void*)(t + 1);
64         strcpy((char*)t->Name, ActionName);
65         t->Window = Target;
66         t->Index = Index;
67
68         // TODO: Register to be informed when the window dies/closes?
69
70         // Append to list
71         if( gpWM_HotkeyTargets ) {
72                 gpWM_HotkeyTargets_Last->Next = t;
73         }
74         else {
75                 gpWM_HotkeyTargets = t;
76         }
77         gpWM_HotkeyTargets_Last = t;
78 }
79
80 void WM_Hotkey_KeyDown(uint32_t Scancode)
81 {
82         _SetKey(Scancode);
83         gbWM_HasBeenKeyDown = true;
84 }
85
86 void WM_Hotkey_KeyUp(uint32_t Scancode)
87 {
88         _UnsetKey(Scancode);
89
90         // Ensure that hotkeys are triggered on the longest sequence
91         // (so Win-Shift-R doesn't trigger Win-R if shift is released)
92         if( !gbWM_HasBeenKeyDown )
93                 return ;
94
95         for( tHotkey *hk = gpWM_Hotkeys; hk; hk = hk->Next )
96         {
97                 int i;
98                 for( i = 0; i < hk->nKeys; i ++ )
99                 {
100                         if( hk->Keys[i] == Scancode )   continue ;
101                         if( _IsKeySet(hk->Keys[i]) )    continue ;
102                         break;
103                 }
104                 _SysDebug("%i/%i satisfied for %s", i, hk->nKeys, hk->Target);
105                 if( i != hk->nKeys )
106                         continue ;
107                 
108                 // Fire shortcut
109                 WM_Hotkey_FireEvent(hk->Target);
110
111                 break;
112         }
113         
114         gbWM_HasBeenKeyDown = false;
115 }
116
117 void WM_Hotkey_FireEvent(const char *Target)
118 {
119 //      _SysDebug("WM_Hotkey_FireEvent: (%s)", Target);
120         // - Internal events (Alt-Tab, Close, Maximize, etc...)
121         // TODO: Internal event handling
122         
123         // - Application registered events
124         for( tHotkeyTarget *t = gpWM_HotkeyTargets, *prev=NULL; t; t = t->Next )
125         {
126                 if( strcmp(t->Name, Target) != 0 )
127                         continue ;
128
129                 struct sWndMsg_Hotkey   info = {.ID=t->Index};
130                 WM_SendMessage(NULL, t->Window, WNDMSG_HOTKEY, sizeof(info), &info);
131
132                 // Sort the list by most-recently-used
133                 if(prev != NULL) {
134                         prev->Next = t->Next;
135                         t->Next = gpWM_HotkeyTargets;
136                         gpWM_HotkeyTargets = t;
137                 }
138
139                 return ;
140         }
141 }
142
143 static void _SetKey(uint32_t sc)
144 {
145 //      _SysDebug("_SetKey: (%x)", sc);
146         if( sc >= MAX_STATE_SCANCODE )  return;
147         gWM_KeyStates[sc/8] |= 1 << (sc % 8);
148 }
149 static void _UnsetKey(uint32_t sc)
150 {
151 //      _SysDebug("_UnsetKey: (%x)", sc);
152         if( sc >= MAX_STATE_SCANCODE )  return;
153         gWM_KeyStates[sc/8] &= ~(1 << (sc % 8));
154 }
155 static int _IsKeySet(uint32_t sc)
156 {
157         if( sc >= MAX_STATE_SCANCODE )  return 0;
158
159         return !!(gWM_KeyStates[sc/8] & (1 << (sc % 8)));
160 }
161

UCC git Repository :: git.ucc.asn.au