Skip to content
This repository has been archived by the owner on Jan 11, 2018. It is now read-only.

Commit

Permalink
add new keyboard_mode property that can be 'global' or 'local'.
Browse files Browse the repository at this point in the history
'local' will request the keyboard when a textarea / input[type=text] is focused.
+ (implement on_javascript_callback + on_external_host (not used))
-> 1.3 !
  • Loading branch information
tito committed Feb 6, 2013
1 parent 74dc8e2 commit fa2d38c
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 36 deletions.
171 changes: 157 additions & 14 deletions berkelium/__init__.py
Expand Up @@ -206,6 +206,16 @@ def onPaint(self):
print 'Wb(%x).onPaint()' % id(self)
self.impl.dispatch('on_paint')

def onJavascriptCallback(self, url, funcname):
if self.debug:
print 'Wb(%x).onJavascriptCallback()' % id(self)
self.impl.dispatch('on_javascript_callback', url, funcname)

def onExternalHost(self, message, origin, target):
if self.debug:
print 'Wb(%x).onExternalHost()' % id(self)
self.impl.dispatch('on_external_host', message, origin, target)


class Webbrowser(Widget):
'''Webbrowser class. See module documentation for more information.
Expand Down Expand Up @@ -241,6 +251,11 @@ class Webbrowser(Widget):
Fired when the Widget texture is updated
`on_paint`:
Fired when the texture is updated
`on_javascript_callback`:
Fired when a proxy function has been called (via
:meth:`add_bind_proxy_function_on_start_loading`)
`on_external_host`:
TBD
'''

#
Expand Down Expand Up @@ -356,12 +371,27 @@ def get_bk(self):
default to None.
'''

keyboard_mode = OptionProperty('global', options=('global', 'local'))
'''Keyboard mode to use.
The default behavior is "global": the global keyboard is binded to the
berkelium window. That's mean if you have 2 Berkelium widget, keys will be
used by both.
The other behavior is "local": the keyboard will be requested only when a
input[type="text"] will be focused. You can have more than one berkelium
window. If you're not in the input, no keys will works.
.. warning::
The keyboard_mode can be set only at the __init__() time. Any further
changes to the property will have no impact.
'''

def __init__(self, **kwargs):
_init_berkelium()

# Before doing anything, ensure the windows exist.
EventLoop.ensure_window()
EventLoop.window.bind(on_keyboard=self.on_window_keyboard)

self._touches = []
self._bk = _WindowDelegate(self, self.width, self.height,
Expand All @@ -381,6 +411,8 @@ def __init__(self, **kwargs):
self.register_event_type('on_widget_move')
self.register_event_type('on_widget_paint')
self.register_event_type('on_paint')
self.register_event_type('on_javascript_callback')
self.register_event_type('on_external_host')
super(Webbrowser, self).__init__(**kwargs)
if self.url is not None:
self.open_url(self.url)
Expand All @@ -390,19 +422,11 @@ def __init__(self, **kwargs):
self._g_rect.tex_coords = (0, 1, 1, 1, 1, 0, 0, 0)
_install_berkelium_update(self)

def on_window_keyboard(self, instance, key, scancode, text, modifiers):
# handle first special keys
if key in map(ord, ('\b', '\r', '\n', ' ')) or \
ord('a') >= key <= ord('z') or \
ord('A') >= key <= ord('Z'):
vk_code = ord(chr(key).lower())
vwmods = 0
for modifier in modifiers:
vwmods |= self._bk.modifiers.get(modifier, 0)
self._bk.keyEvent(1, vwmods, vk_code, 0)

if text is not None:
self._bk.textEvent(text)
self._keyboard = None
if self.keyboard_mode == 'global':
EventLoop.window.bind(on_keyboard=self._on_global_keyboard)
else:
self._install_local_keyboard()

def on_size(self, instance, value):
w, h = map(int, value)
Expand Down Expand Up @@ -654,6 +678,29 @@ def execute_javascript(self, string):
'''
return self._bk.executeJavascript(string)

def bind_proxy_function(self, name, sync=False):
'''Bind a JS name as a function. You get the result in the
`on_javascript_callback`
'''
self._bk.bindProxyFunction(name, sync)

def add_bind_proxy_function_on_start_loading(self, name, sync=False):
'''Same as :meth:`bind_proxy_function`, except that it will be done
every page load
'''
self._bk.addBindProxyFunctionOnStartLoading(name, sync)

def add_eval_on_start_loading(self, script):
'''Add a script to eval every page
'''
self._bk.addEvalOnStartLoading(script)

def clear_start_loading(self):
'''Clear any previous work done via :meth:`add_eval_on_start_loading`
and :meth:`add_bind_proxy_function_on_start_loading`.
'''
self._bk.clearStartLoading()

# default handlers
def on_start_loading(self, url):
pass
Expand Down Expand Up @@ -713,6 +760,102 @@ def on_widget_paint(self, _id, texture):
def on_paint(self):
self.canvas.ask_update()

def on_javascript_callback(self, url, funcname):
pass

def on_external_host(self, message, origin, target):
pass


#
# Local keyboard handlers
#

def _install_local_keyboard(self):
def _on_javascript_callback(instance, url, func):
if func == 'bk_request_keyboard':
self._request_keyboard()
return True
if func == 'bk_release_keyboard':
self._release_keyboard()
return True
self.bind(on_javascript_callback=_on_javascript_callback)
self.add_bind_proxy_function_on_start_loading('bk_request_keyboard')
self.add_bind_proxy_function_on_start_loading('bk_release_keyboard')
self.add_eval_on_start_loading('''
var _keyboard_requested = false;
function _check_keyboard_needed() {
setTimeout('_check_keyboard_needed()', 200);
var obj = document.activeElement;
if ( !obj )
return;
if (
(obj.tagName == 'INPUT' && obj.type == 'text') ||
(obj.tagName == 'TEXTAREA')
) {
if ( !_keyboard_requested ) {
bk_request_keyboard();
_keyboard_requested = true;
}
return;
}
if ( _keyboard_requested ) {
bk_release_keyboard();
_keyboard_requested = false;
}
}
_check_keyboard_needed();
''')

def _request_keyboard(self):
self._keyboard = EventLoop.window.request_keyboard(self._on_keyboard_released, self)
self._keyboard.bind(on_key_down=self._on_local_keyboard)

def _release_keyboard(self):
if not self._keyboard:
return
self._keyboard.unbind(on_key_down=self._on_local_keyboard)
self._keyboard.release()

def _on_keyboard_released(self):
self._release_keyboard()

def _on_global_keyboard(self, instance, key, scancode, text, modifiers):
# handle first special keys
if key in map(ord, ('\b', '\r', '\n', ' ')) or \
ord('a') >= key <= ord('z') or \
ord('A') >= key <= ord('Z'):
vk_code = ord(chr(key).lower())
vwmods = 0
for modifier in modifiers:
vwmods |= self._bk.modifiers.get(modifier, 0)
self._bk.focus()
self._bk.keyEvent(1, vwmods, vk_code, 0)

if text is not None:
self._bk.textEvent(text)

def _on_local_keyboard(self, instance, key, text, modifiers):
if key[0] == 27:
self.unfocus()
self._keyboard.release()
return

if key[0] in map(ord, ('\b', '\r', '\n', ' ')) or \
ord('a') >= key <= ord('z') or \
ord('A') >= key <= ord('Z'):
vk_code = ord(chr(key[0]).lower())
vwmods = 0
for modifier in modifiers:
vwmods |= self._bk.modifiers.get(modifier, 0)
self._bk.keyEvent(1, vwmods, vk_code, 0)

# needed to make the enter key working.
if key[0] == 13:
text = '\r'

if text is not None:
self._bk.textEvent(text)

class WebbrowserChildWidget(Widget):
'''WebbrowserWidget class. See module documentation for more information.
Expand Down
60 changes: 56 additions & 4 deletions berkelium/_berkelium.pyx
Expand Up @@ -52,6 +52,9 @@ cdef extern from "berkelium/StringUtil.hpp":
cdef extern from "berkelium/Window.hpp":
ctypedef char* const_wchar_ptr "const wchar_t*"
ctypedef char* wchar_t "wchar_t*"
cdef cppclass ScriptVariant "Script::Variant":
pass
ctypedef ScriptVariant ScriptVariantConst "const Script::Variant"
cdef cppclass Window "Berkelium::Window":
#int is_crashed()
void ShowRepostFormWarningDialog()
Expand Down Expand Up @@ -80,8 +83,14 @@ cdef extern from "berkelium/Window.hpp":
bool canGoForward()
void setTransparent(bool istrans)
void executeJavascript(WideString js)
void bind(WideString lvalue, ScriptVariantConst rvalue)
void addBindOnStartLoading(WideString lvalue, ScriptVariantConst rvalue)
void addEvalOnStartLoading(WideString script)
void clearStartLoading()

cdef Window *Window_create "Berkelium::Window::create"(Context *)
cdef ScriptVariant Script_Variant_bindFunction \
"Berkelium::Script::Variant::bindFunction" (WideString s, bool)

cdef extern from "berkelium/Widget.hpp":
ctypedef object _Rect "Rect"
Expand Down Expand Up @@ -136,6 +145,11 @@ cdef extern from "berkelium_wrapper.h":
ctypedef void (*tp_onWidgetPaint)(object obj, Window *win, Widget *wid, unsigned char * bitmap_in, Rect &bitmap_rect, size_t num_copy_rects, Rect *copy_rects, int dx, int dy, Rect &scroll_rect)
ctypedef void (*tp_onWidgetDestroyed)(object obj, Window *win, Widget *wid)
ctypedef void (*tp_onPaint)(object obj, Window *wini, unsigned char *bitmap_in, Rect &bitmap_rect, size_t num_copy_rects, Rect *copy_rects, int dx, int dy, Rect &scroll_rect)
ctypedef void (*tp_onJavascriptCallback)(object obj, Window *win, char *url,
int url_length, char *funcName, int funcName_length)
ctypedef void (*tp_onExternalHost)(object obj, Window *win, char *message,
int message_length, char *origin, int origin_length, char *target,
int target_length)

cdef cppclass CyWindowDelegate:
CyWindowDelegate(object obj)
Expand All @@ -161,8 +175,10 @@ cdef extern from "berkelium_wrapper.h":
tp_onWidgetResize impl_onWidgetResize
tp_onWidgetMove impl_onWidgetMove
tp_onWidgetPaint impl_onWidgetPaint
tp_onWidgetDestroyed impl_onWidgetDestroyed
tp_onWidgetDestroyed impl_onWidgetDestroyed
tp_onPaint impl_onPaint
tp_onJavascriptCallback impl_onJavascriptCallback
tp_onExternalHost impl_onExternalHost


def init(bytes berkelium_path):
Expand Down Expand Up @@ -385,6 +401,8 @@ cdef class WindowDelegate:
self.impl.impl_onWidgetPaint = <tp_onWidgetPaint>self.impl_onWidgetPaint
self.impl.impl_onWidgetDestroyed = <tp_onWidgetDestroyed>self.impl_onWidgetDestroyed
self.impl.impl_onPaint = <tp_onPaint>self.impl_onPaint
self.impl.impl_onJavascriptCallback = <tp_onJavascriptCallback>self.impl_onJavascriptCallback
self.impl.impl_onExternalHost = <tp_onExternalHost>self.impl_onExternalHost

def __init__(self, int width, int height, int usetrans):
self.scroll_buffer = <char *>malloc(width*(height+1)*4)
Expand Down Expand Up @@ -577,6 +595,14 @@ cdef class WindowDelegate:
self.needs_full_refresh = 0
self.onPaint()

cdef void impl_onJavascriptCallback(self, Window *win, char *url, int
url_length, char *funcName, int funcName_length):
self.onJavascriptCallback(url[:url_length], funcName[:funcName_length])

cdef void impl_onExternalHost(self, Window *win, char *message, int message_length, char *origin, int origin_length, char *target, int target_length):
self.onExternalHost(message[:message_length], origin[:origin_length],
target[:target_length])

#
# Default Python handlers
# XXX This could be removed, since they are all already defined in the
Expand Down Expand Up @@ -643,6 +669,12 @@ cdef class WindowDelegate:
def onPaint(self):
pass

def onJavascriptCallback(self, url, func):
pass

def onExternalHost(self, message, origin, target):
pass

#
# Public methods
#
Expand Down Expand Up @@ -749,11 +781,31 @@ cdef class WindowDelegate:
self.impl.getWindow().setTransparent(is_trans)

def executeJavascript(self, js):
cdef char *c_js = <bytes>js
cdef UTF8String u1 = UTF8String().point_to(c_js, len(js))
cdef WideString w1 = UTF8ToWide(u1)
cdef WideString w1 = self.createWideString(<bytes>js)
self.impl.getWindow().executeJavascript(w1)

def bindProxyFunction(self, name, sync=False):
cdef WideString w1 = self.createWideString(<bytes>name)
cdef ScriptVariant s1 = Script_Variant_bindFunction(w1, sync)
self.impl.getWindow().bind(w1, s1)

def addBindProxyFunctionOnStartLoading(self, name, sync=False):
cdef WideString w1 = self.createWideString(<bytes>name)
cdef ScriptVariant s1 = Script_Variant_bindFunction(w1, sync)
self.impl.getWindow().addBindOnStartLoading(w1, s1)

def addEvalOnStartLoading(self, script):
cdef WideString w1 = self.createWideString(<bytes>script)
self.impl.getWindow().addEvalOnStartLoading(w1)

def clearStartLoading(self):
self.impl.getWindow().clearStartLoading()

cdef WideString createWideString(self, bytes s):
cdef UTF8String u1 = UTF8String().point_to(s, len(s))
cdef WideString w1 = UTF8ToWide(u1)
return w1

property texture:
def __get__(self):
return self.fbo.texture
Expand Down

0 comments on commit fa2d38c

Please sign in to comment.