1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
|
diff --git a/Action.c b/Action.c
index 4049a952..8bd8e13c 100644
--- a/Action.c
+++ b/Action.c
@@ -644,7 +644,7 @@ static const struct {
} helpLeft[] = {
{ .key = " #: ", .roInactive = false, .info = "hide/show header meters" },
{ .key = " Tab: ", .roInactive = false, .info = "switch to next screen tab" },
- { .key = " Arrows: ", .roInactive = false, .info = "scroll process list" },
+ { .key = " hjkl: ", .roInactive = false, .info = "scroll process list" },
{ .key = " Digits: ", .roInactive = false, .info = "incremental PID search" },
{ .key = " F3 /: ", .roInactive = false, .info = "incremental name search" },
{ .key = " F4 \\: ", .roInactive = false, .info = "incremental name filtering" },
@@ -673,7 +673,7 @@ static const struct {
{ .key = " Space: ", .roInactive = false, .info = "tag process" },
{ .key = " c: ", .roInactive = false, .info = "tag process and its children" },
{ .key = " U: ", .roInactive = false, .info = "untag all processes" },
- { .key = " F9 k: ", .roInactive = true, .info = "kill process/tagged processes" },
+ { .key = " F9 x: ", .roInactive = true, .info = "kill process/tagged processes" },
{ .key = " F7 ]: ", .roInactive = true, .info = "higher priority (root only)" },
{ .key = " F8 [: ", .roInactive = true, .info = "lower priority (+ nice)" },
#if (defined(HAVE_LIBHWLOC) || defined(HAVE_AFFINITY))
@@ -681,15 +681,15 @@ static const struct {
#endif
{ .key = " e: ", .roInactive = false, .info = "show process environment" },
{ .key = " i: ", .roInactive = true, .info = "set IO priority" },
- { .key = " l: ", .roInactive = true, .info = "list open files with lsof" },
- { .key = " x: ", .roInactive = false, .info = "list file locks of process" },
+ { .key = " L: ", .roInactive = true, .info = "list open files with lsof" },
+ { .key = " X: ", .roInactive = false, .info = "list file locks of process" },
{ .key = " s: ", .roInactive = true, .info = "trace syscalls with strace" },
{ .key = " w: ", .roInactive = false, .info = "wrap process command in multiple lines" },
#ifdef SCHEDULER_SUPPORT
{ .key = " Y: ", .roInactive = true, .info = "set scheduling policy" },
#endif
{ .key = " F2 C S: ", .roInactive = false, .info = "setup" },
- { .key = " F1 h ?: ", .roInactive = false, .info = "show this help screen" },
+ { .key = " F1 ?: ", .roInactive = false, .info = "show this help screen" },
{ .key = " F10 q: ", .roInactive = false, .info = "quit" },
{ .key = NULL, .info = NULL }
};
@@ -901,6 +901,7 @@ void Action_setBindings(Htop_Action* keys) {
keys['H'] = actionToggleUserlandThreads;
keys['I'] = actionInvertSortOrder;
keys['K'] = actionToggleKernelThreads;
+ keys['L'] = actionLsof;
keys['M'] = actionSortByMemory;
keys['N'] = actionSortByPID;
keys['O'] = actionToggleRunningInContainer;
@@ -908,6 +909,7 @@ void Action_setBindings(Htop_Action* keys) {
keys['S'] = actionSetup;
keys['T'] = actionSortByTime;
keys['U'] = actionUntagAll;
+ keys['X'] = actionShowLocks;
#ifdef SCHEDULER_SUPPORT
keys['Y'] = actionSetSchedPolicy;
#endif
@@ -920,17 +922,15 @@ void Action_setBindings(Htop_Action* keys) {
keys['a'] = actionSetAffinity;
keys['c'] = actionTagAllChildren;
keys['e'] = actionShowEnvScreen;
- keys['h'] = actionHelp;
- keys['k'] = actionKill;
- keys['l'] = actionLsof;
keys['m'] = actionToggleMergedCommand;
+ keys['o'] = actionExpandCollapseOrSortColumn;
keys['p'] = actionToggleProgramPath;
keys['q'] = actionQuit;
keys['s'] = actionStrace;
keys['t'] = actionToggleTreeView;
keys['u'] = actionFilterByUser;
keys['w'] = actionShowCommandScreen;
- keys['x'] = actionShowLocks;
+ keys['x'] = actionKill;
keys[KEY_F(1)] = actionHelp;
keys[KEY_F(2)] = actionSetup;
keys[KEY_F(3)] = actionIncSearch;
diff --git a/CategoriesPanel.c b/CategoriesPanel.c
index 64a3f062..5c225980 100644
--- a/CategoriesPanel.c
+++ b/CategoriesPanel.c
@@ -124,6 +124,12 @@ static HandlerResult CategoriesPanel_eventHandler(Panel* super, int ch) {
HandlerResult result = IGNORED;
int selected = Panel_getSelectedIndex(super);
+ switch (ch) {
+ case 'h': ch = KEY_LEFT; break;
+ case 'j': ch = KEY_DOWN; break;
+ case 'k': ch = KEY_UP; break;
+ case 'l': ch = KEY_RIGHT; break;
+ }
switch (ch) {
case EVENT_SET_SELECTED:
result = HANDLED;
diff --git a/MainPanel.c b/MainPanel.c
index 83490236..78dcb3e0 100644
--- a/MainPanel.c
+++ b/MainPanel.c
@@ -56,7 +56,7 @@ static const char* MainPanel_getValue(Panel* this, int i) {
return Row_sortKeyString(row);
}
-static HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
+HandlerResult MainPanel_eventHandler(Panel* super, int ch) {
MainPanel* this = (MainPanel*) super;
Machine* host = this->state->host;
Htop_Reaction reaction = HTOP_OK;
diff --git a/MainPanel.h b/MainPanel.h
index 105b46de..c92cac3a 100644
--- a/MainPanel.h
+++ b/MainPanel.h
@@ -49,4 +49,6 @@ void MainPanel_setFunctionBar(MainPanel* this, bool readonly);
void MainPanel_delete(Object* object);
+HandlerResult MainPanel_eventHandler(Panel* super, int ch);
+
#endif
diff --git a/Panel.c b/Panel.c
index 4784a658..5a0619ff 100644
--- a/Panel.c
+++ b/Panel.c
@@ -360,6 +360,7 @@ bool Panel_onKey(Panel* this, int key) {
switch (key) {
case KEY_DOWN:
+ case 'j':
case KEY_CTRL('N'):
#ifdef KEY_C_DOWN
case KEY_C_DOWN:
@@ -368,6 +369,7 @@ bool Panel_onKey(Panel* this, int key) {
break;
case KEY_UP:
+ case 'k':
case KEY_CTRL('P'):
#ifdef KEY_C_UP
case KEY_C_UP:
@@ -376,7 +378,7 @@ bool Panel_onKey(Panel* this, int key) {
break;
case KEY_LEFT:
- case KEY_CTRL('B'):
+ case 'h':
if (this->scrollH > 0) {
this->scrollH -= MAXIMUM(CRT_scrollHAmount, 0);
this->needsRedraw = true;
@@ -384,16 +386,28 @@ bool Panel_onKey(Panel* this, int key) {
break;
case KEY_RIGHT:
- case KEY_CTRL('F'):
+ case 'l':
this->scrollH += CRT_scrollHAmount;
this->needsRedraw = true;
break;
+ case KEY_CTRL('U'):
+ this->selected -= (this->h - 1) / 2;
+ this->needsRedraw = true;
+ break;
+
+ case KEY_CTRL('D'):
+ this->selected += (this->h - 1) / 2;
+ this->needsRedraw = true;
+ break;
+
case KEY_PPAGE:
+ case KEY_CTRL('B'):
PANEL_SCROLL(-(this->h - Panel_headerHeight(this)));
break;
case KEY_NPAGE:
+ case KEY_CTRL('F'):
PANEL_SCROLL(+(this->h - Panel_headerHeight(this)));
break;
@@ -406,10 +420,12 @@ bool Panel_onKey(Panel* this, int key) {
break;
case KEY_HOME:
+ case 'g':
this->selected = 0;
break;
case KEY_END:
+ case 'G':
this->selected = size - 1;
break;
diff --git a/ScreenManager.c b/ScreenManager.c
index e7e82e1d..eaba5ffa 100644
--- a/ScreenManager.c
+++ b/ScreenManager.c
@@ -17,6 +17,7 @@ in the source distribution for its full text.
#include "CRT.h"
#include "FunctionBar.h"
+#include "MainPanel.h"
#include "Machine.h"
#include "Macros.h"
#include "Object.h"
@@ -322,15 +323,16 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, con
continue;
}
- switch (ch) {
- case KEY_ALT('H'): ch = KEY_LEFT; break;
- case KEY_ALT('J'): ch = KEY_DOWN; break;
- case KEY_ALT('K'): ch = KEY_UP; break;
- case KEY_ALT('L'): ch = KEY_RIGHT; break;
- }
-
redraw = true;
if (Panel_eventHandlerFn(panelFocus)) {
+ if (Panel_eventHandlerFn(panelFocus) != MainPanel_eventHandler) {
+ switch (ch) {
+ case 'h': case KEY_ALT('H'): ch = KEY_LEFT; break;
+ case 'j': case KEY_ALT('J'): ch = KEY_DOWN; break;
+ case 'k': case KEY_ALT('K'): ch = KEY_UP; break;
+ case 'l': case KEY_ALT('L'): ch = KEY_RIGHT; break;
+ }
+ }
result = Panel_eventHandler(panelFocus, ch);
}
if (result & SYNTH_KEY) {
@@ -364,7 +366,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, con
continue;
}
case KEY_LEFT:
- case KEY_CTRL('B'):
+ case 'h':
if (this->panelCount < 2) {
goto defaultHandler;
}
@@ -385,7 +387,7 @@ tryLeft:
break;
case KEY_RIGHT:
- case KEY_CTRL('F'):
+ case 'l':
case 9:
if (this->panelCount < 2) {
goto defaultHandler;
diff --git a/htop.1.in b/htop.1.in
index 2376b7a5..dbc30e0a 100644
--- a/htop.1.in
+++ b/htop.1.in
@@ -100,27 +100,30 @@ The following commands are supported while in
Select the next / the previous screen tab to display.
You can enable showing the screen tab names in the Setup screen (F2).
.TP
-.B Up, Alt-k
+.B Up, k (vim patch)
Select (highlight) the previous process in the process list. Scroll the list
if necessary.
.TP
-.B Down, Alt-j
+.B Down, j (vim patch)
Select (highlight) the next process in the process list. Scroll the list if
necessary.
.TP
-.B Left, Alt-h
+.B Left, h (vim patch)
Scroll the process list left.
.TP
-.B Right, Alt-l
+.B Right, l (vim patch)
Scroll the process list right.
.TP
-.B PgUp, PgDn
+.B PgUp, Ctrl-B (vim patch), PgDn, Ctrl-F (vim patch)
Scroll the process list up or down one window.
.TP
-.B Home
+.B Ctrl-U (vim patch), Ctrl-D (vim patch)
+Scroll the process list up or down half a window.
+.TP
+.B Home, g (vim patch)
Scroll to the top of the process list and select the first process.
.TP
-.B End
+.B End, G (vim patch)
Scroll to the bottom of the process list and select the last process.
.TP
.B Ctrl-A, ^
@@ -147,7 +150,7 @@ Trace process system calls: if strace(1) is installed, pressing this key
will attach it to the currently selected process, presenting a live
update of system calls issued by the process.
.TP
-.B l
+.B L (vim patch)
Display open files for a process: if lsof(1) is installed, pressing this key
will display the list of file descriptors opened by the process.
.TP
@@ -155,10 +158,10 @@ will display the list of file descriptors opened by the process.
Display the command line of the selected process in a separate screen, wrapped
onto multiple lines as needed.
.TP
-.B x
+.B X (vim patch)
Display the active file locks of the selected process in a separate screen.
.TP
-.B F1, h, ?
+.B F1, ?
Go to the help screen
.TP
.B F2, S
@@ -189,7 +192,7 @@ between them as a tree. Toggling the key will switch between tree and
your previously selected sort view. Selecting a sort view will exit
tree view.
.TP
-.B F6, <, >
+.B F6, <, >, o (vim patch)
Selects a field for sorting, also accessible through < and >.
The current sort field is indicated by a highlight in the header.
.TP
@@ -207,7 +210,7 @@ This can only be done by the superuser.
.B Shift-F8, {
Decrease the selected process's autogroup priority (add to autogroup 'nice' value)
.TP
-.B F9, k
+.B F9, x (vim patch)
"Kill" process: sends a signal which is selected in a menu, to one or a group
of processes. If processes were tagged, sends the signal to all tagged processes.
If none is tagged, sends to the currently selected process.
@@ -219,7 +222,7 @@ Quit
Invert the sort order: if sort order is increasing, switch to decreasing, and
vice-versa.
.TP
-.B +, \-, *
+.B +, \-, *, o (vim patch)
When in tree view mode, expand or collapse subtree. When a subtree is collapsed
a "+" sign shows to the left of the process name.
Pressing "*" will expand or collapse all children of PIDs without parents, so
|